|
@@ -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;
|