diff options
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 196 |
1 files changed, 134 insertions, 62 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4b2ecbcbe66..d0c71d5be83 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2929,6 +2929,7 @@ static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin, static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) { struct alc_spec *spec = codec->spec; + int i; if (found_in_nid_list(nid, spec->multiout.dac_nids, ARRAY_SIZE(spec->private_dac_nids)) || found_in_nid_list(nid, spec->multiout.hp_out_nid, @@ -2936,6 +2937,10 @@ static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) found_in_nid_list(nid, spec->multiout.extra_out_nid, ARRAY_SIZE(spec->multiout.extra_out_nid))) return true; + for (i = 0; i < spec->multi_ios; i++) { + if (spec->multi_io[i].dac == nid) + return true; + } return false; } @@ -3028,20 +3033,20 @@ enum { BAD_NO_PRIMARY_DAC = 0x10000, /* No DAC is found for the extra output */ BAD_NO_DAC = 0x4000, + /* No possible multi-ios */ + BAD_MULTI_IO = 0x103, /* No individual DAC for extra output */ - BAD_NO_EXTRA_DAC = 0x1000, + BAD_NO_EXTRA_DAC = 0x102, /* No individual DAC for extra surrounds */ - BAD_NO_EXTRA_SURR_DAC = 0x200, + BAD_NO_EXTRA_SURR_DAC = 0x101, /* Primary DAC shared with main surrounds */ BAD_SHARED_SURROUND = 0x100, - /* Volume widget is shared */ - BAD_SHARED_VOL = 0x10, /* Primary DAC shared with main CLFE */ BAD_SHARED_CLFE = 0x10, /* Primary DAC shared with extra surrounds */ BAD_SHARED_EXTRA_SURROUND = 0x10, - /* No possible multi-ios */ - BAD_MULTI_IO = 0x1, + /* Volume widget is shared */ + BAD_SHARED_VOL = 0x10, }; static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec, @@ -3140,7 +3145,8 @@ static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs, } static int alc_auto_fill_multi_ios(struct hda_codec *codec, - unsigned int location, int offset); + hda_nid_t reference_pin, + bool hardwired, int offset); static bool alc_map_singles(struct hda_codec *codec, int outs, const hda_nid_t *pins, hda_nid_t *dacs) @@ -3159,11 +3165,11 @@ static bool alc_map_singles(struct hda_codec *codec, int outs, /* fill in the dac_nids table from the parsed pin configuration */ static int fill_and_eval_dacs(struct hda_codec *codec, - bool fill_hardwired) + bool fill_hardwired, + bool fill_mio_first) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int location, defcfg; int i, j, err, badness; /* set num_dacs once to full for alc_auto_look_for_dac() */ @@ -3181,14 +3187,20 @@ static int fill_and_eval_dacs(struct hda_codec *codec, bool mapped; do { mapped = alc_map_singles(codec, cfg->line_outs, - cfg->line_out_pins, - spec->private_dac_nids); + cfg->line_out_pins, + spec->private_dac_nids); mapped |= alc_map_singles(codec, cfg->hp_outs, cfg->hp_pins, spec->multiout.hp_out_nid); mapped |= alc_map_singles(codec, cfg->speaker_outs, cfg->speaker_pins, spec->multiout.extra_out_nid); + if (fill_mio_first && cfg->line_outs == 1 && + cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], true, 0); + if (!err) + mapped = true; + } } while (mapped); } @@ -3240,14 +3252,13 @@ static int fill_and_eval_dacs(struct hda_codec *codec, } } - if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + if (fill_mio_first && + cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { /* try to fill multi-io first */ - defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]); - location = get_defcfg_location(defcfg); - err = alc_auto_fill_multi_ios(codec, location, 0); + err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0); if (err < 0) return err; - badness += err; + /* we don't count badness at this stage yet */ } if (cfg->line_out_type != AUTO_PIN_HP_OUT) { @@ -3266,18 +3277,30 @@ static int fill_and_eval_dacs(struct hda_codec *codec, return err; badness += err; } - if (!spec->multi_ios && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && - cfg->hp_outs) { + if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0); + if (err < 0) + return err; + badness += err; + } + if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { /* try multi-ios with HP + inputs */ - defcfg = snd_hda_codec_get_pincfg(codec, cfg->hp_pins[0]); - location = get_defcfg_location(defcfg); - err = alc_auto_fill_multi_ios(codec, location, 1); + err = alc_auto_fill_multi_ios(codec, cfg->hp_pins[0], false, 1); if (err < 0) return err; badness += err; } + if (spec->multi_ios == 2) { + for (i = 0; i < 2; i++) + spec->private_dac_nids[spec->multiout.num_dacs++] = + spec->multi_io[i].dac; + spec->ext_channel_count = 2; + } else if (spec->multi_ios) { + spec->multi_ios = 0; + badness += BAD_MULTI_IO; + } + return badness; } @@ -3326,8 +3349,8 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) struct auto_pin_cfg *best_cfg; int best_badness = INT_MAX; int badness; - bool fill_hardwired = true; - bool best_wired = true; + bool fill_hardwired = true, fill_mio_first = true; + bool best_wired = true, best_mio = true; bool hp_spk_swapped = false; best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); @@ -3336,23 +3359,28 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) *best_cfg = *cfg; for (;;) { - badness = fill_and_eval_dacs(codec, fill_hardwired); + badness = fill_and_eval_dacs(codec, fill_hardwired, + fill_mio_first); if (badness < 0) return badness; - debug_badness("==> lo_type=%d, wired=%d, badness=0x%x\n", - cfg->line_out_type, fill_hardwired, badness); + debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", + cfg->line_out_type, fill_hardwired, fill_mio_first, + badness); debug_show_configs(spec, cfg); if (badness < best_badness) { best_badness = badness; *best_cfg = *cfg; best_wired = fill_hardwired; + best_mio = fill_mio_first; } if (!badness) break; - if (fill_hardwired) { - fill_hardwired = false; + fill_mio_first = !fill_mio_first; + if (!fill_mio_first) + continue; + fill_hardwired = !fill_hardwired; + if (!fill_hardwired) continue; - } if (hp_spk_swapped) break; hp_spk_swapped = true; @@ -3389,10 +3417,10 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) if (badness) { *cfg = *best_cfg; - fill_and_eval_dacs(codec, best_wired); + fill_and_eval_dacs(codec, best_wired, best_mio); } - debug_badness("==> Best config: lo_type=%d, wired=%d\n", - cfg->line_out_type, best_wired); + debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", + cfg->line_out_type, best_wired, best_mio); debug_show_configs(spec, cfg); if (cfg->line_out_pins[0]) @@ -3791,66 +3819,110 @@ static void alc_auto_init_extra_out(struct hda_codec *codec) } } +/* check whether the given pin can be a multi-io pin */ +static bool can_be_multiio_pin(struct hda_codec *codec, + unsigned int location, hda_nid_t nid) +{ + unsigned int defcfg, caps; + + defcfg = snd_hda_codec_get_pincfg(codec, nid); + if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) + return false; + if (location && get_defcfg_location(defcfg) != location) + return false; + caps = snd_hda_query_pin_caps(codec, nid); + if (!(caps & AC_PINCAP_OUT)) + return false; + return true; +} + /* * multi-io helper + * + * When hardwired is set, try to fill ony hardwired pins, and returns + * zero if any pins are filled, non-zero if nothing found. + * When hardwired is off, try to fill possible input pins, and returns + * the badness value. */ static int alc_auto_fill_multi_ios(struct hda_codec *codec, - unsigned int location, - int offset) + hda_nid_t reference_pin, + bool hardwired, int offset) { 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, dacs, num_pins = 0; + int type, i, j, dacs, num_pins, old_pins; + unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); + unsigned int location = get_defcfg_location(defcfg); int badness = 0; + old_pins = spec->multi_ios; + if (old_pins >= 2) + goto end_fill; + + num_pins = 0; + for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].type != type) + continue; + if (can_be_multiio_pin(codec, location, + cfg->inputs[i].pin)) + num_pins++; + } + } + if (num_pins < 2) + goto end_fill; + dacs = spec->multiout.num_dacs; for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; hda_nid_t dac = 0; - unsigned int defcfg, caps; + if (cfg->inputs[i].type != type) continue; - defcfg = snd_hda_codec_get_pincfg(codec, nid); - if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) - continue; - if (location && get_defcfg_location(defcfg) != location) + if (!can_be_multiio_pin(codec, location, nid)) continue; - caps = snd_hda_query_pin_caps(codec, nid); - if (!(caps & AC_PINCAP_OUT)) + for (j = 0; j < spec->multi_ios; j++) { + if (nid == spec->multi_io[j].pin) + break; + } + if (j < spec->multi_ios) continue; - if (offset && offset + num_pins < dacs) { - dac = spec->private_dac_nids[offset + num_pins]; + + if (offset && offset + spec->multi_ios < dacs) { + dac = spec->private_dac_nids[offset + spec->multi_ios]; if (!alc_auto_is_dac_reachable(codec, nid, dac)) dac = 0; } - if (!dac) + if (hardwired) + dac = get_dac_if_single(codec, nid); + else if (!dac) dac = alc_auto_look_for_dac(codec, nid); if (!dac) { - badness += BAD_MULTI_IO; + badness++; continue; } - spec->multi_io[num_pins].pin = nid; - spec->multi_io[num_pins].dac = dac; - num_pins++; - spec->private_dac_nids[spec->multiout.num_dacs++] = dac; - if (num_pins >= 2) + spec->multi_io[spec->multi_ios].pin = nid; + spec->multi_io[spec->multi_ios].dac = dac; + spec->multi_ios++; + if (spec->multi_ios >= 2) break; } } - spec->multiout.num_dacs = dacs; - if (num_pins < 2) { - /* clear up again */ - memset(spec->private_dac_nids + dacs, 0, - sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - dacs)); - spec->private_dac_nids[0] = prime_dac; + end_fill: + if (badness) + badness = BAD_MULTI_IO; + if (old_pins == spec->multi_ios) { + if (hardwired) + return 1; /* nothing found */ + else + return badness; /* no badness if nothing found */ + } + if (!hardwired && spec->multi_ios < 2) { + spec->multi_ios = old_pins; return badness; } - spec->multi_ios = num_pins; - spec->ext_channel_count = 2; - spec->multiout.num_dacs = num_pins + 1; return 0; } |