Commit a58e7cb1 authored by Jochen Voss's avatar Jochen Voss Committed by Jaroslav Kysela
Browse files

[ALSA] Enable capture from line-in and CD on Revolution 5.1



Enable capture from line-in and CD on the Revolution 5.1 card.
This patch adds support for switching between the 5 input channels of
the AK5365 ADC and modifies the Revolution 5.1 driver to make use of
this facility.  Previously the capture channel was fixed to channel 0
(microphone on the Revolution 5.1 card).

Signed-off-by: default avatarJochen Voss <voss@seehuhn.de>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJaroslav Kysela <perex@suse.cz>
parent e4f8e656
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@ struct snd_akm4xxx_adc_channel {
	char *name;		/* capture gain volume label */
	char *switch_name;	/* capture switch */
	unsigned int num_channels;
	char *selector_name;	/* capture source select label */
	const char **input_names; /* capture source names (NULL terminated) */
};

struct snd_akm4xxx {
+83 −2
Original line number Diff line number Diff line
@@ -513,6 +513,66 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
	return change;
}

#define AK5365_NUM_INPUTS 5

static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
				      struct snd_ctl_elem_info *uinfo)
{
	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
	int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
	const char **input_names;
	int  num_names, idx;

	input_names = ak->adc_info[mixer_ch].input_names;

	num_names = 0;
	while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
		++num_names;
	
	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
	uinfo->count = 1;
	uinfo->value.enumerated.items = num_names;
	idx = uinfo->value.enumerated.item;
	if (idx >= num_names)
		return -EINVAL;
	strncpy(uinfo->value.enumerated.name, input_names[idx],
		sizeof(uinfo->value.enumerated.name));
	return 0;
}

static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
				     struct snd_ctl_elem_value *ucontrol)
{
	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
	int chip = AK_GET_CHIP(kcontrol->private_value);
	int addr = AK_GET_ADDR(kcontrol->private_value);
	int mask = AK_GET_MASK(kcontrol->private_value);
	unsigned char val;

	val = snd_akm4xxx_get(ak, chip, addr) & mask;
	ucontrol->value.enumerated.item[0] = val;
	return 0;
}

static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
				     struct snd_ctl_elem_value *ucontrol)
{
	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
	int chip = AK_GET_CHIP(kcontrol->private_value);
	int addr = AK_GET_ADDR(kcontrol->private_value);
	int mask = AK_GET_MASK(kcontrol->private_value);
	unsigned char oval, val;

	oval = snd_akm4xxx_get(ak, chip, addr);
	val = oval & ~mask;
	val |= ucontrol->value.enumerated.item[0] & mask;
	if (val != oval) {
		snd_akm4xxx_write(ak, chip, addr, val);
		return 1;
	}
	return 0;
}

/*
 * build AK4xxx controls
 */
@@ -647,9 +707,10 @@ static int build_adc_controls(struct snd_akm4xxx *ak)

		if (ak->type == SND_AK5365 && (idx % 2) == 0) {
			if (! ak->adc_info || 
			    ! ak->adc_info[mixer_ch].switch_name)
			    ! ak->adc_info[mixer_ch].switch_name) {
				knew.name = "Capture Switch";
			else
				knew.index = mixer_ch + ak->idx_offset * 2;
			} else
				knew.name = ak->adc_info[mixer_ch].switch_name;
			knew.info = ak4xxx_switch_info;
			knew.get = ak4xxx_switch_get;
@@ -662,6 +723,26 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
			err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
			if (err < 0)
				return err;

			memset(&knew, 0, sizeof(knew));
			knew.name = ak->adc_info[mixer_ch].selector_name;
			if (!knew.name) {
				knew.name = "Capture Channel";
				knew.index = mixer_ch + ak->idx_offset * 2;
			}

			knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
			knew.info = ak4xxx_capture_source_info;
			knew.get = ak4xxx_capture_source_get;
			knew.put = ak4xxx_capture_source_put;
			knew.access = 0;
			/* input selector control: reg. 1, bits 0-2.
			 * mis-use 'shift' to pass mixer_ch */
			knew.private_value
				= AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
			err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
			if (err < 0)
				return err;
		}

		idx += num_stereo;
+9 −1
Original line number Diff line number Diff line
@@ -107,11 +107,19 @@ static struct snd_akm4xxx_dac_channel revo51_dac[] = {
	AK_DAC("PCM Rear Playback Volume", 2),
};

static const char *revo51_adc_input_names[] = {
	"Mic",
	"Line",
	"CD",
	NULL
};

static struct snd_akm4xxx_adc_channel revo51_adc[] = {
	{
		.name = "PCM Capture Volume",
		.switch_name = "PCM Capture Switch",
		.num_channels = 2
		.num_channels = 2,
		.input_names = revo51_adc_input_names
	},
};