Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=7b043899992e5d9c0b1a620cdad9158d2e5484d7
Commit:     7b043899992e5d9c0b1a620cdad9158d2e5484d7
Parent:     7e0af29d6f3964bec3d72c6caeb87a603e660fdf
Author:     Steve Longerbeam <[EMAIL PROTECTED]>
AuthorDate: Thu May 3 20:50:03 2007 +0200
Committer:  Jaroslav Kysela <[EMAIL PROTECTED]>
CommitDate: Fri May 11 16:56:15 2007 +0200

    [ALSA] hda-codec - bug fixes for stac92xx HDA codecs.
    
    * fixed surround playback on stac922x. Pin direction control bits were
      not being set correctly in stac92xx_set_pinctl(). Specifically it
      would refuse to set the port as an output if the port was already
      configured as an input. Last hunk (#8).
    * fixed an input mux bug on 92xx codecs. When there is more than one
      possible input calculated for the muxes, the actual mux widget never
      gets set from its reset default, which is index 0, in the stac9221
      case that is port E. So alsamixer/amixer/gnome-mixer report the Mic
      as being the selected input source, but in fact is something else
      (line-in port E in stac9221 case). Another problem with this is that
      if you actually try to set the mux input to 'Mic', nothing happens
      because *cur_val == idx (see snd_hda_input_mux_put). You have to
      actually toggle input source to line-in then back to mic to actually
      set the mux widget. Hunk #7.
    * fixed some typos in patch_sigmatel.c. Hunk #6.
    * fix to stac92xx_add_dyn_out_pins() that fixes surround playback on
      codecs with less that 4 DACs (stac9205 for example). It reads the widget
      caps cache created by hda_codec to count the total number of analog DACs
      found. It then uses that to determine whether there will be enough
      independent DACs available for line/mic switch controls. Hunk #1, #2,
      and #3.
    * improvements to stac92xx_auto_fill_dac_nids() to make it more general.
      This fixes surround playback on some codecs in combination with the
      fix to stac92xx_add_dyn_out_pins() above. It reads the full connection
      list now, instead of just the first entry, and then locates an analog
      DAC in the list. If one is found and it's free, assign it to that 
line-out.
      If no free DAC is found for the line-out, return -ENODEV. It also makes
      sure to actually select the chosen DAC if more than one DAC is input to
      the pin. Hunks #4, #5.
    
    Signed-off-by: Steve Longerbeam <[EMAIL PROTECTED]>
    Signed-off-by: Takashi Iwai <[EMAIL PROTECTED]>
    Signed-off-by: Jaroslav Kysela <[EMAIL PROTECTED]>
---
 sound/pci/hda/patch_sigmatel.c |  121 ++++++++++++++++++++++++++++-----------
 1 files changed, 87 insertions(+), 34 deletions(-)

diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index ebf7dde..93ae9c2 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -1070,11 +1070,23 @@ static int stac92xx_add_control(struct sigmatel_spec 
*spec, int type, const char
 static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct 
auto_pin_cfg *cfg)
 {
        struct sigmatel_spec *spec = codec->spec;
+       unsigned int wcaps, wtype;
+       int i, num_dacs = 0;
+       
+       /* use the wcaps cache to count all DACs available for line-outs */
+       for (i = 0; i < codec->num_nodes; i++) {
+               wcaps = codec->wcaps[i];
+               wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+               if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
+                       num_dacs++;
+       }
 
+       snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
+       
        switch (cfg->line_outs) {
        case 3:
                /* add line-in as side */
-               if (cfg->input_pins[AUTO_PIN_LINE]) {
+               if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
                        cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_LINE];
                        spec->line_switch = 1;
                        cfg->line_outs++;
@@ -1082,12 +1094,12 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec 
*codec, struct auto_pin_cf
                break;
        case 2:
                /* add line-in as clfe and mic as side */
-               if (cfg->input_pins[AUTO_PIN_LINE]) {
+               if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
                        cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_LINE];
                        spec->line_switch = 1;
                        cfg->line_outs++;
                }
-               if (cfg->input_pins[AUTO_PIN_MIC]) {
+               if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
                        cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_MIC];
                        spec->mic_switch = 1;
                        cfg->line_outs++;
@@ -1095,12 +1107,12 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec 
*codec, struct auto_pin_cf
                break;
        case 1:
                /* add line-in as surr and mic as clfe */
-               if (cfg->input_pins[AUTO_PIN_LINE]) {
+               if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
                        cfg->line_out_pins[1] = cfg->input_pins[AUTO_PIN_LINE];
                        spec->line_switch = 1;
                        cfg->line_outs++;
                }
-               if (cfg->input_pins[AUTO_PIN_MIC]) {
+               if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
                        cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_MIC];
                        spec->mic_switch = 1;
                        cfg->line_outs++;
@@ -1111,33 +1123,76 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec 
*codec, struct auto_pin_cf
        return 0;
 }
 
+
+static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
+{
+       int i;
+       
+       for (i = 0; i < spec->multiout.num_dacs; i++) {
+               if (spec->multiout.dac_nids[i] == nid)
+                       return 1;
+       }
+
+       return 0;
+}
+
 /*
- * XXX The line_out pin widget connection list may not be set to the
- * desired DAC nid. This is the case on 927x where ports A and B can
- * be routed to several DACs.
- *
- * This requires an analysis of the line-out/hp pin configuration
- * to provide a best fit for pin/DAC configurations that are routable.
- * For now, 927x DAC4 is not supported and 927x DAC1 output to ports
- * A and B is not supported.
+ * Fill in the dac_nids table from the parsed pin configuration
+ * This function only works when every pin in line_out_pins[]
+ * contains atleast one DAC in its connection list. Some 92xx
+ * codecs are not connected directly to a DAC, such as the 9200
+ * and 9202/925x. For those, dac_nids[] must be hard-coded.
  */
-/* fill in the dac_nids table from the parsed pin configuration */
 static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
                                       const struct auto_pin_cfg *cfg)
 {
        struct sigmatel_spec *spec = codec->spec;
-       hda_nid_t nid;
-       int i;
-
-       /* check the pins hardwired to audio widget */
+       int i, j, conn_len = 0; 
+       hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
+       unsigned int wcaps, wtype;
+       
        for (i = 0; i < cfg->line_outs; i++) {
                nid = cfg->line_out_pins[i];
-               spec->multiout.dac_nids[i] = snd_hda_codec_read(codec, nid, 0,
-                                       AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
-       }
+               conn_len = snd_hda_get_connections(codec, nid, conn,
+                                                  HDA_MAX_CONNECTIONS);
+               for (j = 0; j < conn_len; j++) {
+                       wcaps = snd_hda_param_read(codec, conn[j],
+                                                  AC_PAR_AUDIO_WIDGET_CAP);
+                       wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+
+                       if (wtype != AC_WID_AUD_OUT ||
+                           (wcaps & AC_WCAP_DIGITAL))
+                               continue;
+                       /* conn[j] is a DAC routed to this line-out */
+                       if (!is_in_dac_nids(spec, conn[j]))
+                               break;
+               }
+
+               if (j == conn_len) {
+                       /* error out, no available DAC found */
+                       snd_printk(KERN_ERR
+                                  "%s: No available DAC for pin 0x%x\n",
+                                  __func__, nid);
+                       return -ENODEV;
+               }
+
+               spec->multiout.dac_nids[i] = conn[j];
+               spec->multiout.num_dacs++;
+               if (conn_len > 1) {
+                       /* select this DAC in the pin's input mux */
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_CONNECT_SEL, j);
 
-       spec->multiout.num_dacs = cfg->line_outs;
+               }
+       }
 
+       snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+                  spec->multiout.num_dacs,
+                  spec->multiout.dac_nids[0],
+                  spec->multiout.dac_nids[1],
+                  spec->multiout.dac_nids[2],
+                  spec->multiout.dac_nids[3],
+                  spec->multiout.dac_nids[4]);
        return 0;
 }
 
@@ -1204,12 +1259,8 @@ static int stac92xx_auto_create_multi_out_ctls(struct 
sigmatel_spec *spec,
 
 static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
 {
-       int i;
-
-       for (i = 0; i < spec->multiout.num_dacs; i++) {
-               if (spec->multiout.dac_nids[i] == nid)
-                       return 1;
-       }
+       if (is_in_dac_nids(spec, nid))
+               return 1;
        if (spec->multiout.hp_nid == nid)
                return 1;
        return 0;
@@ -1251,12 +1302,10 @@ static int stac92xx_auto_create_hp_ctls(struct 
hda_codec *codec,
                add_spec_dacs(spec, nid);
        }
        for (i = 0; i < cfg->speaker_outs; i++) {
-               nid = snd_hda_codec_read(codec, cfg->speaker_pins[0], 0,
+               nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
                                         AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
                if (check_in_dac_nids(spec, nid))
                        nid = 0;
-               if (check_in_dac_nids(spec, nid))
-                       nid = 0;
                if (! nid)
                        continue;
                add_spec_dacs(spec, nid);
@@ -1370,7 +1419,7 @@ static int stac92xx_auto_create_analog_input_ctls(struct 
hda_codec *codec, const
                imux->num_items++;
        }
 
-       if (imux->num_items == 1) {
+       if (imux->num_items) {
                /*
                 * Set the current input for the muxes.
                 * The STAC9221 has two input muxes with identical source
@@ -1690,8 +1739,12 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, 
hda_nid_t nid,
 {
        unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
                        0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
-       if (flag == AC_PINCTL_OUT_EN && (pin_ctl & AC_PINCTL_IN_EN))
-               return;
+
+       /* if setting pin direction bits, clear the current
+          direction bits first */
+       if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
+               pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
+       
        snd_hda_codec_write(codec, nid, 0,
                        AC_VERB_SET_PIN_WIDGET_CONTROL,
                        pin_ctl | flag);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to