Comment 2 for bug 1408295

Revision history for this message
Takashi Iwai (tiwai) wrote : Re: [PATCH] ALSA: hda - Enable mic mute hotkey and LEDs for an HP machine

At Wed, 7 Jan 2015 13:30:14 +0100,
David Henningsson wrote:
>
> On this machine, the mic mute hotkey is connected to GPIO2. We therefore
> create an extra input device for this key.
>
> Also enable LEDs connected to GPIO3 and GPIO4.
>
> (Note: if this patch is backported to older kernels, where KEY_MIC_MUTE is
> not available, change the KEY_MIC_MUTE to KEY_F20, which was previously used
> for mic mute keys.)
>
> BugLink: https://bugs.launchpad.net/bugs/1408295
> Tested-by: Keng-Yu Lin <email address hidden>
> Signed-off-by: David Henningsson <email address hidden>
> ---
> sound/pci/hda/patch_realtek.c | 86 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 86 insertions(+)
>
> diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
> index 65f1f4e..3338c75 100644
> --- a/sound/pci/hda/patch_realtek.c
> +++ b/sound/pci/hda/patch_realtek.c
> @@ -29,6 +29,7 @@
> #include <linux/pci.h>
> #include <linux/dmi.h>
> #include <linux/module.h>
> +#include <linux/input.h>
> #include <sound/core.h>
> #include <sound/jack.h>
> #include "hda_codec.h"
> @@ -120,6 +121,8 @@ struct alc_spec {
> hda_nid_t pll_nid;
> unsigned int pll_coef_idx, pll_coef_bit;
> unsigned int coef0;
> +
> + struct input_dev *kb_dev;
> };
>
> /*
> @@ -3472,6 +3475,83 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
> }
> }
>
> +static void gpio2_mic_hotkey_event(struct hda_codec *codec,
> + struct hda_jack_callback *event)
> +{
> + struct alc_spec *spec = codec->spec;
> +
> + /* GPIO2 just toggles on a keypress/keyrelease cycle. Therefore
> + send both key on and key off event for every interrupt. */
> + input_report_key(spec->kb_dev, KEY_MICMUTE, 1);
> + input_sync(spec->kb_dev);
> + input_report_key(spec->kb_dev, KEY_MICMUTE, 0);
> + input_sync(spec->kb_dev);

Does the build pass without CONFIG_INPUT?

> +}
> +
> +static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
> + const struct hda_fixup *fix, int action)
> +{
> + /* GPIO1 = set according to SKU external amp
> + GPIO2 = mic mute hotkey
> + GPIO3 = mute LED
> + GPIO4 = mic mute LED */
> + static const struct hda_verb gpio_init[] = {
> + { 0x01, AC_VERB_SET_GPIO_MASK, 0x1e },
> + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x1a },
> + { 0x01, AC_VERB_SET_GPIO_DATA, 0x02 },
> + {}
> + };
> +
> + struct alc_spec *spec = codec->spec;
> +
> + if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +
> + spec->kb_dev = input_allocate_device();
> + if (!spec->kb_dev) {
> + snd_printk("Out of memory (input_allocate_device)\n");

Better to use dev_err() (or codec_err()) macro.

> + return;
> + }
> + spec->kb_dev->name = "Microphone Mute Button";
> + spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY);
> + spec->kb_dev->keybit[BIT_WORD(KEY_MICMUTE)] = BIT_MASK(KEY_MICMUTE);
> + if (input_register_device(spec->kb_dev)) {
> + snd_printk("input_register_device failed\n");

Ditto.

> + input_free_device(spec->kb_dev);
> + spec->kb_dev = NULL;
> + return;
> + }
> +
> + snd_hda_add_verbs(codec, gpio_init);
> + snd_hda_codec_write_cache(codec, codec->afg, 0,
> + AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04);
> + snd_hda_jack_detect_enable_callback(codec, codec->afg,
> + gpio2_mic_hotkey_event);
> +
> + spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
> + spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
> + spec->gpio_led = 0;
> + spec->mute_led_polarity = 0;
> + spec->gpio_mute_led_mask = 0x08;
> + spec->gpio_mic_led_mask = 0x10;
> + return;
> + }
> +
> + if (!spec->kb_dev)
> + return;
> +
> + switch (action) {
> + case HDA_FIXUP_ACT_PROBE:
> + spec->init_amp = ALC_INIT_DEFAULT;
> + break;
> + case HDA_FIXUP_ACT_INIT:
> + gpio2_mic_hotkey_event(codec, NULL);

Do you need to generate a key event at each init?

Takashi