2.6.27-stable review patch. If anyone has any objections, please let us know. ------------------ From: Takashi Iwai commit e044c39ae258678d6ebb09fccb2a0fdf7ec51847 upstream Some machines have broken BIOS resume that doesn't restore the default pin configuration properly, which results in a wrong detection of HP pin. This causes a silent speaker output due to missing HP detection. Related bug: Novell bug#406101 https://bugzilla.novell.com/show_bug.cgi?id=406101 This patch fixes the issue by saving/restoring the default pin configs by the driver itself. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 77 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -292,6 +292,13 @@ struct alc_spec { /* for PLL fix */ hda_nid_t pll_nid; unsigned int pll_coef_idx, pll_coef_bit; + +#ifdef SND_HDA_NEEDS_RESUME +#define ALC_MAX_PINS 16 + unsigned int num_pins; + hda_nid_t pin_nids[ALC_MAX_PINS]; + unsigned int pin_cfgs[ALC_MAX_PINS]; +#endif }; /* @@ -2723,6 +2730,64 @@ static void alc_free(struct hda_codec *c codec->spec = NULL; /* to be sure */ } +#ifdef SND_HDA_NEEDS_RESUME +static void store_pin_configs(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid, end_nid; + + end_nid = codec->start_nid + codec->num_nodes; + for (nid = codec->start_nid; nid < end_nid; nid++) { + unsigned int wid_caps = get_wcaps(codec, nid); + unsigned int wid_type = + (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + if (wid_type != AC_WID_PIN) + continue; + if (spec->num_pins >= ARRAY_SIZE(spec->pin_nids)) + break; + spec->pin_nids[spec->num_pins] = nid; + spec->pin_cfgs[spec->num_pins] = + snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + spec->num_pins++; + } +} + +static void resume_pin_configs(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_pins; i++) { + hda_nid_t pin_nid = spec->pin_nids[i]; + unsigned int pin_config = spec->pin_cfgs[i]; + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, + pin_config & 0x000000ff); + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, + (pin_config & 0x0000ff00) >> 8); + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, + (pin_config & 0x00ff0000) >> 16); + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, + pin_config >> 24); + } +} + +static int alc_resume(struct hda_codec *codec) +{ + resume_pin_configs(codec); + codec->patch_ops.init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + return 0; +} +#else +#define store_pin_configs(codec) +#endif + /* */ static struct hda_codec_ops alc_patch_ops = { @@ -2731,6 +2796,9 @@ static struct hda_codec_ops alc_patch_op .init = alc_init, .free = alc_free, .unsol_event = alc_unsol_event, +#ifdef SND_HDA_NEEDS_RESUME + .resume = alc_resume, +#endif #ifdef CONFIG_SND_HDA_POWER_SAVE .check_power_status = alc_check_power_status, #endif @@ -3777,6 +3845,7 @@ static int alc880_parse_auto_config(stru spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; + store_pin_configs(codec); return 1; } @@ -5125,6 +5194,7 @@ static int alc260_parse_auto_config(stru } spec->num_mixers++; + store_pin_configs(codec); return 1; } @@ -9731,6 +9801,7 @@ static int alc262_parse_auto_config(stru if (err < 0) return err; + store_pin_configs(codec); return 1; } @@ -10762,6 +10833,7 @@ static int alc268_parse_auto_config(stru if (err < 0) return err; + store_pin_configs(codec); return 1; } @@ -11427,6 +11499,7 @@ static int alc269_parse_auto_config(stru spec->mixers[spec->num_mixers] = alc269_capture_mixer; spec->num_mixers++; + store_pin_configs(codec); return 1; } @@ -12495,6 +12568,7 @@ static int alc861_parse_auto_config(stru spec->mixers[spec->num_mixers] = alc861_capture_mixer; spec->num_mixers++; + store_pin_configs(codec); return 1; } @@ -13606,6 +13680,7 @@ static int alc861vd_parse_auto_config(st if (err < 0) return err; + store_pin_configs(codec); return 1; } @@ -14853,6 +14928,8 @@ static int alc662_parse_auto_config(stru spec->mixers[spec->num_mixers] = alc662_capture_mixer; spec->num_mixers++; + + store_pin_configs(codec); return 1; } -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/