es18xx.c

来自「linux 内核源代码」· C语言 代码 · 共 2,181 行 · 第 1/5 页

C
2,181
字号
				 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(struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime = substream->runtime;        struct snd_es18xx *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(struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime = substream->runtime;        struct snd_es18xx *chip = snd_pcm_substream_chip(substream);        if (chip->playback_b_substream)                return -EAGAIN;	if ((chip->caps & ES18XX_DUPLEX_MONO) &&	    chip->playback_a_substream &&	    chip->playback_a_substream->runtime->channels != 1)		return -EAGAIN;        chip->capture_a_substream = substream;	substream->runtime->hw = snd_es18xx_capture;	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_playback_close(struct snd_pcm_substream *substream){        struct snd_es18xx *chip = snd_pcm_substream_chip(substream);	if (substream->number == 0 && (chip->caps & ES18XX_PCM2))		chip->playback_a_substream = NULL;	else		chip->playback_b_substream = NULL;		snd_pcm_lib_free_pages(substream);	return 0;}static int snd_es18xx_capture_close(struct snd_pcm_substream *substream){        struct snd_es18xx *chip = snd_pcm_substream_chip(substream);        chip->capture_a_substream = NULL;	snd_pcm_lib_free_pages(substream);        return 0;}/* *  MIXER part *//* Record source mux routines: * Depending on the chipset this mux switches between 4, 5, or 8 possible inputs. * bit table for the 4/5 source mux: * reg 1C: *  b2 b1 b0   muxSource *   x  0  x   microphone *   0  1  x   CD *   1  1  0   line *   1  1  1   mixer * if it's "mixer" and it's a 5 source mux chipset then reg 7A bit 3 determines * either the play mixer or the capture mixer. * * "map4Source" translates from source number to reg bit pattern * "invMap4Source" translates from reg bit pattern to source number */static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){	static char *texts4Source[4] = {		"Mic", "CD", "Line", "Master"	};	static char *texts5Source[5] = {		"Mic", "CD", "Line", "Master", "Mix"	};	static char *texts8Source[8] = {		"Mic", "Mic Master", "CD", "AOUT",		"Mic1", "Mix", "Line", "Master"	};	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 1;	switch (chip->version) {	case 0x1868:	case 0x1878:		uinfo->value.enumerated.items = 4;		if (uinfo->value.enumerated.item > 3)			uinfo->value.enumerated.item = 3;		strcpy(uinfo->value.enumerated.name, texts4Source[uinfo->value.enumerated.item]);		break;	case 0x1887:	case 0x1888:		uinfo->value.enumerated.items = 5;		if (uinfo->value.enumerated.item > 4)			uinfo->value.enumerated.item = 4;		strcpy(uinfo->value.enumerated.name, texts5Source[uinfo->value.enumerated.item]);		break;	case 0x1869: /* DS somewhat contradictory for 1869: could be be 5 or 8 */	case 0x1879:		uinfo->value.enumerated.items = 8;		if (uinfo->value.enumerated.item > 7)			uinfo->value.enumerated.item = 7;		strcpy(uinfo->value.enumerated.name, texts8Source[uinfo->value.enumerated.item]);		break;	default:		return -EINVAL;	}	return 0;}static int snd_es18xx_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	static unsigned char invMap4Source[8] = {0, 0, 1, 1, 0, 0, 2, 3};	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);	int muxSource = snd_es18xx_mixer_read(chip, 0x1c) & 0x07;	if (!(chip->version == 0x1869 || chip->version == 0x1879)) {		muxSource = invMap4Source[muxSource];		if (muxSource==3 && 		    (chip->version == 0x1887 || chip->version == 0x1888) &&		    (snd_es18xx_mixer_read(chip, 0x7a) & 0x08)		) 			muxSource = 4;	}	ucontrol->value.enumerated.item[0] = muxSource;	return 0;}static int snd_es18xx_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	static unsigned char map4Source[4] = {0, 2, 6, 7};	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);	unsigned char val = ucontrol->value.enumerated.item[0];	unsigned char retVal = 0;	switch (chip->version) { /* 5 source chips */	case 0x1887:	case 0x1888:		if (val > 4)			return -EINVAL;		if (val == 4) {			retVal = snd_es18xx_mixer_bits(chip, 0x7a, 0x08, 0x08) != 0x08;			val = 3;		} else			retVal = snd_es18xx_mixer_bits(chip, 0x7a, 0x08, 0x00) != 0x00; /* 4 source chips */	case 0x1868:	case 0x1878:		if (val > 3)			return -EINVAL;		val = map4Source[val];		break; /* 8 source chips */	case 0x1869:	case 0x1879:		if (val > 7)			return -EINVAL;		break;	default:		return -EINVAL;	}	return (snd_es18xx_mixer_bits(chip, 0x1c, 0x07, val) != val) || retVal;}#define snd_es18xx_info_spatializer_enable	snd_ctl_boolean_mono_infostatic int snd_es18xx_get_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);	unsigned char val = snd_es18xx_mixer_read(chip, 0x50);	ucontrol->value.integer.value[0] = !!(val & 8);	return 0;}static int snd_es18xx_put_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);	unsigned char oval, nval;	int change;	nval = ucontrol->value.integer.value[0] ? 0x0c : 0x04;	oval = snd_es18xx_mixer_read(chip, 0x50) & 0x0c;	change = nval != oval;	if (change) {		snd_es18xx_mixer_write(chip, 0x50, nval & ~0x04);		snd_es18xx_mixer_write(chip, 0x50, nval);	}	return change;}static int snd_es18xx_info_hw_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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_es18xx_get_hw_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);	ucontrol->value.integer.value[0] = snd_es18xx_mixer_read(chip, 0x61) & 0x3f;	ucontrol->value.integer.value[1] = snd_es18xx_mixer_read(chip, 0x63) & 0x3f;	return 0;}#define snd_es18xx_info_hw_switch	snd_ctl_boolean_stereo_infostatic int snd_es18xx_get_hw_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);	ucontrol->value.integer.value[0] = !(snd_es18xx_mixer_read(chip, 0x61) & 0x40);	ucontrol->value.integer.value[1] = !(snd_es18xx_mixer_read(chip, 0x63) & 0x40);	return 0;}static void snd_es18xx_hwv_free(struct snd_kcontrol *kcontrol){	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);	chip->master_volume = NULL;	chip->master_switch = NULL;	chip->hw_volume = NULL;	chip->hw_switch = NULL;}static int snd_es18xx_reg_bits(struct snd_es18xx *chip, unsigned char reg,			       unsigned char mask, unsigned char val){	if (reg < 0xa0)		return snd_es18xx_mixer_bits(chip, reg, mask, val);	else		return snd_es18xx_bits(chip, reg, mask, val);}static int snd_es18xx_reg_read(struct snd_es18xx *chip, unsigned char reg){	if (reg < 0xa0)		return snd_es18xx_mixer_read(chip, reg);	else		return snd_es18xx_read(chip, reg);}#define ES18XX_SINGLE(xname, xindex, reg, shift, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \  .info = snd_es18xx_info_single, \  .get = snd_es18xx_get_single, .put = snd_es18xx_put_single, \  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }static int snd_es18xx_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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_es18xx_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_es18xx *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_es18xx_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_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_es18xx *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_es18xx_reg_bits(chip, reg, mask, val) != val;}#define ES18XX_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_es18xx_info_double, \  .get = snd_es18xx_get_double, .put = snd_es18xx_put_double, \  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }static int snd_es18xx_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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_es18xx_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_es18xx *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_es18xx_reg_read(chip, left_reg);	if (left_reg != right_reg)		right = snd_es18xx_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_es18xx_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_es18xx *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_es18xx_reg_bits(chip, left_reg, mask1, val1) != val1)			change = 1;		if (snd_es18xx_reg_bits(chip, right_reg, mask2, val2) != val2)			change = 1;	} else {		change = (snd_es18xx_reg_bits(chip, left_reg, mask1 | mask2, 					      val1 | val2) != (val1 | val2));	}	return change;}/* Mixer controls * These arrays contain setup data for mixer controls. *  * The controls that are universal to all chipsets are fully initialized * here. */static struct snd_kcontrol_new snd_es18xx_base_controls[] = {ES18XX_DOUBLE("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0),ES18XX_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1),ES18XX_DOUBLE("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0),ES18XX_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0),ES18XX_DOUBLE("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0),ES18XX_DOUBLE("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0),ES18XX_DOUBLE("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0),ES18XX_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0),ES18XX_DOUBLE("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0),{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "Capture Source",	.info = snd_es18xx_info_mux,	.get = snd_es18xx_get_mux,	.put = snd_es18xx_put_mux,}};static struct snd_kcontrol_new snd_es18xx_recmix_controls[] = {ES18XX_DOUBLE("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0),ES18XX_DOUBLE("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0),ES18XX_DOUBLE("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0),ES18XX_DOUBLE("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0),ES18XX_DOUBLE("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0),ES18XX_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0)};

⌨️ 快捷键说明

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