aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_realtek.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/patch_realtek.c')
-rw-r--r--sound/pci/hda/patch_realtek.c124
1 files changed, 91 insertions, 33 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4746afa25db..29c1925e918 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -2926,10 +2926,22 @@ static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
return 0;
}
+static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
+{
+ struct alc_spec *spec = codec->spec;
+ 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,
+ ARRAY_SIZE(spec->multiout.hp_out_nid)) ||
+ found_in_nid_list(nid, spec->multiout.extra_out_nid,
+ ARRAY_SIZE(spec->multiout.extra_out_nid)))
+ return true;
+ return false;
+}
+
/* look for an empty DAC slot */
static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
{
- struct alc_spec *spec = codec->spec;
hda_nid_t srcs[5];
int i, num;
@@ -2939,16 +2951,8 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
if (!nid)
continue;
- if (found_in_nid_list(nid, spec->multiout.dac_nids,
- ARRAY_SIZE(spec->private_dac_nids)))
- 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;
- return nid;
+ if (!alc_is_dac_already_used(codec, nid))
+ return nid;
}
return 0;
}
@@ -2974,12 +2978,23 @@ static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
{
struct alc_spec *spec = codec->spec;
hda_nid_t sel = alc_go_down_to_selector(codec, pin);
- hda_nid_t srcs[5];
- int num = snd_hda_get_connections(codec, sel, srcs,
+ hda_nid_t nid, nid_found, srcs[5];
+ int i, num = snd_hda_get_connections(codec, sel, srcs,
ARRAY_SIZE(srcs));
- if (num == 1 || (num == 2 && srcs[1] == spec->mixer_nid))
+ if (num == 1)
return alc_auto_look_for_dac(codec, pin);
- return 0;
+ nid_found = 0;
+ for (i = 0; i < num; i++) {
+ if (srcs[i] == spec->mixer_nid)
+ continue;
+ nid = alc_auto_mix_to_dac(codec, srcs[i]);
+ if (nid && !alc_is_dac_already_used(codec, nid)) {
+ if (nid_found)
+ return 0;
+ nid_found = nid;
+ }
+ }
+ return nid_found;
}
/* mark up volume and mute control NIDs: used during badness parsing and
@@ -3076,16 +3091,30 @@ static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
int badness = 0;
hda_nid_t dac;
- if (num_outs && !dacs[0]) {
- dac = dacs[0] = alc_auto_look_for_dac(codec, pins[0]);
- if (!dacs[0]) {
- dac = spec->private_dac_nids[0];
- if (!alc_auto_is_dac_reachable(codec, pins[0], dac))
- return BAD_NO_DAC;
- badness += BAD_NO_EXTRA_DAC;
+ if (!num_outs)
+ return 0;
+
+ if (!dacs[0])
+ dacs[0] = alc_auto_look_for_dac(codec, pins[0]);
+ if (!dacs[0]) {
+ for (i = 1; i < num_outs; i++) {
+ dac = dacs[i];
+ if (dac && alc_auto_is_dac_reachable(codec, pins[0], dac)) {
+ dacs[0] = dac;
+ dacs[i] = 0;
+ break;
+ }
}
- badness += eval_shared_vol_badness(codec, pins[0], dac);
}
+ dac = dacs[0];
+ if (!dac) {
+ dac = spec->private_dac_nids[0];
+ if (!alc_auto_is_dac_reachable(codec, pins[0], dac))
+ return BAD_NO_DAC;
+ badness += BAD_NO_EXTRA_DAC;
+ }
+ if (dac)
+ badness += eval_shared_vol_badness(codec, pins[0], dac);
for (i = 1; i < num_outs; i++)
dacs[i] = get_dac_if_single(codec, pins[i]);
@@ -3113,6 +3142,21 @@ 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);
+static bool alc_map_singles(struct hda_codec *codec, int outs,
+ const hda_nid_t *pins, hda_nid_t *dacs)
+{
+ int i;
+ bool found = false;
+ for (i = 0; i < outs; i++) {
+ if (dacs[i])
+ continue;
+ dacs[i] = get_dac_if_single(codec, pins[i]);
+ if (dacs[i])
+ found = true;
+ }
+ return found;
+}
+
/* fill in the dac_nids table from the parsed pin configuration */
static int fill_and_eval_dacs(struct hda_codec *codec,
bool fill_hardwired)
@@ -3120,7 +3164,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
struct alc_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
unsigned int location, defcfg;
- int i, err, badness;
+ int i, j, err, badness;
/* set num_dacs once to full for alc_auto_look_for_dac() */
spec->multiout.num_dacs = cfg->line_outs;
@@ -3134,15 +3178,18 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
/* fill hard-wired DACs first */
if (fill_hardwired) {
- for (i = 0; i < cfg->line_outs; i++)
- spec->private_dac_nids[i] =
- get_dac_if_single(codec, cfg->line_out_pins[i]);
- for (i = 0; i < cfg->hp_outs; i++)
- spec->multiout.hp_out_nid[i] =
- get_dac_if_single(codec, cfg->hp_pins[i]);
- for (i = 0; i < cfg->speaker_outs; i++)
- spec->multiout.extra_out_nid[i] =
- get_dac_if_single(codec, cfg->speaker_pins[i]);
+ bool mapped;
+ do {
+ mapped = alc_map_singles(codec, cfg->line_outs,
+ 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);
+ } while (mapped);
}
for (i = 0; i < cfg->line_outs; i++) {
@@ -3152,6 +3199,17 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
spec->private_dac_nids[i] =
alc_auto_look_for_dac(codec, pin);
dac = spec->private_dac_nids[i];
+ if (!dac && !i) {
+ for (j = 1; j < cfg->line_outs; j++) {
+ hda_nid_t dac2 = spec->private_dac_nids[j];
+ if (dac2 &&
+ alc_auto_is_dac_reachable(codec, pin, dac2)) {
+ dac = spec->private_dac_nids[0] = dac2;
+ spec->private_dac_nids[j] = 0;
+ break;
+ }
+ }
+ }
if (!dac) {
if (!i)
badness += BAD_NO_PRIMARY_DAC;