提交 1c20930a 编写于 作者: T Takashi Iwai

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: NTakashi Iwai <tiwai@suse.de>
上级 05ff7e11
...@@ -13685,23 +13685,23 @@ static struct hda_verb alc861_auto_init_verbs[] = { ...@@ -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 = { ...@@ -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;
} }
static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
hda_nid_t nid, unsigned int chs)
{
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 */ /* add playback controls from the parsed DAC table */
static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec, static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg) const struct auto_pin_cfg *cfg)
{ {
char name[32]; 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, ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册