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

📄 vwsnd.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
	ad1843_DAADR  = { 25,  6,  2 },	/* Digital ADC Right Source Select */	ad1843_DRSFLT = { 25, 15,  1 },	/* Digital Reampler Filter Mode */	ad1843_ADLF   = { 26,  0,  2 }, /* ADC Left Channel Data Format */	ad1843_ADRF   = { 26,  2,  2 }, /* ADC Right Channel Data Format */	ad1843_ADTLK  = { 26,  4,  1 },	/* ADC Transmit Lock Mode Select */	ad1843_SCF    = { 26,  7,  1 },	/* SCLK Frequency Select */	ad1843_DA1F   = { 26,  8,  2 },	/* DAC1 Data Format Select */	ad1843_DA1SM  = { 26, 14,  1 },	/* DAC1 Stereo/Mono Mode Select */	ad1843_ADLEN  = { 27,  0,  1 },	/* ADC Left Channel Enable */	ad1843_ADREN  = { 27,  1,  1 },	/* ADC Right Channel Enable */	ad1843_AAMEN  = { 27,  4,  1 },	/* Analog to Analog Mix Enable */	ad1843_ANAEN  = { 27,  7,  1 },	/* Analog Channel Enable */	ad1843_DA1EN  = { 27,  8,  1 },	/* DAC1 Enable */	ad1843_DA2EN  = { 27,  9,  1 },	/* DAC2 Enable */	ad1843_C1EN   = { 28, 11,  1 },	/* Clock Generator 1 Enable */	ad1843_C2EN   = { 28, 12,  1 },	/* Clock Generator 2 Enable */	ad1843_PDNI   = { 28, 15,  1 };	/* Converter Power Down *//* * The various registers of the AD1843 use three different formats for * specifying gain.  The ad1843_gain structure parameterizes the * formats. */typedef struct ad1843_gain {	int	negative;		/* nonzero if gain is negative. */	const ad1843_bitfield_t *lfield;	const ad1843_bitfield_t *rfield;} ad1843_gain_t;static const ad1843_gain_t ad1843_gain_RECLEV				= { 0, &ad1843_LIG,   &ad1843_RIG };static const ad1843_gain_t ad1843_gain_LINE				= { 1, &ad1843_LX1M,  &ad1843_RX1M };static const ad1843_gain_t ad1843_gain_CD				= { 1, &ad1843_LX2M,  &ad1843_RX2M };static const ad1843_gain_t ad1843_gain_MIC				= { 1, &ad1843_LMCM,  &ad1843_RMCM };static const ad1843_gain_t ad1843_gain_PCM				= { 1, &ad1843_LDA1G, &ad1843_RDA1G };/* read the current value of an AD1843 bitfield. */static int ad1843_read_bits(lithium_t *lith, const ad1843_bitfield_t *field){	int w = li_read_ad1843_reg(lith, field->reg);	int val = w >> field->lo_bit & ((1 << field->nbits) - 1);	DBGXV("ad1843_read_bits(lith=0x%p, field->{%d %d %d}) returns 0x%x\n",	      lith, field->reg, field->lo_bit, field->nbits, val);	return val;}/* * write a new value to an AD1843 bitfield and return the old value. */static int ad1843_write_bits(lithium_t *lith,			     const ad1843_bitfield_t *field,			     int newval){	int w = li_read_ad1843_reg(lith, field->reg);	int mask = ((1 << field->nbits) - 1) << field->lo_bit;	int oldval = (w & mask) >> field->lo_bit;	int newbits = (newval << field->lo_bit) & mask;	w = (w & ~mask) | newbits;	(void) li_write_ad1843_reg(lith, field->reg, w);	DBGXV("ad1843_write_bits(lith=0x%p, field->{%d %d %d}, val=0x%x) "	      "returns 0x%x\n",	      lith, field->reg, field->lo_bit, field->nbits, newval,	      oldval);	return oldval;}/* * ad1843_read_multi reads multiple bitfields from the same AD1843 * register.  It uses a single read cycle to do it.  (Reading the * ad1843 requires 256 bit times at 12.288 MHz, or nearly 20 * microseconds.) * * Called ike this. * *  ad1843_read_multi(lith, nfields, *		      &ad1843_FIELD1, &val1, *		      &ad1843_FIELD2, &val2, ...); */static void ad1843_read_multi(lithium_t *lith, int argcount, ...){	va_list ap;	const ad1843_bitfield_t *fp;	int w = 0, mask, *value, reg = -1;	va_start(ap, argcount);	while (--argcount >= 0) {		fp = va_arg(ap, const ad1843_bitfield_t *);		value = va_arg(ap, int *);		if (reg == -1) {			reg = fp->reg;			w = li_read_ad1843_reg(lith, reg);		}		ASSERT(reg == fp->reg);		mask = (1 << fp->nbits) - 1;		*value = w >> fp->lo_bit & mask;	}	va_end(ap);}/* * ad1843_write_multi stores multiple bitfields into the same AD1843 * register.  It uses one read and one write cycle to do it. * * Called like this. * *  ad1843_write_multi(lith, nfields, *		       &ad1843_FIELD1, val1, *		       &ad1843_FIELF2, val2, ...); */static void ad1843_write_multi(lithium_t *lith, int argcount, ...){	va_list ap;	int reg;	const ad1843_bitfield_t *fp;	int value;	int w, m, mask, bits;	mask = 0;	bits = 0;	reg = -1;	va_start(ap, argcount);	while (--argcount >= 0) {		fp = va_arg(ap, const ad1843_bitfield_t *);		value = va_arg(ap, int);		if (reg == -1)			reg = fp->reg;		ASSERT(fp->reg == reg);		m = ((1 << fp->nbits) - 1) << fp->lo_bit;		mask |= m;		bits |= (value << fp->lo_bit) & m;	}	va_end(ap);	ASSERT(!(bits & ~mask));	if (~mask & 0xFFFF)		w = li_read_ad1843_reg(lith, reg);	else		w = 0;	w = (w & ~mask) | bits;	(void) li_write_ad1843_reg(lith, reg, w);}/* * ad1843_get_gain reads the specified register and extracts the gain value * using the supplied gain type.  It returns the gain in OSS format. */static int ad1843_get_gain(lithium_t *lith, const ad1843_gain_t *gp){	int lg, rg;	unsigned short mask = (1 << gp->lfield->nbits) - 1;	ad1843_read_multi(lith, 2, gp->lfield, &lg, gp->rfield, &rg);	if (gp->negative) {		lg = mask - lg;		rg = mask - rg;	}	lg = (lg * 100 + (mask >> 1)) / mask;	rg = (rg * 100 + (mask >> 1)) / mask;	return lg << 0 | rg << 8;}/* * Set an audio channel's gain. Converts from OSS format to AD1843's * format. * * Returns the new gain, which may be lower than the old gain. */static int ad1843_set_gain(lithium_t *lith,			   const ad1843_gain_t *gp,			   int newval){	unsigned short mask = (1 << gp->lfield->nbits) - 1;	int lg = newval >> 0 & 0xFF;	int rg = newval >> 8;	if (lg < 0 || lg > 100 || rg < 0 || rg > 100)		return -EINVAL;	lg = (lg * mask + (mask >> 1)) / 100;	rg = (rg * mask + (mask >> 1)) / 100;	if (gp->negative) {		lg = mask - lg;		rg = mask - rg;	}	ad1843_write_multi(lith, 2, gp->lfield, lg, gp->rfield, rg);	return ad1843_get_gain(lith, gp);}/* Returns the current recording source, in OSS format. */static int ad1843_get_recsrc(lithium_t *lith){	int ls = ad1843_read_bits(lith, &ad1843_LSS);	switch (ls) {	case 1:		return SOUND_MASK_MIC;	case 2:		return SOUND_MASK_LINE;	case 3:		return SOUND_MASK_CD;	case 6:		return SOUND_MASK_PCM;	default:		ASSERT(0);		return -1;	}}/* * Enable/disable digital resample mode in the AD1843. * * The AD1843 requires that ADL, ADR, DA1 and DA2 be powered down * while switching modes.  So we save DA1's state (DA2's state is not * interesting), power them down, switch into/out of resample mode, * power them up, and restore state. * * This will cause audible glitches if D/A or A/D is going on, so the * driver disallows that (in mixer_write_ioctl()). * * The open question is, is this worth doing?  I'm leaving it in, * because it's written, but... */static void ad1843_set_resample_mode(lithium_t *lith, int onoff){	/* Save DA1 mute and gain (addr 9 is DA1 analog gain/attenuation) */	int save_da1 = li_read_ad1843_reg(lith, 9);	/* Power down A/D and D/A. */	ad1843_write_multi(lith, 4,			   &ad1843_DA1EN, 0,			   &ad1843_DA2EN, 0,			   &ad1843_ADLEN, 0,			   &ad1843_ADREN, 0);	/* Switch mode */	ASSERT(onoff == 0 || onoff == 1);	ad1843_write_bits(lith, &ad1843_DRSFLT, onoff); 	/* Power up A/D and D/A. */	ad1843_write_multi(lith, 3,			   &ad1843_DA1EN, 1,			   &ad1843_ADLEN, 1,			   &ad1843_ADREN, 1);	/* Restore DA1 mute and gain. */	li_write_ad1843_reg(lith, 9, save_da1);}/* * Set recording source.  Arg newsrc specifies an OSS channel mask. * * The complication is that when we switch into/out of loopback mode * (i.e., src = SOUND_MASK_PCM), we change the AD1843 into/out of * digital resampling mode. * * Returns newsrc on success, -errno on failure. */static int ad1843_set_recsrc(lithium_t *lith, int newsrc){	int bits;	int oldbits;	switch (newsrc) {	case SOUND_MASK_PCM:		bits = 6;		break;	case SOUND_MASK_MIC:		bits = 1;		break;	case SOUND_MASK_LINE:		bits = 2;		break;	case SOUND_MASK_CD:		bits = 3;		break;	default:		return -EINVAL;	}	oldbits = ad1843_read_bits(lith, &ad1843_LSS);	if (newsrc == SOUND_MASK_PCM && oldbits != 6) {		DBGP("enabling digital resample mode\n");		ad1843_set_resample_mode(lith, 1);		ad1843_write_multi(lith, 2,				   &ad1843_DAADL, 2,				   &ad1843_DAADR, 2);	} else if (newsrc != SOUND_MASK_PCM && oldbits == 6) {		DBGP("disabling digital resample mode\n");		ad1843_set_resample_mode(lith, 0);		ad1843_write_multi(lith, 2,				   &ad1843_DAADL, 0,				   &ad1843_DAADR, 0);	}	ad1843_write_multi(lith, 2, &ad1843_LSS, bits, &ad1843_RSS, bits);	return newsrc;}/* * Return current output sources, in OSS format. */static int ad1843_get_outsrc(lithium_t *lith){	int pcm, line, mic, cd;	pcm  = ad1843_read_bits(lith, &ad1843_LDA1GM) ? 0 : SOUND_MASK_PCM;	line = ad1843_read_bits(lith, &ad1843_LX1MM)  ? 0 : SOUND_MASK_LINE;	cd   = ad1843_read_bits(lith, &ad1843_LX2MM)  ? 0 : SOUND_MASK_CD;	mic  = ad1843_read_bits(lith, &ad1843_LMCMM)  ? 0 : SOUND_MASK_MIC;	return pcm | line | cd | mic;}/* * Set output sources.  Arg is a mask of active sources in OSS format. * * Returns source mask on success, -errno on failure. */static int ad1843_set_outsrc(lithium_t *lith, int mask){	int pcm, line, mic, cd;	if (mask & ~(SOUND_MASK_PCM | SOUND_MASK_LINE |		     SOUND_MASK_CD | SOUND_MASK_MIC))		return -EINVAL;	pcm  = (mask & SOUND_MASK_PCM)  ? 0 : 1;	line = (mask & SOUND_MASK_LINE) ? 0 : 1;	mic  = (mask & SOUND_MASK_MIC)  ? 0 : 1;	cd   = (mask & SOUND_MASK_CD)   ? 0 : 1;	ad1843_write_multi(lith, 2, &ad1843_LDA1GM, pcm, &ad1843_RDA1GM, pcm);	ad1843_write_multi(lith, 2, &ad1843_LX1MM, line, &ad1843_RX1MM, line);	ad1843_write_multi(lith, 2, &ad1843_LX2MM, cd,   &ad1843_RX2MM, cd);	ad1843_write_multi(lith, 2, &ad1843_LMCMM, mic,  &ad1843_RMCMM, mic);	return mask;}/* Setup ad1843 for D/A conversion. */static void ad1843_setup_dac(lithium_t *lith,			     int framerate,			     int fmt,			     int channels){	int ad_fmt = 0, ad_mode = 0;	DBGEV("(lith=0x%p, framerate=%d, fmt=%d, channels=%d)\n",	      lith, framerate, fmt, channels);	switch (fmt) {	case AFMT_S8:		ad_fmt = 1; break;	case AFMT_U8:		ad_fmt = 1; break;	case AFMT_S16_LE:	ad_fmt = 1; break;	case AFMT_MU_LAW:	ad_fmt = 2; break;	case AFMT_A_LAW:	ad_fmt = 3; break;	default:		ASSERT(0);	}	switch (channels) {	case 2:			ad_mode = 0; break;	case 1:			ad_mode = 1; break;	default:		ASSERT(0);	}			DBGPV("ad_mode = %d, ad_fmt = %d\n", ad_mode, ad_fmt);	ASSERT(framerate >= 4000 && framerate <= 49000);	ad1843_write_bits(lith, &ad1843_C1C, framerate);	ad1843_write_multi(lith, 2,			   &ad1843_DA1SM, ad_mode, &ad1843_DA1F, ad_fmt);}static void ad1843_shutdown_dac(lithium_t *lith){	ad1843_write_bits(lith, &ad1843_DA1F, 1);}static void ad1843_setup_adc(lithium_t *lith, int framerate, int fmt, int channels){	int da_fmt = 0;	DBGEV("(lith=0x%p, framerate=%d, fmt=%d, channels=%d)\n",	      lith, framerate, fmt, channels);	switch (fmt) {	case AFMT_S8:		da_fmt = 1; break;	case AFMT_U8:		da_fmt = 1; break;	case AFMT_S16_LE:	da_fmt = 1; break;	case AFMT_MU_LAW:	da_fmt = 2; break;	case AFMT_A_LAW:	da_fmt = 3; break;	default:		ASSERT(0);	}	DBGPV("da_fmt = %d\n", da_fmt);	ASSERT(framerate >= 4000 && framerate <= 49000);	ad1843_write_bits(lith, &ad1843_C2C, framerate);	ad1843_write_multi(lith, 2,			   &ad1843_ADLF, da_fmt, &ad1843_ADRF, da_fmt);}static void ad1843_shutdown_adc(lithium_t *lith){	/* nothing to do */}/* * Fully initialize the ad1843.  As described in the AD1843 data * sheet, section "START-UP SEQUENCE".  The numbered comments are * subsection headings from the data sheet.  See the data sheet, pages * 52-54, for more info. * * return 0 on success, -errno on failure.  */static int __init ad1843_init(lithium_t *lith){	unsigned long later;	int err;	err = li_init(lith);	if (err)		return err;	if (ad1843_read_bits(lith, &ad1843_INIT) != 0) {		printk(KERN_ERR "vwsnd sound: AD1843 won't initialize\n");		return -EIO;	}	ad1843_write_bits(lith, &ad1843_SCF, 1);

⌨️ 快捷键说明

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