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

📄 cs4231_lib.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
static unsigned char snd_cs4231_get_rate(unsigned int rate){	int i;	for (i = 0; i < 14; i++)		if (rate == rates[i])			return freq_bits[i];	// snd_BUG();	return freq_bits[13];}static unsigned char snd_cs4231_get_format(cs4231_t *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;#if 0	snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);#endif	return rformat;}static void snd_cs4231_calibrate_mute(cs4231_t *chip, int mute){	unsigned long flags;	mute = mute ? 1 : 0;	spin_lock_irqsave(&chip->reg_lock, flags);	if (chip->calibrate_mute == mute) {		spin_unlock_irqrestore(&chip->reg_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]);	if (chip->hardware == CS4231_HW_INTERWAVE) {		snd_cs4231_dout(chip, CS4231_LEFT_MIC_INPUT, mute ? 0x80 : chip->image[CS4231_LEFT_MIC_INPUT]);		snd_cs4231_dout(chip, CS4231_RIGHT_MIC_INPUT, mute ? 0x80 : chip->image[CS4231_RIGHT_MIC_INPUT]);				snd_cs4231_dout(chip, CS4231_LINE_LEFT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LINE_LEFT_OUTPUT]);		snd_cs4231_dout(chip, CS4231_LINE_RIGHT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LINE_RIGHT_OUTPUT]);	}	chip->calibrate_mute = mute;	spin_unlock_irqrestore(&chip->reg_lock, flags);}static void snd_cs4231_playback_format(cs4231_t *chip,				       snd_pcm_hw_params_t *params,				       unsigned char pdfr){	unsigned long flags;	int full_calib = 1;	down(&chip->mce_mutex);	snd_cs4231_calibrate_mute(chip, 1);	if (chip->hardware == CS4231_HW_CS4231A ||	    (chip->hardware & CS4231_HW_CS4232_MASK)) {		spin_lock_irqsave(&chip->reg_lock, flags);		if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (pdfr & 0x0f)) {	/* rate is same? */			snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10);			snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr);			snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~0x10);			udelay(100); /* Fixes audible clicks at least on GUS MAX */			full_calib = 0;		}		spin_unlock_irqrestore(&chip->reg_lock, flags);	}	if (full_calib) {		snd_cs4231_mce_up(chip);		spin_lock_irqsave(&chip->reg_lock, flags);		if (chip->hardware != CS4231_HW_INTERWAVE && !chip->single_dma) {			snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,					(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ?					(pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) :				        pdfr);		} else {			snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr);		}		spin_unlock_irqrestore(&chip->reg_lock, flags);		snd_cs4231_mce_down(chip);	}	snd_cs4231_calibrate_mute(chip, 0);	up(&chip->mce_mutex);}static void snd_cs4231_capture_format(cs4231_t *chip,				      snd_pcm_hw_params_t *params,                                      unsigned char cdfr){	unsigned long flags;	int full_calib = 1;	down(&chip->mce_mutex);	snd_cs4231_calibrate_mute(chip, 1);	if (chip->hardware == CS4231_HW_CS4231A ||	    (chip->hardware & CS4231_HW_CS4232_MASK)) {		spin_lock_irqsave(&chip->reg_lock, flags);		if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (cdfr & 0x0f) ||	/* rate is same? */		    (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {			snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x20);			snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT] = cdfr);			snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~0x20);			full_calib = 0;		}		spin_unlock_irqrestore(&chip->reg_lock, flags);	}	if (full_calib) {		snd_cs4231_mce_up(chip);		spin_lock_irqsave(&chip->reg_lock, flags);		if (chip->hardware != CS4231_HW_INTERWAVE) {			if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {				snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,					       ((chip->single_dma ? cdfr : chip->image[CS4231_PLAYBK_FORMAT]) & 0xf0) |					       (cdfr & 0x0f));				spin_unlock_irqrestore(&chip->reg_lock, flags);				snd_cs4231_mce_down(chip);				snd_cs4231_mce_up(chip);				spin_lock_irqsave(&chip->reg_lock, flags);			}		}		snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr);		spin_unlock_irqrestore(&chip->reg_lock, flags);		snd_cs4231_mce_down(chip);	}	snd_cs4231_calibrate_mute(chip, 0);	up(&chip->mce_mutex);}/* *  Timer interface */static unsigned long snd_cs4231_timer_resolution(snd_timer_t * timer){	cs4231_t *chip = snd_timer_chip(timer);	if (chip->hardware & CS4231_HW_CS4236B_MASK)		return 14467;	else		return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;}static int snd_cs4231_timer_start(snd_timer_t * timer){	unsigned long flags;	unsigned int ticks;	cs4231_t *chip = snd_timer_chip(timer);	spin_lock_irqsave(&chip->reg_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->reg_lock, flags);	return 0;}static int snd_cs4231_timer_stop(snd_timer_t * timer){	unsigned long flags;	cs4231_t *chip = snd_timer_chip(timer);	spin_lock_irqsave(&chip->reg_lock, flags);	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE);	spin_unlock_irqrestore(&chip->reg_lock, flags);	return 0;}static void snd_cs4231_init(cs4231_t *chip){	unsigned long flags;	snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE	snd_printk("init: (1)\n");#endif	snd_cs4231_mce_up(chip);	spin_lock_irqsave(&chip->reg_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->reg_lock, flags);	snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE	snd_printk("init: (2)\n");#endif	snd_cs4231_mce_up(chip);	spin_lock_irqsave(&chip->reg_lock, flags);	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);	spin_unlock_irqrestore(&chip->reg_lock, flags);	snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE	snd_printk("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);#endif	spin_lock_irqsave(&chip->reg_lock, flags);	snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, chip->image[CS4231_ALT_FEATURE_2]);	spin_unlock_irqrestore(&chip->reg_lock, flags);	snd_cs4231_mce_up(chip);	spin_lock_irqsave(&chip->reg_lock, flags);	snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT]);	spin_unlock_irqrestore(&chip->reg_lock, flags);	snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE	snd_printk("init: (4)\n");#endif	snd_cs4231_mce_up(chip);	spin_lock_irqsave(&chip->reg_lock, flags);	snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]);	spin_unlock_irqrestore(&chip->reg_lock, flags);	snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE	snd_printk("init: (5)\n");#endif}static int snd_cs4231_open(cs4231_t *chip, unsigned int mode){	unsigned long flags;	down(&chip->open_mutex);	if ((chip->mode & mode) ||	    ((chip->mode & CS4231_MODE_OPEN) && chip->single_dma)) {		up(&chip->open_mutex);		return -EAGAIN;	}	if (chip->mode & CS4231_MODE_OPEN) {		chip->mode |= mode;		up(&chip->open_mutex);		return 0;	}	/* ok. now enable and ack CODEC IRQ */	spin_lock_irqsave(&chip->reg_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_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */	chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE;	snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);	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->reg_lock, flags);	chip->mode = mode;	up(&chip->open_mutex);	return 0;}static void snd_cs4231_close(cs4231_t *chip, unsigned int mode){	unsigned long flags;	down(&chip->open_mutex);	chip->mode &= ~mode;	if (chip->mode & CS4231_MODE_OPEN) {		up(&chip->open_mutex);		return;	}	snd_cs4231_calibrate_mute(chip, 1);	/* disable IRQ */	spin_lock_irqsave(&chip->reg_lock, flags);	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */	chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE;	snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);	/* 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->reg_lock, flags);		snd_cs4231_mce_up(chip);		spin_lock_irqsave(&chip->reg_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->reg_lock, flags);		snd_cs4231_mce_down(chip);		spin_lock_irqsave(&chip->reg_lock, flags);	}	/* clear IRQ again */	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */	spin_unlock_irqrestore(&chip->reg_lock, flags);	snd_cs4231_calibrate_mute(chip, 0);	chip->mode = 0;	up(&chip->open_mutex);}/* *  timer open/close */static int snd_cs4231_timer_open(snd_timer_t * timer){	cs4231_t *chip = snd_timer_chip(timer);	snd_cs4231_open(chip, CS4231_MODE_TIMER);	return 0;}static int snd_cs4231_timer_close(snd_timer_t * timer){	cs4231_t *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(snd_pcm_substream_t * substream,					 snd_pcm_hw_params_t * hw_params){	cs4231_t *chip = snd_pcm_substream_chip(substream);	unsigned char new_pdfr;	int err;	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 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));	chip->set_playback_format(chip, hw_params, new_pdfr);	return 0;}static int snd_cs4231_playback_hw_free(snd_pcm_substream_t * substream){	return snd_pcm_lib_free_pages(substream);}#ifdef LEGACY_SUPPORTstatic int snd_cs4231_playback_prepare(snd_pcm_substream_t * substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	unsigned long flags;	unsigned int size = snd_pcm_lib_buffer_bytes(substream);	unsigned int count = snd_pcm_lib_period_bytes(substream);	spin_lock_irqsave(&chip->reg_lock, flags);	chip->p_dma_size = size;	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO);	snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);	count = snd_cs4231_get_count(chip->image[CS4231_PLAYBK_FORMAT], count) - 1;	snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);	snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));	spin_unlock_irqrestore(&chip->reg_lock, flags);#if 0	snd_cs4231_debug(chip);#endif	return 0;}#endif /* LEGACY_SUPPORT */static int snd_cs4231_capture_hw_params(snd_pcm_substream_t * substream,					snd_pcm_hw_params_t * hw_params){	cs4231_t *chip = snd_pcm_substream_chip(substream);	unsigned char new_cdfr;	int err;	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 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));	chip->set_capture_format(chip, hw_params, new_cdfr);	return 0;}static int snd_cs4231_capture_hw_free(snd_pcm_substream_t * substream){	return snd_pcm_lib_free_pages(substream);}#ifdef LEGACY_SUPPORTstatic int snd_cs4231_capture_prepare(snd_pcm_substream_t * substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	unsigned long flags;	unsigned int size = snd_pcm_lib_buffer_bytes(substream);	unsigned int count = snd_pcm_lib_period_bytes(substream);	spin_lock_irqsave(&chip->reg_lock, flags);	chip->c_dma_size = size;	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);	snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);	count = snd_cs4231_get_count(chip->image[CS4231_REC_FORMAT], count) - 1;	if (chip->single_dma && chip->hardware != CS4231_HW_INTERWAVE) {		snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);		snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));	} else {		snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (unsigned char) count);		snd_cs4231_out(chip, CS4231_REC_UPR_CNT, (unsigned char) (count >> 8));	}	spin_unlock_irqrestore(&chip->reg_lock, flags);	return 0;}#endifstatic void snd_cs4231_overrange(cs4231_t *chip){	unsigned long flags;	unsigned char res;	spin_lock_irqsave(&chip->reg_lock, flags);	res = snd_cs4231_in(chip, CS4231_TEST_INIT);	spin_unlock_irqrestore(&chip->reg_lock, flags);	if (res & (0x08 | 0x02))	/* detect overrange only above 0dB; may be user selectable? */		chip->capture_substream->runtime->overrange++;}irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs){	cs4231_t *chip = dev_id;	unsigned char status;	status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);	if (status & CS4231_TIMER_IRQ) {		if (chip->timer)			snd_timer_interrupt(chip->timer, chip->timer->sticks);	}			if (chip->single_dma && chip->hardware != CS4231_HW_INTERWAVE) {		if (status & CS4231_PLAYBACK_IRQ) {			if (chip->mode & CS4231_MODE_PLAY) {				if (chip->playback_substream)					snd_pcm_period_elapsed(chip->playback_substream);			}			if (chip->mode & CS4231_MODE_RECORD) {				if (chip->capture_substream) {					snd_cs4231_overrange(chip);					snd_pcm_period_elapsed(chip->capture_substream);				}			}		}	} else {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -