⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cs4231.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	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 + -