Loading sound/pci/hda/patch_realtek.c +86 −15 Original line number Diff line number Diff line Loading @@ -67,6 +67,10 @@ enum { ALC_HEADSET_TYPE_OMTP, }; enum { ALC_KEY_MICMUTE_INDEX, }; struct alc_customize_define { unsigned int sku_cfg; unsigned char port_connectivity; Loading Loading @@ -123,6 +127,7 @@ struct alc_spec { unsigned int pll_coef_idx, pll_coef_bit; unsigned int coef0; struct input_dev *kb_dev; u8 alc_mute_keycode_map[1]; }; /* Loading Loading @@ -3462,12 +3467,43 @@ static void gpio2_mic_hotkey_event(struct hda_codec *codec, /* 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_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 1); input_sync(spec->kb_dev); input_report_key(spec->kb_dev, KEY_MICMUTE, 0); input_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 0); input_sync(spec->kb_dev); } static int alc_register_micmute_input_device(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int i; spec->kb_dev = input_allocate_device(); if (!spec->kb_dev) { codec_err(codec, "Out of memory (input_allocate_device)\n"); return -ENOMEM; } spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX] = KEY_MICMUTE; spec->kb_dev->name = "Microphone Mute Button"; spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY); spec->kb_dev->keycodesize = sizeof(spec->alc_mute_keycode_map[0]); spec->kb_dev->keycodemax = ARRAY_SIZE(spec->alc_mute_keycode_map); spec->kb_dev->keycode = spec->alc_mute_keycode_map; for (i = 0; i < ARRAY_SIZE(spec->alc_mute_keycode_map); i++) set_bit(spec->alc_mute_keycode_map[i], spec->kb_dev->keybit); if (input_register_device(spec->kb_dev)) { codec_err(codec, "input_register_device failed\n"); input_free_device(spec->kb_dev); spec->kb_dev = NULL; return -ENOMEM; } return 0; } static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, const struct hda_fixup *fix, int action) { Loading @@ -3485,20 +3521,8 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, struct alc_spec *spec = codec->spec; if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->kb_dev = input_allocate_device(); if (!spec->kb_dev) { codec_err(codec, "Out of memory (input_allocate_device)\n"); if (alc_register_micmute_input_device(codec) != 0) 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)) { codec_err(codec, "input_register_device failed\n"); 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->core.afg, 0, Loading Loading @@ -3528,6 +3552,47 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, } } static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec, const struct hda_fixup *fix, int action) { /* Line2 = mic mute hotkey GPIO2 = mic mute LED */ static const struct hda_verb gpio_init[] = { { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 }, { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 }, {} }; struct alc_spec *spec = codec->spec; if (action == HDA_FIXUP_ACT_PRE_PROBE) { if (alc_register_micmute_input_device(codec) != 0) return; snd_hda_add_verbs(codec, gpio_init); snd_hda_jack_detect_enable_callback(codec, 0x1b, gpio2_mic_hotkey_event); spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; spec->gpio_led = 0; spec->mute_led_polarity = 0; spec->gpio_mic_led_mask = 0x04; return; } if (!spec->kb_dev) return; switch (action) { case HDA_FIXUP_ACT_PROBE: spec->init_amp = ALC_INIT_DEFAULT; break; case HDA_FIXUP_ACT_FREE: input_unregister_device(spec->kb_dev); spec->kb_dev = NULL; } } static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, const struct hda_fixup *fix, int action) { Loading Loading @@ -4628,6 +4693,7 @@ enum { ALC275_FIXUP_DELL_XPS, ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE, ALC293_FIXUP_LENOVO_SPK_NOISE, ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, }; static const struct hda_fixup alc269_fixups[] = { Loading Loading @@ -5237,6 +5303,10 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_THINKPAD_ACPI }, [ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY] = { .type = HDA_FIXUP_FUNC, .v.func = alc233_fixup_lenovo_line2_mic_hotkey, }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { Loading Loading @@ -5386,6 +5456,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE), SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), Loading Loading
sound/pci/hda/patch_realtek.c +86 −15 Original line number Diff line number Diff line Loading @@ -67,6 +67,10 @@ enum { ALC_HEADSET_TYPE_OMTP, }; enum { ALC_KEY_MICMUTE_INDEX, }; struct alc_customize_define { unsigned int sku_cfg; unsigned char port_connectivity; Loading Loading @@ -123,6 +127,7 @@ struct alc_spec { unsigned int pll_coef_idx, pll_coef_bit; unsigned int coef0; struct input_dev *kb_dev; u8 alc_mute_keycode_map[1]; }; /* Loading Loading @@ -3462,12 +3467,43 @@ static void gpio2_mic_hotkey_event(struct hda_codec *codec, /* 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_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 1); input_sync(spec->kb_dev); input_report_key(spec->kb_dev, KEY_MICMUTE, 0); input_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 0); input_sync(spec->kb_dev); } static int alc_register_micmute_input_device(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int i; spec->kb_dev = input_allocate_device(); if (!spec->kb_dev) { codec_err(codec, "Out of memory (input_allocate_device)\n"); return -ENOMEM; } spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX] = KEY_MICMUTE; spec->kb_dev->name = "Microphone Mute Button"; spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY); spec->kb_dev->keycodesize = sizeof(spec->alc_mute_keycode_map[0]); spec->kb_dev->keycodemax = ARRAY_SIZE(spec->alc_mute_keycode_map); spec->kb_dev->keycode = spec->alc_mute_keycode_map; for (i = 0; i < ARRAY_SIZE(spec->alc_mute_keycode_map); i++) set_bit(spec->alc_mute_keycode_map[i], spec->kb_dev->keybit); if (input_register_device(spec->kb_dev)) { codec_err(codec, "input_register_device failed\n"); input_free_device(spec->kb_dev); spec->kb_dev = NULL; return -ENOMEM; } return 0; } static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, const struct hda_fixup *fix, int action) { Loading @@ -3485,20 +3521,8 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, struct alc_spec *spec = codec->spec; if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->kb_dev = input_allocate_device(); if (!spec->kb_dev) { codec_err(codec, "Out of memory (input_allocate_device)\n"); if (alc_register_micmute_input_device(codec) != 0) 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)) { codec_err(codec, "input_register_device failed\n"); 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->core.afg, 0, Loading Loading @@ -3528,6 +3552,47 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, } } static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec, const struct hda_fixup *fix, int action) { /* Line2 = mic mute hotkey GPIO2 = mic mute LED */ static const struct hda_verb gpio_init[] = { { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 }, { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 }, {} }; struct alc_spec *spec = codec->spec; if (action == HDA_FIXUP_ACT_PRE_PROBE) { if (alc_register_micmute_input_device(codec) != 0) return; snd_hda_add_verbs(codec, gpio_init); snd_hda_jack_detect_enable_callback(codec, 0x1b, gpio2_mic_hotkey_event); spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; spec->gpio_led = 0; spec->mute_led_polarity = 0; spec->gpio_mic_led_mask = 0x04; return; } if (!spec->kb_dev) return; switch (action) { case HDA_FIXUP_ACT_PROBE: spec->init_amp = ALC_INIT_DEFAULT; break; case HDA_FIXUP_ACT_FREE: input_unregister_device(spec->kb_dev); spec->kb_dev = NULL; } } static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, const struct hda_fixup *fix, int action) { Loading Loading @@ -4628,6 +4693,7 @@ enum { ALC275_FIXUP_DELL_XPS, ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE, ALC293_FIXUP_LENOVO_SPK_NOISE, ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, }; static const struct hda_fixup alc269_fixups[] = { Loading Loading @@ -5237,6 +5303,10 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_THINKPAD_ACPI }, [ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY] = { .type = HDA_FIXUP_FUNC, .v.func = alc233_fixup_lenovo_line2_mic_hotkey, }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { Loading Loading @@ -5386,6 +5456,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE), SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), Loading