📄 ali5451.c
字号:
((CTRL & 0x0000000f) << 12) | (EC & 0x00000fff); outb(Channel, ALI_REG(codec, ALI_GC_CIR)); outl(ctlcmds[0], ALI_REG(codec,ALI_CSO_ALPHA_FMS)); outl(ctlcmds[1], ALI_REG(codec,ALI_LBA)); outl(ctlcmds[2], ALI_REG(codec,ALI_ESO_DELTA)); outl(ctlcmds[3], ALI_REG(codec,ALI_GVSEL_PAN_VOC_CTRL_EC)); outl(0x30000000, ALI_REG(codec, ALI_EBUF1)); /* Still Mode */ outl(0x30000000, ALI_REG(codec, ALI_EBUF2)); /* Still Mode */}static unsigned int snd_ali_convert_rate(unsigned int rate, int rec){ unsigned int delta; if (rate < 4000) rate = 4000; if (rate > 48000) rate = 48000; if (rec) { if (rate == 44100) delta = 0x116a; else if (rate == 8000) delta = 0x6000; else if (rate == 48000) delta = 0x1000; else delta = ((48000 << 12) / rate) & 0x0000ffff; } else { if (rate == 44100) delta = 0xeb3; else if (rate == 8000) delta = 0x2ab; else if (rate == 48000) delta = 0x1000; else delta = (((rate << 12) + rate) / 48000) & 0x0000ffff; } return delta;}static unsigned int snd_ali_control_mode(snd_pcm_substream_t *substream){ unsigned int CTRL; snd_pcm_runtime_t *runtime = substream->runtime; /* set ctrl mode CTRL default: 8-bit (unsigned) mono, loop mode enabled */ CTRL = 0x00000001; if (snd_pcm_format_width(runtime->format) == 16) CTRL |= 0x00000008; // 16-bit data if (!snd_pcm_format_unsigned(runtime->format)) CTRL |= 0x00000002; // signed data if (runtime->channels > 1) CTRL |= 0x00000004; // stereo data return CTRL;}/* * PCM part */static int snd_ali_ioctl(snd_pcm_substream_t * substream, unsigned int cmd, void *arg){ return snd_pcm_lib_ioctl(substream, cmd, arg);}static int snd_ali_trigger(snd_pcm_substream_t *substream, int cmd) { ali_t *codec = snd_pcm_substream_chip(substream); struct list_head *pos; snd_pcm_substream_t *s; unsigned int what, whati, capture_flag; snd_ali_voice_t *pvoice = NULL, *evoice = NULL; unsigned int val; int do_start; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: do_start = 1; break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: do_start = 0; break; default: return -EINVAL; } what = whati = capture_flag = 0; snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); if ((ali_t *) snd_pcm_substream_chip(s) == codec) { pvoice = (snd_ali_voice_t *) s->runtime->private_data; evoice = pvoice->extra; what |= 1 << (pvoice->number & 0x1f); if (evoice == NULL) { whati |= 1 << (pvoice->number & 0x1f); } else { whati |= 1 << (evoice->number & 0x1f); what |= 1 << (evoice->number & 0x1f); } 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(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_ali_voice_t *pvoice = (snd_ali_voice_t *) runtime->private_data; snd_ali_voice_t *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 == NULL) { evoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0); if (evoice == NULL) return -ENOMEM; pvoice->extra = evoice; evoice->substream = substream; } } else { if (evoice != NULL) { snd_ali_free_voice(codec, evoice); pvoice->extra = evoice = NULL; } } return 0;}static int snd_ali_playback_hw_free(snd_pcm_substream_t * substream){ ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_ali_voice_t *pvoice = (snd_ali_voice_t *) runtime->private_data; snd_ali_voice_t *evoice = pvoice ? pvoice->extra : NULL; snd_pcm_lib_free_pages(substream); if (evoice != NULL) { snd_ali_free_voice(codec, evoice); pvoice->extra = NULL; } return 0;}static int snd_ali_capture_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_ali_capture_hw_free(snd_pcm_substream_t * substream){ return snd_pcm_lib_free_pages(substream);}static int snd_ali_playback_prepare(snd_pcm_substream_t * substream){ ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_ali_voice_t *pvoice = (snd_ali_voice_t *) runtime->private_data; snd_ali_voice_t *evoice = pvoice->extra; unsigned long flags; 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_irqsave(&codec->reg_lock, flags); /* 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 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 != NULL) { 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, (unsigned int)0x7f, (unsigned int)0x3ff, CTRL, EC); } spin_unlock_irqrestore(&codec->reg_lock, flags); return 0;}static int snd_ali_capture_prepare(snd_pcm_substream_t * substream){ ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_ali_voice_t *pvoice = (snd_ali_voice_t *) runtime->private_data; unsigned long flags; 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_irqsave(&codec->reg_lock, flags); snd_ali_printk("capture_prepare...\n"); snd_ali_enable_special_channel(codec,pvoice->number); Delta = snd_ali_convert_rate(runtime->rate, 1); // Prepare capture intr channel if (pvoice->number == ALI_SPDIF_IN_CHANNEL) { unsigned int rate; if (codec->revision != ALI_5451_V02) { spin_unlock_irqrestore(&codec->reg_lock, flags); return -1; } rate = snd_ali_get_spdif_in_rate(codec); if (rate == 0) { snd_printk("ali_capture_preapre: spdif rate detect err!\n"); rate = 48000; } bValue = inb(ALI_REG(codec,ALI_SPDIF_CTRL)); if (bValue & 0x10) { outb(bValue,ALI_REG(codec,ALI_SPDIF_CTRL)); printk("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_irqrestore(&codec->reg_lock, flags); return 0;}static snd_pcm_uframes_t snd_ali_playback_pointer(snd_pcm_substream_t *substream){ ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_ali_voice_t *pvoice = (snd_ali_voice_t *) 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_capture_pointer(snd_pcm_substream_t *substream){ ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_ali_voice_t *pvoice = (snd_ali_voice_t *) runtime->private_data; unsigned int cso; unsigned long flags; spin_lock_irqsave(&codec->reg_lock, flags); if (!pvoice->running) { spin_unlock_irqrestore(&codec->reg_lock, flags); return 0; } outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR)); cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2)); spin_unlock_irqrestore(&codec->reg_lock, flags); return cso;}static snd_pcm_hardware_t 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 snd_pcm_hardware_t 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(snd_pcm_runtime_t *runtime){ unsigned long flags; snd_ali_voice_t *pvoice = (snd_ali_voice_t *) runtime->private_data; ali_t *codec; if (pvoice) { codec = pvoice->codec; spin_lock_irqsave(&codec->reg_lock, flags); snd_ali_free_voice(pvoice->codec, pvoice); spin_unlock_irqrestore(&codec->reg_lock, flags); }}static int snd_ali_playback_open(snd_pcm_substream_t * substream){ ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_ali_voice_t *pvoice; unsigned long flags = 0; spin_lock_irqsave(&codec->reg_lock, flags); pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0); if (pvoice == NULL) { spin_unlock_irqrestore(&codec->reg_lock, flags); return -EAGAIN; } pvoice->codec = codec; spin_unlock_irqrestore(&codec->reg_lock, flags); pvoice->substream = substream; runtime->private_data = pvoice; runtime->private_free = snd_ali_pcm_free_substream; runtime->hw = snd_ali_playback; 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_capture_open(snd_pcm_substream_t * substream){ ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_ali_voice_t *pvoice; unsigned long flags; spin_lock_irqsave(&codec->reg_lock, flags); pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 1); if (pvoice == NULL) { spin_unlock_irqrestore(&codec->reg_lock, flags); return -EAGAIN; } pvoice->codec = codec; spin_unlock_irqrestore(&codec->reg_lock, flags); pvoice->substream = substream; runtime->private_data = pvoice; runtime->private_free = snd_ali_pcm_free_substream; runtime->hw = snd_ali_capture; 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_close(snd_pcm_substream_t * substream){ return 0;}static int snd_ali_capture_close(snd_pcm_substream_t * substream){ ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_ali_voice_t *pvoice = (snd_ali_voice_t *) runtime->private_data; snd_ali_disable_special_channel(codec,pvoice->number); return 0;}static snd_pcm_ops_t snd_ali_playback_ops = { .open = snd_ali_playback_open, .close = snd_ali_playback_close, .ioctl = snd_ali_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 snd_pcm_ops_t snd_ali_capture_ops = { .open = snd_ali_capture_open, .close = snd_ali_capture_close, .ioctl = snd_ali_ioctl, .hw_params = snd_ali_capture_hw_params, .hw_free = snd_ali_capture_hw_free, .prepare = snd_ali_capture_prepare, .trigger = snd_ali_trigger, .pointer = snd_ali_capture_pointer,};static void snd_ali_pcm_free(snd_pcm_t *pcm){ ali_t *codec = pcm->private_data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -