cs4231.c

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

C
2,248
字号
	snd_printdd("cs4231: port = 0x%lx, id = 0x%x\n", chip->port, id);	if (id != 0x0a)		return -ENODEV;	/* no valid device found */	spin_lock_irqsave(&chip->lock, flags);	/* Reset DMA engine.  */#ifdef EBUS_SUPPORT	if (chip->flags & CS4231_FLAG_EBUS) {		/* Done by ebus_dma_register */	} else {#endif#ifdef SBUS_SUPPORT                sbus_writel(APC_CHIP_RESET, chip->port + APCCSR);                sbus_writel(0x00, chip->port + APCCSR);                sbus_writel(sbus_readl(chip->port + APCCSR) | APC_CDC_RESET,			    chip->port + APCCSR);                  udelay(20);                  sbus_writel(sbus_readl(chip->port + APCCSR) & ~APC_CDC_RESET,			    chip->port + APCCSR);                sbus_writel(sbus_readl(chip->port + APCCSR) | (APC_XINT_ENA |							       APC_XINT_PENA |							       APC_XINT_CENA),			    chip->port + APCCSR);#endif#ifdef EBUS_SUPPORT	}#endif	__cs4231_readb(chip, CS4231P(chip, STATUS));	/* clear any pendings IRQ */	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));	mb();	spin_unlock_irqrestore(&chip->lock, flags);	chip->image[CS4231_MISC_INFO] = CS4231_MODE2;	chip->image[CS4231_IFACE_CTRL] =		chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA;	chip->image[CS4231_ALT_FEATURE_1] = 0x80;	chip->image[CS4231_ALT_FEATURE_2] = 0x01;	if (vers & 0x20)		chip->image[CS4231_ALT_FEATURE_2] |= 0x02;	ptr = (unsigned char *) &chip->image;	snd_cs4231_mce_down(chip);	spin_lock_irqsave(&chip->lock, flags);	for (i = 0; i < 32; i++)	/* ok.. fill all CS4231 registers */		snd_cs4231_out(chip, i, *ptr++);	spin_unlock_irqrestore(&chip->lock, flags);	snd_cs4231_mce_up(chip);	snd_cs4231_mce_down(chip);	mdelay(2);	return 0;		/* all things are ok.. */}static snd_pcm_hardware_t snd_cs4231_playback ={	.info			= (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),	.formats		= (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |				 SNDRV_PCM_FMTBIT_IMA_ADPCM |				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |				 SNDRV_PCM_FMTBIT_S16_BE),	.rates			= SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,	.rate_min		= 5510,	.rate_max		= 48000,	.channels_min		= 1,	.channels_max		= 2,	.buffer_bytes_max	= (32*1024),	.period_bytes_min	= 4096,	.period_bytes_max	= (32*1024),	.periods_min		= 1,	.periods_max		= 1024,};static snd_pcm_hardware_t snd_cs4231_capture ={	.info			= (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),	.formats		= (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |				 SNDRV_PCM_FMTBIT_IMA_ADPCM |				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |				 SNDRV_PCM_FMTBIT_S16_BE),	.rates			= SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,	.rate_min		= 5510,	.rate_max		= 48000,	.channels_min		= 1,	.channels_max		= 2,	.buffer_bytes_max	= (32*1024),	.period_bytes_min	= 4096,	.period_bytes_max	= (32*1024),	.periods_min		= 1,	.periods_max		= 1024,};static int snd_cs4231_playback_open(snd_pcm_substream_t *substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int err;	runtime->hw = snd_cs4231_playback;	if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 0) {		snd_free_pages(runtime->dma_area, runtime->dma_bytes);		return err;	}	chip->playback_substream = substream;	chip->p_periods_sent = 0;	snd_pcm_set_sync(substream);	snd_cs4231_xrate(runtime);	return 0;}static int snd_cs4231_capture_open(snd_pcm_substream_t *substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int err;	runtime->hw = snd_cs4231_capture;	if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 0) {		snd_free_pages(runtime->dma_area, runtime->dma_bytes);		return err;	}	chip->capture_substream = substream;	chip->c_periods_sent = 0;	snd_pcm_set_sync(substream);	snd_cs4231_xrate(runtime);	return 0;}static int snd_cs4231_playback_close(snd_pcm_substream_t *substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	chip->playback_substream = NULL;	snd_cs4231_close(chip, CS4231_MODE_PLAY);	return 0;}static int snd_cs4231_capture_close(snd_pcm_substream_t *substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	chip->capture_substream = NULL;	snd_cs4231_close(chip, CS4231_MODE_RECORD);	return 0;}/* XXX We can do some power-management, in particular on EBUS using * XXX the audio AUXIO register... */static snd_pcm_ops_t snd_cs4231_playback_ops = {	.open		=	snd_cs4231_playback_open,	.close		=	snd_cs4231_playback_close,	.ioctl		=	snd_pcm_lib_ioctl,	.hw_params	=	snd_cs4231_playback_hw_params,	.hw_free	=	snd_cs4231_playback_hw_free,	.prepare	=	snd_cs4231_playback_prepare,	.trigger	=	snd_cs4231_trigger,	.pointer	=	snd_cs4231_playback_pointer,};static snd_pcm_ops_t snd_cs4231_capture_ops = {	.open		=	snd_cs4231_capture_open,	.close		=	snd_cs4231_capture_close,	.ioctl		=	snd_pcm_lib_ioctl,	.hw_params	=	snd_cs4231_capture_hw_params,	.hw_free	=	snd_cs4231_capture_hw_free,	.prepare	=	snd_cs4231_capture_prepare,	.trigger	=	snd_cs4231_trigger,	.pointer	=	snd_cs4231_capture_pointer,};static void snd_cs4231_pcm_free(snd_pcm_t *pcm){	cs4231_t *chip = pcm->private_data;	chip->pcm = NULL;	snd_pcm_lib_preallocate_free_for_all(pcm);}int snd_cs4231_pcm(cs4231_t *chip){	snd_pcm_t *pcm;	int err;	if ((err = snd_pcm_new(chip->card, "CS4231", 0, 1, 1, &pcm)) < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4231_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs4231_capture_ops);		/* global setup */	pcm->private_data = chip;	pcm->private_free = snd_cs4231_pcm_free;	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;	strcpy(pcm->name, "CS4231");#ifdef EBUS_SUPPORT	if (chip->flags & CS4231_FLAG_EBUS) {		snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,						      snd_dma_pci_data(chip->dev_u.pdev),						      64*1024, 128*1024);	} else {#endif#ifdef SBUS_SUPPORT		snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS,						      snd_dma_sbus_data(chip->dev_u.sdev),						      64*1024, 128*1024);#endif#ifdef EBUS_SUPPORT	}#endif	chip->pcm = pcm;	return 0;}static void snd_cs4231_timer_free(snd_timer_t *timer){	cs4231_t *chip = timer->private_data;	chip->timer = NULL;}int snd_cs4231_timer(cs4231_t *chip){	snd_timer_t *timer;	snd_timer_id_t tid;	int err;	/* Timer initialization */	tid.dev_class = SNDRV_TIMER_CLASS_CARD;	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;	tid.card = chip->card->number;	tid.device = 0;	tid.subdevice = 0;	if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0)		return err;	strcpy(timer->name, "CS4231");	timer->private_data = chip;	timer->private_free = snd_cs4231_timer_free;	timer->hw = snd_cs4231_timer_table;	chip->timer = timer;	return 0;}	/* *  MIXER part */static int snd_cs4231_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){	static char *texts[4] = {		"Line", "CD", "Mic", "Mix"	};	cs4231_t *chip = snd_kcontrol_chip(kcontrol);	snd_assert(chip->card != NULL, return -EINVAL);	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 2;	uinfo->value.enumerated.items = 4;	if (uinfo->value.enumerated.item > 3)		uinfo->value.enumerated.item = 3;	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);	return 0;}static int snd_cs4231_get_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	cs4231_t *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;		spin_lock_irqsave(&chip->lock, flags);	ucontrol->value.enumerated.item[0] =		(chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6;	ucontrol->value.enumerated.item[1] =		(chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6;	spin_unlock_irqrestore(&chip->lock, flags);	return 0;}static int snd_cs4231_put_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	cs4231_t *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	unsigned short left, right;	int change;		if (ucontrol->value.enumerated.item[0] > 3 ||	    ucontrol->value.enumerated.item[1] > 3)		return -EINVAL;	left = ucontrol->value.enumerated.item[0] << 6;	right = ucontrol->value.enumerated.item[1] << 6;	spin_lock_irqsave(&chip->lock, flags);	left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left;	right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right;	change = left != chip->image[CS4231_LEFT_INPUT] ||	         right != chip->image[CS4231_RIGHT_INPUT];	snd_cs4231_out(chip, CS4231_LEFT_INPUT, left);	snd_cs4231_out(chip, CS4231_RIGHT_INPUT, right);	spin_unlock_irqrestore(&chip->lock, flags);	return change;}int snd_cs4231_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){	int mask = (kcontrol->private_value >> 16) & 0xff;	uinfo->type = (mask == 1) ?		SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = mask;	return 0;}int snd_cs4231_get_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	cs4231_t *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 8) & 0xff;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0xff;		spin_lock_irqsave(&chip->lock, flags);	ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;	spin_unlock_irqrestore(&chip->lock, flags);	if (invert)		ucontrol->value.integer.value[0] =			(mask - ucontrol->value.integer.value[0]);	return 0;}int snd_cs4231_put_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	cs4231_t *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 8) & 0xff;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0xff;	int change;	unsigned short val;		val = (ucontrol->value.integer.value[0] & mask);	if (invert)		val = mask - val;	val <<= shift;	spin_lock_irqsave(&chip->lock, flags);	val = (chip->image[reg] & ~(mask << shift)) | val;	change = val != chip->image[reg];	snd_cs4231_out(chip, reg, val);	spin_unlock_irqrestore(&chip->lock, flags);	return change;}int snd_cs4231_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){	int mask = (kcontrol->private_value >> 24) & 0xff;	uinfo->type = mask == 1 ?		SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = mask;	return 0;}int snd_cs4231_get_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	cs4231_t *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int left_reg = kcontrol->private_value & 0xff;	int right_reg = (kcontrol->private_value >> 8) & 0xff;	int shift_left = (kcontrol->private_value >> 16) & 0x07;	int shift_right = (kcontrol->private_value >> 19) & 0x07;	int mask = (kcontrol->private_value >> 24) & 0xff;	int invert = (kcontrol->private_value >> 22) & 1;		spin_lock_irqsave(&chip->lock, flags);	ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;	ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;	spin_unlock_irqrestore(&chip->lock, flags);	if (invert) {		ucontrol->value.integer.value[0] =			(mask - ucontrol->value.integer.value[0]);		ucontrol->value.integer.value[1] =			(mask - ucontrol->value.integer.value[1]);	}	return 0;}int snd_cs4231_put_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	cs4231_t *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int left_reg = kcontrol->private_value & 0xff;	int right_reg = (kcontrol->private_value >> 8) & 0xff;	int shift_left = (kcontrol->private_value >> 16) & 0x07;	int shift_right = (kcontrol->private_value >> 19) & 0x07;	int mask = (kcontrol->private_value >> 24) & 0xff;	int invert = (kcontrol->private_value >> 22) & 1;	int change;	unsigned short val1, val2;		val1 = ucontrol->value.integer.value[0] & mask;	val2 = ucontrol->value.integer.value[1] & mask;	if (invert) {		val1 = mask - val1;

⌨️ 快捷键说明

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