ALSA: hda - Fix ALC861 auto-mode parser
Fix the logic of ALC861 auto-mode parser for the outputs. Instead of assuming the fixed DAC list, parse the conection and assign the DAC dynamically. Also, unmute the unused output connections to avoid noises on inputs. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
05ff7e11b7
commit
1c20930a41
|
@ -13685,23 +13685,23 @@ static struct hda_verb alc861_auto_init_verbs[] = {
|
||||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
|
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
|
||||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
|
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
|
||||||
|
|
||||||
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||||
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||||
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||||
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||||
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||||
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||||
|
|
||||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
|
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
|
||||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
|
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
|
||||||
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||||
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||||
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
|
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
|
||||||
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
|
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
|
||||||
|
|
||||||
{0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
|
{0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
|
||||||
|
|
||||||
|
@ -13773,64 +13773,97 @@ static struct hda_input_mux alc861_capture_source = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
|
||||||
|
{
|
||||||
|
struct alc_spec *spec = codec->spec;
|
||||||
|
hda_nid_t mix, srcs[5];
|
||||||
|
int i, j, num;
|
||||||
|
|
||||||
|
if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
|
||||||
|
return 0;
|
||||||
|
num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
|
||||||
|
if (num < 0)
|
||||||
|
return 0;
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
unsigned int type;
|
||||||
|
type = (get_wcaps(codec, srcs[i]) & AC_WCAP_TYPE)
|
||||||
|
>> AC_WCAP_TYPE_SHIFT;
|
||||||
|
if (type != AC_WID_AUD_OUT)
|
||||||
|
continue;
|
||||||
|
for (j = 0; j < spec->multiout.num_dacs; j++)
|
||||||
|
if (spec->multiout.dac_nids[j] == srcs[i])
|
||||||
|
break;
|
||||||
|
if (j >= spec->multiout.num_dacs)
|
||||||
|
return srcs[i];
|
||||||
|
}
|
||||||
|
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 alc861_auto_fill_dac_nids(struct alc_spec *spec,
|
static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
|
||||||
const struct auto_pin_cfg *cfg)
|
const struct auto_pin_cfg *cfg)
|
||||||
{
|
{
|
||||||
|
struct alc_spec *spec = codec->spec;
|
||||||
int i;
|
int i;
|
||||||
hda_nid_t nid;
|
hda_nid_t nid, dac;
|
||||||
|
|
||||||
spec->multiout.dac_nids = spec->private_dac_nids;
|
spec->multiout.dac_nids = spec->private_dac_nids;
|
||||||
for (i = 0; i < cfg->line_outs; i++) {
|
for (i = 0; i < cfg->line_outs; i++) {
|
||||||
nid = cfg->line_out_pins[i];
|
nid = cfg->line_out_pins[i];
|
||||||
if (nid) {
|
dac = alc861_look_for_dac(codec, nid);
|
||||||
if (i >= ARRAY_SIZE(alc861_dac_nids))
|
if (!dac)
|
||||||
continue;
|
continue;
|
||||||
spec->multiout.dac_nids[i] = alc861_dac_nids[i];
|
spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
spec->multiout.num_dacs = cfg->line_outs;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add playback controls from the parsed DAC table */
|
static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
|
||||||
static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
|
hda_nid_t nid, unsigned int chs)
|
||||||
const struct auto_pin_cfg *cfg)
|
|
||||||
{
|
{
|
||||||
char name[32];
|
char name[32];
|
||||||
|
snprintf(name, sizeof(name), "%s Playback Switch", pfx);
|
||||||
|
return add_control(codec->spec, ALC_CTL_WIDGET_MUTE, name,
|
||||||
|
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add playback controls from the parsed DAC table */
|
||||||
|
static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
|
||||||
|
const struct auto_pin_cfg *cfg)
|
||||||
|
{
|
||||||
|
struct alc_spec *spec = codec->spec;
|
||||||
static const char *chname[4] = {
|
static const char *chname[4] = {
|
||||||
"Front", "Surround", NULL /*CLFE*/, "Side"
|
"Front", "Surround", NULL /*CLFE*/, "Side"
|
||||||
};
|
};
|
||||||
hda_nid_t nid;
|
hda_nid_t nid;
|
||||||
int i, idx, err;
|
int i, err;
|
||||||
|
|
||||||
|
if (cfg->line_outs == 1) {
|
||||||
|
const char *pfx = NULL;
|
||||||
|
if (!cfg->hp_outs)
|
||||||
|
pfx = "Master";
|
||||||
|
else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
|
||||||
|
pfx = "Speaker";
|
||||||
|
if (pfx) {
|
||||||
|
nid = spec->multiout.dac_nids[0];
|
||||||
|
return alc861_create_out_sw(codec, pfx, nid, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < cfg->line_outs; i++) {
|
for (i = 0; i < cfg->line_outs; i++) {
|
||||||
nid = spec->multiout.dac_nids[i];
|
nid = spec->multiout.dac_nids[i];
|
||||||
if (!nid)
|
if (!nid)
|
||||||
continue;
|
continue;
|
||||||
if (nid == 0x05) {
|
if (i == 2) {
|
||||||
/* Center/LFE */
|
/* Center/LFE */
|
||||||
err = add_control(spec, ALC_CTL_BIND_MUTE,
|
err = alc861_create_out_sw(codec, "Center", nid, 1);
|
||||||
"Center Playback Switch",
|
|
||||||
HDA_COMPOSE_AMP_VAL(nid, 1, 0,
|
|
||||||
HDA_OUTPUT));
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
err = add_control(spec, ALC_CTL_BIND_MUTE,
|
err = alc861_create_out_sw(codec, "LFE", nid, 2);
|
||||||
"LFE Playback Switch",
|
|
||||||
HDA_COMPOSE_AMP_VAL(nid, 2, 0,
|
|
||||||
HDA_OUTPUT));
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
} else {
|
} else {
|
||||||
for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
|
err = alc861_create_out_sw(codec, chname[i], nid, 3);
|
||||||
idx++)
|
|
||||||
if (nid == alc861_dac_nids[idx])
|
|
||||||
break;
|
|
||||||
sprintf(name, "%s Playback Switch", chname[idx]);
|
|
||||||
err = add_control(spec, ALC_CTL_BIND_MUTE, name,
|
|
||||||
HDA_COMPOSE_AMP_VAL(nid, 3, 0,
|
|
||||||
HDA_OUTPUT));
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -13838,8 +13871,9 @@ static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
|
static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
|
||||||
{
|
{
|
||||||
|
struct alc_spec *spec = codec->spec;
|
||||||
int err;
|
int err;
|
||||||
hda_nid_t nid;
|
hda_nid_t nid;
|
||||||
|
|
||||||
|
@ -13847,21 +13881,22 @@ static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
|
if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
|
||||||
nid = 0x03;
|
nid = alc861_look_for_dac(codec, pin);
|
||||||
err = add_control(spec, ALC_CTL_WIDGET_MUTE,
|
if (nid) {
|
||||||
"Headphone Playback Switch",
|
err = alc861_create_out_sw(codec, "Headphone", nid, 3);
|
||||||
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
spec->multiout.hp_nid = nid;
|
spec->multiout.hp_nid = nid;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create playback/capture controls for input pins */
|
/* create playback/capture controls for input pins */
|
||||||
static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
|
static int alc861_auto_create_analog_input_ctls(struct hda_codec *codec,
|
||||||
const struct auto_pin_cfg *cfg)
|
const struct auto_pin_cfg *cfg)
|
||||||
{
|
{
|
||||||
|
struct alc_spec *spec = codec->spec;
|
||||||
struct hda_input_mux *imux = &spec->private_imux[0];
|
struct hda_input_mux *imux = &spec->private_imux[0];
|
||||||
int i, err, idx, idx1;
|
int i, err, idx, idx1;
|
||||||
|
|
||||||
|
@ -13905,12 +13940,29 @@ static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
|
||||||
|
|
||||||
static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
|
static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
|
||||||
hda_nid_t nid,
|
hda_nid_t nid,
|
||||||
int pin_type, int dac_idx)
|
int pin_type, hda_nid_t dac)
|
||||||
{
|
{
|
||||||
|
hda_nid_t mix, srcs[5];
|
||||||
|
int i, num;
|
||||||
|
|
||||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||||
pin_type);
|
pin_type);
|
||||||
snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
||||||
AMP_OUT_UNMUTE);
|
AMP_OUT_UNMUTE);
|
||||||
|
if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
|
||||||
|
return;
|
||||||
|
num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
|
||||||
|
if (num < 0)
|
||||||
|
return;
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
unsigned int mute;
|
||||||
|
if (srcs[i] == dac || srcs[i] == 0x15)
|
||||||
|
mute = AMP_IN_UNMUTE(i);
|
||||||
|
else
|
||||||
|
mute = AMP_IN_MUTE(i);
|
||||||
|
snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
||||||
|
mute);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alc861_auto_init_multi_out(struct hda_codec *codec)
|
static void alc861_auto_init_multi_out(struct hda_codec *codec)
|
||||||
|
@ -13933,12 +13985,13 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec)
|
||||||
hda_nid_t pin;
|
hda_nid_t pin;
|
||||||
|
|
||||||
pin = spec->autocfg.hp_pins[0];
|
pin = spec->autocfg.hp_pins[0];
|
||||||
if (pin) /* connect to front */
|
if (pin)
|
||||||
alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
|
alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
|
||||||
spec->multiout.dac_nids[0]);
|
spec->multiout.hp_nid);
|
||||||
pin = spec->autocfg.speaker_pins[0];
|
pin = spec->autocfg.speaker_pins[0];
|
||||||
if (pin)
|
if (pin)
|
||||||
alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
|
alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT,
|
||||||
|
spec->multiout.dac_nids[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alc861_auto_init_analog_input(struct hda_codec *codec)
|
static void alc861_auto_init_analog_input(struct hda_codec *codec)
|
||||||
|
@ -13970,16 +14023,16 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
|
||||||
if (!spec->autocfg.line_outs)
|
if (!spec->autocfg.line_outs)
|
||||||
return 0; /* can't find valid BIOS pin config */
|
return 0; /* can't find valid BIOS pin config */
|
||||||
|
|
||||||
err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
|
err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
|
err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
|
err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
|
err = alc861_auto_create_analog_input_ctls(codec, &spec->autocfg);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue