[ALSA] Enable capture from line-in and CD on Revolution 5.1
Jochen Voss [Wed, 4 Oct 2006 16:04:10 +0000 (18:04 +0200)]
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>

include/sound/ak4xxx-adda.h
sound/i2c/other/ak4xxx-adda.c
sound/pci/ice1712/revo.c

index d0deca6..d01d535 100644 (file)
@@ -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 {
index 5da49e2..fe61b92 100644 (file)
@@ -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;
index bf98ea3..d556de5 100644 (file)
@@ -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
        },
 };