ALSA: HDA - remove the custom implementation for the audio LED trigger
authorJaroslav Kysela <perex@perex.cz>
Wed, 17 Mar 2021 17:29:43 +0000 (18:29 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 30 Mar 2021 13:35:15 +0000 (15:35 +0200)
With the new snd-ctl-led module, we have a generic way
to trigger audio LEDs based on the sound control changes.

Remove the custom implementation from the HDA driver.

Move the LED initialization before snd_hda_gen_parse_auto_config()
call in all drivers to create marked controls there.

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Link: https://lore.kernel.org/r/20210317172945.842280-5-perex@perex.cz
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/Kconfig
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/hda_local.h
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/thinkpad_helper.c

index 90759391cbac826b81bf5d5242b92dc0a3aaeeb5..c4360cdbc7282e4bb4bf2541bc2c41f23d27dd94 100644 (file)
@@ -221,10 +221,8 @@ comment "Set to Y if you want auto-loading the codec driver"
 
 config SND_HDA_GENERIC
        tristate "Enable generic HD-audio codec parser"
-       select NEW_LEDS if SND_HDA_GENERIC_LEDS
+       select SND_CTL_LED if SND_HDA_GENERIC_LEDS
        select LEDS_CLASS if SND_HDA_GENERIC_LEDS
-       select LEDS_TRIGGERS if SND_HDA_GENERIC_LEDS
-       select LEDS_TRIGGER_AUDIO if SND_HDA_GENERIC_LEDS
        help
          Say Y or M here to enable the generic HD-audio codec parser
          in snd-hda-intel driver.
index 2026f1ccaf5a7c62e4ffb7e45aeddd2dcac9b2ca..e54e39b35709718afcdeba3976148f683bf38bc9 100644 (file)
@@ -1952,7 +1952,7 @@ static int add_follower(struct hda_codec *codec,
 int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
                          unsigned int *tlv, const char * const *followers,
                          const char *suffix, bool init_follower_vol,
-                         struct snd_kcontrol **ctl_ret)
+                         unsigned int access, struct snd_kcontrol **ctl_ret)
 {
        struct snd_kcontrol *kctl;
        int err;
@@ -1968,6 +1968,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
        kctl = snd_ctl_make_virtual_master(name, tlv);
        if (!kctl)
                return -ENOMEM;
+       kctl->vd[0].access |= access;
        err = snd_hda_ctl_add(codec, 0, kctl);
        if (err < 0)
                return err;
@@ -1994,87 +1995,29 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
 }
 EXPORT_SYMBOL_GPL(__snd_hda_add_vmaster);
 
-/*
- * mute-LED control using vmaster
- */
-static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_info *uinfo)
-{
-       static const char * const texts[] = {
-               "On", "Off", "Follow Master"
-       };
-
-       return snd_ctl_enum_info(uinfo, 1, 3, texts);
-}
-
-static int vmaster_mute_mode_get(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol);
-       ucontrol->value.enumerated.item[0] = hook->mute_mode;
-       return 0;
-}
-
-static int vmaster_mute_mode_put(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol);
-       unsigned int old_mode = hook->mute_mode;
-
-       hook->mute_mode = ucontrol->value.enumerated.item[0];
-       if (hook->mute_mode > HDA_VMUTE_FOLLOW_MASTER)
-               hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
-       if (old_mode == hook->mute_mode)
-               return 0;
-       snd_hda_sync_vmaster_hook(hook);
-       return 1;
-}
-
-static const struct snd_kcontrol_new vmaster_mute_mode = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Mute-LED Mode",
-       .info = vmaster_mute_mode_info,
-       .get = vmaster_mute_mode_get,
-       .put = vmaster_mute_mode_put,
-};
-
 /* meta hook to call each driver's vmaster hook */
 static void vmaster_hook(void *private_data, int enabled)
 {
        struct hda_vmaster_mute_hook *hook = private_data;
 
-       if (hook->mute_mode != HDA_VMUTE_FOLLOW_MASTER)
-               enabled = hook->mute_mode;
        hook->hook(hook->codec, enabled);
 }
 
 /**
- * snd_hda_add_vmaster_hook - Add a vmaster hook for mute-LED
+ * snd_hda_add_vmaster_hook - Add a vmaster hw specific hook
  * @codec: the HDA codec
  * @hook: the vmaster hook object
- * @expose_enum_ctl: flag to create an enum ctl
  *
- * Add a mute-LED hook with the given vmaster switch kctl.
- * When @expose_enum_ctl is set, "Mute-LED Mode" control is automatically
- * created and associated with the given hook.
+ * Add a hw specific hook (like EAPD) with the given vmaster switch kctl.
  */
 int snd_hda_add_vmaster_hook(struct hda_codec *codec,
-                            struct hda_vmaster_mute_hook *hook,
-                            bool expose_enum_ctl)
+                            struct hda_vmaster_mute_hook *hook)
 {
-       struct snd_kcontrol *kctl;
-
        if (!hook->hook || !hook->sw_kctl)
                return 0;
        hook->codec = codec;
-       hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
        snd_ctl_add_vmaster_hook(hook->sw_kctl, vmaster_hook, hook);
-       if (!expose_enum_ctl)
-               return 0;
-       kctl = snd_ctl_new1(&vmaster_mute_mode, hook);
-       if (!kctl)
-               return -ENOMEM;
-       return snd_hda_ctl_add(codec, 0, kctl);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(snd_hda_add_vmaster_hook);
 
index f5cba7afd1c662e2e5ced46397ef1924f26cb91b..3998e17718057e2db4027d40a218f15a6b251884 100644 (file)
@@ -981,6 +981,8 @@ add_control(struct hda_gen_spec *spec, int type, const char *name,
        knew->index = cidx;
        if (get_amp_nid_(val))
                knew->subdevice = HDA_SUBDEV_AMP_FLAG;
+       if (knew->access == 0)
+               knew->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
        knew->private_value = val;
        return knew;
 }
@@ -3618,8 +3620,11 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
                           amp_val_replace_channels(ctl, chs));
        if (!knew)
                return -ENOMEM;
-       if (is_switch)
+       if (is_switch) {
                knew->put = cap_single_sw_put;
+               if (spec->mic_mute_led)
+                       knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
+       }
        if (!inv_dmic)
                return 0;
 
@@ -3634,8 +3639,11 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
                           amp_val_replace_channels(ctl, 2));
        if (!knew)
                return -ENOMEM;
-       if (is_switch)
+       if (is_switch) {
                knew->put = cap_single_sw_put;
+               if (spec->mic_mute_led)
+                       knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
+       }
        return 0;
 }
 
@@ -3676,6 +3684,8 @@ static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx,
                knew->index = idx;
                knew->private_value = sw_ctl;
                knew->subdevice = HDA_SUBDEV_AMP_FLAG;
+               if (spec->mic_mute_led)
+                       knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
        }
        return 0;
 }
@@ -3917,11 +3927,6 @@ static int create_mute_led_cdev(struct hda_codec *codec,
        return devm_led_classdev_register(&codec->core.dev, cdev);
 }
 
-static void vmaster_update_mute_led(void *private_data, int enabled)
-{
-       ledtrig_audio_set(LED_AUDIO_MUTE, enabled ? LED_OFF : LED_ON);
-}
-
 /**
  * snd_hda_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED
  * @codec: the HDA codec
@@ -3945,134 +3950,11 @@ int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
        if (spec->vmaster_mute.hook)
                codec_err(codec, "vmaster hook already present before cdev!\n");
 
-       spec->vmaster_mute.hook = vmaster_update_mute_led;
-       spec->vmaster_mute_enum = 1;
+       spec->vmaster_mute_led = 1;
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_hda_gen_add_mute_led_cdev);
 
-/*
- * mic mute LED hook helpers
- */
-enum {
-       MICMUTE_LED_ON,
-       MICMUTE_LED_OFF,
-       MICMUTE_LED_FOLLOW_CAPTURE,
-       MICMUTE_LED_FOLLOW_MUTE,
-};
-
-static void call_micmute_led_update(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       unsigned int val;
-
-       switch (spec->micmute_led.led_mode) {
-       case MICMUTE_LED_ON:
-               val = 1;
-               break;
-       case MICMUTE_LED_OFF:
-               val = 0;
-               break;
-       case MICMUTE_LED_FOLLOW_CAPTURE:
-               val = !!spec->micmute_led.capture;
-               break;
-       case MICMUTE_LED_FOLLOW_MUTE:
-       default:
-               val = !spec->micmute_led.capture;
-               break;
-       }
-
-       if (val == spec->micmute_led.led_value)
-               return;
-       spec->micmute_led.led_value = val;
-       ledtrig_audio_set(LED_AUDIO_MICMUTE,
-                         spec->micmute_led.led_value ? LED_ON : LED_OFF);
-}
-
-static void update_micmute_led(struct hda_codec *codec,
-                              struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       unsigned int mask;
-
-       if (spec->micmute_led.old_hook)
-               spec->micmute_led.old_hook(codec, kcontrol, ucontrol);
-
-       if (!ucontrol)
-               return;
-       mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       if (!strcmp("Capture Switch", ucontrol->id.name)) {
-               /* TODO: How do I verify if it's a mono or stereo here? */
-               if (ucontrol->value.integer.value[0] ||
-                   ucontrol->value.integer.value[1])
-                       spec->micmute_led.capture |= mask;
-               else
-                       spec->micmute_led.capture &= ~mask;
-               call_micmute_led_update(codec);
-       }
-}
-
-static int micmute_led_mode_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       static const char * const texts[] = {
-               "On", "Off", "Follow Capture", "Follow Mute",
-       };
-
-       return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
-}
-
-static int micmute_led_mode_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->micmute_led.led_mode;
-       return 0;
-}
-
-static int micmute_led_mode_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       unsigned int mode;
-
-       mode = ucontrol->value.enumerated.item[0];
-       if (mode > MICMUTE_LED_FOLLOW_MUTE)
-               mode = MICMUTE_LED_FOLLOW_MUTE;
-       if (mode == spec->micmute_led.led_mode)
-               return 0;
-       spec->micmute_led.led_mode = mode;
-       call_micmute_led_update(codec);
-       return 1;
-}
-
-static const struct snd_kcontrol_new micmute_led_mode_ctl = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Mic Mute-LED Mode",
-       .info = micmute_led_mode_info,
-       .get = micmute_led_mode_get,
-       .put = micmute_led_mode_put,
-};
-
-/* Set up the capture sync hook for controlling the mic-mute LED */
-static int add_micmute_led_hook(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       spec->micmute_led.led_mode = MICMUTE_LED_FOLLOW_MUTE;
-       spec->micmute_led.capture = 0;
-       spec->micmute_led.led_value = -1;
-       spec->micmute_led.old_hook = spec->cap_sync_hook;
-       spec->cap_sync_hook = update_micmute_led;
-       if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl))
-               return -ENOMEM;
-       return 0;
-}
-
 /**
  * snd_hda_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED
  * @codec: the HDA codec
@@ -4091,6 +3973,7 @@ int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
                                     int (*callback)(struct led_classdev *,
                                                     enum led_brightness))
 {
+       struct hda_gen_spec *spec = codec->spec;
        int err;
 
        if (callback) {
@@ -4101,7 +3984,8 @@ int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
                }
        }
 
-       return add_micmute_led_hook(codec);
+       spec->mic_mute_led = 1;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led_cdev);
 #endif /* CONFIG_SND_HDA_GENERIC_LEDS */
@@ -5060,6 +4944,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
 
        parse_user_hints(codec);
 
+       if (spec->vmaster_mute_led || spec->mic_mute_led)
+               snd_ctl_led_request();
+
        if (spec->mixer_nid && !spec->mixer_merge_nid)
                spec->mixer_merge_nid = spec->mixer_nid;
 
@@ -5291,7 +5178,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
            !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
                err = snd_hda_add_vmaster(codec, "Master Playback Volume",
                                          spec->vmaster_tlv, follower_pfxs,
-                                         "Playback Volume");
+                                         "Playback Volume", 0);
                if (err < 0)
                        return err;
        }
@@ -5299,13 +5186,14 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
            !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
                err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
                                            NULL, follower_pfxs,
-                                           "Playback Switch",
-                                           true, &spec->vmaster_mute.sw_kctl);
+                                           "Playback Switch", true,
+                                           spec->vmaster_mute_led ?
+                                               SNDRV_CTL_ELEM_ACCESS_SPK_LED : 0,
+                                           &spec->vmaster_mute.sw_kctl);
                if (err < 0)
                        return err;
                if (spec->vmaster_mute.hook) {
-                       snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute,
-                                                spec->vmaster_mute_enum);
+                       snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute);
                        snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
                }
        }
index 0886bc81f40be64901b50d6db1a21145891dc810..d4dd1b8a2e7ecb02b7a24eb099f0e7dca02193dd 100644 (file)
@@ -84,15 +84,6 @@ struct badness_table {
 extern const struct badness_table hda_main_out_badness;
 extern const struct badness_table hda_extra_out_badness;
 
-struct hda_micmute_hook {
-       unsigned int led_mode;
-       unsigned int capture;
-       unsigned int led_value;
-       void (*old_hook)(struct hda_codec *codec,
-                        struct snd_kcontrol *kcontrol,
-                        struct snd_ctl_elem_value *ucontrol);
-};
-
 struct hda_gen_spec {
        char stream_name_analog[32];    /* analog PCM stream */
        const struct hda_pcm_stream *stream_analog_playback;
@@ -229,7 +220,8 @@ struct hda_gen_spec {
        unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
        unsigned int own_eapd_ctl:1; /* set EAPD by own function */
        unsigned int keep_eapd_on:1; /* don't turn off EAPD automatically */
-       unsigned int vmaster_mute_enum:1; /* add vmaster mute mode enum */
+       unsigned int vmaster_mute_led:1; /* add SPK-LED flag to vmaster mute switch */
+       unsigned int mic_mute_led:1; /* add MIC-LED flag to capture mute switch */
        unsigned int indep_hp:1; /* independent HP supported */
        unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */
        unsigned int add_stereo_mix_input:2; /* add aamix as a capture src */
@@ -285,9 +277,6 @@ struct hda_gen_spec {
                              struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol);
 
-       /* mic mute LED hook; called via cap_sync_hook */
-       struct hda_micmute_hook micmute_led;
-
        /* PCM hooks */
        void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo,
                                  struct hda_codec *codec,
index 5beb8aa44ecd8ead5cef2b3d85784e42145c25ea..06d4486a496127cb44b08b592d454e60aae37bf5 100644 (file)
@@ -131,21 +131,15 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
 int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
                          unsigned int *tlv, const char * const *followers,
                          const char *suffix, bool init_follower_vol,
-                         struct snd_kcontrol **ctl_ret);
-#define snd_hda_add_vmaster(codec, name, tlv, followers, suffix) \
-       __snd_hda_add_vmaster(codec, name, tlv, followers, suffix, true, NULL)
+                         unsigned int access, struct snd_kcontrol **ctl_ret);
+#define snd_hda_add_vmaster(codec, name, tlv, followers, suffix, access) \
+       __snd_hda_add_vmaster(codec, name, tlv, followers, suffix, true, access, NULL)
 int snd_hda_codec_reset(struct hda_codec *codec);
 void snd_hda_codec_register(struct hda_codec *codec);
 void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec);
 
 #define snd_hda_regmap_sync(codec)     snd_hdac_regmap_sync(&(codec)->core)
 
-enum {
-       HDA_VMUTE_OFF,
-       HDA_VMUTE_ON,
-       HDA_VMUTE_FOLLOW_MASTER,
-};
-
 struct hda_vmaster_mute_hook {
        /* below two fields must be filled by the caller of
         * snd_hda_add_vmaster_hook() beforehand
@@ -153,13 +147,11 @@ struct hda_vmaster_mute_hook {
        struct snd_kcontrol *sw_kctl;
        void (*hook)(void *, int);
        /* below are initialized automatically */
-       unsigned int mute_mode; /* HDA_VMUTE_XXX */
        struct hda_codec *codec;
 };
 
 int snd_hda_add_vmaster_hook(struct hda_codec *codec,
-                            struct hda_vmaster_mute_hook *hook,
-                            bool expose_enum_ctl);
+                            struct hda_vmaster_mute_hook *hook);
 void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook);
 
 /* amp value bits */
index b2b620f6c832094efd4a70bb0dfea6fec21901ed..49b4fdd2feab1a43f33aaf5ea9462e6dc3c61d5d 100644 (file)
@@ -7041,11 +7041,11 @@ static int ca0132_build_controls(struct hda_codec *codec)
                                        spec->tlv);
                snd_hda_add_vmaster(codec, "Master Playback Volume",
                                        spec->tlv, ca0132_alt_follower_pfxs,
-                                       "Playback Volume");
+                                       "Playback Volume", 0);
                err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
                                            NULL, ca0132_alt_follower_pfxs,
                                            "Playback Switch",
-                                           true, &spec->vmaster_mute.sw_kctl);
+                                           true, 0, &spec->vmaster_mute.sw_kctl);
                if (err < 0)
                        return err;
        }
index 316b9b4ccb32d179a00a2c87645d85b231a5ee1d..2c35d2df09d6f4e125cbe8a7915fcdcf30e142b4 100644 (file)
@@ -292,7 +292,7 @@ static void alc_fixup_gpio4(struct hda_codec *codec,
 static void alc_fixup_micmute_led(struct hda_codec *codec,
                                  const struct hda_fixup *fix, int action)
 {
-       if (action == HDA_FIXUP_ACT_PROBE)
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
                snd_hda_gen_add_micmute_led_cdev(codec, NULL);
 }
 
index c662431bf13a51b6514af8c8fe5a141513041c14..3bd592e126a3eaf2f098e99ea791dab71ce0716d 100644 (file)
@@ -4277,6 +4277,9 @@ static int stac_parse_auto_config(struct hda_codec *codec)
 
        spec->gen.automute_hook = stac_update_outputs;
 
+       if (spec->gpio_led)
+               snd_hda_gen_add_mute_led_cdev(codec, stac_vmaster_hook);
+
        err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
        if (err < 0)
                return err;
@@ -4318,9 +4321,6 @@ static int stac_parse_auto_config(struct hda_codec *codec)
        }
 #endif
 
-       if (spec->gpio_led)
-               snd_hda_gen_add_mute_led_cdev(codec, stac_vmaster_hook);
-
        if (spec->aloopback_ctl &&
            snd_hda_get_bool_hint(codec, "loopback") == 1) {
                unsigned int wr_verb =
index 6698ae241efcb9c810d9c0834a32f7830ab7abc3..de4d8deed102e1463f0c4f087591013acc4a59d0 100644 (file)
@@ -18,7 +18,7 @@ static bool is_thinkpad(struct hda_codec *codec)
 static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
                                    const struct hda_fixup *fix, int action)
 {
-       if (action == HDA_FIXUP_ACT_PROBE) {
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
                if (!is_thinkpad(codec))
                        return;
                snd_hda_gen_add_mute_led_cdev(codec, NULL);