ALSA: hda/realtek - Fix lost speaker volume controls
When there are the same or more number of HP pins are available, HP pins are used as the primary outputs instead of the speaker pins. But, in some cases (especially with ALC663 & co), some DACs are available only with a later pin and it's assigned to a speaker, and since the driver parses the pins from the lower NID, such a DAC was skipped eventually without assignments. This resulted in a regression, the missing speaker volume control in the new parser. As a workaround for this, now the driver retries the pin->DAC mapping again after restoring the speaker-pins as primary. This is still an ad hoc fix, but it works so far for most of Realtek codecs. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
fbabc24619
commit
0a34b42b62
1 changed files with 30 additions and 7 deletions
|
@ -2906,7 +2906,7 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
|
||||||
if (!nid)
|
if (!nid)
|
||||||
continue;
|
continue;
|
||||||
if (found_in_nid_list(nid, spec->multiout.dac_nids,
|
if (found_in_nid_list(nid, spec->multiout.dac_nids,
|
||||||
spec->multiout.num_dacs))
|
ARRAY_SIZE(spec->private_dac_nids)))
|
||||||
continue;
|
continue;
|
||||||
if (found_in_nid_list(nid, spec->multiout.hp_out_nid,
|
if (found_in_nid_list(nid, spec->multiout.hp_out_nid,
|
||||||
ARRAY_SIZE(spec->multiout.hp_out_nid)))
|
ARRAY_SIZE(spec->multiout.hp_out_nid)))
|
||||||
|
@ -2927,6 +2927,7 @@ static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* return 0 if no possible DAC is found, 1 if one or more found */
|
||||||
static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
|
static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
|
||||||
const hda_nid_t *pins, hda_nid_t *dacs)
|
const hda_nid_t *pins, hda_nid_t *dacs)
|
||||||
{
|
{
|
||||||
|
@ -2944,7 +2945,7 @@ static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
|
||||||
if (!dacs[i])
|
if (!dacs[i])
|
||||||
dacs[i] = alc_auto_look_for_dac(codec, pins[i]);
|
dacs[i] = alc_auto_look_for_dac(codec, pins[i]);
|
||||||
}
|
}
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alc_auto_fill_multi_ios(struct hda_codec *codec,
|
static int alc_auto_fill_multi_ios(struct hda_codec *codec,
|
||||||
|
@ -2954,7 +2955,7 @@ static int alc_auto_fill_multi_ios(struct hda_codec *codec,
|
||||||
static int alc_auto_fill_dac_nids(struct hda_codec *codec)
|
static int alc_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;
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||||
bool redone = false;
|
bool redone = false;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -2965,6 +2966,7 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
|
||||||
spec->multiout.extra_out_nid[0] = 0;
|
spec->multiout.extra_out_nid[0] = 0;
|
||||||
memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
|
memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
|
||||||
spec->multiout.dac_nids = spec->private_dac_nids;
|
spec->multiout.dac_nids = spec->private_dac_nids;
|
||||||
|
spec->multi_ios = 0;
|
||||||
|
|
||||||
/* fill hard-wired DACs first */
|
/* fill hard-wired DACs first */
|
||||||
if (!redone) {
|
if (!redone) {
|
||||||
|
@ -2998,10 +3000,12 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
|
||||||
for (i = 0; i < cfg->line_outs; i++) {
|
for (i = 0; i < cfg->line_outs; i++) {
|
||||||
if (spec->private_dac_nids[i])
|
if (spec->private_dac_nids[i])
|
||||||
spec->multiout.num_dacs++;
|
spec->multiout.num_dacs++;
|
||||||
else
|
else {
|
||||||
memmove(spec->private_dac_nids + i,
|
memmove(spec->private_dac_nids + i,
|
||||||
spec->private_dac_nids + i + 1,
|
spec->private_dac_nids + i + 1,
|
||||||
sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
|
sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
|
||||||
|
spec->private_dac_nids[cfg->line_outs - 1] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
|
if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
|
||||||
|
@ -3023,9 +3027,28 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
|
||||||
if (cfg->line_out_type != AUTO_PIN_HP_OUT)
|
if (cfg->line_out_type != AUTO_PIN_HP_OUT)
|
||||||
alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins,
|
alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins,
|
||||||
spec->multiout.hp_out_nid);
|
spec->multiout.hp_out_nid);
|
||||||
if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
|
if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
|
||||||
alc_auto_fill_extra_dacs(codec, cfg->speaker_outs, cfg->speaker_pins,
|
int err = alc_auto_fill_extra_dacs(codec, cfg->speaker_outs,
|
||||||
spec->multiout.extra_out_nid);
|
cfg->speaker_pins,
|
||||||
|
spec->multiout.extra_out_nid);
|
||||||
|
/* if no speaker volume is assigned, try again as the primary
|
||||||
|
* output
|
||||||
|
*/
|
||||||
|
if (!err && cfg->speaker_outs > 0 &&
|
||||||
|
cfg->line_out_type == AUTO_PIN_HP_OUT) {
|
||||||
|
cfg->hp_outs = cfg->line_outs;
|
||||||
|
memcpy(cfg->hp_pins, cfg->line_out_pins,
|
||||||
|
sizeof(cfg->hp_pins));
|
||||||
|
cfg->line_outs = cfg->speaker_outs;
|
||||||
|
memcpy(cfg->line_out_pins, cfg->speaker_pins,
|
||||||
|
sizeof(cfg->speaker_pins));
|
||||||
|
cfg->speaker_outs = 0;
|
||||||
|
memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
|
||||||
|
cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
|
||||||
|
redone = false;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue