es1938.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,732 行 · 第 1/4 页

C
1,732
字号
	snd_es1938_bits(chip, ESS_CMD_DRQCONTROL, 0xf0, 0x50);	snd_es1938_write_cmd(chip, ESS_CMD_ENABLEAUDIO1);	/* Set spatializer parameters to recommended values */	snd_es1938_mixer_write(chip, 0x54, 0x8f);	snd_es1938_mixer_write(chip, 0x56, 0x95);	snd_es1938_mixer_write(chip, 0x58, 0x94);	snd_es1938_mixer_write(chip, 0x5a, 0x80);}/* -------------------------------------------------------------------- * Reset the FIFOs * --------------------------------------------------------------------*/static void snd_es1938_reset_fifo(es1938_t *chip){	outb(2, SLSB_REG(chip, RESET));	outb(0, SLSB_REG(chip, RESET));}static ratnum_t clocks[2] = {	{		.num = 793800,		.den_min = 1,		.den_max = 128,		.den_step = 1,	},	{		.num = 768000,		.den_min = 1,		.den_max = 128,		.den_step = 1,	}};static snd_pcm_hw_constraint_ratnums_t hw_constraints_clocks = {	.nrats = 2,	.rats = clocks,};static void snd_es1938_rate_set(es1938_t *chip, 				snd_pcm_substream_t *substream,				int mode){	unsigned int bits, div0;	snd_pcm_runtime_t *runtime = substream->runtime;	if (runtime->rate_num == clocks[0].num)		bits = 128 - runtime->rate_den;	else		bits = 256 - runtime->rate_den;	/* set filter register */	div0 = 256 - 7160000*20/(8*82*runtime->rate);			if (mode == DAC2) {		snd_es1938_mixer_write(chip, 0x70, bits);		snd_es1938_mixer_write(chip, 0x72, div0);	} else {		snd_es1938_write(chip, 0xA1, bits);		snd_es1938_write(chip, 0xA2, div0);	}}/* -------------------------------------------------------------------- * Configure Solo1 builtin DMA Controller * --------------------------------------------------------------------*/static void snd_es1938_playback1_setdma(es1938_t *chip){	outb(0x00, SLIO_REG(chip, AUDIO2MODE));	outl(chip->dma2_start, SLIO_REG(chip, AUDIO2DMAADDR));	outw(0, SLIO_REG(chip, AUDIO2DMACOUNT));	outw(chip->dma2_size, SLIO_REG(chip, AUDIO2DMACOUNT));}static void snd_es1938_playback2_setdma(es1938_t *chip){	/* Enable DMA controller */	outb(0xc4, SLDM_REG(chip, DMACOMMAND));	/* 1. Master reset */	outb(0, SLDM_REG(chip, DMACLEAR));	/* 2. Mask DMA */	outb(1, SLDM_REG(chip, DMAMASK));	outb(0x18, SLDM_REG(chip, DMAMODE));	outl(chip->dma1_start, SLDM_REG(chip, DMAADDR));	outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT));	/* 3. Unmask DMA */	outb(0, SLDM_REG(chip, DMAMASK));}static void snd_es1938_capture_setdma(es1938_t *chip){	/* Enable DMA controller */	outb(0xc4, SLDM_REG(chip, DMACOMMAND));	/* 1. Master reset */	outb(0, SLDM_REG(chip, DMACLEAR));	/* 2. Mask DMA */	outb(1, SLDM_REG(chip, DMAMASK));	outb(0x14, SLDM_REG(chip, DMAMODE));	outl(chip->dma1_start, SLDM_REG(chip, DMAADDR));	outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT));	/* 3. Unmask DMA */	outb(0, SLDM_REG(chip, DMAMASK));}/* ---------------------------------------------------------------------- * *                           *** PCM part *** */static int snd_es1938_capture_trigger(snd_pcm_substream_t * substream,				      int cmd){	es1938_t *chip = snd_pcm_substream_chip(substream);	int val;	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		val = 0x0f;		chip->active |= ADC1;		break;	case SNDRV_PCM_TRIGGER_STOP:		val = 0x00;		chip->active &= ~ADC1;		break;	default:		return -EINVAL;	}	snd_es1938_write(chip, ESS_CMD_DMACONTROL, val);	return 0;}static int snd_es1938_playback1_trigger(snd_pcm_substream_t * substream,					int cmd){	es1938_t *chip = snd_pcm_substream_chip(substream);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		/* According to the documentation this should be:		   0x13 but that value may randomly swap stereo channels */                snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0x92);                udelay(10);		snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0x93);                /* This two stage init gives the FIFO -> DAC connection time to                 * settle before first data from DMA flows in.  This should ensure                 * no swapping of stereo channels.  Report a bug if otherwise :-) */		outb(0x0a, SLIO_REG(chip, AUDIO2MODE));		chip->active |= DAC2;		break;	case SNDRV_PCM_TRIGGER_STOP:		outb(0, SLIO_REG(chip, AUDIO2MODE));		snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0);		chip->active &= ~DAC2;		break;	default:		return -EINVAL;	}	return 0;}static int snd_es1938_playback2_trigger(snd_pcm_substream_t * substream,					int cmd){	es1938_t *chip = snd_pcm_substream_chip(substream);	int val;	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		val = 5;		chip->active |= DAC1;		break;	case SNDRV_PCM_TRIGGER_STOP:		val = 0;		chip->active &= ~DAC1;		break;	default:		return -EINVAL;	}	snd_es1938_write(chip, ESS_CMD_DMACONTROL, val);	return 0;}static int snd_es1938_playback_trigger(snd_pcm_substream_t *substream,				       int cmd){	switch (substream->number) {	case 0:		return snd_es1938_playback1_trigger(substream, cmd);	case 1:		return snd_es1938_playback2_trigger(substream, cmd);	}	snd_BUG();	return -EINVAL;}/* -------------------------------------------------------------------- * First channel for Extended Mode Audio 1 ADC Operation * --------------------------------------------------------------------*/static int snd_es1938_capture_prepare(snd_pcm_substream_t * substream){	es1938_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int u, is8, mono;	unsigned int size = snd_pcm_lib_buffer_bytes(substream);	unsigned int count = snd_pcm_lib_period_bytes(substream);	chip->dma1_size = size;	chip->dma1_start = runtime->dma_addr;	mono = (runtime->channels > 1) ? 0 : 1;	is8 = snd_pcm_format_width(runtime->format) == 16 ? 0 : 1;	u = snd_pcm_format_unsigned(runtime->format);	chip->dma1_shift = 2 - mono - is8;	snd_es1938_reset_fifo(chip);		/* program type */	snd_es1938_bits(chip, ESS_CMD_ANALOGCONTROL, 0x03, (mono ? 2 : 1));	/* set clock and counters */        snd_es1938_rate_set(chip, substream, ADC1);	count = 0x10000 - count;	snd_es1938_write(chip, ESS_CMD_DMACNTRELOADL, count & 0xff);	snd_es1938_write(chip, ESS_CMD_DMACNTRELOADH, count >> 8);	/* initialize and configure ADC */	snd_es1938_write(chip, ESS_CMD_SETFORMAT2, u ? 0x51 : 0x71);	snd_es1938_write(chip, ESS_CMD_SETFORMAT2, 0x90 | 		       (u ? 0x00 : 0x20) | 		       (is8 ? 0x00 : 0x04) | 		       (mono ? 0x40 : 0x08));	//	snd_es1938_reset_fifo(chip);		/* 11. configure system interrupt controller and DMA controller */	snd_es1938_capture_setdma(chip);	return 0;}/* ------------------------------------------------------------------------------ * Second Audio channel DAC Operation * ------------------------------------------------------------------------------*/static int snd_es1938_playback1_prepare(snd_pcm_substream_t * substream){	es1938_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int u, is8, mono;	unsigned int size = snd_pcm_lib_buffer_bytes(substream);	unsigned int count = snd_pcm_lib_period_bytes(substream);	chip->dma2_size = size;	chip->dma2_start = runtime->dma_addr;	mono = (runtime->channels > 1) ? 0 : 1;	is8 = snd_pcm_format_width(runtime->format) == 16 ? 0 : 1;	u = snd_pcm_format_unsigned(runtime->format);	chip->dma2_shift = 2 - mono - is8;        snd_es1938_reset_fifo(chip);	/* set clock and counters */        snd_es1938_rate_set(chip, substream, DAC2);	count >>= 1;	count = 0x10000 - count;	snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2TCOUNTL, count & 0xff);	snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2TCOUNTH, count >> 8);	/* initialize and configure Audio 2 DAC */	snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL2, 0x40 | (u ? 0 : 4) | (mono ? 0 : 2) | (is8 ? 0 : 1));	/* program DMA */	snd_es1938_playback1_setdma(chip);		return 0;}static int snd_es1938_playback2_prepare(snd_pcm_substream_t * substream){	es1938_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int u, is8, mono;	unsigned int size = snd_pcm_lib_buffer_bytes(substream);	unsigned int count = snd_pcm_lib_period_bytes(substream);	chip->dma1_size = size;	chip->dma1_start = runtime->dma_addr;	mono = (runtime->channels > 1) ? 0 : 1;	is8 = snd_pcm_format_width(runtime->format) == 16 ? 0 : 1;	u = snd_pcm_format_unsigned(runtime->format);	chip->dma1_shift = 2 - mono - is8;	count = 0x10000 - count; 	/* reset */	snd_es1938_reset_fifo(chip);		snd_es1938_bits(chip, ESS_CMD_ANALOGCONTROL, 0x03, (mono ? 2 : 1));	/* set clock and counters */        snd_es1938_rate_set(chip, substream, DAC1);	snd_es1938_write(chip, ESS_CMD_DMACNTRELOADL, count & 0xff);	snd_es1938_write(chip, ESS_CMD_DMACNTRELOADH, count >> 8);	/* initialized and configure DAC */        snd_es1938_write(chip, ESS_CMD_SETFORMAT, u ? 0x80 : 0x00);        snd_es1938_write(chip, ESS_CMD_SETFORMAT, u ? 0x51 : 0x71);        snd_es1938_write(chip, ESS_CMD_SETFORMAT2, 			 0x90 | (mono ? 0x40 : 0x08) |			 (is8 ? 0x00 : 0x04) | (u ? 0x00 : 0x20));	/* program DMA */	snd_es1938_playback2_setdma(chip);		return 0;}static int snd_es1938_playback_prepare(snd_pcm_substream_t *substream){	switch (substream->number) {	case 0:		return snd_es1938_playback1_prepare(substream);	case 1:		return snd_es1938_playback2_prepare(substream);	}	snd_BUG();	return -EINVAL;}static snd_pcm_uframes_t snd_es1938_capture_pointer(snd_pcm_substream_t * substream){	es1938_t *chip = snd_pcm_substream_chip(substream);	size_t ptr;	size_t old, new;#if 1	/* This stuff is *needed*, don't ask why - AB */	old = inw(SLDM_REG(chip, DMACOUNT));	while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old)		old = new;	ptr = chip->dma1_size - 1 - new;#else	ptr = inl(SLDM_REG(chip, DMAADDR)) - chip->dma1_start;#endif	return ptr >> chip->dma1_shift;}static snd_pcm_uframes_t snd_es1938_playback1_pointer(snd_pcm_substream_t * substream){	es1938_t *chip = snd_pcm_substream_chip(substream);	size_t ptr;#if 1	ptr = chip->dma2_size - inw(SLIO_REG(chip, AUDIO2DMACOUNT));#else	ptr = inl(SLIO_REG(chip, AUDIO2DMAADDR)) - chip->dma2_start;#endif	return ptr >> chip->dma2_shift;}static snd_pcm_uframes_t snd_es1938_playback2_pointer(snd_pcm_substream_t * substream){	es1938_t *chip = snd_pcm_substream_chip(substream);	size_t ptr;	size_t old, new;#if 1	/* This stuff is *needed*, don't ask why - AB */	old = inw(SLDM_REG(chip, DMACOUNT));	while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old)		old = new;	ptr = chip->dma1_size - 1 - new;#else	ptr = inl(SLDM_REG(chip, DMAADDR)) - chip->dma1_start;#endif	return ptr >> chip->dma1_shift;}static snd_pcm_uframes_t snd_es1938_playback_pointer(snd_pcm_substream_t *substream){	switch (substream->number) {	case 0:		return snd_es1938_playback1_pointer(substream);	case 1:		return snd_es1938_playback2_pointer(substream);	}	snd_BUG();	return -EINVAL;}static int snd_es1938_capture_copy(snd_pcm_substream_t *substream,				   int channel,				   snd_pcm_uframes_t pos,				   void __user *dst,				   snd_pcm_uframes_t count){	snd_pcm_runtime_t *runtime = substream->runtime;	es1938_t *chip = snd_pcm_substream_chip(substream);	pos <<= chip->dma1_shift;	count <<= chip->dma1_shift;	snd_assert(pos + count <= chip->dma1_size, return -EINVAL);	if (pos + count < chip->dma1_size) {		if (copy_to_user(dst, runtime->dma_area + pos + 1, count))			return -EFAULT;	} else {		if (copy_to_user(dst, runtime->dma_area + pos + 1, count - 1))			return -EFAULT;		if (put_user(runtime->dma_area[0], ((unsigned char __user *)dst) + count - 1))			return -EFAULT;	}	return 0;}/* * buffer management */static int snd_es1938_pcm_hw_params(snd_pcm_substream_t *substream,				    snd_pcm_hw_params_t * hw_params){	int err;	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)		return err;	return 0;}static int snd_es1938_pcm_hw_free(snd_pcm_substream_t *substream){	return snd_pcm_lib_free_pages(substream);}

⌨️ 快捷键说明

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