es18xx.c

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

C
2,223
字号
			return -EBUSY;		}		chip->dma2_shift = shift;	} else {		chip->dma1_shift = shift;	}	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)		return err;	return 0;}static int snd_es18xx_pcm_hw_free(snd_pcm_substream_t * substream){	return snd_pcm_lib_free_pages(substream);}static int snd_es18xx_playback1_prepare(es18xx_t *chip,					snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime = substream->runtime;	unsigned int size = snd_pcm_lib_buffer_bytes(substream);	unsigned int count = snd_pcm_lib_period_bytes(substream);	chip->dma2_size = size;        snd_es18xx_rate_set(chip, substream, DAC2);        /* Transfer Count Reload */        count = 0x10000 - count;        snd_es18xx_mixer_write(chip, 0x74, count & 0xff);        snd_es18xx_mixer_write(chip, 0x76, count >> 8);	/* Set format */        snd_es18xx_mixer_bits(chip, 0x7A, 0x07,			      ((runtime->channels == 1) ? 0x00 : 0x02) |			      (snd_pcm_format_width(runtime->format) == 16 ? 0x01 : 0x00) |			      (snd_pcm_format_unsigned(runtime->format) ? 0x00 : 0x04));        /* Set DMA controller */        snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);	return 0;}static int snd_es18xx_playback1_trigger(es18xx_t *chip,					snd_pcm_substream_t * substream,					int cmd){	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_RESUME:		if (chip->active & DAC2)			return 0;		chip->active |= DAC2;                /* Start DMA */		if (chip->dma2 >= 4)			snd_es18xx_mixer_write(chip, 0x78, 0xb3);		else			snd_es18xx_mixer_write(chip, 0x78, 0x93);#ifdef AVOID_POPS		/* Avoid pops */                udelay(100000);		if (chip->caps & ES18XX_PCM2)			/* Restore Audio 2 volume */			snd_es18xx_mixer_write(chip, 0x7C, chip->audio2_vol);		else			/* Enable PCM output */			snd_es18xx_dsp_command(chip, 0xD1);#endif		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_SUSPEND:		if (!(chip->active & DAC2))			return 0;		chip->active &= ~DAC2;                /* Stop DMA */                snd_es18xx_mixer_write(chip, 0x78, 0x00);#ifdef AVOID_POPS                udelay(25000);		if (chip->caps & ES18XX_PCM2)			/* Set Audio 2 volume to 0 */			snd_es18xx_mixer_write(chip, 0x7C, 0);		else			/* Disable PCM output */			snd_es18xx_dsp_command(chip, 0xD3);#endif		break;	default:		return -EINVAL;	}	return 0;}static int snd_es18xx_capture_hw_params(snd_pcm_substream_t * substream,					snd_pcm_hw_params_t * hw_params){	es18xx_t *chip = snd_pcm_substream_chip(substream);	int shift, err;	shift = 0;	if ((chip->caps & ES18XX_DUPLEX_MONO) &&	    chip->playback_a_substream &&	    params_channels(hw_params) != 1) {		_snd_pcm_hw_param_setempty(hw_params, SNDRV_PCM_HW_PARAM_CHANNELS);		return -EBUSY;	}	if (params_channels(hw_params) == 2)		shift++;	if (snd_pcm_format_width(params_format(hw_params)) == 16)		shift++;	chip->dma1_shift = shift;	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)		return err;	return 0;}static int snd_es18xx_capture_prepare(snd_pcm_substream_t *substream){        es18xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	unsigned int size = snd_pcm_lib_buffer_bytes(substream);	unsigned int count = snd_pcm_lib_period_bytes(substream);	chip->dma1_size = size;	snd_es18xx_reset_fifo(chip);        /* Set stereo/mono */        snd_es18xx_bits(chip, 0xA8, 0x03, runtime->channels == 1 ? 0x02 : 0x01);        snd_es18xx_rate_set(chip, substream, ADC1);        /* Transfer Count Reload */	count = 0x10000 - count;	snd_es18xx_write(chip, 0xA4, count & 0xff);	snd_es18xx_write(chip, 0xA5, count >> 8);#ifdef AVOID_POPS	udelay(100000);#endif        /* Set format */        snd_es18xx_write(chip, 0xB7,                          snd_pcm_format_unsigned(runtime->format) ? 0x51 : 0x71);        snd_es18xx_write(chip, 0xB7, 0x90 |                         ((runtime->channels == 1) ? 0x40 : 0x08) |                         (snd_pcm_format_width(runtime->format) == 16 ? 0x04 : 0x00) |                         (snd_pcm_format_unsigned(runtime->format) ? 0x00 : 0x20));        /* Set DMA controler */        snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);	return 0;}static int snd_es18xx_capture_trigger(snd_pcm_substream_t *substream,				      int cmd){        es18xx_t *chip = snd_pcm_substream_chip(substream);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_RESUME:		if (chip->active & ADC1)			return 0;		chip->active |= ADC1;                /* Start DMA */                snd_es18xx_write(chip, 0xB8, 0x0f);		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_SUSPEND:		if (!(chip->active & ADC1))			return 0;		chip->active &= ~ADC1;                /* Stop DMA */                snd_es18xx_write(chip, 0xB8, 0x00);		break;	default:		return -EINVAL;	}	return 0;}static int snd_es18xx_playback2_prepare(es18xx_t *chip,					snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime = substream->runtime;	unsigned int size = snd_pcm_lib_buffer_bytes(substream);	unsigned int count = snd_pcm_lib_period_bytes(substream);	chip->dma1_size = size;	snd_es18xx_reset_fifo(chip);        /* Set stereo/mono */        snd_es18xx_bits(chip, 0xA8, 0x03, runtime->channels == 1 ? 0x02 : 0x01);        snd_es18xx_rate_set(chip, substream, DAC1);        /* Transfer Count Reload */	count = 0x10000 - count;	snd_es18xx_write(chip, 0xA4, count & 0xff);	snd_es18xx_write(chip, 0xA5, count >> 8);        /* Set format */        snd_es18xx_write(chip, 0xB6,                         snd_pcm_format_unsigned(runtime->format) ? 0x80 : 0x00);        snd_es18xx_write(chip, 0xB7,                          snd_pcm_format_unsigned(runtime->format) ? 0x51 : 0x71);        snd_es18xx_write(chip, 0xB7, 0x90 |                         (runtime->channels == 1 ? 0x40 : 0x08) |                         (snd_pcm_format_width(runtime->format) == 16 ? 0x04 : 0x00) |                         (snd_pcm_format_unsigned(runtime->format) ? 0x00 : 0x20));        /* Set DMA controler */        snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);	return 0;}static int snd_es18xx_playback2_trigger(es18xx_t *chip,					snd_pcm_substream_t *substream,					int cmd){	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_RESUME:		if (chip->active & DAC1)			return 0;		chip->active |= DAC1;                /* Start DMA */                snd_es18xx_write(chip, 0xB8, 0x05);#ifdef AVOID_POPS		/* Avoid pops */                udelay(100000);                /* Enable Audio 1 */                snd_es18xx_dsp_command(chip, 0xD1);#endif		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_SUSPEND:		if (!(chip->active & DAC1))			return 0;		chip->active &= ~DAC1;                /* Stop DMA */                snd_es18xx_write(chip, 0xB8, 0x00);#ifdef AVOID_POPS		/* Avoid pops */                udelay(25000);                /* Disable Audio 1 */                snd_es18xx_dsp_command(chip, 0xD3);#endif		break;	default:		return -EINVAL;	}	return 0;}static int snd_es18xx_playback_prepare(snd_pcm_substream_t *substream){        es18xx_t *chip = snd_pcm_substream_chip(substream);	if (substream->number == 0 && (chip->caps & ES18XX_PCM2))		return snd_es18xx_playback1_prepare(chip, substream);	else		return snd_es18xx_playback2_prepare(chip, substream);}static int snd_es18xx_playback_trigger(snd_pcm_substream_t *substream,				       int cmd){        es18xx_t *chip = snd_pcm_substream_chip(substream);	if (substream->number == 0 && (chip->caps & ES18XX_PCM2))		return snd_es18xx_playback1_trigger(chip, substream, cmd);	else		return snd_es18xx_playback2_trigger(chip, substream, cmd);}static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *regs){	es18xx_t *chip = dev_id;	unsigned char status;	if (chip->caps & ES18XX_CONTROL) {		/* Read Interrupt status */		status = inb(chip->ctrl_port + 6);	} else {		/* Read Interrupt status */		status = snd_es18xx_mixer_read(chip, 0x7f) >> 4;	}#if 0	else {		status = 0;		if (inb(chip->port + 0x0C) & 0x01)			status |= AUDIO1_IRQ;		if (snd_es18xx_mixer_read(chip, 0x7A) & 0x80)			status |= AUDIO2_IRQ;		if ((chip->caps & ES18XX_HWV) &&		    snd_es18xx_mixer_read(chip, 0x64) & 0x10)			status |= HWV_IRQ;	}#endif	/* Audio 1 & Audio 2 */        if (status & AUDIO2_IRQ) {                if (chip->active & DAC2)                	snd_pcm_period_elapsed(chip->playback_a_substream);		/* ack interrupt */                snd_es18xx_mixer_bits(chip, 0x7A, 0x80, 0x00);        }        if (status & AUDIO1_IRQ) {                /* ok.. capture is active */                if (chip->active & ADC1)                	snd_pcm_period_elapsed(chip->capture_a_substream);                /* ok.. playback2 is active */                else if (chip->active & DAC1)                	snd_pcm_period_elapsed(chip->playback_b_substream);		/* ack interrupt */		inb(chip->port + 0x0E);        }	/* MPU */	if ((status & MPU_IRQ) && chip->rmidi)		snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);	/* Hardware volume */	if (status & HWV_IRQ) {		int split = snd_es18xx_mixer_read(chip, 0x64) & 0x80;		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id);		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id);		if (!split) {			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id);			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id);		}		/* ack interrupt */		snd_es18xx_mixer_write(chip, 0x66, 0x00);	}	return IRQ_HANDLED;}static snd_pcm_uframes_t snd_es18xx_playback_pointer(snd_pcm_substream_t * substream){        es18xx_t *chip = snd_pcm_substream_chip(substream);	int pos;	if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) {		if (!(chip->active & DAC2))			return 0;		pos = snd_dma_pointer(chip->dma2, chip->dma2_size);		return pos >> chip->dma2_shift;	} else {		if (!(chip->active & DAC1))			return 0;		pos = snd_dma_pointer(chip->dma1, chip->dma1_size);		return pos >> chip->dma1_shift;	}}static snd_pcm_uframes_t snd_es18xx_capture_pointer(snd_pcm_substream_t * substream){        es18xx_t *chip = snd_pcm_substream_chip(substream);	int pos;        if (!(chip->active & ADC1))                return 0;	pos = snd_dma_pointer(chip->dma1, chip->dma1_size);	return pos >> chip->dma1_shift;}static snd_pcm_hardware_t snd_es18xx_playback ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_RESUME |				 SNDRV_PCM_INFO_MMAP_VALID),	.formats =		(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | 				 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		4000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	65536,	.period_bytes_min =	64,	.period_bytes_max =	65536,	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};static snd_pcm_hardware_t snd_es18xx_capture ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_RESUME |				 SNDRV_PCM_INFO_MMAP_VALID),	.formats =		(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | 				 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		4000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	65536,	.period_bytes_min =	64,	.period_bytes_max =	65536,	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};static int snd_es18xx_playback_open(snd_pcm_substream_t * substream){	snd_pcm_runtime_t *runtime = substream->runtime;        es18xx_t *chip = snd_pcm_substream_chip(substream);	if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) {		if ((chip->caps & ES18XX_DUPLEX_MONO) &&		    chip->capture_a_substream && 		    chip->capture_a_substream->runtime->channels != 1)			return -EAGAIN;		chip->playback_a_substream = substream;	} else if (substream->number <= 1) {		if (chip->capture_a_substream)			return -EAGAIN;		chip->playback_b_substream = substream;	} else {		snd_BUG();		return -EINVAL;	}	substream->runtime->hw = snd_es18xx_playback;	snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,				      (chip->caps & ES18XX_NEW_RATE) ? &new_hw_constraints_clocks : &old_hw_constraints_clocks);        return 0;}static int snd_es18xx_capture_open(snd_pcm_substream_t * substream){	snd_pcm_runtime_t *runtime = substream->runtime;        es18xx_t *chip = snd_pcm_substream_chip(substream);        if (chip->playback_b_substream)                return -EAGAIN;	if ((chip->caps & ES18XX_DUPLEX_MONO) &&

⌨️ 快捷键说明

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