Commit 185d99f1 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda/realtek - Try harder to fit the single-connections

So far, the Realtek driver tires to assign the single-connected routes
for all pins only once at the beginning.  However, since some DACs have
been already mapped, the rest pins might have also single conections.

In this patch, the driver does the single-connection assignment in a
loop until all possbile single-connections are checked.  This will
improve the DAC assignment, e.g. for ASUS G72.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 1c4a54b4
...@@ -2926,10 +2926,22 @@ static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin, ...@@ -2926,10 +2926,22 @@ static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
return 0; 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 */ /* look for an empty DAC slot */
static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) 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]; hda_nid_t srcs[5];
int i, num; int i, num;
...@@ -2939,15 +2951,7 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) ...@@ -2939,15 +2951,7 @@ 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]); hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
if (!nid) if (!nid)
continue; continue;
if (found_in_nid_list(nid, spec->multiout.dac_nids, if (!alc_is_dac_already_used(codec, nid))
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; return nid;
} }
return 0; return 0;
...@@ -2974,12 +2978,23 @@ static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) ...@@ -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; struct alc_spec *spec = codec->spec;
hda_nid_t sel = alc_go_down_to_selector(codec, pin); hda_nid_t sel = alc_go_down_to_selector(codec, pin);
hda_nid_t srcs[5]; hda_nid_t nid, nid_found, srcs[5];
int num = snd_hda_get_connections(codec, sel, srcs, int i, num = snd_hda_get_connections(codec, sel, srcs,
ARRAY_SIZE(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 alc_auto_look_for_dac(codec, pin);
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; return 0;
nid_found = nid;
}
}
return nid_found;
} }
/* mark up volume and mute control NIDs: used during badness parsing and /* 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, ...@@ -3076,16 +3091,30 @@ static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
int badness = 0; int badness = 0;
hda_nid_t dac; hda_nid_t dac;
if (num_outs && !dacs[0]) { if (!num_outs)
dac = dacs[0] = alc_auto_look_for_dac(codec, pins[0]); return 0;
if (!dacs[0])
dacs[0] = alc_auto_look_for_dac(codec, pins[0]);
if (!dacs[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;
}
}
}
dac = dacs[0];
if (!dac) {
dac = spec->private_dac_nids[0]; dac = spec->private_dac_nids[0];
if (!alc_auto_is_dac_reachable(codec, pins[0], dac)) if (!alc_auto_is_dac_reachable(codec, pins[0], dac))
return BAD_NO_DAC; return BAD_NO_DAC;
badness += BAD_NO_EXTRA_DAC; badness += BAD_NO_EXTRA_DAC;
} }
if (dac)
badness += eval_shared_vol_badness(codec, pins[0], dac); badness += eval_shared_vol_badness(codec, pins[0], dac);
}
for (i = 1; i < num_outs; i++) for (i = 1; i < num_outs; i++)
dacs[i] = get_dac_if_single(codec, pins[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, ...@@ -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, static int alc_auto_fill_multi_ios(struct hda_codec *codec,
unsigned int location, int offset); 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 */ /* fill in the dac_nids table from the parsed pin configuration */
static int fill_and_eval_dacs(struct hda_codec *codec, static int fill_and_eval_dacs(struct hda_codec *codec,
bool fill_hardwired) bool fill_hardwired)
...@@ -3120,7 +3164,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec, ...@@ -3120,7 +3164,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg; struct auto_pin_cfg *cfg = &spec->autocfg;
unsigned int location, defcfg; 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() */ /* set num_dacs once to full for alc_auto_look_for_dac() */
spec->multiout.num_dacs = cfg->line_outs; spec->multiout.num_dacs = cfg->line_outs;
...@@ -3134,15 +3178,18 @@ static int fill_and_eval_dacs(struct hda_codec *codec, ...@@ -3134,15 +3178,18 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
/* fill hard-wired DACs first */ /* fill hard-wired DACs first */
if (fill_hardwired) { if (fill_hardwired) {
for (i = 0; i < cfg->line_outs; i++) bool mapped;
spec->private_dac_nids[i] = do {
get_dac_if_single(codec, cfg->line_out_pins[i]); mapped = alc_map_singles(codec, cfg->line_outs,
for (i = 0; i < cfg->hp_outs; i++) cfg->line_out_pins,
spec->multiout.hp_out_nid[i] = spec->private_dac_nids);
get_dac_if_single(codec, cfg->hp_pins[i]); mapped |= alc_map_singles(codec, cfg->hp_outs,
for (i = 0; i < cfg->speaker_outs; i++) cfg->hp_pins,
spec->multiout.extra_out_nid[i] = spec->multiout.hp_out_nid);
get_dac_if_single(codec, cfg->speaker_pins[i]); 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++) { for (i = 0; i < cfg->line_outs; i++) {
...@@ -3152,6 +3199,17 @@ static int fill_and_eval_dacs(struct hda_codec *codec, ...@@ -3152,6 +3199,17 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
spec->private_dac_nids[i] = spec->private_dac_nids[i] =
alc_auto_look_for_dac(codec, pin); alc_auto_look_for_dac(codec, pin);
dac = spec->private_dac_nids[i]; 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 (!dac) {
if (!i) if (!i)
badness += BAD_NO_PRIMARY_DAC; badness += BAD_NO_PRIMARY_DAC;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment