📄 cs4231.c
字号:
int i; for (i = 0; i < 14; i++) if (rate == rates[i]) return freq_bits[i]; return freq_bits[13];}static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip, int format, int channels){ unsigned char rformat; rformat = CS4231_LINEAR_8; switch (format) { case SNDRV_PCM_FORMAT_MU_LAW: rformat = CS4231_ULAW_8; break; case SNDRV_PCM_FORMAT_A_LAW: rformat = CS4231_ALAW_8; break; case SNDRV_PCM_FORMAT_S16_LE: rformat = CS4231_LINEAR_16; break; case SNDRV_PCM_FORMAT_S16_BE: rformat = CS4231_LINEAR_16_BIG; break; case SNDRV_PCM_FORMAT_IMA_ADPCM: rformat = CS4231_ADPCM_16; break; } if (channels > 1) rformat |= CS4231_STEREO; return rformat;}static void snd_cs4231_calibrate_mute(struct snd_cs4231 *chip, int mute){ unsigned long flags; mute = mute ? 1 : 0; spin_lock_irqsave(&chip->lock, flags); if (chip->calibrate_mute == mute) { spin_unlock_irqrestore(&chip->lock, flags); return; } if (!mute) { snd_cs4231_dout(chip, CS4231_LEFT_INPUT, chip->image[CS4231_LEFT_INPUT]); snd_cs4231_dout(chip, CS4231_RIGHT_INPUT, chip->image[CS4231_RIGHT_INPUT]); snd_cs4231_dout(chip, CS4231_LOOPBACK, chip->image[CS4231_LOOPBACK]); } snd_cs4231_dout(chip, CS4231_AUX1_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_LEFT_INPUT]); snd_cs4231_dout(chip, CS4231_AUX1_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_RIGHT_INPUT]); snd_cs4231_dout(chip, CS4231_AUX2_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_LEFT_INPUT]); snd_cs4231_dout(chip, CS4231_AUX2_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_RIGHT_INPUT]); snd_cs4231_dout(chip, CS4231_LEFT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]); snd_cs4231_dout(chip, CS4231_RIGHT_OUTPUT, mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]); snd_cs4231_dout(chip, CS4231_LEFT_LINE_IN, mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]); snd_cs4231_dout(chip, CS4231_RIGHT_LINE_IN, mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]); snd_cs4231_dout(chip, CS4231_MONO_CTRL, mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]); chip->calibrate_mute = mute; spin_unlock_irqrestore(&chip->lock, flags);}static void snd_cs4231_playback_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, unsigned char pdfr){ unsigned long flags; mutex_lock(&chip->mce_mutex); snd_cs4231_calibrate_mute(chip, 1); snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ? (pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) : pdfr); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip); snd_cs4231_calibrate_mute(chip, 0); mutex_unlock(&chip->mce_mutex);}static void snd_cs4231_capture_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, unsigned char cdfr){ unsigned long flags; mutex_lock(&chip->mce_mutex); snd_cs4231_calibrate_mute(chip, 1); snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) { snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, ((chip->image[CS4231_PLAYBK_FORMAT]) & 0xf0) | (cdfr & 0x0f)); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip); snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); } snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip); snd_cs4231_calibrate_mute(chip, 0); mutex_unlock(&chip->mce_mutex);}/* * Timer interface */static unsigned long snd_cs4231_timer_resolution(struct snd_timer *timer){ struct snd_cs4231 *chip = snd_timer_chip(timer); return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;}static int snd_cs4231_timer_start(struct snd_timer *timer){ unsigned long flags; unsigned int ticks; struct snd_cs4231 *chip = snd_timer_chip(timer); spin_lock_irqsave(&chip->lock, flags); ticks = timer->sticks; if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 || (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] || (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) { snd_cs4231_out(chip, CS4231_TIMER_HIGH, chip->image[CS4231_TIMER_HIGH] = (unsigned char) (ticks >> 8)); snd_cs4231_out(chip, CS4231_TIMER_LOW, chip->image[CS4231_TIMER_LOW] = (unsigned char) ticks); snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | CS4231_TIMER_ENABLE); } spin_unlock_irqrestore(&chip->lock, flags); return 0;}static int snd_cs4231_timer_stop(struct snd_timer *timer){ unsigned long flags; struct snd_cs4231 *chip = snd_timer_chip(timer); spin_lock_irqsave(&chip->lock, flags); chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE; snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]); spin_unlock_irqrestore(&chip->lock, flags); return 0;}static void __init snd_cs4231_init(struct snd_cs4231 *chip){ unsigned long flags; snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE snd_printdd("init: (1)\n");#endif snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO | CS4231_RECORD_ENABLE | CS4231_RECORD_PIO | CS4231_CALIB_MODE); chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB; snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE snd_printdd("init: (2)\n");#endif snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE snd_printdd("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);#endif spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, chip->image[CS4231_ALT_FEATURE_2]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE snd_printdd("init: (4)\n");#endif snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE snd_printdd("init: (5)\n");#endif}static int snd_cs4231_open(struct snd_cs4231 *chip, unsigned int mode){ unsigned long flags; mutex_lock(&chip->open_mutex); if ((chip->mode & mode)) { mutex_unlock(&chip->open_mutex); return -EAGAIN; } if (chip->mode & CS4231_MODE_OPEN) { chip->mode |= mode; mutex_unlock(&chip->open_mutex); return 0; } /* ok. now enable and ack CODEC IRQ */ spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ | CS4231_RECORD_IRQ | CS4231_TIMER_IRQ); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); /* clear IRQ */ __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); /* clear IRQ */ snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ | CS4231_RECORD_IRQ | CS4231_TIMER_IRQ); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); spin_unlock_irqrestore(&chip->lock, flags); chip->mode = mode; mutex_unlock(&chip->open_mutex); return 0;}static void snd_cs4231_close(struct snd_cs4231 *chip, unsigned int mode){ unsigned long flags; mutex_lock(&chip->open_mutex); chip->mode &= ~mode; if (chip->mode & CS4231_MODE_OPEN) { mutex_unlock(&chip->open_mutex); return; } snd_cs4231_calibrate_mute(chip, 1); /* disable IRQ */ spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); /* clear IRQ */ __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); /* clear IRQ */ /* now disable record & playback */ if (chip->image[CS4231_IFACE_CTRL] & (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO | CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) { spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO | CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip); spin_lock_irqsave(&chip->lock, flags); } /* clear IRQ again */ snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); /* clear IRQ */ __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); /* clear IRQ */ spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_calibrate_mute(chip, 0); chip->mode = 0; mutex_unlock(&chip->open_mutex);}/* * timer open/close */static int snd_cs4231_timer_open(struct snd_timer *timer){ struct snd_cs4231 *chip = snd_timer_chip(timer); snd_cs4231_open(chip, CS4231_MODE_TIMER); return 0;}static int snd_cs4231_timer_close(struct snd_timer *timer){ struct snd_cs4231 *chip = snd_timer_chip(timer); snd_cs4231_close(chip, CS4231_MODE_TIMER); return 0;}static struct snd_timer_hardware snd_cs4231_timer_table = { .flags = SNDRV_TIMER_HW_AUTO, .resolution = 9945, .ticks = 65535, .open = snd_cs4231_timer_open, .close = snd_cs4231_timer_close, .c_resolution = snd_cs4231_timer_resolution, .start = snd_cs4231_timer_start, .stop = snd_cs4231_timer_stop,};/* * ok.. exported functions.. */static int snd_cs4231_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params){ struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); unsigned char new_pdfr; int err; err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; new_pdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) | snd_cs4231_get_rate(params_rate(hw_params)); snd_cs4231_playback_format(chip, hw_params, new_pdfr); return 0;}static int snd_cs4231_playback_prepare(struct snd_pcm_substream *substream){ struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned long flags; spin_lock_irqsave(&chip->lock, flags); chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO); BUG_ON(runtime->period_size > 0xffff + 1); chip->p_periods_sent = 0; spin_unlock_irqrestore(&chip->lock, flags); return 0;}static int snd_cs4231_capture_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params){ struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); unsigned char new_cdfr; int err; err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; new_cdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) | snd_cs4231_get_rate(params_rate(hw_params)); snd_cs4231_capture_format(chip, hw_params, new_cdfr); return 0;}static int snd_cs4231_capture_prepare(struct snd_pcm_substream *substream){ struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); unsigned long flags; spin_lock_irqsave(&chip->lock, flags); chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); chip->c_periods_sent = 0; spin_unlock_irqrestore(&chip->lock, flags); return 0;}static void snd_cs4231_overrange(struct snd_cs4231 *chip){ unsigned long flags; unsigned char res; spin_lock_irqsave(&chip->lock, flags); res = snd_cs4231_in(chip, CS4231_TEST_INIT); spin_unlock_irqrestore(&chip->lock, flags); /* detect overrange only above 0dB; may be user selectable? */ if (res & (0x08 | 0x02)) chip->capture_substream->runtime->overrange++;}static void snd_cs4231_play_callback(struct snd_cs4231 *chip){ if (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) { snd_pcm_period_elapsed(chip->playback_substream); snd_cs4231_advance_dma(&chip->p_dma, chip->playback_substream, &chip->p_periods_sent); }}static void snd_cs4231_capture_callback(struct snd_cs4231 *chip){ if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) { snd_pcm_period_elapsed(chip->capture_substream); snd_cs4231_advance_dma(&chip->c_dma, chip->capture_substream, &chip->c_periods_sent); }}static snd_pcm_uframes_t snd_cs4231_playback_pointer( struct snd_pcm_substream *substream){ struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); struct cs4231_dma_control *dma_cont = &chip->p_dma; size_t ptr; if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) return 0; ptr = dma_cont->address(dma_cont); if (ptr != 0) ptr -= substream->runtime->dma_addr; return bytes_to_frames(substream->runtime, ptr);}static snd_pcm_uframes_t snd_cs4231_capture_pointer( struct snd_pcm_substream *substream){ struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); struct cs4231_dma_control *dma_cont = &chip->c_dma; size_t ptr; if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)) return 0; ptr = dma_cont->address(dma_cont); if (ptr != 0) ptr -= substream->runtime->dma_addr; return bytes_to_frames(substream->runtime, ptr);}static int __init snd_cs4231_probe(struct snd_cs4231 *chip){ unsigned long flags; int i; int id = 0; int vers = 0; unsigned char *ptr; for (i = 0; i < 50; i++) { mb(); if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT) msleep(2); else { spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2); id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f; vers = snd_cs4231_in(chip, CS4231_VERSION); spin_unlock_irqrestore(&chip->lock, flags); if (id == 0x0a) break; /* this is valid value */ } } snd_printdd("cs4231: port = %p, id = 0x%x\n", chip->port, id); if (id != 0x0a) return -ENODEV; /* no valid device found */ spin_lock_irqsave(&chip->lock, flags); /* clear any pendings IRQ */ __cs4231_readb(chip, CS4231U(chip, STATUS)); __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); mb(); spin_unlock_irqrestore(&chip->lock, flags); chip->image[CS4231_MISC_INFO] = CS4231_MODE2; chip->image[CS4231_IFACE_CTRL] = chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA; chip->image[CS4231_ALT_FEATURE_1] = 0x80; chip->image[CS4231_ALT_FEATURE_2] = 0x01; if (vers & 0x20) chip->image[CS4231_ALT_FEATURE_2] |= 0x02; ptr = (unsigned char *) &chip->image;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -