ALSA: hda - Fix IDT/STAC multiple HP detection

Due to the recent change for multiple HP as line-out switch, only
one of the multiple headphons (usually a wrong one) is toggled
and the other pins are still disabled. This causes the silent output
problem on some Dell laptops.

Also, the hp_switch check is screwed up when a line-in or a mic-in
jack exists. This is added as an additional output, but hp_switch
check doesn't take it into account.

This patch fixes these issues: simplify hp_switch check by using
the NID instead of bool, and clean up / fix the toggle of HP pins
in unsol event handler code.

Reference: Novell bnc#443267
https://bugzilla.novell.com/show_bug.cgi?id=443267

Signed-off-by: Takashi Iwai <tiwai@suse.de>

+45 -14
+45 -14
sound/pci/hda/patch_sigmatel.c
··· 212 /* i/o switches */ 213 unsigned int io_switch[2]; 214 unsigned int clfe_swap; 215 - unsigned int hp_switch; 216 unsigned int aloopback; 217 218 struct hda_pcm pcm_rec[2]; /* PCM information */ ··· 2443 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2444 struct sigmatel_spec *spec = codec->spec; 2445 2446 - ucontrol->value.integer.value[0] = spec->hp_switch; 2447 return 0; 2448 } 2449 ··· 2452 { 2453 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2454 struct sigmatel_spec *spec = codec->spec; 2455 - 2456 - spec->hp_switch = ucontrol->value.integer.value[0]; 2457 2458 /* check to be sure that the ports are upto date with 2459 * switch changes ··· 2863 if (cfg->hp_outs > 1) { 2864 err = stac92xx_add_control(spec, 2865 STAC_CTL_WIDGET_HP_SWITCH, 2866 - "Headphone as Line Out Switch", 0); 2867 if (err < 0) 2868 return err; 2869 } ··· 3788 return 0; 3789 } 3790 3791 static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) 3792 { 3793 struct sigmatel_spec *spec = codec->spec; 3794 struct auto_pin_cfg *cfg = &spec->autocfg; 3795 - int nid = cfg->hp_pins[cfg->hp_outs - 1]; 3796 int i, presence; 3797 3798 presence = 0; ··· 3822 for (i = 0; i < cfg->hp_outs; i++) { 3823 if (presence) 3824 break; 3825 - if (spec->hp_switch && cfg->hp_pins[i] == nid) 3826 - break; 3827 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); 3828 } 3829 3830 if (presence) { 3831 - /* disable lineouts, enable hp */ 3832 if (spec->hp_switch) 3833 - stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN); 3834 for (i = 0; i < cfg->line_outs; i++) 3835 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], 3836 AC_PINCTL_OUT_EN); ··· 3843 spec->gpio_dir, spec->gpio_data & 3844 ~spec->eapd_mask); 3845 } else { 3846 - /* enable lineouts, disable hp */ 3847 if (spec->hp_switch) 3848 - stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); 3849 for (i = 0; i < cfg->line_outs; i++) 3850 stac92xx_set_pinctl(codec, cfg->line_out_pins[i], 3851 AC_PINCTL_OUT_EN); ··· 3858 spec->gpio_dir, spec->gpio_data | 3859 spec->eapd_mask); 3860 } 3861 - if (!spec->hp_switch && cfg->hp_outs > 1 && presence) 3862 - stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); 3863 } 3864 3865 static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
··· 212 /* i/o switches */ 213 unsigned int io_switch[2]; 214 unsigned int clfe_swap; 215 + unsigned int hp_switch; /* NID of HP as line-out */ 216 unsigned int aloopback; 217 218 struct hda_pcm pcm_rec[2]; /* PCM information */ ··· 2443 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2444 struct sigmatel_spec *spec = codec->spec; 2445 2446 + ucontrol->value.integer.value[0] = !!spec->hp_switch; 2447 return 0; 2448 } 2449 ··· 2452 { 2453 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2454 struct sigmatel_spec *spec = codec->spec; 2455 + int nid = kcontrol->private_value; 2456 + 2457 + spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0; 2458 2459 /* check to be sure that the ports are upto date with 2460 * switch changes ··· 2862 if (cfg->hp_outs > 1) { 2863 err = stac92xx_add_control(spec, 2864 STAC_CTL_WIDGET_HP_SWITCH, 2865 + "Headphone as Line Out Switch", 2866 + cfg->hp_pins[cfg->hp_outs - 1]); 2867 if (err < 0) 2868 return err; 2869 } ··· 3786 return 0; 3787 } 3788 3789 + /* return non-zero if the hp-pin of the given array index isn't 3790 + * a jack-detection target 3791 + */ 3792 + static int no_hp_sensing(struct sigmatel_spec *spec, int i) 3793 + { 3794 + struct auto_pin_cfg *cfg = &spec->autocfg; 3795 + 3796 + /* ignore sensing of shared line and mic jacks */ 3797 + if (spec->line_switch && 3798 + cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE]) 3799 + return 1; 3800 + if (spec->mic_switch && 3801 + cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC]) 3802 + return 1; 3803 + /* ignore if the pin is set as line-out */ 3804 + if (cfg->hp_pins[i] == spec->hp_switch) 3805 + return 1; 3806 + return 0; 3807 + } 3808 + 3809 static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) 3810 { 3811 struct sigmatel_spec *spec = codec->spec; 3812 struct auto_pin_cfg *cfg = &spec->autocfg; 3813 int i, presence; 3814 3815 presence = 0; ··· 3801 for (i = 0; i < cfg->hp_outs; i++) { 3802 if (presence) 3803 break; 3804 + if (no_hp_sensing(spec, i)) 3805 + continue; 3806 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); 3807 } 3808 3809 if (presence) { 3810 + /* disable lineouts */ 3811 if (spec->hp_switch) 3812 + stac92xx_reset_pinctl(codec, spec->hp_switch, 3813 + AC_PINCTL_OUT_EN); 3814 for (i = 0; i < cfg->line_outs; i++) 3815 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], 3816 AC_PINCTL_OUT_EN); ··· 3821 spec->gpio_dir, spec->gpio_data & 3822 ~spec->eapd_mask); 3823 } else { 3824 + /* enable lineouts */ 3825 if (spec->hp_switch) 3826 + stac92xx_set_pinctl(codec, spec->hp_switch, 3827 + AC_PINCTL_OUT_EN); 3828 for (i = 0; i < cfg->line_outs; i++) 3829 stac92xx_set_pinctl(codec, cfg->line_out_pins[i], 3830 AC_PINCTL_OUT_EN); ··· 3835 spec->gpio_dir, spec->gpio_data | 3836 spec->eapd_mask); 3837 } 3838 + /* toggle hp outs */ 3839 + for (i = 0; i < cfg->hp_outs; i++) { 3840 + unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN; 3841 + if (no_hp_sensing(spec, i)) 3842 + continue; 3843 + if (presence) 3844 + stac92xx_set_pinctl(codec, cfg->hp_pins[i], val); 3845 + else 3846 + stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val); 3847 + } 3848 } 3849 3850 static void stac92xx_pin_sense(struct hda_codec *codec, int idx)