[ALSA] hda-codec - Fix BIOS auto-configuration
Modules: HDA Codec driver,HDA generic driver - Fix autoconfig speaker/hp detection Now it allows multiple speaker pins (e.g. Dell laptops have such config) - Use speaker or hp pins if no line-outs are available This fixes the silence output on recent Dell laptops with STAC9200 (ALSA bug#1843) - Fix analog/realtek/sigmatel autoconfig parser Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
19739fef02
commit
82bc955f63
|
@ -1899,6 +1899,13 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_o
|
||||||
if (mout->hp_nid)
|
if (mout->hp_nid)
|
||||||
/* headphone out will just decode front left/right (stereo) */
|
/* headphone out will just decode front left/right (stereo) */
|
||||||
snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);
|
snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);
|
||||||
|
/* extra outputs copied from front */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
|
||||||
|
if (mout->extra_out_nid[i])
|
||||||
|
snd_hda_codec_setup_stream(codec,
|
||||||
|
mout->extra_out_nid[i],
|
||||||
|
stream_tag, 0, format);
|
||||||
|
|
||||||
/* surrounds */
|
/* surrounds */
|
||||||
for (i = 1; i < mout->num_dacs; i++) {
|
for (i = 1; i < mout->num_dacs; i++) {
|
||||||
if (chs >= (i + 1) * 2) /* independent out */
|
if (chs >= (i + 1) * 2) /* independent out */
|
||||||
|
@ -1923,6 +1930,11 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_o
|
||||||
snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
|
snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
|
||||||
if (mout->hp_nid)
|
if (mout->hp_nid)
|
||||||
snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0);
|
snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0);
|
||||||
|
for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
|
||||||
|
if (mout->extra_out_nid[i])
|
||||||
|
snd_hda_codec_setup_stream(codec,
|
||||||
|
mout->extra_out_nid[i],
|
||||||
|
0, 0, 0);
|
||||||
mutex_lock(&codec->spdif_mutex);
|
mutex_lock(&codec->spdif_mutex);
|
||||||
if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
|
if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
|
||||||
snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
|
snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
|
||||||
|
@ -1944,13 +1956,29 @@ static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse all pin widgets and store the useful pin nids to cfg */
|
/*
|
||||||
|
* Parse all pin widgets and store the useful pin nids to cfg
|
||||||
|
*
|
||||||
|
* The number of line-outs or any primary output is stored in line_outs,
|
||||||
|
* and the corresponding output pins are assigned to line_out_pins[],
|
||||||
|
* in the order of front, rear, CLFE, side, ...
|
||||||
|
*
|
||||||
|
* If more extra outputs (speaker and headphone) are found, the pins are
|
||||||
|
* assisnged to hp_pin and speaker_pins[], respectively. If no line-out jack
|
||||||
|
* is detected, one of speaker of HP pins is assigned as the primary
|
||||||
|
* output, i.e. to line_out_pins[0]. So, line_outs is always positive
|
||||||
|
* if any analog output exists.
|
||||||
|
*
|
||||||
|
* The analog input pins are assigned to input_pins array.
|
||||||
|
* The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
|
||||||
|
* respectively.
|
||||||
|
*/
|
||||||
int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg,
|
int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg,
|
||||||
hda_nid_t *ignore_nids)
|
hda_nid_t *ignore_nids)
|
||||||
{
|
{
|
||||||
hda_nid_t nid, nid_start;
|
hda_nid_t nid, nid_start;
|
||||||
int i, j, nodes;
|
int i, j, nodes;
|
||||||
short seq, sequences[4], assoc_line_out;
|
short seq, assoc_line_out, sequences[ARRAY_SIZE(cfg->line_out_pins)];
|
||||||
|
|
||||||
memset(cfg, 0, sizeof(*cfg));
|
memset(cfg, 0, sizeof(*cfg));
|
||||||
|
|
||||||
|
@ -1992,7 +2020,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
|
||||||
cfg->line_outs++;
|
cfg->line_outs++;
|
||||||
break;
|
break;
|
||||||
case AC_JACK_SPEAKER:
|
case AC_JACK_SPEAKER:
|
||||||
cfg->speaker_pin = nid;
|
if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))
|
||||||
|
continue;
|
||||||
|
cfg->speaker_pins[cfg->speaker_outs] = nid;
|
||||||
|
cfg->speaker_outs++;
|
||||||
break;
|
break;
|
||||||
case AC_JACK_HP_OUT:
|
case AC_JACK_HP_OUT:
|
||||||
cfg->hp_pin = nid;
|
cfg->hp_pin = nid;
|
||||||
|
@ -2057,6 +2088,46 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* debug prints of the parsed results
|
||||||
|
*/
|
||||||
|
snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
|
||||||
|
cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
|
||||||
|
cfg->line_out_pins[2], cfg->line_out_pins[3],
|
||||||
|
cfg->line_out_pins[4]);
|
||||||
|
snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
|
||||||
|
cfg->speaker_outs, cfg->speaker_pins[0],
|
||||||
|
cfg->speaker_pins[1], cfg->speaker_pins[2],
|
||||||
|
cfg->speaker_pins[3], cfg->speaker_pins[4]);
|
||||||
|
snd_printd(" hp=0x%x, dig_out=0x%x, din_in=0x%x\n",
|
||||||
|
cfg->hp_pin, cfg->dig_out_pin, cfg->dig_in_pin);
|
||||||
|
snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
|
||||||
|
" cd=0x%x, aux=0x%x\n",
|
||||||
|
cfg->input_pins[AUTO_PIN_MIC],
|
||||||
|
cfg->input_pins[AUTO_PIN_FRONT_MIC],
|
||||||
|
cfg->input_pins[AUTO_PIN_LINE],
|
||||||
|
cfg->input_pins[AUTO_PIN_FRONT_LINE],
|
||||||
|
cfg->input_pins[AUTO_PIN_CD],
|
||||||
|
cfg->input_pins[AUTO_PIN_AUX]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIX-UP: if no line-outs are detected, try to use speaker or HP pin
|
||||||
|
* as a primary output
|
||||||
|
*/
|
||||||
|
if (! cfg->line_outs) {
|
||||||
|
if (cfg->speaker_outs) {
|
||||||
|
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));
|
||||||
|
} else if (cfg->hp_pin) {
|
||||||
|
cfg->line_outs = 1;
|
||||||
|
cfg->line_out_pins[0] = cfg->hp_pin;
|
||||||
|
cfg->hp_pin = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,7 @@ struct hda_multi_out {
|
||||||
int num_dacs; /* # of DACs, must be more than 1 */
|
int num_dacs; /* # of DACs, must be more than 1 */
|
||||||
hda_nid_t *dac_nids; /* DAC list */
|
hda_nid_t *dac_nids; /* DAC list */
|
||||||
hda_nid_t hp_nid; /* optional DAC for HP, 0 when not exists */
|
hda_nid_t hp_nid; /* optional DAC for HP, 0 when not exists */
|
||||||
|
hda_nid_t extra_out_nid[3]; /* optional DACs, 0 when not exists */
|
||||||
hda_nid_t dig_out_nid; /* digital out audio widget */
|
hda_nid_t dig_out_nid; /* digital out audio widget */
|
||||||
int max_channels; /* currently supported analog channels */
|
int max_channels; /* currently supported analog channels */
|
||||||
int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */
|
int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */
|
||||||
|
@ -221,7 +222,8 @@ extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST];
|
||||||
struct auto_pin_cfg {
|
struct auto_pin_cfg {
|
||||||
int line_outs;
|
int line_outs;
|
||||||
hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */
|
hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */
|
||||||
hda_nid_t speaker_pin;
|
int speaker_outs;
|
||||||
|
hda_nid_t speaker_pins[5];
|
||||||
hda_nid_t hp_pin;
|
hda_nid_t hp_pin;
|
||||||
hda_nid_t input_pins[AUTO_PIN_LAST];
|
hda_nid_t input_pins[AUTO_PIN_LAST];
|
||||||
hda_nid_t dig_out_pin;
|
hda_nid_t dig_out_pin;
|
||||||
|
|
|
@ -786,6 +786,8 @@ enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD };
|
||||||
static struct hda_board_config ad1986a_cfg_tbl[] = {
|
static struct hda_board_config ad1986a_cfg_tbl[] = {
|
||||||
{ .modelname = "6stack", .config = AD1986A_6STACK },
|
{ .modelname = "6stack", .config = AD1986A_6STACK },
|
||||||
{ .modelname = "3stack", .config = AD1986A_3STACK },
|
{ .modelname = "3stack", .config = AD1986A_3STACK },
|
||||||
|
{ .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84,
|
||||||
|
.config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */
|
||||||
{ .modelname = "laptop", .config = AD1986A_LAPTOP },
|
{ .modelname = "laptop", .config = AD1986A_LAPTOP },
|
||||||
{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e,
|
{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e,
|
||||||
.config = AD1986A_LAPTOP }, /* FSC V2060 */
|
.config = AD1986A_LAPTOP }, /* FSC V2060 */
|
||||||
|
@ -2253,14 +2255,11 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
|
||||||
|
|
||||||
idx = ad1988_pin_idx(pin);
|
idx = ad1988_pin_idx(pin);
|
||||||
nid = ad1988_idx_to_dac(codec, idx);
|
nid = ad1988_idx_to_dac(codec, idx);
|
||||||
if (! spec->multiout.dac_nids[0]) {
|
/* specify the DAC as the extra output */
|
||||||
/* use this as the primary output */
|
if (! spec->multiout.hp_nid)
|
||||||
spec->multiout.dac_nids[0] = nid;
|
|
||||||
if (! spec->multiout.num_dacs)
|
|
||||||
spec->multiout.num_dacs = 1;
|
|
||||||
} else
|
|
||||||
/* specify the DAC as the extra output */
|
|
||||||
spec->multiout.hp_nid = nid;
|
spec->multiout.hp_nid = nid;
|
||||||
|
else
|
||||||
|
spec->multiout.extra_out_nid[0] = nid;
|
||||||
/* control HP volume/switch on the output mixer amp */
|
/* control HP volume/switch on the output mixer amp */
|
||||||
sprintf(name, "%s Playback Volume", pfx);
|
sprintf(name, "%s Playback Volume", pfx);
|
||||||
if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
|
if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
|
||||||
|
@ -2379,7 +2378,7 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec)
|
||||||
struct ad198x_spec *spec = codec->spec;
|
struct ad198x_spec *spec = codec->spec;
|
||||||
hda_nid_t pin;
|
hda_nid_t pin;
|
||||||
|
|
||||||
pin = spec->autocfg.speaker_pin;
|
pin = spec->autocfg.speaker_pins[0];
|
||||||
if (pin) /* connect to front */
|
if (pin) /* connect to front */
|
||||||
ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
|
ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
|
||||||
pin = spec->autocfg.hp_pin;
|
pin = spec->autocfg.hp_pin;
|
||||||
|
@ -2428,13 +2427,13 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
|
||||||
return err;
|
return err;
|
||||||
if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
|
if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
|
||||||
return err;
|
return err;
|
||||||
if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
|
if (! spec->autocfg.line_outs)
|
||||||
! spec->autocfg.hp_pin)
|
|
||||||
return 0; /* can't find valid BIOS pin config */
|
return 0; /* can't find valid BIOS pin config */
|
||||||
if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
|
if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
|
||||||
(err = ad1988_auto_create_extra_out(codec, spec->autocfg.speaker_pin,
|
(err = ad1988_auto_create_extra_out(codec,
|
||||||
|
spec->autocfg.speaker_pins[0],
|
||||||
"Speaker")) < 0 ||
|
"Speaker")) < 0 ||
|
||||||
(err = ad1988_auto_create_extra_out(codec, spec->autocfg.speaker_pin,
|
(err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pin,
|
||||||
"Headphone")) < 0 ||
|
"Headphone")) < 0 ||
|
||||||
(err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
(err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -2431,14 +2431,11 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
|
||||||
|
|
||||||
if (alc880_is_fixed_pin(pin)) {
|
if (alc880_is_fixed_pin(pin)) {
|
||||||
nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
|
nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
|
||||||
if (! spec->multiout.dac_nids[0]) {
|
/* specify the DAC as the extra output */
|
||||||
/* use this as the primary output */
|
if (! spec->multiout.hp_nid)
|
||||||
spec->multiout.dac_nids[0] = nid;
|
|
||||||
if (! spec->multiout.num_dacs)
|
|
||||||
spec->multiout.num_dacs = 1;
|
|
||||||
} else
|
|
||||||
/* specify the DAC as the extra output */
|
|
||||||
spec->multiout.hp_nid = nid;
|
spec->multiout.hp_nid = nid;
|
||||||
|
else
|
||||||
|
spec->multiout.extra_out_nid[0] = nid;
|
||||||
/* control HP volume/switch on the output mixer amp */
|
/* control HP volume/switch on the output mixer amp */
|
||||||
nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
|
nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
|
||||||
sprintf(name, "%s Playback Volume", pfx);
|
sprintf(name, "%s Playback Volume", pfx);
|
||||||
|
@ -2451,12 +2448,6 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
|
||||||
return err;
|
return err;
|
||||||
} else if (alc880_is_multi_pin(pin)) {
|
} else if (alc880_is_multi_pin(pin)) {
|
||||||
/* set manual connection */
|
/* set manual connection */
|
||||||
if (! spec->multiout.dac_nids[0]) {
|
|
||||||
/* use this as the primary output */
|
|
||||||
spec->multiout.dac_nids[0] = alc880_idx_to_dac(alc880_multi_pin_idx(pin));
|
|
||||||
if (! spec->multiout.num_dacs)
|
|
||||||
spec->multiout.num_dacs = 1;
|
|
||||||
}
|
|
||||||
/* we have only a switch on HP-out PIN */
|
/* we have only a switch on HP-out PIN */
|
||||||
sprintf(name, "%s Playback Switch", pfx);
|
sprintf(name, "%s Playback Switch", pfx);
|
||||||
if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
|
if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
|
||||||
|
@ -2540,7 +2531,7 @@ static void alc880_auto_init_extra_out(struct hda_codec *codec)
|
||||||
struct alc_spec *spec = codec->spec;
|
struct alc_spec *spec = codec->spec;
|
||||||
hda_nid_t pin;
|
hda_nid_t pin;
|
||||||
|
|
||||||
pin = spec->autocfg.speaker_pin;
|
pin = spec->autocfg.speaker_pins[0];
|
||||||
if (pin) /* connect to front */
|
if (pin) /* connect to front */
|
||||||
alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
|
alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
|
||||||
pin = spec->autocfg.hp_pin;
|
pin = spec->autocfg.hp_pin;
|
||||||
|
@ -2576,15 +2567,15 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
|
||||||
if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
|
if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
|
||||||
alc880_ignore)) < 0)
|
alc880_ignore)) < 0)
|
||||||
return err;
|
return err;
|
||||||
if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
|
if (! spec->autocfg.line_outs)
|
||||||
! spec->autocfg.hp_pin)
|
|
||||||
return 0; /* can't find valid BIOS pin config */
|
return 0; /* can't find valid BIOS pin config */
|
||||||
|
|
||||||
if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
|
if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
|
||||||
(err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
|
(err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
|
||||||
(err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin,
|
(err = alc880_auto_create_extra_out(spec,
|
||||||
|
spec->autocfg.speaker_pins[0],
|
||||||
"Speaker")) < 0 ||
|
"Speaker")) < 0 ||
|
||||||
(err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin,
|
(err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pin,
|
||||||
"Headphone")) < 0 ||
|
"Headphone")) < 0 ||
|
||||||
(err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
(err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -3445,7 +3436,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
nid = cfg->speaker_pin;
|
nid = cfg->speaker_pins[0];
|
||||||
if (nid) {
|
if (nid) {
|
||||||
err = alc260_add_playback_controls(spec, nid, "Speaker");
|
err = alc260_add_playback_controls(spec, nid, "Speaker");
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -3518,7 +3509,7 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec)
|
||||||
if (nid)
|
if (nid)
|
||||||
alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
|
alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
|
||||||
|
|
||||||
nid = spec->autocfg.speaker_pin;
|
nid = spec->autocfg.speaker_pins[0];
|
||||||
if (nid)
|
if (nid)
|
||||||
alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
|
alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
|
||||||
|
|
||||||
|
@ -4602,7 +4593,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
nid = cfg->speaker_pin;
|
nid = cfg->speaker_pins[0];
|
||||||
if (nid) {
|
if (nid) {
|
||||||
if (nid == 0x16) {
|
if (nid == 0x16) {
|
||||||
if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume",
|
if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume",
|
||||||
|
@ -4612,10 +4603,6 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct
|
||||||
HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
|
HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
|
||||||
return err;
|
return err;
|
||||||
} else {
|
} else {
|
||||||
if (! cfg->line_out_pins[0])
|
|
||||||
if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume",
|
|
||||||
HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0)
|
|
||||||
return err;
|
|
||||||
if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch",
|
if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch",
|
||||||
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
|
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -4632,10 +4619,6 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct
|
||||||
HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
|
HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
|
||||||
return err;
|
return err;
|
||||||
} else {
|
} else {
|
||||||
if (! cfg->line_out_pins[0])
|
|
||||||
if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume",
|
|
||||||
HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0)
|
|
||||||
return err;
|
|
||||||
if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
|
if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
|
||||||
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
|
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -4729,8 +4712,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
|
||||||
if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
|
if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
|
||||||
alc262_ignore)) < 0)
|
alc262_ignore)) < 0)
|
||||||
return err;
|
return err;
|
||||||
if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
|
if (! spec->autocfg.line_outs)
|
||||||
! spec->autocfg.hp_pin)
|
|
||||||
return 0; /* can't find valid BIOS pin config */
|
return 0; /* can't find valid BIOS pin config */
|
||||||
if ((err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
|
if ((err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
|
||||||
(err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
(err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
||||||
|
@ -5404,8 +5386,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
|
||||||
if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
|
if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
|
||||||
alc861_ignore)) < 0)
|
alc861_ignore)) < 0)
|
||||||
return err;
|
return err;
|
||||||
if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
|
if (! spec->autocfg.line_outs)
|
||||||
! spec->autocfg.hp_pin)
|
|
||||||
return 0; /* can't find valid BIOS pin config */
|
return 0; /* can't find valid BIOS pin config */
|
||||||
|
|
||||||
if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
|
if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
|
||||||
|
|
|
@ -51,6 +51,7 @@ struct sigmatel_spec {
|
||||||
unsigned int line_switch: 1;
|
unsigned int line_switch: 1;
|
||||||
unsigned int mic_switch: 1;
|
unsigned int mic_switch: 1;
|
||||||
unsigned int alt_switch: 1;
|
unsigned int alt_switch: 1;
|
||||||
|
unsigned int hp_detect: 1;
|
||||||
|
|
||||||
/* playback */
|
/* playback */
|
||||||
struct hda_multi_out multiout;
|
struct hda_multi_out multiout;
|
||||||
|
@ -697,13 +698,7 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct aut
|
||||||
AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
|
AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfg->line_outs)
|
spec->multiout.num_dacs = cfg->line_outs;
|
||||||
spec->multiout.num_dacs = cfg->line_outs;
|
|
||||||
else if (cfg->hp_pin) {
|
|
||||||
spec->multiout.dac_nids[0] = snd_hda_codec_read(codec, cfg->hp_pin, 0,
|
|
||||||
AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
|
|
||||||
spec->multiout.num_dacs = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -772,11 +767,13 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
wid_caps = get_wcaps(codec, pin);
|
wid_caps = get_wcaps(codec, pin);
|
||||||
if (wid_caps & AC_WCAP_UNSOL_CAP)
|
if (wid_caps & AC_WCAP_UNSOL_CAP) {
|
||||||
/* Enable unsolicited responses on the HP widget */
|
/* Enable unsolicited responses on the HP widget */
|
||||||
snd_hda_codec_write(codec, pin, 0,
|
snd_hda_codec_write(codec, pin, 0,
|
||||||
AC_VERB_SET_UNSOLICITED_ENABLE,
|
AC_VERB_SET_UNSOLICITED_ENABLE,
|
||||||
STAC_UNSOL_ENABLE);
|
STAC_UNSOL_ENABLE);
|
||||||
|
spec->hp_detect = 1;
|
||||||
|
}
|
||||||
|
|
||||||
nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
|
nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
|
||||||
for (i = 0; i < cfg->line_outs; i++) {
|
for (i = 0; i < cfg->line_outs; i++) {
|
||||||
|
@ -810,9 +807,6 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
|
||||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||||
int index = -1;
|
int index = -1;
|
||||||
if (cfg->input_pins[i]) {
|
if (cfg->input_pins[i]) {
|
||||||
/* Enable active pin widget as an input */
|
|
||||||
stac92xx_auto_set_pinctl(codec, cfg->input_pins[i], AC_PINCTL_IN_EN);
|
|
||||||
|
|
||||||
imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
|
imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
|
||||||
|
|
||||||
for (j=0; j<spec->num_muxes; j++) {
|
for (j=0; j<spec->num_muxes; j++) {
|
||||||
|
@ -861,10 +855,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
|
||||||
|
|
||||||
if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
|
if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
|
||||||
return err;
|
return err;
|
||||||
if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin)
|
if (! spec->autocfg.line_outs)
|
||||||
return 0; /* can't find valid pin config */
|
return 0; /* can't find valid pin config */
|
||||||
stac92xx_auto_init_multi_out(codec);
|
|
||||||
stac92xx_auto_init_hp_out(codec);
|
|
||||||
if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
|
if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
|
||||||
return err;
|
return err;
|
||||||
if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
|
if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
|
||||||
|
@ -879,14 +871,10 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
|
||||||
if (spec->multiout.max_channels > 2)
|
if (spec->multiout.max_channels > 2)
|
||||||
spec->surr_switch = 1;
|
spec->surr_switch = 1;
|
||||||
|
|
||||||
if (spec->autocfg.dig_out_pin) {
|
if (spec->autocfg.dig_out_pin)
|
||||||
spec->multiout.dig_out_nid = dig_out;
|
spec->multiout.dig_out_nid = dig_out;
|
||||||
stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN);
|
if (spec->autocfg.dig_in_pin)
|
||||||
}
|
|
||||||
if (spec->autocfg.dig_in_pin) {
|
|
||||||
spec->dig_in_nid = dig_in;
|
spec->dig_in_nid = dig_in;
|
||||||
stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spec->kctl_alloc)
|
if (spec->kctl_alloc)
|
||||||
spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
|
spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
|
||||||
|
@ -896,6 +884,29 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* add playback controls for HP output */
|
||||||
|
static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
|
||||||
|
struct auto_pin_cfg *cfg)
|
||||||
|
{
|
||||||
|
struct sigmatel_spec *spec = codec->spec;
|
||||||
|
hda_nid_t pin = cfg->hp_pin;
|
||||||
|
unsigned int wid_caps;
|
||||||
|
|
||||||
|
if (! pin)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
wid_caps = get_wcaps(codec, pin);
|
||||||
|
if (wid_caps & AC_WCAP_UNSOL_CAP) {
|
||||||
|
/* Enable unsolicited responses on the HP widget */
|
||||||
|
snd_hda_codec_write(codec, pin, 0,
|
||||||
|
AC_VERB_SET_UNSOLICITED_ENABLE,
|
||||||
|
STAC_UNSOL_ENABLE);
|
||||||
|
spec->hp_detect = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int stac9200_parse_auto_config(struct hda_codec *codec)
|
static int stac9200_parse_auto_config(struct hda_codec *codec)
|
||||||
{
|
{
|
||||||
struct sigmatel_spec *spec = codec->spec;
|
struct sigmatel_spec *spec = codec->spec;
|
||||||
|
@ -907,14 +918,13 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
|
||||||
if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
|
if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (spec->autocfg.dig_out_pin) {
|
if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (spec->autocfg.dig_out_pin)
|
||||||
spec->multiout.dig_out_nid = 0x05;
|
spec->multiout.dig_out_nid = 0x05;
|
||||||
stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN);
|
if (spec->autocfg.dig_in_pin)
|
||||||
}
|
|
||||||
if (spec->autocfg.dig_in_pin) {
|
|
||||||
spec->dig_in_nid = 0x04;
|
spec->dig_in_nid = 0x04;
|
||||||
stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spec->kctl_alloc)
|
if (spec->kctl_alloc)
|
||||||
spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
|
spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
|
||||||
|
@ -927,9 +937,31 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
|
||||||
static int stac92xx_init(struct hda_codec *codec)
|
static int stac92xx_init(struct hda_codec *codec)
|
||||||
{
|
{
|
||||||
struct sigmatel_spec *spec = codec->spec;
|
struct sigmatel_spec *spec = codec->spec;
|
||||||
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||||
|
int i;
|
||||||
|
|
||||||
snd_hda_sequence_write(codec, spec->init);
|
snd_hda_sequence_write(codec, spec->init);
|
||||||
|
|
||||||
|
/* set up pins */
|
||||||
|
if (spec->hp_detect) {
|
||||||
|
/* fake event to set up pins */
|
||||||
|
codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
|
||||||
|
} else {
|
||||||
|
stac92xx_auto_init_multi_out(codec);
|
||||||
|
stac92xx_auto_init_hp_out(codec);
|
||||||
|
}
|
||||||
|
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||||
|
if (cfg->input_pins[i])
|
||||||
|
stac92xx_auto_set_pinctl(codec, cfg->input_pins[i],
|
||||||
|
AC_PINCTL_IN_EN);
|
||||||
|
}
|
||||||
|
if (cfg->dig_out_pin)
|
||||||
|
stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
|
||||||
|
AC_PINCTL_OUT_EN);
|
||||||
|
if (cfg->dig_in_pin)
|
||||||
|
stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
|
||||||
|
AC_PINCTL_IN_EN);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue