diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-02-20 12:30:59 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-02-29 17:38:51 +0100 |
commit | 07cafff288266c3aa082f4bda3d47989e73ee85d (patch) | |
tree | 1557aee6baa4039240c927153a8c53d5d03da6f2 /sound/pci | |
parent | 3e93f5efaf9cd48bae97ae6436cbc5f91be8003c (diff) |
ALSA: hda/conexant - Clear unsol events on unused pins
It seems that Lenovo machines (or codec chip itself?) leave the unsol
event tags and the enablement-flag from other pins bogusly even on the
unused pins. Although this shouldn't be too critical, it's better to
clear them up sanely.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 6bbdbb6dd4e..f3b79031fcc 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3931,6 +3931,50 @@ static void enable_unsol_pins(struct hda_codec *codec, int num_pins, snd_hda_jack_detect_enable(codec, pins[i], action); } +static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) +{ + int i; + for (i = 0; i < nums; i++) + if (list[i] == nid) + return true; + return false; +} + +/* is the given NID found in any of autocfg items? */ +static bool found_in_autocfg(struct auto_pin_cfg *cfg, hda_nid_t nid) +{ + int i; + + if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) || + found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) || + found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs) || + found_in_nid_list(nid, cfg->dig_out_pins, cfg->dig_outs)) + return true; + for (i = 0; i < cfg->num_inputs; i++) + if (cfg->inputs[i].pin == nid) + return true; + if (cfg->dig_in_pin == nid) + return true; + return false; +} + +/* clear unsol-event tags on unused pins; Conexant codecs seem to leave + * invalid unsol tags by some reason + */ +static void clear_unsol_on_unused_pins(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < codec->init_pins.used; i++) { + struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); + if (!found_in_autocfg(cfg, pin->nid)) + snd_hda_codec_write(codec, pin->nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, 0); + } +} + static void cx_auto_init_output(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -3971,6 +4015,7 @@ static void cx_auto_init_output(struct hda_codec *codec) /* turn on all EAPDs if no individual EAPD control is available */ if (!spec->pin_eapd_ctrls) cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); + clear_unsol_on_unused_pins(codec); } static void cx_auto_init_input(struct hda_codec *codec) |