Commit 3af9ee6b authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Check hard-wired DACs at first for ALC662 & co

Some Realtek codecs have the output pins hardwired with certain DACs.
These DACs have to be assigned at first and assign the rest for
multi-DAC pins so that all DACs can be assigned properly.

Without such an optimization, speaker outputs may be assigned to the
same DAC as the headphone or others.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent cb053a82
...@@ -1760,6 +1760,15 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec) ...@@ -1760,6 +1760,15 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec)
return 0; return 0;
} }
static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
{
int i;
for (i = 0; i < nums; i++)
if (list[i] == nid)
return true;
return false;
}
/* check subsystem ID and set up device-specific initialization; /* check subsystem ID and set up device-specific initialization;
* return 1 if initialized, 0 if invalid SSID * return 1 if initialized, 0 if invalid SSID
*/ */
...@@ -1869,9 +1878,9 @@ static int alc_subsystem_id(struct hda_codec *codec, ...@@ -1869,9 +1878,9 @@ static int alc_subsystem_id(struct hda_codec *codec,
nid = porti; nid = porti;
else else
return 1; return 1;
for (i = 0; i < spec->autocfg.line_outs; i++) if (found_in_nid_list(nid, spec->autocfg.line_out_pins,
if (spec->autocfg.line_out_pins[i] == nid) spec->autocfg.line_outs))
return 1; return 1;
spec->autocfg.hp_pins[0] = nid; spec->autocfg.hp_pins[0] = nid;
} }
return 1; return 1;
...@@ -15839,7 +15848,7 @@ static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin) ...@@ -15839,7 +15848,7 @@ static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
hda_nid_t mix, srcs[5]; hda_nid_t mix, srcs[5];
int i, j, num; int i, num;
if (snd_hda_get_connections(codec, pin, &mix, 1) != 1) if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
return 0; return 0;
...@@ -15851,10 +15860,8 @@ static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin) ...@@ -15851,10 +15860,8 @@ static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
type = get_wcaps_type(get_wcaps(codec, srcs[i])); type = get_wcaps_type(get_wcaps(codec, srcs[i]));
if (type != AC_WID_AUD_OUT) if (type != AC_WID_AUD_OUT)
continue; continue;
for (j = 0; j < spec->multiout.num_dacs; j++) if (!found_in_nid_list(srcs[i], spec->multiout.dac_nids,
if (spec->multiout.dac_nids[j] == srcs[i]) spec->multiout.num_dacs))
break;
if (j >= spec->multiout.num_dacs)
return srcs[i]; return srcs[i];
} }
return 0; return 0;
...@@ -18748,7 +18755,7 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) ...@@ -18748,7 +18755,7 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
hda_nid_t srcs[5]; hda_nid_t srcs[5];
int i, j, num; int i, num;
pin = alc_go_down_to_selector(codec, pin); pin = alc_go_down_to_selector(codec, pin);
num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
...@@ -18756,31 +18763,78 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) ...@@ -18756,31 +18763,78 @@ 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;
for (j = 0; j < spec->multiout.num_dacs; j++) if (found_in_nid_list(nid, spec->multiout.dac_nids,
if (spec->multiout.dac_nids[j] == nid) spec->multiout.num_dacs))
break; continue;
if (j >= spec->multiout.num_dacs) if (spec->multiout.hp_nid == nid)
return nid; continue;
if (found_in_nid_list(nid, spec->multiout.extra_out_nid,
ARRAY_SIZE(spec->multiout.extra_out_nid)))
continue;
return nid;
} }
return 0; return 0;
} }
static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
{
hda_nid_t sel = alc_go_down_to_selector(codec, pin);
if (snd_hda_get_conn_list(codec, sel, NULL) == 1)
return alc_auto_look_for_dac(codec, pin);
return 0;
}
/* fill in the dac_nids table from the parsed pin configuration */ /* fill in the dac_nids table from the parsed pin configuration */
static int alc662_auto_fill_dac_nids(struct hda_codec *codec) static int alc662_auto_fill_dac_nids(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
const struct auto_pin_cfg *cfg = &spec->autocfg; const struct auto_pin_cfg *cfg = &spec->autocfg;
bool redone;
int i; int i;
hda_nid_t dac;
spec->multiout.dac_nids = spec->private_dac_nids; again:
spec->multiout.num_dacs = 0; spec->multiout.num_dacs = 0;
spec->multiout.hp_nid = 0;
spec->multiout.extra_out_nid[0] = 0;
memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
spec->multiout.dac_nids = spec->private_dac_nids;
/* fill hard-wired DACs first */
if (!redone) {
for (i = 0; i < cfg->line_outs; i++)
spec->private_dac_nids[i] =
get_dac_if_single(codec, cfg->line_out_pins[i]);
if (cfg->hp_outs)
spec->multiout.hp_nid =
get_dac_if_single(codec, cfg->hp_pins[0]);
if (cfg->speaker_outs)
spec->multiout.extra_out_nid[0] =
get_dac_if_single(codec, cfg->speaker_pins[0]);
}
for (i = 0; i < cfg->line_outs; i++) { for (i = 0; i < cfg->line_outs; i++) {
dac = alc_auto_look_for_dac(codec, cfg->line_out_pins[i]); hda_nid_t pin = cfg->line_out_pins[i];
if (!dac) if (spec->private_dac_nids[i])
continue; continue;
spec->private_dac_nids[spec->multiout.num_dacs++] = dac; spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin);
if (!spec->private_dac_nids[i] && !redone) {
/* if we can't find primary DACs, re-probe without
* checking the hard-wired DACs
*/
redone = true;
goto again;
}
}
for (i = 0; i < cfg->line_outs; i++) {
if (spec->private_dac_nids[i])
spec->multiout.num_dacs++;
else
memmove(spec->private_dac_nids + i,
spec->private_dac_nids + i + 1,
sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
} }
return 0; return 0;
} }
...@@ -18860,18 +18914,16 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, ...@@ -18860,18 +18914,16 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
} }
/* add playback controls for speaker and HP outputs */ /* add playback controls for speaker and HP outputs */
/* return DAC nid if any new DAC is assigned */
static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
const char *pfx) hda_nid_t dac, const char *pfx)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
hda_nid_t nid, mix; hda_nid_t mix;
int err; int err;
if (!pin) if (!pin)
return 0; return 0;
nid = alc_auto_look_for_dac(codec, pin); if (!dac) {
if (!nid) {
/* the corresponding DAC is already occupied */ /* the corresponding DAC is already occupied */
if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
return 0; /* no way */ return 0; /* no way */
...@@ -18880,16 +18932,16 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, ...@@ -18880,16 +18932,16 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
} }
mix = alc_auto_dac_to_mix(codec, pin, nid); mix = alc_auto_dac_to_mix(codec, pin, dac);
if (!mix) if (!mix)
return 0; return 0;
err = alc662_add_vol_ctl(spec, pfx, nid, 3); err = alc662_add_vol_ctl(spec, pfx, dac, 3);
if (err < 0) if (err < 0)
return err; return err;
err = alc662_add_sw_ctl(spec, pfx, mix, 3); err = alc662_add_sw_ctl(spec, pfx, mix, 3);
if (err < 0) if (err < 0)
return err; return err;
return nid; return 0;
} }
/* create playback/capture controls for input pins */ /* create playback/capture controls for input pins */
...@@ -19146,17 +19198,15 @@ static int alc662_parse_auto_config(struct hda_codec *codec) ...@@ -19146,17 +19198,15 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
return err; return err;
err = alc662_auto_create_extra_out(codec, err = alc662_auto_create_extra_out(codec,
spec->autocfg.speaker_pins[0], spec->autocfg.speaker_pins[0],
spec->multiout.extra_out_nid[0],
"Speaker"); "Speaker");
if (err < 0) if (err < 0)
return err; return err;
if (err)
spec->multiout.extra_out_nid[0] = err;
err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
spec->multiout.hp_nid,
"Headphone"); "Headphone");
if (err < 0) if (err < 0)
return err; return err;
if (err)
spec->multiout.hp_nid = err;
err = alc662_auto_create_input_ctls(codec, &spec->autocfg); err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
if (err < 0) if (err < 0)
return err; return err;
......
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