es1938.c

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

C
1,732
字号
/* ---------------------------------------------------------------------- * Audio1 Capture (ADC) * ----------------------------------------------------------------------*/static snd_pcm_hardware_t snd_es1938_capture ={	.info =			(SNDRV_PCM_INFO_INTERLEAVED |				SNDRV_PCM_INFO_BLOCK_TRANSFER),	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE,	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		6000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,        .buffer_bytes_max =	0x8000,       /* DMA controller screws on higher values */	.period_bytes_min =	64,	.period_bytes_max =	0x8000,	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		256,};/* ----------------------------------------------------------------------- * Audio2 Playback (DAC) * -----------------------------------------------------------------------*/static snd_pcm_hardware_t snd_es1938_playback ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_MMAP_VALID),	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE,	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		6000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,        .buffer_bytes_max =	0x8000,       /* DMA controller screws on higher values */	.period_bytes_min =	64,	.period_bytes_max =	0x8000,	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		256,};static int snd_es1938_capture_open(snd_pcm_substream_t * substream){	es1938_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	if (chip->playback2_substream)		return -EAGAIN;	chip->capture_substream = substream;	runtime->hw = snd_es1938_capture;	snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,				      &hw_constraints_clocks);	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, 0xff00);	return 0;}static int snd_es1938_playback_open(snd_pcm_substream_t * substream){	es1938_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	switch (substream->number) {	case 0:		chip->playback1_substream = substream;		break;	case 1:		if (chip->capture_substream)			return -EAGAIN;		chip->playback2_substream = substream;		break;	default:		snd_BUG();		return -EINVAL;	}	runtime->hw = snd_es1938_playback;	snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,				      &hw_constraints_clocks);	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, 0xff00);	return 0;}static int snd_es1938_capture_close(snd_pcm_substream_t * substream){	es1938_t *chip = snd_pcm_substream_chip(substream);	chip->capture_substream = NULL;	return 0;}static int snd_es1938_playback_close(snd_pcm_substream_t * substream){	es1938_t *chip = snd_pcm_substream_chip(substream);	switch (substream->number) {	case 0:		chip->playback1_substream = NULL;		break;	case 1:		chip->playback2_substream = NULL;		break;	default:		snd_BUG();		return -EINVAL;	}	return 0;}static snd_pcm_ops_t snd_es1938_playback_ops = {	.open =		snd_es1938_playback_open,	.close =	snd_es1938_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_es1938_pcm_hw_params,	.hw_free =	snd_es1938_pcm_hw_free,	.prepare =	snd_es1938_playback_prepare,	.trigger =	snd_es1938_playback_trigger,	.pointer =	snd_es1938_playback_pointer,};static snd_pcm_ops_t snd_es1938_capture_ops = {	.open =		snd_es1938_capture_open,	.close =	snd_es1938_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_es1938_pcm_hw_params,	.hw_free =	snd_es1938_pcm_hw_free,	.prepare =	snd_es1938_capture_prepare,	.trigger =	snd_es1938_capture_trigger,	.pointer =	snd_es1938_capture_pointer,	.copy =		snd_es1938_capture_copy,};static void snd_es1938_free_pcm(snd_pcm_t *pcm){	snd_pcm_lib_preallocate_free_for_all(pcm);}static int __devinit snd_es1938_new_pcm(es1938_t *chip, int device){	snd_pcm_t *pcm;	int err;	if ((err = snd_pcm_new(chip->card, "es-1938-1946", device, 2, 1, &pcm)) < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_es1938_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_es1938_capture_ops);		pcm->private_data = chip;	pcm->private_free = snd_es1938_free_pcm;	pcm->info_flags = 0;	strcpy(pcm->name, "ESS Solo-1");	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,					      snd_dma_pci_data(chip->pci), 64*1024, 64*1024);	chip->pcm = pcm;	return 0;}/* ------------------------------------------------------------------- *  *                       *** Mixer part *** */static int snd_es1938_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	static char *texts[8] = {		"Mic", "Mic Master", "CD", "AOUT",		"Mic1", "Mix", "Line", "Master"	};	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 1;	uinfo->value.enumerated.items = 8;	if (uinfo->value.enumerated.item > 7)		uinfo->value.enumerated.item = 7;	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);	return 0;}static int snd_es1938_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	es1938_t *chip = snd_kcontrol_chip(kcontrol);	ucontrol->value.enumerated.item[0] = snd_es1938_mixer_read(chip, 0x1c) & 0x07;	return 0;}static int snd_es1938_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	es1938_t *chip = snd_kcontrol_chip(kcontrol);	unsigned char val = ucontrol->value.enumerated.item[0];		if (val > 7)		return -EINVAL;	return snd_es1938_mixer_bits(chip, 0x1c, 0x07, val) != val;}static int snd_es1938_info_spatializer_enable(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}static int snd_es1938_get_spatializer_enable(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	es1938_t *chip = snd_kcontrol_chip(kcontrol);	unsigned char val = snd_es1938_mixer_read(chip, 0x50);	ucontrol->value.integer.value[0] = !!(val & 8);	return 0;}static int snd_es1938_put_spatializer_enable(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	es1938_t *chip = snd_kcontrol_chip(kcontrol);	unsigned char oval, nval;	int change;	nval = ucontrol->value.integer.value[0] ? 0x0c : 0x04;	oval = snd_es1938_mixer_read(chip, 0x50) & 0x0c;	change = nval != oval;	if (change) {		snd_es1938_mixer_write(chip, 0x50, nval & ~0x04);		snd_es1938_mixer_write(chip, 0x50, nval);	}	return change;}static int snd_es1938_info_hw_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 63;	return 0;}static int snd_es1938_get_hw_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	es1938_t *chip = snd_kcontrol_chip(kcontrol);	ucontrol->value.integer.value[0] = snd_es1938_mixer_read(chip, 0x61) & 0x3f;	ucontrol->value.integer.value[1] = snd_es1938_mixer_read(chip, 0x63) & 0x3f;	return 0;}static int snd_es1938_info_hw_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}static int snd_es1938_get_hw_switch(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	es1938_t *chip = snd_kcontrol_chip(kcontrol);	ucontrol->value.integer.value[0] = !(snd_es1938_mixer_read(chip, 0x61) & 0x40);	ucontrol->value.integer.value[1] = !(snd_es1938_mixer_read(chip, 0x63) & 0x40);	return 0;}static void snd_es1938_hwv_free(snd_kcontrol_t *kcontrol){	es1938_t *chip = snd_kcontrol_chip(kcontrol);	chip->master_volume = NULL;	chip->master_switch = NULL;	chip->hw_volume = NULL;	chip->hw_switch = NULL;}static int snd_es1938_reg_bits(es1938_t *chip, unsigned char reg,			       unsigned char mask, unsigned char val){	if (reg < 0xa0)		return snd_es1938_mixer_bits(chip, reg, mask, val);	else		return snd_es1938_bits(chip, reg, mask, val);}static int snd_es1938_reg_read(es1938_t *chip, unsigned char reg){	if (reg < 0xa0)		return snd_es1938_mixer_read(chip, reg);	else		return snd_es1938_read(chip, reg);}#define ES1938_SINGLE(xname, xindex, reg, shift, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \  .info = snd_es1938_info_single, \  .get = snd_es1938_get_single, .put = snd_es1938_put_single, \  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }static int snd_es1938_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;}static int snd_es1938_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	es1938_t *chip = snd_kcontrol_chip(kcontrol);	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 val;		val = snd_es1938_reg_read(chip, reg);	ucontrol->value.integer.value[0] = (val >> shift) & mask;	if (invert)		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];	return 0;}static int snd_es1938_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	es1938_t *chip = snd_kcontrol_chip(kcontrol);	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;	unsigned char val;		val = (ucontrol->value.integer.value[0] & mask);	if (invert)		val = mask - val;	mask <<= shift;	val <<= shift;	return snd_es1938_reg_bits(chip, reg, mask, val) != val;}#define ES1938_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \  .info = snd_es1938_info_double, \  .get = snd_es1938_get_double, .put = snd_es1938_put_double, \  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }static int snd_es1938_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;}static int snd_es1938_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	es1938_t *chip = snd_kcontrol_chip(kcontrol);	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;	unsigned char left, right;		left = snd_es1938_reg_read(chip, left_reg);	if (left_reg != right_reg)		right = snd_es1938_reg_read(chip, right_reg);	else		right = left;	ucontrol->value.integer.value[0] = (left >> shift_left) & mask;	ucontrol->value.integer.value[1] = (right >> shift_right) & mask;	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;}static int snd_es1938_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	es1938_t *chip = snd_kcontrol_chip(kcontrol);	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 char val1, val2, mask1, mask2;		val1 = ucontrol->value.integer.value[0] & mask;	val2 = ucontrol->value.integer.value[1] & mask;	if (invert) {		val1 = mask - val1;		val2 = mask - val2;	}	val1 <<= shift_left;	val2 <<= shift_right;	mask1 = mask << shift_left;	mask2 = mask << shift_right;	if (left_reg != right_reg) {		change = 0;		if (snd_es1938_reg_bits(chip, left_reg, mask1, val1) != val1)			change = 1;		if (snd_es1938_reg_bits(chip, right_reg, mask2, val2) != val2)			change = 1;	} else {		change = (snd_es1938_reg_bits(chip, left_reg, mask1 | mask2, 					      val1 | val2) != (val1 | val2));	}	return change;}static snd_kcontrol_new_t snd_es1938_controls[] = {ES1938_DOUBLE("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0),ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1),{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "Hardware Master Playback Volume",	.access = SNDRV_CTL_ELEM_ACCESS_READ,	.info = snd_es1938_info_hw_volume,	.get = snd_es1938_get_hw_volume,},{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "Hardware Master Playback Switch",	.access = SNDRV_CTL_ELEM_ACCESS_READ,	.info = snd_es1938_info_hw_switch,	.get = snd_es1938_get_hw_switch,},

⌨️ 快捷键说明

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