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

📄 cs46xx_lib.c

📁 h内核
💻 C
📖 第 1 页 / 共 5 页
字号:
	for (idx = 0; idx < 0xFF; idx++) {		/*		 *  Make sure the previous FIFO write operation has completed.		 */		if (cs46xx_wait_for_fifo(chip,1)) {			snd_printdd ("failed waiting for FIFO at addr (%02X)\n",idx);			if (powerdown)				snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp);          			break;		}		/*		 *  Write the serial port FIFO index.		 */		snd_cs46xx_pokeBA0(chip, BA0_SERBAD, idx);		/*		 *  Tell the serial port to load the new value into the FIFO location.		 */		snd_cs46xx_pokeBA0(chip, BA0_SERBCM, SERBCM_WRC);	}	/*	 *  Now, if we powered up the devices, then power them back down again.	 *  This is kinda ugly, but should never happen.	 */	if (powerdown)		snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp);}static void snd_cs46xx_proc_start(cs46xx_t *chip){	int cnt;	/*	 *  Set the frame timer to reflect the number of cycles per frame.	 */	snd_cs46xx_poke(chip, BA1_FRMT, 0xadf);	/*	 *  Turn on the run, run at frame, and DMA enable bits in the local copy of	 *  the SP control register.	 */	snd_cs46xx_poke(chip, BA1_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN);	/*	 *  Wait until the run at frame bit resets itself in the SP control	 *  register.	 */	for (cnt = 0; cnt < 25; cnt++) {		udelay(50);		if (!(snd_cs46xx_peek(chip, BA1_SPCR) & SPCR_RUNFR))			break;	}	if (snd_cs46xx_peek(chip, BA1_SPCR) & SPCR_RUNFR)		snd_printk("SPCR_RUNFR never reset\n");}static void snd_cs46xx_proc_stop(cs46xx_t *chip){	/*	 *  Turn off the run, run at frame, and DMA enable bits in the local copy of	 *  the SP control register.	 */	snd_cs46xx_poke(chip, BA1_SPCR, 0);}/* *  Sample rate routines */#define GOF_PER_SEC 200static void snd_cs46xx_set_play_sample_rate(cs46xx_t *chip, unsigned int rate){	unsigned long flags;	unsigned int tmp1, tmp2;	unsigned int phiIncr;	unsigned int correctionPerGOF, correctionPerSec;	/*	 *  Compute the values used to drive the actual sample rate conversion.	 *  The following formulas are being computed, using inline assembly	 *  since we need to use 64 bit arithmetic to compute the values:	 *	 *  phiIncr = floor((Fs,in * 2^26) / Fs,out)	 *  correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /         *                                   GOF_PER_SEC)         *  ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M         *                       GOF_PER_SEC * correctionPerGOF	 *	 *  i.e.	 *	 *  phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)	 *  correctionPerGOF:correctionPerSec =	 *      dividend:remainder(ulOther / GOF_PER_SEC)	 */	tmp1 = rate << 16;	phiIncr = tmp1 / 48000;	tmp1 -= phiIncr * 48000;	tmp1 <<= 10;	phiIncr <<= 10;	tmp2 = tmp1 / 48000;	phiIncr += tmp2;	tmp1 -= tmp2 * 48000;	correctionPerGOF = tmp1 / GOF_PER_SEC;	tmp1 -= correctionPerGOF * GOF_PER_SEC;	correctionPerSec = tmp1;	/*	 *  Fill in the SampleRateConverter control block.	 */	spin_lock_irqsave(&chip->reg_lock, flags);	snd_cs46xx_poke(chip, BA1_PSRC,	  ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));	snd_cs46xx_poke(chip, BA1_PPI, phiIncr);	spin_unlock_irqrestore(&chip->reg_lock, flags);}static void snd_cs46xx_set_capture_sample_rate(cs46xx_t *chip, unsigned int rate){	unsigned long flags;	unsigned int phiIncr, coeffIncr, tmp1, tmp2;	unsigned int correctionPerGOF, correctionPerSec, initialDelay;	unsigned int frameGroupLength, cnt;	/*	 *  We can only decimate by up to a factor of 1/9th the hardware rate.	 *  Correct the value if an attempt is made to stray outside that limit.	 */	if ((rate * 9) < 48000)		rate = 48000 / 9;	/*	 *  We can not capture at at rate greater than the Input Rate (48000).	 *  Return an error if an attempt is made to stray outside that limit.	 */	if (rate > 48000)		rate = 48000;	/*	 *  Compute the values used to drive the actual sample rate conversion.	 *  The following formulas are being computed, using inline assembly	 *  since we need to use 64 bit arithmetic to compute the values:	 *	 *     coeffIncr = -floor((Fs,out * 2^23) / Fs,in)	 *     phiIncr = floor((Fs,in * 2^26) / Fs,out)	 *     correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /	 *                                GOF_PER_SEC)	 *     correctionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -	 *                          GOF_PER_SEC * correctionPerGOF	 *     initialDelay = ceil((24 * Fs,in) / Fs,out)	 *	 * i.e.	 *	 *     coeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in))	 *     phiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out)	 *     correctionPerGOF:correctionPerSec =	 * 	    dividend:remainder(ulOther / GOF_PER_SEC)	 *     initialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out)	 */	tmp1 = rate << 16;	coeffIncr = tmp1 / 48000;	tmp1 -= coeffIncr * 48000;	tmp1 <<= 7;	coeffIncr <<= 7;	coeffIncr += tmp1 / 48000;	coeffIncr ^= 0xFFFFFFFF;	coeffIncr++;	tmp1 = 48000 << 16;	phiIncr = tmp1 / rate;	tmp1 -= phiIncr * rate;	tmp1 <<= 10;	phiIncr <<= 10;	tmp2 = tmp1 / rate;	phiIncr += tmp2;	tmp1 -= tmp2 * rate;	correctionPerGOF = tmp1 / GOF_PER_SEC;	tmp1 -= correctionPerGOF * GOF_PER_SEC;	correctionPerSec = tmp1;	initialDelay = ((48000 * 24) + rate - 1) / rate;	/*	 *  Fill in the VariDecimate control block.	 */	spin_lock_irqsave(&chip->reg_lock, flags);	snd_cs46xx_poke(chip, BA1_CSRC,		((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));	snd_cs46xx_poke(chip, BA1_CCI, coeffIncr);	snd_cs46xx_poke(chip, BA1_CD,		(((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80);	snd_cs46xx_poke(chip, BA1_CPI, phiIncr);	spin_unlock_irqrestore(&chip->reg_lock, flags);	/*	 *  Figure out the frame group length for the write back task.  Basically,	 *  this is just the factors of 24000 (2^6*3*5^3) that are not present in	 *  the output sample rate.	 */	frameGroupLength = 1;	for (cnt = 2; cnt <= 64; cnt *= 2) {		if (((rate / cnt) * cnt) != rate)			frameGroupLength *= 2;	}	if (((rate / 3) * 3) != rate) {		frameGroupLength *= 3;	}	for (cnt = 5; cnt <= 125; cnt *= 5) {		if (((rate / cnt) * cnt) != rate) 			frameGroupLength *= 5;        }	/*	 * Fill in the WriteBack control block.	 */	spin_lock_irqsave(&chip->reg_lock, flags);	snd_cs46xx_poke(chip, BA1_CFG1, frameGroupLength);	snd_cs46xx_poke(chip, BA1_CFG2, (0x00800000 | frameGroupLength));	snd_cs46xx_poke(chip, BA1_CCST, 0x0000FFFF);	snd_cs46xx_poke(chip, BA1_CSPB, ((65536 * rate) / 24000));	snd_cs46xx_poke(chip, (BA1_CSPB + 4), 0x0000FFFF);	spin_unlock_irqrestore(&chip->reg_lock, flags);}/* *  PCM part */static void snd_cs46xx_pb_trans_copy(snd_pcm_substream_t *substream,				     snd_pcm_indirect_t *rec, size_t bytes){	snd_pcm_runtime_t *runtime = substream->runtime;	cs46xx_pcm_t * cpcm = runtime->private_data;	memcpy(cpcm->hw_buf.area + rec->hw_data, runtime->dma_area + rec->sw_data, bytes);}static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime = substream->runtime;	cs46xx_pcm_t * cpcm = runtime->private_data;	snd_pcm_indirect_playback_transfer(substream, &cpcm->pcm_rec, snd_cs46xx_pb_trans_copy);	return 0;}static void snd_cs46xx_cp_trans_copy(snd_pcm_substream_t *substream,				     snd_pcm_indirect_t *rec, size_t bytes){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	memcpy(runtime->dma_area + rec->sw_data,	       chip->capt.hw_buf.area + rec->hw_data, bytes);}static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_indirect_capture_transfer(substream, &chip->capt.pcm_rec, snd_cs46xx_cp_trans_copy);	return 0;}static snd_pcm_uframes_t snd_cs46xx_playback_direct_pointer(snd_pcm_substream_t * substream){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	size_t ptr;	cs46xx_pcm_t *cpcm = substream->runtime->private_data;	snd_assert (cpcm->pcm_channel,return -ENXIO);#ifdef CONFIG_SND_CS46XX_NEW_DSP	ptr = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 2) << 2);#else	ptr = snd_cs46xx_peek(chip, BA1_PBA);#endif	ptr -= cpcm->hw_buf.addr;	return ptr >> cpcm->shift;}static snd_pcm_uframes_t snd_cs46xx_playback_indirect_pointer(snd_pcm_substream_t * substream){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	size_t ptr;	cs46xx_pcm_t *cpcm = substream->runtime->private_data;#ifdef CONFIG_SND_CS46XX_NEW_DSP	snd_assert (cpcm->pcm_channel,return -ENXIO);	ptr = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 2) << 2);#else	ptr = snd_cs46xx_peek(chip, BA1_PBA);#endif	ptr -= cpcm->hw_buf.addr;	return snd_pcm_indirect_playback_pointer(substream, &cpcm->pcm_rec, ptr);}static snd_pcm_uframes_t snd_cs46xx_capture_direct_pointer(snd_pcm_substream_t * substream){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_buf.addr;	return ptr >> chip->capt.shift;}static snd_pcm_uframes_t snd_cs46xx_capture_indirect_pointer(snd_pcm_substream_t * substream){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_buf.addr;	return snd_pcm_indirect_capture_pointer(substream, &chip->capt.pcm_rec, ptr);}static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,				       int cmd){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	/*snd_pcm_runtime_t *runtime = substream->runtime;*/	int result = 0;#ifdef CONFIG_SND_CS46XX_NEW_DSP	cs46xx_pcm_t *cpcm = substream->runtime->private_data;	if (! cpcm->pcm_channel) {		return -ENXIO;	}#endif	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_RESUME:#ifdef CONFIG_SND_CS46XX_NEW_DSP		/* magic value to unmute PCM stream  playback volume */		snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 				       SCBVolumeCtrl) << 2, 0x80008000);		if (cpcm->pcm_channel->unlinked)			cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel);		if (substream->runtime->periods != CS46XX_FRAGS)			snd_cs46xx_playback_transfer(substream);#else		spin_lock(&chip->reg_lock);		if (substream->runtime->periods != CS46XX_FRAGS)			snd_cs46xx_playback_transfer(substream);		{ unsigned int tmp;		tmp = snd_cs46xx_peek(chip, BA1_PCTL);		tmp &= 0x0000ffff;		snd_cs46xx_poke(chip, BA1_PCTL, chip->play_ctl | tmp);		}		spin_unlock(&chip->reg_lock);#endif		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_SUSPEND:#ifdef CONFIG_SND_CS46XX_NEW_DSP		/* magic mute channel */		snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 				       SCBVolumeCtrl) << 2, 0xffffffff);		if (!cpcm->pcm_channel->unlinked)			cs46xx_dsp_pcm_unlink(chip,cpcm->pcm_channel);#else		spin_lock(&chip->reg_lock);		{ unsigned int tmp;		tmp = snd_cs46xx_peek(chip, BA1_PCTL);		tmp &= 0x0000ffff;		snd_cs46xx_poke(chip, BA1_PCTL, tmp);		}		spin_unlock(&chip->reg_lock);#endif		break;	default:		result = -EINVAL;		break;	}	return result;}static int snd_cs46xx_capture_trigger(snd_pcm_substream_t * substream,				      int cmd){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	unsigned int tmp;	int result = 0;	spin_lock(&chip->reg_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_RESUME:		tmp = snd_cs46xx_peek(chip, BA1_CCTL);		tmp &= 0xffff0000;		snd_cs46xx_poke(chip, BA1_CCTL, chip->capt.ctl | tmp);		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_SUSPEND:		tmp = snd_cs46xx_peek(chip, BA1_CCTL);		tmp &= 0xffff0000;		snd_cs46xx_poke(chip, BA1_CCTL, tmp);		break;	default:		result = -EINVAL;		break;	}	spin_unlock(&chip->reg_lock);	return result;}#ifdef CONFIG_SND_CS46XX_NEW_DSPstatic int _cs46xx_adjust_sample_rate (cs46xx_t *chip, cs46xx_pcm_t *cpcm,				       int sample_rate) {	/* If PCMReaderSCB and SrcTaskSCB not created yet ... */	if ( cpcm->pcm_channel == NULL) {		cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, 								   cpcm, cpcm->hw_buf.addr,cpcm->pcm_channel_id);		if (cpcm->pcm_channel == NULL) {			snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n");			return -ENOMEM;		}		cpcm->pcm_channel->sample_rate = sample_rate;	} else	/* if sample rate is changed */	if ((int)cpcm->pcm_channel->sample_rate != sample_rate) {		int unlinked = cpcm->pcm_channel->unlinked;		cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel);		if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm, 									 cpcm->hw_buf.addr,									 cpcm->pcm_channel_id)) == NULL) {			snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n");			return -ENOMEM;		}		if (!unlinked) cs46xx_dsp_pcm_link (chip,cpcm->pcm_channel);		cpcm->pcm_channel->sample_rate = sample_rate;	}	return 0;}#endifstatic int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,					 snd_pcm_hw_params_t * hw_params){	snd_pcm_runtime_t *runtime = substream->runtime;	cs46xx_pcm_t *cpcm;	int err;#ifdef CONFIG_SND_CS46XX_NEW_DSP	cs46xx_t *chip = snd_pcm_substream_chip(substream);	int sample_rate = params_rate(hw_params);	int period_size = params_period_bytes(hw_params);#endif	cpcm = runtime->private_data;#ifdef CONFIG_SND_CS46XX_NEW_DSP	snd_assert (sample_rate != 0, return -ENXIO);	down (&chip->spos_mutex);	if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) {		up (&chip->spos_mutex);		return -ENXIO;	}

⌨️ 快捷键说明

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