ALSA: hda - Prefer multi-io to speakers for realtek auto-parser
authorTakashi Iwai <tiwai@suse.de>
Wed, 24 Aug 2011 15:57:44 +0000 (17:57 +0200)
committerTakashi Iwai <tiwai@suse.de>
Wed, 24 Aug 2011 15:57:44 +0000 (17:57 +0200)
When the multi-io jacks are available, parse them first and assign DACs
before parsing speakers and headphones.  This allows a better chance of
surround I/O in some desktops and laptops with limited DACs.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/patch_realtek.c

index de63619..fa95825 100644 (file)
@@ -2814,8 +2814,9 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
                if (found_in_nid_list(nid, spec->multiout.dac_nids,
                                      spec->multiout.num_dacs))
                        continue;
-               if (spec->multiout.hp_out_nid[0] == nid)
-                       continue;
+               if (found_in_nid_list(nid, spec->multiout.hp_out_nid,
+                                     ARRAY_SIZE(spec->multiout.hp_out_nid)))
+                   continue;
                if (found_in_nid_list(nid, spec->multiout.extra_out_nid,
                                      ARRAY_SIZE(spec->multiout.extra_out_nid)))
                    continue;
@@ -2832,6 +2833,29 @@ static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
        return 0;
 }
 
+static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
+                                   const hda_nid_t *pins, hda_nid_t *dacs)
+{
+       int i;
+
+       if (num_outs && !dacs[0]) {
+               dacs[0] = alc_auto_look_for_dac(codec, pins[0]);
+               if (!dacs[0])
+                       return 0;
+       }
+
+       for (i = 1; i < num_outs; i++)
+               dacs[i] = get_dac_if_single(codec, pins[i]);
+       for (i = 1; i < num_outs; i++) {
+               if (!dacs[i])
+                       dacs[i] = alc_auto_look_for_dac(codec, pins[i]);
+       }
+       return 0;
+}
+
+static int alc_auto_fill_multi_ios(struct hda_codec *codec,
+                                  unsigned int location);
+
 /* fill in the dac_nids table from the parsed pin configuration */
 static int alc_auto_fill_dac_nids(struct hda_codec *codec)
 {
@@ -2886,35 +2910,27 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
                                sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
        }
 
-       if (cfg->hp_outs && !spec->multiout.hp_out_nid[0])
-               spec->multiout.hp_out_nid[0] =
-                       alc_auto_look_for_dac(codec, cfg->hp_pins[0]);
-       if (cfg->speaker_outs && !spec->multiout.extra_out_nid[0])
-               spec->multiout.extra_out_nid[0] =
-                       alc_auto_look_for_dac(codec, cfg->speaker_pins[0]);
+       if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+               /* try to fill multi-io first */
+               unsigned int location, defcfg;
+               int num_pins;
 
-       return 0;
-}
+               defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
+               location = get_defcfg_location(defcfg);
 
-/* fill in the dac_nids table for surround speakers, etc */
-static int alc_auto_fill_extra_dacs(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       const struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
+               num_pins = alc_auto_fill_multi_ios(codec, location);
+               if (num_pins > 0) {
+                       spec->multi_ios = num_pins;
+                       spec->ext_channel_count = 2;
+                       spec->multiout.num_dacs = num_pins + 1;
+               }
+       }
 
-       if (cfg->speaker_outs < 2 || !spec->multiout.extra_out_nid[0])
-               return 0;
+       alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins,
+                                spec->multiout.hp_out_nid);
+       alc_auto_fill_extra_dacs(codec, cfg->speaker_outs, cfg->speaker_pins,
+                                spec->multiout.extra_out_nid);
 
-       for (i = 1; i < cfg->speaker_outs; i++)
-               spec->multiout.extra_out_nid[i] =
-                       get_dac_if_single(codec, cfg->speaker_pins[i]);
-       for (i = 1; i < cfg->speaker_outs; i++) {
-               if (spec->multiout.extra_out_nid[i])
-                       continue;
-               spec->multiout.extra_out_nid[i] =
-                       alc_auto_look_for_dac(codec, cfg->speaker_pins[0]);
-       }
        return 0;
 }
 
@@ -3264,6 +3280,7 @@ static int alc_auto_fill_multi_ios(struct hda_codec *codec,
 {
        struct alc_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t prime_dac = spec->private_dac_nids[0];
        int type, i, num_pins = 0;
 
        for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
@@ -3291,8 +3308,13 @@ static int alc_auto_fill_multi_ios(struct hda_codec *codec,
                }
        }
        spec->multiout.num_dacs = 1;
-       if (num_pins < 2)
+       if (num_pins < 2) {
+               /* clear up again */
+               memset(spec->private_dac_nids, 0,
+                      sizeof(spec->private_dac_nids));
+               spec->private_dac_nids[0] = prime_dac;
                return 0;
+       }
        return num_pins;
 }
 
@@ -3381,19 +3403,8 @@ static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
 static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int location, defcfg;
-       int num_pins;
-
-       if (cfg->line_outs != 1 ||
-           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-               return 0;
 
-       defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
-       location = get_defcfg_location(defcfg);
-
-       num_pins = alc_auto_fill_multi_ios(codec, location);
-       if (num_pins > 0) {
+       if (spec->multi_ios > 0) {
                struct snd_kcontrol_new *knew;
 
                knew = alc_kcontrol_new(spec);
@@ -3403,10 +3414,6 @@ static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
                knew->name = kstrdup("Channel Mode", GFP_KERNEL);
                if (!knew->name)
                        return -ENOMEM;
-
-               spec->multi_ios = num_pins;
-               spec->ext_channel_count = 2;
-               spec->multiout.num_dacs = num_pins + 1;
        }
        return 0;
 }
@@ -3723,9 +3730,6 @@ static int alc_parse_auto_config(struct hda_codec *codec,
        err = alc_auto_add_multi_channel_mode(codec);
        if (err < 0)
                return err;
-       err = alc_auto_fill_extra_dacs(codec);
-       if (err < 0)
-               return err;
        err = alc_auto_create_multi_out_ctls(codec, cfg);
        if (err < 0)
                return err;