📄 ali5451.c
字号:
if (do_start) { pvoice->running = 1; if (evoice != NULL) evoice->running = 1; } else { pvoice->running = 0; if (evoice != NULL) evoice->running = 0; } snd_pcm_trigger_done(s, substream); if (pvoice->mode) capture_flag = 1; } } spin_lock(&codec->reg_lock); if (!do_start) outl(what, ALI_REG(codec, ALI_STOP)); val = inl(ALI_REG(codec, ALI_AINTEN)); if (do_start) val |= whati; else val &= ~whati; outl(val, ALI_REG(codec, ALI_AINTEN)); if (do_start) outl(what, ALI_REG(codec, ALI_START)); snd_ali_printk("trigger: what=%xh whati=%xh\n", what, whati); spin_unlock(&codec->reg_lock); return 0;}static int snd_ali_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params){ struct snd_ali *codec = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ali_voice *pvoice = runtime->private_data; struct snd_ali_voice *evoice = pvoice->extra; int err; err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; /* voice management */ if (params_buffer_size(hw_params) / 2 != params_period_size(hw_params)) { if (!evoice) { evoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0, -1); if (!evoice) return -ENOMEM; pvoice->extra = evoice; evoice->substream = substream; } } else { if (evoice) { snd_ali_free_voice(codec, evoice); pvoice->extra = evoice = NULL; } } return 0;}static int snd_ali_playback_hw_free(struct snd_pcm_substream *substream){ struct snd_ali *codec = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ali_voice *pvoice = runtime->private_data; struct snd_ali_voice *evoice = pvoice ? pvoice->extra : NULL; snd_pcm_lib_free_pages(substream); if (evoice) { snd_ali_free_voice(codec, evoice); pvoice->extra = NULL; } return 0;}static int snd_ali_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params){ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_ali_hw_free(struct snd_pcm_substream *substream){ return snd_pcm_lib_free_pages(substream);}static int snd_ali_playback_prepare(struct snd_pcm_substream *substream){ struct snd_ali *codec = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ali_voice *pvoice = runtime->private_data; struct snd_ali_voice *evoice = pvoice->extra; unsigned int LBA; unsigned int Delta; unsigned int ESO; unsigned int CTRL; unsigned int GVSEL; unsigned int PAN; unsigned int VOL; unsigned int EC; snd_ali_printk("playback_prepare ...\n"); spin_lock_irq(&codec->reg_lock); /* set Delta (rate) value */ Delta = snd_ali_convert_rate(runtime->rate, 0); if (pvoice->number == ALI_SPDIF_IN_CHANNEL || pvoice->number == ALI_PCM_IN_CHANNEL) snd_ali_disable_special_channel(codec, pvoice->number); else if (codec->spdif_support && (inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)) & ALI_SPDIF_OUT_CH_ENABLE) && pvoice->number == ALI_SPDIF_OUT_CHANNEL) { snd_ali_set_spdif_out_rate(codec, runtime->rate); Delta = 0x1000; } /* set Loop Back Address */ LBA = runtime->dma_addr; /* set interrupt count size */ pvoice->count = runtime->period_size; /* set target ESO for channel */ pvoice->eso = runtime->buffer_size; snd_ali_printk("playback_prepare: eso=%xh count=%xh\n", pvoice->eso, pvoice->count); /* set ESO to capture first MIDLP interrupt */ ESO = pvoice->eso -1; /* set ctrl mode */ CTRL = snd_ali_control_mode(substream); GVSEL = 1; PAN = 0; VOL = 0; EC = 0; snd_ali_printk("playback_prepare:\n"); snd_ali_printk("ch=%d, Rate=%d Delta=%xh,GVSEL=%xh,PAN=%xh,CTRL=%xh\n", pvoice->number,runtime->rate,Delta,GVSEL,PAN,CTRL); snd_ali_write_voice_regs(codec, pvoice->number, LBA, 0, /* cso */ ESO, Delta, 0, /* alpha */ GVSEL, PAN, VOL, CTRL, EC); if (evoice) { evoice->count = pvoice->count; evoice->eso = pvoice->count << 1; ESO = evoice->eso - 1; snd_ali_write_voice_regs(codec, evoice->number, LBA, 0, /* cso */ ESO, Delta, 0, /* alpha */ GVSEL, 0x7f, 0x3ff, CTRL, EC); } spin_unlock_irq(&codec->reg_lock); return 0;}static int snd_ali_prepare(struct snd_pcm_substream *substream){ struct snd_ali *codec = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ali_voice *pvoice = runtime->private_data; unsigned int LBA; unsigned int Delta; unsigned int ESO; unsigned int CTRL; unsigned int GVSEL; unsigned int PAN; unsigned int VOL; unsigned int EC; u8 bValue; spin_lock_irq(&codec->reg_lock); snd_ali_printk("ali_prepare...\n"); snd_ali_enable_special_channel(codec,pvoice->number); Delta = (pvoice->number == ALI_MODEM_IN_CHANNEL || pvoice->number == ALI_MODEM_OUT_CHANNEL) ? 0x1000 : snd_ali_convert_rate(runtime->rate, pvoice->mode); /* Prepare capture intr channel */ if (pvoice->number == ALI_SPDIF_IN_CHANNEL) { unsigned int rate; spin_unlock_irq(&codec->reg_lock); if (codec->revision != ALI_5451_V02) return -1; rate = snd_ali_get_spdif_in_rate(codec); if (rate == 0) { snd_printk(KERN_WARNING "ali_capture_preapre: " "spdif rate detect err!\n"); rate = 48000; } spin_lock_irq(&codec->reg_lock); bValue = inb(ALI_REG(codec,ALI_SPDIF_CTRL)); if (bValue & 0x10) { outb(bValue,ALI_REG(codec,ALI_SPDIF_CTRL)); printk(KERN_WARNING "clear SPDIF parity error flag.\n"); } if (rate != 48000) Delta = ((rate << 12) / runtime->rate) & 0x00ffff; } /* set target ESO for channel */ pvoice->eso = runtime->buffer_size; /* set interrupt count size */ pvoice->count = runtime->period_size; /* set Loop Back Address */ LBA = runtime->dma_addr; /* set ESO to capture first MIDLP interrupt */ ESO = pvoice->eso - 1; CTRL = snd_ali_control_mode(substream); GVSEL = 0; PAN = 0x00; VOL = 0x00; EC = 0; snd_ali_write_voice_regs( codec, pvoice->number, LBA, 0, /* cso */ ESO, Delta, 0, /* alpha */ GVSEL, PAN, VOL, CTRL, EC); spin_unlock_irq(&codec->reg_lock); return 0;}static snd_pcm_uframes_tsnd_ali_playback_pointer(struct snd_pcm_substream *substream){ struct snd_ali *codec = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ali_voice *pvoice = runtime->private_data; unsigned int cso; spin_lock(&codec->reg_lock); if (!pvoice->running) { spin_unlock(&codec->reg_lock); return 0; } outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR)); cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2)); spin_unlock(&codec->reg_lock); snd_ali_printk("playback pointer returned cso=%xh.\n", cso); return cso;}static snd_pcm_uframes_t snd_ali_pointer(struct snd_pcm_substream *substream){ struct snd_ali *codec = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ali_voice *pvoice = runtime->private_data; unsigned int cso; spin_lock(&codec->reg_lock); if (!pvoice->running) { spin_unlock_irq(&codec->reg_lock); return 0; } outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR)); cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2)); spin_unlock(&codec->reg_lock); return cso;}static struct snd_pcm_hardware snd_ali_playback ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_SYNC_START), .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE), .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 4000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (256*1024), .period_bytes_min = 64, .period_bytes_max = (256*1024), .periods_min = 1, .periods_max = 1024, .fifo_size = 0,};/* * Capture support device description */static struct snd_pcm_hardware snd_ali_capture ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_SYNC_START), .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE), .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 4000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (128*1024), .period_bytes_min = 64, .period_bytes_max = (128*1024), .periods_min = 1, .periods_max = 1024, .fifo_size = 0,};static void snd_ali_pcm_free_substream(struct snd_pcm_runtime *runtime){ struct snd_ali_voice *pvoice = runtime->private_data; struct snd_ali *codec; if (pvoice) { codec = pvoice->codec; snd_ali_free_voice(pvoice->codec, pvoice); }}static int snd_ali_open(struct snd_pcm_substream *substream, int rec, int channel, struct snd_pcm_hardware *phw){ struct snd_ali *codec = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ali_voice *pvoice; pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, rec, channel); if (!pvoice) return -EAGAIN; pvoice->substream = substream; runtime->private_data = pvoice; runtime->private_free = snd_ali_pcm_free_substream; runtime->hw = *phw; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024); return 0;}static int snd_ali_playback_open(struct snd_pcm_substream *substream){ return snd_ali_open(substream, 0, -1, &snd_ali_playback);}static int snd_ali_capture_open(struct snd_pcm_substream *substream){ return snd_ali_open(substream, 1, -1, &snd_ali_capture);}static int snd_ali_playback_close(struct snd_pcm_substream *substream){ return 0;}static int snd_ali_close(struct snd_pcm_substream *substream){ struct snd_ali *codec = snd_pcm_substream_chip(substream); struct snd_ali_voice *pvoice = substream->runtime->private_data; snd_ali_disable_special_channel(codec,pvoice->number); return 0;}static struct snd_pcm_ops snd_ali_playback_ops = { .open = snd_ali_playback_open, .close = snd_ali_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_ali_playback_hw_params, .hw_free = snd_ali_playback_hw_free, .prepare = snd_ali_playback_prepare, .trigger = snd_ali_trigger, .pointer = snd_ali_playback_pointer,};static struct snd_pcm_ops snd_ali_capture_ops = { .open = snd_ali_capture_open, .close = snd_ali_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_ali_hw_params, .hw_free = snd_ali_hw_free, .prepare = snd_ali_prepare, .trigger = snd_ali_trigger, .pointer = snd_ali_pointer,};/* * Modem PCM */static int snd_ali_modem_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params){ struct snd_ali *chip = snd_pcm_substream_chip(substream); unsigned int modem_num = chip->num_of_codecs - 1; snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_RATE, params_rate(hw_params)); snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_LEVEL, 0); return snd_ali_hw_params(substream, hw_params);}static struct snd_pcm_hardware snd_ali_modem ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_SYNC_START), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), .rate_min = 8000, .rate_max = 16000, .channels_min = 1, .channels_max = 1, .buffer_bytes_max = (256*1024), .period_bytes_min = 64, .period_bytes_max = (256*1024), .periods_min = 1, .periods_max = 1024, .fifo_size = 0,};static int snd_ali_modem_open(struct snd_pcm_substream *substream, int rec, int channel){ static unsigned int rates[] = {8000, 9600, 12000, 16000}; static struct snd_pcm_hw_constraint_list hw_constraint_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; int err = snd_ali_open(substream, rec, channel, &snd_ali_modem); if (err) return err; return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates);}static int snd_ali_modem_playback_open(struct snd_pcm_substream *substream){ return snd_ali_modem_open(substream, 0, ALI_MODEM_OUT_CHANNEL);}static int snd_ali_modem_capture_open(struct snd_pcm_substream *substream){ return snd_ali_modem_open(substream, 1, ALI_MODEM_IN_CHANNEL);}static struct snd_pcm_ops snd_ali_modem_playback_ops = { .open = snd_ali_modem_playback_open, .close = snd_ali_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_ali_modem_hw_params, .hw_free = snd_ali_hw_free, .prepare = snd_ali_prepare, .trigger = snd_ali_trigger, .pointer = snd_ali_pointer,};static struct snd_pcm_ops snd_ali_modem_capture_ops = { .open = snd_ali_modem_capture_open, .close = snd_ali_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_ali_modem_hw_params, .hw_free = snd_ali_hw_free, .prepare = snd_ali_prepare, .trigger = snd_ali_trigger, .pointer = snd_ali_pointer,};struct ali_pcm_description { char *name; unsigned int playback_num; unsigned int capture_num; struct snd_pcm_ops *playback_ops; struct snd_pcm_ops *capture_ops; unsigned short class;};static void snd_ali_pcm_free(struct snd_pcm *pcm){ struct snd_ali *codec = pcm->private_data; codec->pcm[pcm->device] = NULL;}static int __devinit snd_ali_pcm(struct snd_ali * codec, int device, struct ali_pcm_description *desc){ struct snd_pcm *pcm; int err; err = snd_pcm_new(codec->card, desc->name, device, desc->playback_num, desc->capture_num, &pcm); if (err < 0) { snd_printk(KERN_ERR "snd_ali_pcm: err called snd_pcm_new.\n"); return err; } pcm->private_data = codec; pcm->private_free = snd_ali_pcm_free; if (desc->playback_ops) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, desc->playback_ops); if (desc->capture_ops) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, desc->capture_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(codec->pci), 64*1024, 128*1024); pcm->info_flags = 0; pcm->dev_class = desc->class; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; strcpy(pcm->name, desc->name); codec->pcm[0] = pcm; return 0;}static struct ali_pcm_description ali_pcms[] = { { .name = "ALI 5451", .playback_num = ALI_CHANNELS, .capture_num = 1, .playback_ops = &snd_ali_playback_ops, .capture_ops = &snd_ali_capture_ops }, { .name = "ALI 5451 modem", .playback_num = 1, .capture_num = 1, .playback_ops = &snd_ali_modem_playback_ops, .capture_ops = &snd_ali_modem_capture_ops, .class = SNDRV_PCM_CLASS_MODEM }};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -