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

📄 cs46xx_lib.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 5 页
字号:
}/* *  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 int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream, 					snd_pcm_uframes_t frames){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	snd_pcm_sframes_t diff = runtime->control->appl_ptr - chip->play.appl_ptr;	if (diff) {		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))			diff += runtime->boundary;		chip->play.sw_ready += diff << chip->play.shift;	}	chip->play.sw_ready += frames << chip->play.shift;	chip->play.appl_ptr = runtime->control->appl_ptr + frames;	while (chip->play.hw_ready < CS46XX_BUFFER_SIZE && 	       chip->play.sw_ready > 0) {		size_t hw_to_end = CS46XX_BUFFER_SIZE - chip->play.hw_data;		size_t sw_to_end = chip->play.sw_bufsize - chip->play.sw_data;		size_t bytes = CS46XX_BUFFER_SIZE - chip->play.hw_ready;		if (chip->play.sw_ready < bytes)			bytes = chip->play.sw_ready;		if (hw_to_end < bytes)			bytes = hw_to_end;		if (sw_to_end < bytes)			bytes = sw_to_end;		memcpy(chip->play.hw_area + chip->play.hw_data,		       runtime->dma_area + chip->play.sw_data,		       bytes);		chip->play.hw_data += bytes;		if (chip->play.hw_data == CS46XX_BUFFER_SIZE)			chip->play.hw_data = 0;		chip->play.sw_data += bytes;		if (chip->play.sw_data == chip->play.sw_bufsize)			chip->play.sw_data = 0;		chip->play.hw_ready += bytes;		chip->play.sw_ready -= bytes;	}	return 0;}static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream, 				       snd_pcm_uframes_t frames){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	snd_pcm_sframes_t diff = runtime->control->appl_ptr - chip->capt.appl_ptr;	if (diff) {		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))			diff += runtime->boundary;		chip->capt.sw_ready -= diff << chip->capt.shift;	}	chip->capt.sw_ready -= frames << chip->capt.shift;	chip->capt.appl_ptr = runtime->control->appl_ptr + frames;	while (chip->capt.hw_ready > 0 && 	       chip->capt.sw_ready < chip->capt.sw_bufsize) {		size_t hw_to_end = CS46XX_BUFFER_SIZE - chip->capt.hw_data;		size_t sw_to_end = chip->capt.sw_bufsize - chip->capt.sw_data;		size_t bytes = chip->capt.sw_bufsize - chip->capt.sw_ready;		if (chip->capt.hw_ready < bytes)			bytes = chip->capt.hw_ready;		if (hw_to_end < bytes)			bytes = hw_to_end;		if (sw_to_end < bytes)			bytes = sw_to_end;		memcpy(runtime->dma_area + chip->capt.sw_data,		       chip->capt.hw_area + chip->capt.hw_data,		       bytes);		chip->capt.hw_data += bytes;		if (chip->capt.hw_data == CS46XX_BUFFER_SIZE)			chip->capt.hw_data = 0;		chip->capt.sw_data += bytes;		if (chip->capt.sw_data == chip->capt.sw_bufsize)			chip->capt.sw_data = 0;		chip->capt.hw_ready -= bytes;		chip->capt.sw_ready += bytes;	}	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 = snd_cs46xx_peek(chip, BA1_PBA) - chip->play.hw_addr;	return ptr >> chip->play.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 = snd_cs46xx_peek(chip, BA1_PBA) - chip->play.hw_addr;	ssize_t bytes = ptr - chip->play.hw_io;	if (bytes < 0)		bytes += CS46XX_BUFFER_SIZE;	chip->play.hw_io = ptr;	chip->play.hw_ready -= bytes;	chip->play.sw_io += bytes;	if (chip->play.sw_io > chip->play.sw_bufsize)		chip->play.sw_io -= chip->play.sw_bufsize;	snd_cs46xx_playback_transfer(substream, 0);	return chip->play.sw_io >> chip->play.shift;}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_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_addr;	ssize_t bytes = ptr - chip->capt.hw_io;	if (bytes < 0)		bytes += CS46XX_BUFFER_SIZE;	chip->capt.hw_io = ptr;	chip->capt.hw_ready += bytes;	chip->capt.sw_io += bytes;	if (chip->capt.sw_io > chip->capt.sw_bufsize)		chip->capt.sw_io -= chip->capt.sw_bufsize;	snd_cs46xx_capture_transfer(substream, 0);	return chip->capt.sw_io >> chip->capt.shift;}static int snd_cs46xx_playback_copy(snd_pcm_substream_t *substream,				    int channel,				    snd_pcm_uframes_t hwoff,				    void *src,				    snd_pcm_uframes_t frames){	snd_pcm_runtime_t *runtime = substream->runtime;	cs46xx_t *chip = snd_pcm_substream_chip(substream);	size_t hwoffb = hwoff << chip->play.shift;	size_t bytes = frames << chip->play.shift;	char *hwbuf = runtime->dma_area + hwoffb;	if (copy_from_user(hwbuf, src, bytes))		return -EFAULT;	spin_lock_irq(&runtime->lock);	snd_cs46xx_playback_transfer(substream, frames);	spin_unlock_irq(&runtime->lock);	return 0;}	static int snd_cs46xx_capture_copy(snd_pcm_substream_t *substream,				   int channel,				   snd_pcm_uframes_t hwoff,				   void *dst,				   snd_pcm_uframes_t frames){	snd_pcm_runtime_t *runtime = substream->runtime;	cs46xx_t *chip = snd_pcm_substream_chip(substream);	size_t hwoffb = hwoff << chip->capt.shift;	size_t bytes = frames << chip->capt.shift;	char *hwbuf = runtime->dma_area + hwoffb;	if (copy_to_user(dst, hwbuf, bytes))		return -EFAULT;	spin_lock_irq(&runtime->lock);	snd_cs46xx_capture_transfer(substream, frames);	spin_unlock_irq(&runtime->lock);	return 0;}	static int snd_cs46xx_playback_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:		if (substream->runtime->periods != CS46XX_FRAGS)			snd_cs46xx_playback_transfer(substream, 0);		tmp = snd_cs46xx_peek(chip, BA1_PCTL);		tmp &= 0x0000ffff;		snd_cs46xx_poke(chip, BA1_PCTL, chip->play.ctl | tmp);		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_SUSPEND:		tmp = snd_cs46xx_peek(chip, BA1_PCTL);		tmp &= 0x0000ffff;		snd_cs46xx_poke(chip, BA1_PCTL, tmp);		break;	default:		result = -EINVAL;		break;	}	spin_unlock(&chip->reg_lock);	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;}static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,					 snd_pcm_hw_params_t * hw_params){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int err;	if (params_periods(hw_params) == CS46XX_FRAGS) {		if (runtime->dma_area != chip->play.hw_area)			snd_pcm_lib_free_pages(substream);		runtime->dma_area = chip->play.hw_area;		runtime->dma_addr = chip->play.hw_addr;		runtime->dma_bytes = chip->play.hw_size;		substream->ops = &snd_cs46xx_playback_ops;	} else {		if (runtime->dma_area == chip->play.hw_area) {			runtime->dma_area = NULL;			runtime->dma_addr = 0;			runtime->dma_bytes = 0;		}		if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)			return err;		substream->ops = &snd_cs46xx_playback_indirect_ops;	}	return 0;}static int snd_cs46xx_playback_hw_free(snd_pcm_substream_t * substream){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	if (runtime->dma_area != chip->play.hw_area)		snd_pcm_lib_free_pages(substream);	runtime->dma_area = NULL;	runtime->dma_addr = 0;	runtime->dma_bytes = 0;	return 0;}static int snd_cs46xx_playback_prepare(snd_pcm_substream_t * substream){	unsigned int tmp;	unsigned int pfie;	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	pfie = snd_cs46xx_peek(chip, BA1_PFIE);	pfie &= ~0x0000f03f;	chip->play.shift = 2;	if (runtime->channels == 1) {		chip->play.shift--;		pfie |= 0x00002000;	}	if (snd_pcm_format_width(runtime->format) == 8) {		chip->play.shift--;		pfie |= 0x00001000;	}	if (snd_pcm_format_unsigned(runtime->format))		pfie |= 0x00008000;	if (snd_pcm_format_big_endian(runtime->format))		pfie |= 0x00004000;		chip->play.sw_bufsize = snd_pcm_lib_buffer_bytes(substream);	chip->play.sw_data = chip->play.sw_io = chip->play.sw_ready = 0;	chip->play.hw_data = chip->play.hw_io = chip->play.hw_ready = 0;	chip->play.appl_ptr = 0;	snd_cs46xx_poke(chip, BA1_PBA, chip->play.hw_addr);	tmp = snd_cs46xx_peek(chip, BA1_PDTC);	tmp &= ~0x000003ff;	tmp |= (4 << chip->play.shift) - 1;	snd_cs46xx_poke(chip, BA1_PDTC, tmp);	snd_cs46xx_poke(chip, BA1_PFIE, pfie);	snd_cs46xx_set_play_sample_rate(chip, runtime->rate);	return 0;}static int snd_cs46xx_capture_hw_params(snd_pcm_substream_t * substream,					snd_pcm_hw_params_t * hw_params){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int err;

⌨️ 快捷键说明

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