[ALSA] ac97 - Smart 5.1 for VIA 1617a codec
authorJohn Utz <john.utz@dmx.com>
Mon, 12 Mar 2007 11:30:06 +0000 (12:30 +0100)
committerJaroslav Kysela <perex@suse.cz>
Fri, 11 May 2007 14:55:48 +0000 (16:55 +0200)
This patch provides a single 8 way enum called 'Smart 5.1 Select' with
some reasonable names for each enum that allows the user to choose
which of the 8 possible settings for vt1617a's version of what via
calls 'Smart 5.1'.

Signed-off-by: John Utz <john.utz@dmx.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
sound/pci/ac97/ac97_patch.c

index 43455fc..3eac0f8 100644 (file)
@@ -3277,16 +3277,111 @@ static int patch_vt1616(struct snd_ac97 * ac97)
 /*
  * VT1617A codec
  */
-static int patch_vt1617a(struct snd_ac97 * ac97)
+
+/*
+ * unfortunately, the vt1617a stashes the twiddlers required for
+ * nooding the i/o jacks on 2 different regs. * thameans that we cant
+ * use the easy way provided by AC97_ENUM_DOUBLE() we have to write
+ * are own funcs.
+ *
+ * NB: this is absolutely and utterly different from the vt1618. dunno
+ * about the 1616.
+ */
+
+/* copied from ac97_surround_jack_mode_info() */
+static int snd_ac97_vt1617a_smart51_info(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_info *uinfo)
 {
-       /* bring analog power consumption to normal, like WinXP driver
-        * for EPIA SP
+       /* ordering in this list reflects vt1617a docs for Reg 20 and
+        * 7a and Table 6 that lays out the matrix NB WRT Table6: SM51
+        * is SM51EN *AND* it's Bit14, not Bit15 so the table is very
+        * counter-intuitive */ 
+
+       static const char* texts[] = { "LineIn Mic1", "LineIn Mic1 Mic3",
+                                      "Surr LFE/C Mic3", "LineIn LFE/C Mic3",
+                                      "LineIn Mic2", "LineIn Mic2 Mic1",
+                                      "Surr LFE Mic1", "Surr LFE Mic1 Mic2"};
+       return ac97_enum_text_info(kcontrol, uinfo, texts, 8);
+}
+
+static int snd_ac97_vt1617a_smart51_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ushort usSM51, usMS;  
+
+       struct snd_ac97 *pac97;
+       
+       pac97 = snd_kcontrol_chip(kcontrol); /* grab codec handle */
+
+       /* grab our desirec bits, then mash them together in a manner
+        * consistent with Table 6 on page 17 in the 1617a docs */
+       usSM51 = snd_ac97_read(pac97, 0x7a) >> 14;
+       usMS   = snd_ac97_read(pac97, 0x20) >> 8;
+  
+       ucontrol->value.enumerated.item[0] = (usSM51 << 1) + usMS;
+
+       return 0;
+}
+
+static int snd_ac97_vt1617a_smart51_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ushort usSM51, usMS, usReg;  
+
+       struct snd_ac97 *pac97;
+
+       pac97 = snd_kcontrol_chip(kcontrol); /* grab codec handle */
+
+       usSM51 = ucontrol->value.enumerated.item[0] >> 1;
+       usMS   = ucontrol->value.enumerated.item[0] &  1;
+
+       /* push our values into the register - consider that things will be left
+        * in a funky state if the write fails */
+
+       usReg = snd_ac97_read(pac97, 0x7a);
+       snd_ac97_write_cache(pac97, 0x7a, (usReg & 0x3FFF) + (usSM51 << 14));
+       usReg = snd_ac97_read(pac97, 0x20);
+       snd_ac97_write_cache(pac97, 0x20, (usReg & 0xFEFF) + (usMS   <<  8));
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new snd_ac97_controls_vt1617a[] = {
+
+       AC97_SINGLE("Center/LFE Exchange", 0x5a, 8, 1, 0),
+       /*
+        * These are used to enable/disable surround sound on motherboards
+        * that have 3 bidirectional analog jacks
+        */
+       {
+               .iface         = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name          = "Smart 5.1 Select",
+               .info          = snd_ac97_vt1617a_smart51_info,
+               .get           = snd_ac97_vt1617a_smart51_get,
+               .put           = snd_ac97_vt1617a_smart51_put,
+       },
+};
+
+int patch_vt1617a(struct snd_ac97 * ac97)
+{
+       int err = 0;
+
+       /* we choose to not fail out at this point, but we tell the
+          caller when we return */
+
+       err = patch_build_controls(ac97, &snd_ac97_controls_vt1617a[0],
+                                  ARRAY_SIZE(snd_ac97_controls_vt1617a));
+
+       /* bring analog power consumption to normal by turning off the
+        * headphone amplifier, like WinXP driver for EPIA SP
         */
        snd_ac97_write_cache(ac97, 0x5c, 0x20);
        ac97->ext_id |= AC97_EI_SPDIF;  /* force the detection of spdif */
        ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
        ac97->build_ops = &patch_vt1616_ops;
-       return 0;
+
+       return err;
 }
 
 /*