ALSA: hda - Fix inconsistent Mic mute LED
authorTakashi Iwai <tiwai@suse.de>
Thu, 30 Jan 2014 16:59:02 +0000 (17:59 +0100)
committerJiri Slaby <jslaby@suse.cz>
Tue, 1 Apr 2014 20:12:08 +0000 (22:12 +0200)
commit 7fe307117db5bd7ec6efb93c563dcf44577b6d2b upstream.

The current code for controlling mic mute LED in patch_sigmatel.c
blindly assumes that there is a single capture switch.  But, there can
be multiple multiple ones, and each of them flips the state, ended up
in an inconsistent state.

For fixing this problem, this patch adds kcontrol to be passed to the
hook function so that the callee can check which switch is being
accessed.  In stac_capture_led_hook(), the state is checked as a
bitmask, and turns on the LED when all capture switches are off.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c

index 7d4ccfa48008ad351ff01f8b241238bb2050bfd3..31da88bf6c1ca138be7aa4f2b92d82536ca74dc2 100644 (file)
@@ -3264,7 +3264,7 @@ static int cap_put_caller(struct snd_kcontrol *kcontrol,
        mutex_unlock(&codec->control_mutex);
        snd_hda_codec_flush_cache(codec); /* flush the updates */
        if (err >= 0 && spec->cap_sync_hook)
-               spec->cap_sync_hook(codec, ucontrol);
+               spec->cap_sync_hook(codec, kcontrol, ucontrol);
        return err;
 }
 
@@ -3385,7 +3385,7 @@ static int cap_single_sw_put(struct snd_kcontrol *kcontrol,
                return ret;
 
        if (spec->cap_sync_hook)
-               spec->cap_sync_hook(codec, ucontrol);
+               spec->cap_sync_hook(codec, kcontrol, ucontrol);
 
        return ret;
 }
@@ -3790,7 +3790,7 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
                return 0;
        snd_hda_activate_path(codec, path, true, false);
        if (spec->cap_sync_hook)
-               spec->cap_sync_hook(codec, NULL);
+               spec->cap_sync_hook(codec, NULL, NULL);
        path_power_down_sync(codec, old_path);
        return 1;
 }
@@ -5233,7 +5233,7 @@ static void init_input_src(struct hda_codec *codec)
        }
 
        if (spec->cap_sync_hook)
-               spec->cap_sync_hook(codec, NULL);
+               spec->cap_sync_hook(codec, NULL, NULL);
 }
 
 /* set right pin controls for digital I/O */
index 0929a06df8128495f5e717768fcfa28eaed7360d..a1095de808c8eb08447742cd6fb6f804bd39d0d3 100644 (file)
@@ -274,6 +274,7 @@ struct hda_gen_spec {
        void (*init_hook)(struct hda_codec *codec);
        void (*automute_hook)(struct hda_codec *codec);
        void (*cap_sync_hook)(struct hda_codec *codec,
+                             struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol);
 
        /* PCM hooks */
index 96f07ce566038577098e14101c9beaf70c8bf426..fde381d02afd6591283623a9b6d9510cc201fb96 100644 (file)
@@ -3282,7 +3282,8 @@ static void cxt_update_headset_mode(struct hda_codec *codec)
 }
 
 static void cxt_update_headset_mode_hook(struct hda_codec *codec,
-                            struct snd_ctl_elem_value *ucontrol)
+                                        struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
 {
        cxt_update_headset_mode(codec);
 }
index deddee9c15653f986755c79ed444f9ade1d62502..6a32c857f7042bd6640d0e27d9a8eb1476eecc30 100644 (file)
@@ -695,7 +695,8 @@ static void alc_inv_dmic_sync(struct hda_codec *codec, bool force)
 }
 
 static void alc_inv_dmic_hook(struct hda_codec *codec,
-                            struct snd_ctl_elem_value *ucontrol)
+                             struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
 {
        alc_inv_dmic_sync(codec, false);
 }
@@ -3141,7 +3142,8 @@ static void alc269_fixup_hp_gpio_mute_hook(void *private_data, int enabled)
 
 /* turn on/off mic-mute LED per capture hook */
 static void alc269_fixup_hp_gpio_mic_mute_hook(struct hda_codec *codec,
-                              struct snd_ctl_elem_value *ucontrol)
+                                              struct snd_kcontrol *kcontrol,
+                                              struct snd_ctl_elem_value *ucontrol)
 {
        struct alc_spec *spec = codec->spec;
        unsigned int oldval = spec->gpio_led;
@@ -3403,7 +3405,8 @@ static void alc_update_headset_mode(struct hda_codec *codec)
 }
 
 static void alc_update_headset_mode_hook(struct hda_codec *codec,
-                            struct snd_ctl_elem_value *ucontrol)
+                                        struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
 {
        alc_update_headset_mode(codec);
 }
index 6133423821d15ed787e8366c7923509018de6710..d761c0b879c977949530b25754411f7b44d99c76 100644 (file)
@@ -195,7 +195,7 @@ struct sigmatel_spec {
        int default_polarity;
 
        unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */
-       bool mic_mute_led_on; /* current mic mute state */
+       unsigned int mic_enabled; /* current mic mute state (bitmask) */
 
        /* stream */
        unsigned int stream_delay;
@@ -325,19 +325,26 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
 
 /* hook for controlling mic-mute LED GPIO */
 static void stac_capture_led_hook(struct hda_codec *codec,
-                              struct snd_ctl_elem_value *ucontrol)
+                                 struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
 {
        struct sigmatel_spec *spec = codec->spec;
-       bool mute;
+       unsigned int mask;
+       bool cur_mute, prev_mute;
 
-       if (!ucontrol)
+       if (!kcontrol || !ucontrol)
                return;
 
-       mute = !(ucontrol->value.integer.value[0] ||
-                ucontrol->value.integer.value[1]);
-       if (spec->mic_mute_led_on != mute) {
-               spec->mic_mute_led_on = mute;
-               if (mute)
+       mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       prev_mute = !spec->mic_enabled;
+       if (ucontrol->value.integer.value[0] ||
+           ucontrol->value.integer.value[1])
+               spec->mic_enabled |= mask;
+       else
+               spec->mic_enabled &= ~mask;
+       cur_mute = !spec->mic_enabled;
+       if (cur_mute != prev_mute) {
+               if (cur_mute)
                        spec->gpio_data |= spec->mic_mute_led_gpio;
                else
                        spec->gpio_data &= ~spec->mic_mute_led_gpio;
@@ -3974,7 +3981,7 @@ static void stac_setup_gpio(struct hda_codec *codec)
        if (spec->mic_mute_led_gpio) {
                spec->gpio_mask |= spec->mic_mute_led_gpio;
                spec->gpio_dir |= spec->mic_mute_led_gpio;
-               spec->mic_mute_led_on = true;
+               spec->mic_enabled = 0;
                spec->gpio_data |= spec->mic_mute_led_gpio;
 
                spec->gen.cap_sync_hook = stac_capture_led_hook;