summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJochen Voss <voss@seehuhn.de>2006-10-04 18:04:10 +0200
committerJaroslav Kysela <perex@suse.cz>2007-02-09 09:00:03 +0100
commita58e7cb16dfae8a3c1c98a7ab7ca02a9e9b38921 (patch)
treea81382ccf27b01f0c28b1e9812fe27cb8a84fbd0
parente4f8e656d8c152c08cd44d0e3c21f009fab09952 (diff)
[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: Jochen Voss <voss@seehuhn.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
-rw-r--r--include/sound/ak4xxx-adda.h2
-rw-r--r--sound/i2c/other/ak4xxx-adda.c85
-rw-r--r--sound/pci/ice1712/revo.c10
3 files changed, 94 insertions, 3 deletions
diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h
index d0deca669b92..d01d53528015 100644
--- a/include/sound/ak4xxx-adda.h
+++ b/include/sound/ak4xxx-adda.h
@@ -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 {
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 5da49e2eb350..fe61b92f4e47 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -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;
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
index bf98ea34feb0..d556de59b9ae 100644
--- a/sound/pci/ice1712/revo.c
+++ b/sound/pci/ice1712/revo.c
@@ -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
},
};