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

[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
...@@ -50,6 +50,8 @@ struct snd_akm4xxx_adc_channel { ...@@ -50,6 +50,8 @@ struct snd_akm4xxx_adc_channel {
char *name; /* capture gain volume label */ char *name; /* capture gain volume label */
char *switch_name; /* capture switch */ char *switch_name; /* capture switch */
unsigned int num_channels; unsigned int num_channels;
char *selector_name; /* capture source select label */
const char **input_names; /* capture source names (NULL terminated) */
}; };
struct snd_akm4xxx { struct snd_akm4xxx {
......
...@@ -513,6 +513,66 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol, ...@@ -513,6 +513,66 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
return change; 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 * build AK4xxx controls
*/ */
...@@ -647,9 +707,10 @@ static int build_adc_controls(struct snd_akm4xxx *ak) ...@@ -647,9 +707,10 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
if (ak->type == SND_AK5365 && (idx % 2) == 0) { if (ak->type == SND_AK5365 && (idx % 2) == 0) {
if (! ak->adc_info || if (! ak->adc_info ||
! ak->adc_info[mixer_ch].switch_name) ! ak->adc_info[mixer_ch].switch_name) {
knew.name = "Capture Switch"; knew.name = "Capture Switch";
else knew.index = mixer_ch + ak->idx_offset * 2;
} else
knew.name = ak->adc_info[mixer_ch].switch_name; knew.name = ak->adc_info[mixer_ch].switch_name;
knew.info = ak4xxx_switch_info; knew.info = ak4xxx_switch_info;
knew.get = ak4xxx_switch_get; knew.get = ak4xxx_switch_get;
...@@ -662,6 +723,26 @@ static int build_adc_controls(struct snd_akm4xxx *ak) ...@@ -662,6 +723,26 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
if (err < 0) if (err < 0)
return err; 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; idx += num_stereo;
......
...@@ -107,11 +107,19 @@ static struct snd_akm4xxx_dac_channel revo51_dac[] = { ...@@ -107,11 +107,19 @@ static struct snd_akm4xxx_dac_channel revo51_dac[] = {
AK_DAC("PCM Rear Playback Volume", 2), 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[] = { static struct snd_akm4xxx_adc_channel revo51_adc[] = {
{ {
.name = "PCM Capture Volume", .name = "PCM Capture Volume",
.switch_name = "PCM Capture Switch", .switch_name = "PCM Capture Switch",
.num_channels = 2 .num_channels = 2,
.input_names = revo51_adc_input_names
}, },
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment