From 38faddb1afdd37218c196ac3db1cb5fbe7fc9c75 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Jul 2010 14:21:55 +0200 Subject: [PATCH 1/4] ALSA: hda - Fix pin-detection of Nvidia HDMI The behavior of Nvidia HDMI codec regarding the pin-detection unsol events is based on the old HD-audio spec, i.e. PD bit indicates only the update and doesn't show the current state. Since the current code assumes the new behavior, the pin-detection doesn't work relialby with these h/w. This patch adds a flag for indicating the old spec, and fixes the issue by checking the pin-detection explicitly for such hardware. Tested-by: Wei Ni Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 13 +++++++++++++ sound/pci/hda/patch_nvhdmi.c | 3 +++ 2 files changed, 16 insertions(+) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 86067ee7863..2fc53961054 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -52,6 +52,10 @@ struct hdmi_spec { */ struct hda_multi_out multiout; unsigned int codec_type; + + /* misc flags */ + /* PD bit indicates only the update, not the current state */ + unsigned int old_pin_detect:1; }; @@ -616,6 +620,9 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, * Unsolicited events */ +static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, + struct hdmi_eld *eld); + static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) { struct hdmi_spec *spec = codec->spec; @@ -632,6 +639,12 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) if (index < 0) return; + if (spec->old_pin_detect) { + if (pind) + hdmi_present_sense(codec, tag, &spec->sink_eld[index]); + pind = spec->sink_eld[index].monitor_present; + } + spec->sink_eld[index].monitor_present = pind; spec->sink_eld[index].eld_valid = eldv; diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 3c10c0b149f..b0652acee9b 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -478,6 +478,7 @@ static int patch_nvhdmi_8ch_89(struct hda_codec *codec) codec->spec = spec; spec->codec_type = HDA_CODEC_NVIDIA_MCP89; + spec->old_pin_detect = 1; if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; @@ -508,6 +509,7 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) spec->multiout.max_channels = 8; spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; spec->codec_type = HDA_CODEC_NVIDIA_MCP7X; + spec->old_pin_detect = 1; codec->patch_ops = nvhdmi_patch_ops_8ch_7x; @@ -528,6 +530,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) spec->multiout.max_channels = 2; spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; spec->codec_type = HDA_CODEC_NVIDIA_MCP7X; + spec->old_pin_detect = 1; codec->patch_ops = nvhdmi_patch_ops_2ch; From 8af2591d6342a9e4bb79b4f1236246a79d20ebee Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Jul 2010 17:37:16 +0200 Subject: [PATCH 2/4] ALSA: hda - Don't register beep input device when no beep is available We check now the availability of PC beep and skip the build of beep mixers, but the driver still registers the input device. This should be checked as well. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ff614dd824c..d7fd846e6c4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10566,10 +10566,12 @@ static int patch_alc882(struct hda_codec *codec) } } - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; + if (spec->cdefine.enable_pcbeep) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } } if (board_config != ALC882_AUTO) @@ -12435,7 +12437,7 @@ static int patch_alc262(struct hda_codec *codec) } } - if (!spec->no_analog) { + if (!spec->no_analog && spec->cdefine.enable_pcbeep) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) { alc_free(codec); @@ -14458,10 +14460,12 @@ static int patch_alc269(struct hda_codec *codec) } } - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; + if (spec->cdefine.enable_pcbeep) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } } if (board_config != ALC269_AUTO) @@ -18691,10 +18695,12 @@ static int patch_alc662(struct hda_codec *codec) } } - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; + if (spec->cdefine.enable_pcbeep) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } } if (board_config != ALC662_AUTO) From b6cbe517b9a4f21e1ca5e58356929383974500f3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Jul 2010 17:43:36 +0200 Subject: [PATCH 3/4] ALSA: hda - Assume PC-beep as default for Realtek Enable PC-beep as default for hardwares that aren't compliant with the SSID value Realtek requires. In such a case, better to enable the beep to avoid a regression. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d7fd846e6c4..92955279736 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1267,11 +1267,11 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec) unsigned nid = 0; struct alc_spec *spec = codec->spec; + spec->cdefine.enable_pcbeep = 1; /* assume always enabled */ + ass = codec->subsystem_id & 0xffff; - if (ass != codec->bus->pci->subsystem_device && (ass & 1)) { - spec->cdefine.enable_pcbeep = 1; /* assume always enabled */ + if (ass != codec->bus->pci->subsystem_device && (ass & 1)) goto do_sku; - } nid = 0x1d; if (codec->vendor_id == 0x10ec0260) From dc1eae256cfac03bf17bf3eb016e3a6423d3f9d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 29 Jul 2010 15:30:02 +0200 Subject: [PATCH 4/4] ALSA: hda - Add a PC-beep workaround for ASUS P5-V ASUS P5-V provides a SSID that unexpectedly matches with the value compilant with Realtek's specification. Thus the driver interprets it badly, resulting in non-working PC beep. This patch adds a white-list for such a case; a white-list of known devices with working PC beep. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 92955279736..596ea2f12cf 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5180,8 +5180,24 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, #ifdef CONFIG_SND_HDA_INPUT_BEEP #define set_beep_amp(spec, nid, idx, dir) \ ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir)) + +static struct snd_pci_quirk beep_white_list[] = { + SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), + {} +}; + +static inline int has_cdefine_beep(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + const struct snd_pci_quirk *q; + q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list); + if (q) + return q->value; + return spec->cdefine.enable_pcbeep; +} #else #define set_beep_amp(spec, nid, idx, dir) /* NOP */ +#define has_cdefine_beep(codec) 0 #endif /* @@ -10566,7 +10582,7 @@ static int patch_alc882(struct hda_codec *codec) } } - if (spec->cdefine.enable_pcbeep) { + if (has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) { alc_free(codec); @@ -10621,7 +10637,7 @@ static int patch_alc882(struct hda_codec *codec) set_capture_mixer(codec); - if (spec->cdefine.enable_pcbeep) + if (has_cdefine_beep(codec)) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); if (board_config == ALC882_AUTO) @@ -12437,7 +12453,7 @@ static int patch_alc262(struct hda_codec *codec) } } - if (!spec->no_analog && spec->cdefine.enable_pcbeep) { + if (!spec->no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) { alc_free(codec); @@ -12488,7 +12504,7 @@ static int patch_alc262(struct hda_codec *codec) } if (!spec->cap_mixer && !spec->no_analog) set_capture_mixer(codec); - if (!spec->no_analog && spec->cdefine.enable_pcbeep) + if (!spec->no_analog && has_cdefine_beep(codec)) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x0c; @@ -14460,7 +14476,7 @@ static int patch_alc269(struct hda_codec *codec) } } - if (spec->cdefine.enable_pcbeep) { + if (has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) { alc_free(codec); @@ -14498,7 +14514,7 @@ static int patch_alc269(struct hda_codec *codec) if (!spec->cap_mixer) set_capture_mixer(codec); - if (spec->cdefine.enable_pcbeep) + if (has_cdefine_beep(codec)) set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); if (board_config == ALC269_AUTO) @@ -18695,7 +18711,7 @@ static int patch_alc662(struct hda_codec *codec) } } - if (spec->cdefine.enable_pcbeep) { + if (has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) { alc_free(codec); @@ -18722,7 +18738,7 @@ static int patch_alc662(struct hda_codec *codec) if (!spec->cap_mixer) set_capture_mixer(codec); - if (spec->cdefine.enable_pcbeep) { + if (has_cdefine_beep(codec)) { switch (codec->vendor_id) { case 0x10ec0662: set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);