Commit dc04d1b4 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Create output controls according to pin types for IDT/STAC

Improve the parser to pick up more intuitive control names for the
outputs judging from the pin type, instead of fixed names assigned
to channels.

Also, revive the multi-HP workaround since this change fixes the
problem with the multi-HP detection.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent b3225190
...@@ -3039,35 +3039,33 @@ static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid) ...@@ -3039,35 +3039,33 @@ static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
return 1; return 1;
} }
static int is_unique_dac(struct sigmatel_spec *spec, hda_nid_t nid) /* Create output controls
{ * The mixer elements are named depending on the given type (AUTO_PIN_XXX_OUT)
int i; */
static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
if (spec->autocfg.line_outs != 1) const hda_nid_t *pins,
return 0; const hda_nid_t *dac_nids,
if (spec->multiout.hp_nid == nid) int type)
return 0;
for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++)
if (spec->multiout.extra_out_nid[i] == nid)
return 0;
return 1;
}
/* add playback controls from the parsed DAC table */
static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{ {
struct sigmatel_spec *spec = codec->spec; struct sigmatel_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 = 0; static const char *hp_pfxs[] = {
"Headphone", "Headphone2", "Headphone3", "Headphone4"
};
static const char *speaker_pfxs[] = {
"Speaker", "External Speaker", "Speaker2", "Speaker3"
};
hda_nid_t nid;
int i, err; int i, err;
unsigned int wid_caps; unsigned int wid_caps;
for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) { for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) {
nid = spec->multiout.dac_nids[i]; nid = dac_nids[i];
if (i == 2) { if (!nid)
continue;
if (type != AUTO_PIN_HP_OUT && i == 2) {
/* Center/LFE */ /* Center/LFE */
err = create_controls(codec, "Center", nid, 1); err = create_controls(codec, "Center", nid, 1);
if (err < 0) if (err < 0)
...@@ -3088,23 +3086,43 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, ...@@ -3088,23 +3086,43 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
} }
} else { } else {
const char *name = chname[i]; const char *name;
/* if it's a single DAC, assign a better name */ switch (type) {
if (!i && is_unique_dac(spec, nid)) { case AUTO_PIN_HP_OUT:
switch (cfg->line_out_type) { name = hp_pfxs[i];
case AUTO_PIN_HP_OUT: break;
name = "Headphone"; case AUTO_PIN_SPEAKER_OUT:
break; name = speaker_pfxs[i];
case AUTO_PIN_SPEAKER_OUT: break;
name = "Speaker"; default:
break; name = chname[i];
} break;
} }
err = create_controls(codec, name, nid, 3); err = create_controls(codec, name, nid, 3);
if (err < 0) if (err < 0)
return err; return err;
if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) {
wid_caps = get_wcaps(codec, pins[i]);
if (wid_caps & AC_WCAP_UNSOL_CAP)
spec->hp_detect = 1;
}
} }
} }
return 0;
}
/* add playback controls from the parsed DAC table */
static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
struct sigmatel_spec *spec = codec->spec;
int err;
err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins,
spec->multiout.dac_nids,
cfg->line_out_type);
if (err < 0)
return err;
if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) {
err = stac92xx_add_control(spec, err = stac92xx_add_control(spec,
...@@ -3139,40 +3157,18 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, ...@@ -3139,40 +3157,18 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
struct auto_pin_cfg *cfg) struct auto_pin_cfg *cfg)
{ {
struct sigmatel_spec *spec = codec->spec; struct sigmatel_spec *spec = codec->spec;
hda_nid_t nid; int err;
int i, err, nums;
err = create_multi_out_ctls(codec, cfg->hp_outs, cfg->hp_pins,
spec->hp_dacs, AUTO_PIN_HP_OUT);
if (err < 0)
return err;
err = create_multi_out_ctls(codec, cfg->speaker_outs, cfg->speaker_pins,
spec->speaker_dacs, AUTO_PIN_SPEAKER_OUT);
if (err < 0)
return err;
nums = 0;
for (i = 0; i < cfg->hp_outs; i++) {
static const char *pfxs[] = {
"Headphone", "Headphone2", "Headphone3",
};
unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
if (wid_caps & AC_WCAP_UNSOL_CAP)
spec->hp_detect = 1;
if (nums >= ARRAY_SIZE(pfxs))
continue;
nid = spec->hp_dacs[i];
if (!nid)
continue;
err = create_controls(codec, pfxs[nums++], nid, 3);
if (err < 0)
return err;
}
nums = 0;
for (i = 0; i < cfg->speaker_outs; i++) {
static const char *pfxs[] = {
"Speaker", "External Speaker", "Speaker2",
};
if (nums >= ARRAY_SIZE(pfxs))
continue;
nid = spec->speaker_dacs[i];
if (!nid)
continue;
err = create_controls(codec, pfxs[nums++], nid, 3);
if (err < 0)
return err;
}
return 0; return 0;
} }
...@@ -3505,6 +3501,7 @@ static void stac92xx_auto_init_hp_out(struct hda_codec *codec) ...@@ -3505,6 +3501,7 @@ static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in)
{ {
struct sigmatel_spec *spec = codec->spec; struct sigmatel_spec *spec = codec->spec;
int hp_swap = 0;
int err; int err;
if ((err = snd_hda_parse_pin_def_config(codec, if ((err = snd_hda_parse_pin_def_config(codec,
...@@ -3514,7 +3511,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out ...@@ -3514,7 +3511,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
if (! spec->autocfg.line_outs) if (! spec->autocfg.line_outs)
return 0; /* can't find valid pin config */ return 0; /* can't find valid pin config */
#if 0 /* FIXME: temporarily disabled */
/* If we have no real line-out pin and multiple hp-outs, HPs should /* If we have no real line-out pin and multiple hp-outs, HPs should
* be set up as multi-channel outputs. * be set up as multi-channel outputs.
*/ */
...@@ -3533,8 +3529,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out ...@@ -3533,8 +3529,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
spec->autocfg.line_outs = spec->autocfg.hp_outs; spec->autocfg.line_outs = spec->autocfg.hp_outs;
spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
spec->autocfg.hp_outs = 0; spec->autocfg.hp_outs = 0;
hp_swap = 1;
} }
#endif /* FIXME: temporarily disabled */
if (spec->autocfg.mono_out_pin) { if (spec->autocfg.mono_out_pin) {
int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) & int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
(AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
...@@ -3627,12 +3623,19 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out ...@@ -3627,12 +3623,19 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
#endif #endif
err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
if (err < 0) if (err < 0)
return err; return err;
err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); /* All output parsing done, now restore the swapped hp pins */
if (hp_swap) {
memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
sizeof(spec->autocfg.hp_pins));
spec->autocfg.hp_outs = spec->autocfg.line_outs;
spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
spec->autocfg.line_outs = 0;
}
err = stac92xx_auto_create_analog_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