LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH 3/3] ALSA:hda: add support for Huawei WMI MicMute LED
@ 2018-10-31 15:59 ab24580
  2018-10-31 16:06 ` ayman.bagabas
  0 siblings, 1 reply; 5+ messages in thread
From: ab24580 @ 2018-10-31 15:59 UTC (permalink / raw)
  To: perex, tiwai, Ayman Bagabas, kailang, hui.wang, linux-kernel, alsa-devel
  Cc: Ayman Bagabas

[-- Attachment #1: Type: text/plain, Size: 3 bytes --]




[-- Attachment #2: 0003-ALSA-hda-add-support-for-Huawei-WMI-MicMute-LED.patch --]
[-- Type: text/x-patch, Size: 5684 bytes --]

From e7291d296d748b4bdeb3c906b654bf5838c6f8dd Mon Sep 17 00:00:00 2001
From: Ayman Bagabas <ayman.bagabas@gmail.com>
Date: Wed, 31 Oct 2018 11:51:09 -0400
Subject: [PATCH 3/3] ALSA:hda: add support for Huawei WMI MicMute LED

Some of Huawei laptops come with a LED in the mic mute key. This patch
enables and disable this LED when the internal microphone status is
changed.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 include/linux/huawei_wmi.h        |  7 ++++
 sound/pci/hda/huawei_wmi_helper.c | 66 +++++++++++++++++++++++++++++++
 sound/pci/hda/patch_realtek.c     | 12 ++++++
 3 files changed, 85 insertions(+)
 create mode 100644 include/linux/huawei_wmi.h
 create mode 100644 sound/pci/hda/huawei_wmi_helper.c

diff --git a/include/linux/huawei_wmi.h b/include/linux/huawei_wmi.h
new file mode 100644
index 000000000000..69b656c5029b
--- /dev/null
+++ b/include/linux/huawei_wmi.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __HUAWEI_WMI_H__
+#define __HUAWEI_WMI_H__
+
+int huawei_wmi_micmute_led_set(bool on);
+
+#endif
diff --git a/sound/pci/hda/huawei_wmi_helper.c b/sound/pci/hda/huawei_wmi_helper.c
new file mode 100644
index 000000000000..57256f51fd88
--- /dev/null
+++ b/sound/pci/hda/huawei_wmi_helper.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Helper functions for Huawei WMI Mic Mute LED;
+ * to be included from codec driver
+ */
+
+#if IS_ENABLED(CONFIG_HUAWEI_LAPTOP)
+#include <linux/huawei_wmi.h>
+
+static int (*huawei_wmi_micmute_led_set_func)(bool);
+
+static void update_huawei_wmi_micmute_led(struct hda_codec *codec,
+					  struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	if (!ucontrol || !huawei_wmi_micmute_led_set_func)
+		return;
+	if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) {
+		/* TODO: How do I verify if it's a mono or stereo here? */
+		bool val = ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1];
+		huawei_wmi_micmute_led_set_func(!val);
+	}
+}
+
+static void alc_fixup_huawei_wmi(struct hda_codec *codec,
+				   const struct hda_fixup *fix, int action)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	bool removefunc = false;
+
+	codec_info(codec, "In alc_fixup_huawei_wmi\n");
+
+	if (action == HDA_FIXUP_ACT_PROBE) {
+		if (!huawei_wmi_micmute_led_set_func)
+			huawei_wmi_micmute_led_set_func = symbol_request(huawei_wmi_micmute_led_set);
+		if (!huawei_wmi_micmute_led_set_func) {
+			codec_warn(codec, "Failed to find huawei_wmi symbol huawei_wmi_micmute_led_set\n");
+			return;
+		}
+
+		removefunc = true;
+		if (huawei_wmi_micmute_led_set_func(false) >= 0) {
+			if (spec->num_adc_nids > 1 && !spec->dyn_adc_switch)
+				codec_dbg(codec, "Skipping micmute LED control due to several ADCs");
+			else {
+				spec->cap_sync_hook = update_huawei_wmi_micmute_led;
+				removefunc = false;
+			}
+		}
+		codec_info(codec, "In alc_fixup_huawei_wmi IF\n");
+
+	}
+
+	if (huawei_wmi_micmute_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
+		symbol_put(huawei_wmi_micmute_led_set);
+		huawei_wmi_micmute_led_set_func = NULL;
+	}
+}
+
+#else
+
+static void hda_fixup_huawei_wmi(struct hda_codec *codec,
+				   const struct hda_fixup *fix, int action)
+{
+}
+
+#endif
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4f7a39c7883c..0dab00c0df50 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -5371,6 +5371,9 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
 /* for dell wmi mic mute led */
 #include "dell_wmi_helper.c"
 
+/* for huawei wmi mic mute led */
+#include "huawei_wmi_helper.c"
+
 /* for alc295_fixup_hp_top_speakers */
 #include "hp_x360_helper.c"
 
@@ -5494,6 +5497,7 @@ enum {
 	ALC255_FIXUP_DUMMY_LINEOUT_VERB,
 	ALC255_FIXUP_DELL_HEADSET_MIC,
 	ALC256_FIXUP_HUAWEI_MBXP_PINS,
+	ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED,
 	ALC295_FIXUP_HP_X360,
 	ALC221_FIXUP_HP_HEADSET_MIC,
 };
@@ -6348,6 +6352,10 @@ static const struct hda_fixup alc269_fixups[] = {
 		.chained = true,
 		.chain_id = ALC269_FIXUP_HEADSET_MIC
 	},
+	[ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_huawei_wmi,
+	},
 	[ALC256_FIXUP_HUAWEI_MBXP_PINS] = {
 		.type = HDA_FIXUP_PINS,
 		.v.pins = (const struct hda_pintbl[]) {
@@ -6363,6 +6371,8 @@ static const struct hda_fixup alc269_fixups[] = {
 			{0x21, 0x04211020},
 			{ },
 		},
+		.chained = true,
+		.chain_id = ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED
 	},
 	[ALC295_FIXUP_HP_X360] = {
 		.type = HDA_FIXUP_FUNC,
@@ -6610,6 +6620,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
 	SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MBXP", ALC256_FIXUP_HUAWEI_MBXP_PINS),
+	SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MBXP", ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED),
 	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
 	SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
 	SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
@@ -6775,6 +6786,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
 	{.id = ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, .name = "alc274-dell-aio"},
 	{.id = ALC255_FIXUP_DUMMY_LINEOUT_VERB, .name = "alc255-dummy-lineout"},
 	{.id = ALC255_FIXUP_DELL_HEADSET_MIC, .name = "alc255-dell-headset"},
+	{.id = ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED, .name = "alc256-huawei-micmute"},
 	{.id = ALC295_FIXUP_HP_X360, .name = "alc295-hp-x360"},
 	{}
 };
-- 
2.17.2


[-- Attachment #3: 0002-ALSA-hda-fix-front-speakers-on-Huawei-MBXP.patch --]
[-- Type: text/x-patch, Size: 2210 bytes --]

From d472c06898cf5a2aebf1a6ef7d5095a672e08901 Mon Sep 17 00:00:00 2001
From: Ayman Bagabas <ayman.bagabas@gmail.com>
Date: Wed, 31 Oct 2018 11:34:15 -0400
Subject: [PATCH 2/3] ALSA:hda: fix front speakers on Huawei MBXP.

This patch enables the front speakers on Huawei Matebook X Pro laptops.
These laptops come with Dolby Atmos sound system and these pins
configuration enables the front speakers.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 sound/pci/hda/patch_realtek.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 3ac7ba9b342d..4f7a39c7883c 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -5493,6 +5493,7 @@ enum {
 	ALC298_FIXUP_TPT470_DOCK,
 	ALC255_FIXUP_DUMMY_LINEOUT_VERB,
 	ALC255_FIXUP_DELL_HEADSET_MIC,
+	ALC256_FIXUP_HUAWEI_MBXP_PINS,
 	ALC295_FIXUP_HP_X360,
 	ALC221_FIXUP_HP_HEADSET_MIC,
 };
@@ -6347,6 +6348,22 @@ static const struct hda_fixup alc269_fixups[] = {
 		.chained = true,
 		.chain_id = ALC269_FIXUP_HEADSET_MIC
 	},
+	[ALC256_FIXUP_HUAWEI_MBXP_PINS] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{0x12, 0x90a60130},
+			{0x13, 0x40000000},
+			{0x14, 0x90170110},
+			{0x18, 0x411111f0},
+			{0x19, 0x04a11040},
+			{0x1a, 0x411111f0},
+			{0x1b, 0x90170112},
+			{0x1d, 0x40759a05},
+			{0x1e, 0x411111f0},
+			{0x21, 0x04211020},
+			{ },
+		},
+	},
 	[ALC295_FIXUP_HP_X360] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc295_fixup_hp_top_speakers,
@@ -6592,6 +6609,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+	SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MBXP", ALC256_FIXUP_HUAWEI_MBXP_PINS),
 	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
 	SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
 	SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
-- 
2.17.2


[-- Attachment #4: 0001-x86-add-support-for-Huawei-WMI-hotkeys.patch --]
[-- Type: text/x-patch, Size: 7619 bytes --]

From bc069762e7e86dd3ab39e55d7b145deb85884dec Mon Sep 17 00:00:00 2001
From: Ayman Bagabas <ayman.bagabas@gmail.com>
Date: Wed, 31 Oct 2018 11:24:43 -0400
Subject: [PATCH 1/3] x86: add support for Huawei WMI hotkeys.

This driver adds support for missing hotkeys on some Huawei laptops.
Currently, only Huawei Matebook X Pro is supported. The driver
recognizes the following keys: brightness keys, micmute, wlan, and
Huawei special key. The brightness keys are ignored since they work out
of the box.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 drivers/platform/x86/Kconfig      |  13 ++
 drivers/platform/x86/Makefile     |   1 +
 drivers/platform/x86/huawei_wmi.c | 225 ++++++++++++++++++++++++++++++
 3 files changed, 239 insertions(+)
 create mode 100644 drivers/platform/x86/huawei_wmi.c

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 0c1aa6c314f5..c6813981e45c 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1229,6 +1229,19 @@ config I2C_MULTI_INSTANTIATE
 	  To compile this driver as a module, choose M here: the module
 	  will be called i2c-multi-instantiate.
 
+config HUAWEI_LAPTOP
+	tristate "Huawei WMI hotkeys driver"
+	depends on ACPI
+	depends on ACPI_WMI
+	depends on INPUT
+	select INPUT_SPARSEKMAP
+	help
+	  This driver provides support for Huawei WMI hotkeys.
+	  It enables the missing keys and adds support to micmute
+	  led found on these laptops.q
+	  Supported devices are:
+	  - Matebook X Pro
+
 endif # X86_PLATFORM_DEVICES
 
 config PMC_ATOM
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index e6d1becf81ce..5984354e18ff 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_ACERHDF)		+= acerhdf.o
 obj-$(CONFIG_HP_ACCEL)		+= hp_accel.o
 obj-$(CONFIG_HP_WIRELESS)	+= hp-wireless.o
 obj-$(CONFIG_HP_WMI)		+= hp-wmi.o
+obj-$(CONFIG_HUAWEI_LAPTOP)		+= huawei_wmi.o
 obj-$(CONFIG_AMILO_RFKILL)	+= amilo-rfkill.o
 obj-$(CONFIG_GPD_POCKET_FAN)	+= gpd-pocket-fan.o
 obj-$(CONFIG_TC1100_WMI)	+= tc1100-wmi.o
diff --git a/drivers/platform/x86/huawei_wmi.c b/drivers/platform/x86/huawei_wmi.c
new file mode 100644
index 000000000000..a430ff860929
--- /dev/null
+++ b/drivers/platform/x86/huawei_wmi.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Huawei WMI Hotkeys Driver
+ *
+ *  Copyright (C) 2018		  Ayman Bagabas <ayman.bagabas@gmail.com>
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/acpi.h>
+#include <linux/wmi.h>
+#include <linux/huawei_wmi.h>
+
+MODULE_AUTHOR("Ayman Bagabas <ayman.bagabas@gmail.com>");
+MODULE_DESCRIPTION("Huawei WMI hotkeys");
+MODULE_LICENSE("GPL");
+
+#define DEVICE_NAME "huawei"
+#define MODULE_NAME DEVICE_NAME"_wmi"
+
+/*
+ * Huawei WMI Devices GUIDs
+ */
+#define AMW0_GUID "ABBC0F5B-8EA1-11D1-A000-C90629100000" // \_SB.AMW0
+
+/*
+ * Huawei WMI Events GUIDs
+ */
+#define EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
+
+MODULE_ALIAS("wmi:"AMW0_GUID);
+MODULE_ALIAS("wmi:"EVENT_GUID);
+
+enum {
+	MICMUTE_LED_ON = 0x00010B04,
+	MICMUTE_LED_OFF = 0x00000B04,
+};
+
+static const struct key_entry huawei_wmi_keymap[] __initconst = {
+		{ KE_IGNORE, 0x281, { KEY_BRIGHTNESSDOWN } },
+		{ KE_IGNORE, 0x282, { KEY_BRIGHTNESSUP } },
+		{ KE_IGNORE, 0x283, { KEY_KBDILLUMTOGGLE } },
+		{ KE_KEY,	0x287, { KEY_MICMUTE } },
+		{ KE_KEY,	0x289, { KEY_WLAN } },
+		// Huawei |M| button
+		{ KE_KEY,	0x28a, { KEY_PROG1 } },
+		{ KE_END,	0 }
+};
+
+struct huawei_wmi_device {
+	struct input_dev *inputdev;
+};
+static struct huawei_wmi_device *wmi_device;
+
+int huawei_wmi_micmute_led_set(bool on)
+{
+	u32 args = (on) ? MICMUTE_LED_ON : MICMUTE_LED_OFF;
+	struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
+	acpi_status status;
+
+	status = wmi_evaluate_method(AMW0_GUID, 0, 1, &input, NULL);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(huawei_wmi_micmute_led_set);
+
+static void huawei_wmi_process_key(struct input_dev *input_dev, int code)
+{
+	const struct key_entry *key;
+
+	key = sparse_keymap_entry_from_scancode(input_dev, code);
+
+	if (!key) {
+		pr_info("%s: Unknown key pressed, code: 0x%04x\n",
+					MODULE_NAME, code);
+		return;
+	}
+
+	sparse_keymap_report_entry(input_dev, key, 1, true);
+}
+
+static void huawei_wmi_notify(u32 value, void *context)
+{
+	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *obj;
+	acpi_status status;
+
+	status = wmi_get_event_data(value, &response);
+	if (ACPI_FAILURE(status)) {
+		pr_err("%s: Bad event status 0x%x\n",
+					MODULE_NAME, status);
+		return;
+	}
+
+	obj = (union acpi_object *)response.pointer;
+
+	if (!obj)
+		return;
+
+	if (obj->type == ACPI_TYPE_INTEGER)
+		huawei_wmi_process_key(wmi_device->inputdev,
+							obj->integer.value);
+	else
+		pr_info("%s: Unknown response received %d\n",
+					MODULE_NAME, obj->type);
+
+	kfree(response.pointer);
+}
+
+static int huawei_input_init(void)
+{
+	acpi_status status;
+	int err;
+
+	wmi_device->inputdev = input_allocate_device();
+	if (!wmi_device->inputdev)
+		return -ENOMEM;
+
+	wmi_device->inputdev->name = "Huawei WMI hotkeys";
+	wmi_device->inputdev->phys = "wmi/input0";
+	wmi_device->inputdev->id.bustype = BUS_HOST;
+
+	err = sparse_keymap_setup(wmi_device->inputdev,
+			huawei_wmi_keymap, NULL);
+	if (err)
+		goto err_free_dev;
+
+	status = wmi_install_notify_handler(EVENT_GUID,
+			huawei_wmi_notify,
+			NULL);
+
+	if (ACPI_FAILURE(status)) {
+		err = -EIO;
+		goto err_free_dev;
+	}
+
+	err = input_register_device(wmi_device->inputdev);
+	if (err)
+		goto err_remove_notifier;
+
+	return 0;
+
+
+err_remove_notifier:
+	wmi_remove_notify_handler(EVENT_GUID);
+err_free_dev:
+	input_free_device(wmi_device->inputdev);
+	return err;
+}
+
+static void huawei_input_exit(void)
+{
+	wmi_remove_notify_handler(EVENT_GUID);
+	input_unregister_device(wmi_device->inputdev);
+}
+
+static int __init huawei_wmi_setup(void)
+{
+	int err;
+
+	wmi_device = kmalloc(sizeof(struct huawei_wmi_device), GFP_KERNEL);
+	if (!wmi_device)
+		return -ENOMEM;
+
+	err = huawei_input_init();
+	if (err)
+		goto err_input;
+
+	return 0;
+
+err_input:
+	return err;
+}
+
+static void huawei_wmi_destroy(void)
+{
+	huawei_input_exit();
+	kfree(wmi_device);
+}
+
+static int __init huawei_wmi_init(void)
+{
+	int err;
+
+	if (!wmi_has_guid(EVENT_GUID)) {
+		pr_warn("%s: No known WMI GUID found\n", MODULE_NAME);
+		return -ENODEV;
+	}
+
+	err = huawei_wmi_setup();
+	if (err) {
+		pr_err("%s: Failed to setup device\n", MODULE_NAME);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __exit huawei_wmi_exit(void)
+{
+	huawei_wmi_destroy();
+	pr_debug("%s: Driver unloaded successfully\n", MODULE_NAME);
+}
+
+module_init(huawei_wmi_init);
+module_exit(huawei_wmi_exit);
-- 
2.17.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 3/3] ALSA:hda: add support for Huawei WMI MicMute LED
  2018-10-31 15:59 [PATCH 3/3] ALSA:hda: add support for Huawei WMI MicMute LED ab24580
@ 2018-10-31 16:06 ` ayman.bagabas
  0 siblings, 0 replies; 5+ messages in thread
From: ayman.bagabas @ 2018-10-31 16:06 UTC (permalink / raw)
  To: perex, tiwai, kailang, hui.wang, linux-kernel, alsa-devel; +Cc: Ayman Bagabas

[-- Attachment #1: Type: text/plain, Size: 3 bytes --]




[-- Attachment #2: 0003-ALSA-hda-add-support-for-Huawei-WMI-MicMute-LED.patch --]
[-- Type: text/x-patch, Size: 5684 bytes --]

From e7291d296d748b4bdeb3c906b654bf5838c6f8dd Mon Sep 17 00:00:00 2001
From: Ayman Bagabas <ayman.bagabas@gmail.com>
Date: Wed, 31 Oct 2018 11:51:09 -0400
Subject: [PATCH 3/3] ALSA:hda: add support for Huawei WMI MicMute LED

Some of Huawei laptops come with a LED in the mic mute key. This patch
enables and disable this LED when the internal microphone status is
changed.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 include/linux/huawei_wmi.h        |  7 ++++
 sound/pci/hda/huawei_wmi_helper.c | 66 +++++++++++++++++++++++++++++++
 sound/pci/hda/patch_realtek.c     | 12 ++++++
 3 files changed, 85 insertions(+)
 create mode 100644 include/linux/huawei_wmi.h
 create mode 100644 sound/pci/hda/huawei_wmi_helper.c

diff --git a/include/linux/huawei_wmi.h b/include/linux/huawei_wmi.h
new file mode 100644
index 000000000000..69b656c5029b
--- /dev/null
+++ b/include/linux/huawei_wmi.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __HUAWEI_WMI_H__
+#define __HUAWEI_WMI_H__
+
+int huawei_wmi_micmute_led_set(bool on);
+
+#endif
diff --git a/sound/pci/hda/huawei_wmi_helper.c b/sound/pci/hda/huawei_wmi_helper.c
new file mode 100644
index 000000000000..57256f51fd88
--- /dev/null
+++ b/sound/pci/hda/huawei_wmi_helper.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Helper functions for Huawei WMI Mic Mute LED;
+ * to be included from codec driver
+ */
+
+#if IS_ENABLED(CONFIG_HUAWEI_LAPTOP)
+#include <linux/huawei_wmi.h>
+
+static int (*huawei_wmi_micmute_led_set_func)(bool);
+
+static void update_huawei_wmi_micmute_led(struct hda_codec *codec,
+					  struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	if (!ucontrol || !huawei_wmi_micmute_led_set_func)
+		return;
+	if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) {
+		/* TODO: How do I verify if it's a mono or stereo here? */
+		bool val = ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1];
+		huawei_wmi_micmute_led_set_func(!val);
+	}
+}
+
+static void alc_fixup_huawei_wmi(struct hda_codec *codec,
+				   const struct hda_fixup *fix, int action)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	bool removefunc = false;
+
+	codec_info(codec, "In alc_fixup_huawei_wmi\n");
+
+	if (action == HDA_FIXUP_ACT_PROBE) {
+		if (!huawei_wmi_micmute_led_set_func)
+			huawei_wmi_micmute_led_set_func = symbol_request(huawei_wmi_micmute_led_set);
+		if (!huawei_wmi_micmute_led_set_func) {
+			codec_warn(codec, "Failed to find huawei_wmi symbol huawei_wmi_micmute_led_set\n");
+			return;
+		}
+
+		removefunc = true;
+		if (huawei_wmi_micmute_led_set_func(false) >= 0) {
+			if (spec->num_adc_nids > 1 && !spec->dyn_adc_switch)
+				codec_dbg(codec, "Skipping micmute LED control due to several ADCs");
+			else {
+				spec->cap_sync_hook = update_huawei_wmi_micmute_led;
+				removefunc = false;
+			}
+		}
+		codec_info(codec, "In alc_fixup_huawei_wmi IF\n");
+
+	}
+
+	if (huawei_wmi_micmute_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
+		symbol_put(huawei_wmi_micmute_led_set);
+		huawei_wmi_micmute_led_set_func = NULL;
+	}
+}
+
+#else
+
+static void hda_fixup_huawei_wmi(struct hda_codec *codec,
+				   const struct hda_fixup *fix, int action)
+{
+}
+
+#endif
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4f7a39c7883c..0dab00c0df50 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -5371,6 +5371,9 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
 /* for dell wmi mic mute led */
 #include "dell_wmi_helper.c"
 
+/* for huawei wmi mic mute led */
+#include "huawei_wmi_helper.c"
+
 /* for alc295_fixup_hp_top_speakers */
 #include "hp_x360_helper.c"
 
@@ -5494,6 +5497,7 @@ enum {
 	ALC255_FIXUP_DUMMY_LINEOUT_VERB,
 	ALC255_FIXUP_DELL_HEADSET_MIC,
 	ALC256_FIXUP_HUAWEI_MBXP_PINS,
+	ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED,
 	ALC295_FIXUP_HP_X360,
 	ALC221_FIXUP_HP_HEADSET_MIC,
 };
@@ -6348,6 +6352,10 @@ static const struct hda_fixup alc269_fixups[] = {
 		.chained = true,
 		.chain_id = ALC269_FIXUP_HEADSET_MIC
 	},
+	[ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_huawei_wmi,
+	},
 	[ALC256_FIXUP_HUAWEI_MBXP_PINS] = {
 		.type = HDA_FIXUP_PINS,
 		.v.pins = (const struct hda_pintbl[]) {
@@ -6363,6 +6371,8 @@ static const struct hda_fixup alc269_fixups[] = {
 			{0x21, 0x04211020},
 			{ },
 		},
+		.chained = true,
+		.chain_id = ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED
 	},
 	[ALC295_FIXUP_HP_X360] = {
 		.type = HDA_FIXUP_FUNC,
@@ -6610,6 +6620,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
 	SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MBXP", ALC256_FIXUP_HUAWEI_MBXP_PINS),
+	SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MBXP", ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED),
 	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
 	SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
 	SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
@@ -6775,6 +6786,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
 	{.id = ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, .name = "alc274-dell-aio"},
 	{.id = ALC255_FIXUP_DUMMY_LINEOUT_VERB, .name = "alc255-dummy-lineout"},
 	{.id = ALC255_FIXUP_DELL_HEADSET_MIC, .name = "alc255-dell-headset"},
+	{.id = ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED, .name = "alc256-huawei-micmute"},
 	{.id = ALC295_FIXUP_HP_X360, .name = "alc295-hp-x360"},
 	{}
 };
-- 
2.17.2


[-- Attachment #3: 0002-ALSA-hda-fix-front-speakers-on-Huawei-MBXP.patch --]
[-- Type: text/x-patch, Size: 2210 bytes --]

From d472c06898cf5a2aebf1a6ef7d5095a672e08901 Mon Sep 17 00:00:00 2001
From: Ayman Bagabas <ayman.bagabas@gmail.com>
Date: Wed, 31 Oct 2018 11:34:15 -0400
Subject: [PATCH 2/3] ALSA:hda: fix front speakers on Huawei MBXP.

This patch enables the front speakers on Huawei Matebook X Pro laptops.
These laptops come with Dolby Atmos sound system and these pins
configuration enables the front speakers.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 sound/pci/hda/patch_realtek.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 3ac7ba9b342d..4f7a39c7883c 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -5493,6 +5493,7 @@ enum {
 	ALC298_FIXUP_TPT470_DOCK,
 	ALC255_FIXUP_DUMMY_LINEOUT_VERB,
 	ALC255_FIXUP_DELL_HEADSET_MIC,
+	ALC256_FIXUP_HUAWEI_MBXP_PINS,
 	ALC295_FIXUP_HP_X360,
 	ALC221_FIXUP_HP_HEADSET_MIC,
 };
@@ -6347,6 +6348,22 @@ static const struct hda_fixup alc269_fixups[] = {
 		.chained = true,
 		.chain_id = ALC269_FIXUP_HEADSET_MIC
 	},
+	[ALC256_FIXUP_HUAWEI_MBXP_PINS] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{0x12, 0x90a60130},
+			{0x13, 0x40000000},
+			{0x14, 0x90170110},
+			{0x18, 0x411111f0},
+			{0x19, 0x04a11040},
+			{0x1a, 0x411111f0},
+			{0x1b, 0x90170112},
+			{0x1d, 0x40759a05},
+			{0x1e, 0x411111f0},
+			{0x21, 0x04211020},
+			{ },
+		},
+	},
 	[ALC295_FIXUP_HP_X360] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc295_fixup_hp_top_speakers,
@@ -6592,6 +6609,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+	SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MBXP", ALC256_FIXUP_HUAWEI_MBXP_PINS),
 	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
 	SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
 	SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
-- 
2.17.2


[-- Attachment #4: 0001-x86-add-support-for-Huawei-WMI-hotkeys.patch --]
[-- Type: text/x-patch, Size: 7619 bytes --]

From bc069762e7e86dd3ab39e55d7b145deb85884dec Mon Sep 17 00:00:00 2001
From: Ayman Bagabas <ayman.bagabas@gmail.com>
Date: Wed, 31 Oct 2018 11:24:43 -0400
Subject: [PATCH 1/3] x86: add support for Huawei WMI hotkeys.

This driver adds support for missing hotkeys on some Huawei laptops.
Currently, only Huawei Matebook X Pro is supported. The driver
recognizes the following keys: brightness keys, micmute, wlan, and
Huawei special key. The brightness keys are ignored since they work out
of the box.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 drivers/platform/x86/Kconfig      |  13 ++
 drivers/platform/x86/Makefile     |   1 +
 drivers/platform/x86/huawei_wmi.c | 225 ++++++++++++++++++++++++++++++
 3 files changed, 239 insertions(+)
 create mode 100644 drivers/platform/x86/huawei_wmi.c

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 0c1aa6c314f5..c6813981e45c 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1229,6 +1229,19 @@ config I2C_MULTI_INSTANTIATE
 	  To compile this driver as a module, choose M here: the module
 	  will be called i2c-multi-instantiate.
 
+config HUAWEI_LAPTOP
+	tristate "Huawei WMI hotkeys driver"
+	depends on ACPI
+	depends on ACPI_WMI
+	depends on INPUT
+	select INPUT_SPARSEKMAP
+	help
+	  This driver provides support for Huawei WMI hotkeys.
+	  It enables the missing keys and adds support to micmute
+	  led found on these laptops.q
+	  Supported devices are:
+	  - Matebook X Pro
+
 endif # X86_PLATFORM_DEVICES
 
 config PMC_ATOM
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index e6d1becf81ce..5984354e18ff 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_ACERHDF)		+= acerhdf.o
 obj-$(CONFIG_HP_ACCEL)		+= hp_accel.o
 obj-$(CONFIG_HP_WIRELESS)	+= hp-wireless.o
 obj-$(CONFIG_HP_WMI)		+= hp-wmi.o
+obj-$(CONFIG_HUAWEI_LAPTOP)		+= huawei_wmi.o
 obj-$(CONFIG_AMILO_RFKILL)	+= amilo-rfkill.o
 obj-$(CONFIG_GPD_POCKET_FAN)	+= gpd-pocket-fan.o
 obj-$(CONFIG_TC1100_WMI)	+= tc1100-wmi.o
diff --git a/drivers/platform/x86/huawei_wmi.c b/drivers/platform/x86/huawei_wmi.c
new file mode 100644
index 000000000000..a430ff860929
--- /dev/null
+++ b/drivers/platform/x86/huawei_wmi.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Huawei WMI Hotkeys Driver
+ *
+ *  Copyright (C) 2018		  Ayman Bagabas <ayman.bagabas@gmail.com>
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/acpi.h>
+#include <linux/wmi.h>
+#include <linux/huawei_wmi.h>
+
+MODULE_AUTHOR("Ayman Bagabas <ayman.bagabas@gmail.com>");
+MODULE_DESCRIPTION("Huawei WMI hotkeys");
+MODULE_LICENSE("GPL");
+
+#define DEVICE_NAME "huawei"
+#define MODULE_NAME DEVICE_NAME"_wmi"
+
+/*
+ * Huawei WMI Devices GUIDs
+ */
+#define AMW0_GUID "ABBC0F5B-8EA1-11D1-A000-C90629100000" // \_SB.AMW0
+
+/*
+ * Huawei WMI Events GUIDs
+ */
+#define EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
+
+MODULE_ALIAS("wmi:"AMW0_GUID);
+MODULE_ALIAS("wmi:"EVENT_GUID);
+
+enum {
+	MICMUTE_LED_ON = 0x00010B04,
+	MICMUTE_LED_OFF = 0x00000B04,
+};
+
+static const struct key_entry huawei_wmi_keymap[] __initconst = {
+		{ KE_IGNORE, 0x281, { KEY_BRIGHTNESSDOWN } },
+		{ KE_IGNORE, 0x282, { KEY_BRIGHTNESSUP } },
+		{ KE_IGNORE, 0x283, { KEY_KBDILLUMTOGGLE } },
+		{ KE_KEY,	0x287, { KEY_MICMUTE } },
+		{ KE_KEY,	0x289, { KEY_WLAN } },
+		// Huawei |M| button
+		{ KE_KEY,	0x28a, { KEY_PROG1 } },
+		{ KE_END,	0 }
+};
+
+struct huawei_wmi_device {
+	struct input_dev *inputdev;
+};
+static struct huawei_wmi_device *wmi_device;
+
+int huawei_wmi_micmute_led_set(bool on)
+{
+	u32 args = (on) ? MICMUTE_LED_ON : MICMUTE_LED_OFF;
+	struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
+	acpi_status status;
+
+	status = wmi_evaluate_method(AMW0_GUID, 0, 1, &input, NULL);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(huawei_wmi_micmute_led_set);
+
+static void huawei_wmi_process_key(struct input_dev *input_dev, int code)
+{
+	const struct key_entry *key;
+
+	key = sparse_keymap_entry_from_scancode(input_dev, code);
+
+	if (!key) {
+		pr_info("%s: Unknown key pressed, code: 0x%04x\n",
+					MODULE_NAME, code);
+		return;
+	}
+
+	sparse_keymap_report_entry(input_dev, key, 1, true);
+}
+
+static void huawei_wmi_notify(u32 value, void *context)
+{
+	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *obj;
+	acpi_status status;
+
+	status = wmi_get_event_data(value, &response);
+	if (ACPI_FAILURE(status)) {
+		pr_err("%s: Bad event status 0x%x\n",
+					MODULE_NAME, status);
+		return;
+	}
+
+	obj = (union acpi_object *)response.pointer;
+
+	if (!obj)
+		return;
+
+	if (obj->type == ACPI_TYPE_INTEGER)
+		huawei_wmi_process_key(wmi_device->inputdev,
+							obj->integer.value);
+	else
+		pr_info("%s: Unknown response received %d\n",
+					MODULE_NAME, obj->type);
+
+	kfree(response.pointer);
+}
+
+static int huawei_input_init(void)
+{
+	acpi_status status;
+	int err;
+
+	wmi_device->inputdev = input_allocate_device();
+	if (!wmi_device->inputdev)
+		return -ENOMEM;
+
+	wmi_device->inputdev->name = "Huawei WMI hotkeys";
+	wmi_device->inputdev->phys = "wmi/input0";
+	wmi_device->inputdev->id.bustype = BUS_HOST;
+
+	err = sparse_keymap_setup(wmi_device->inputdev,
+			huawei_wmi_keymap, NULL);
+	if (err)
+		goto err_free_dev;
+
+	status = wmi_install_notify_handler(EVENT_GUID,
+			huawei_wmi_notify,
+			NULL);
+
+	if (ACPI_FAILURE(status)) {
+		err = -EIO;
+		goto err_free_dev;
+	}
+
+	err = input_register_device(wmi_device->inputdev);
+	if (err)
+		goto err_remove_notifier;
+
+	return 0;
+
+
+err_remove_notifier:
+	wmi_remove_notify_handler(EVENT_GUID);
+err_free_dev:
+	input_free_device(wmi_device->inputdev);
+	return err;
+}
+
+static void huawei_input_exit(void)
+{
+	wmi_remove_notify_handler(EVENT_GUID);
+	input_unregister_device(wmi_device->inputdev);
+}
+
+static int __init huawei_wmi_setup(void)
+{
+	int err;
+
+	wmi_device = kmalloc(sizeof(struct huawei_wmi_device), GFP_KERNEL);
+	if (!wmi_device)
+		return -ENOMEM;
+
+	err = huawei_input_init();
+	if (err)
+		goto err_input;
+
+	return 0;
+
+err_input:
+	return err;
+}
+
+static void huawei_wmi_destroy(void)
+{
+	huawei_input_exit();
+	kfree(wmi_device);
+}
+
+static int __init huawei_wmi_init(void)
+{
+	int err;
+
+	if (!wmi_has_guid(EVENT_GUID)) {
+		pr_warn("%s: No known WMI GUID found\n", MODULE_NAME);
+		return -ENODEV;
+	}
+
+	err = huawei_wmi_setup();
+	if (err) {
+		pr_err("%s: Failed to setup device\n", MODULE_NAME);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __exit huawei_wmi_exit(void)
+{
+	huawei_wmi_destroy();
+	pr_debug("%s: Driver unloaded successfully\n", MODULE_NAME);
+}
+
+module_init(huawei_wmi_init);
+module_exit(huawei_wmi_exit);
-- 
2.17.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 3/3] ALSA:hda: add support for Huawei WMI MicMute LED
  2018-11-01  7:37 ` Takashi Iwai
@ 2018-11-01  7:39   ` Takashi Iwai
  0 siblings, 0 replies; 5+ messages in thread
From: Takashi Iwai @ 2018-11-01  7:39 UTC (permalink / raw)
  To: Ayman Bagabas
  Cc: alsa-devel, Hui Wang, Jaroslav Kysela, Kailang Yang, linux-kernel

On Thu, 01 Nov 2018 08:37:47 +0100,
Takashi Iwai wrote:
> 
> At the next submission, could you give a proper cover letter (PATCH
> 0/3) and submit together with other patches?  git-format-patch will
> give you a nice template with --cover-letter option.

... and don't forget to put "v2" prefix, so that reviewers can
identify the latest version they're reading.


Takashi

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 3/3] ALSA:hda: add support for Huawei WMI MicMute LED
  2018-10-31 19:20 Ayman Bagabas
@ 2018-11-01  7:37 ` Takashi Iwai
  2018-11-01  7:39   ` Takashi Iwai
  0 siblings, 1 reply; 5+ messages in thread
From: Takashi Iwai @ 2018-11-01  7:37 UTC (permalink / raw)
  To: Ayman Bagabas
  Cc: alsa-devel, Hui Wang, Jaroslav Kysela, Kailang Yang, linux-kernel

On Wed, 31 Oct 2018 20:20:38 +0100,
Ayman Bagabas wrote:
> 
> Some of Huawei laptops come with a LED in the mic mute key. This patch
> enables and disable this LED when the internal microphone status is
> changed.
> 
> Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
> ---
>  include/linux/huawei_wmi.h        |  7 ++++
>  sound/pci/hda/huawei_wmi_helper.c | 66 +++++++++++++++++++++++++++++++
>  sound/pci/hda/patch_realtek.c     | 12 ++++++
>  3 files changed, 85 insertions(+)
>  create mode 100644 include/linux/huawei_wmi.h
>  create mode 100644 sound/pci/hda/huawei_wmi_helper.c
> 
> diff --git a/include/linux/huawei_wmi.h b/include/linux/huawei_wmi.h
> new file mode 100644
> index 000000000000..69b656c5029b
> --- /dev/null
> +++ b/include/linux/huawei_wmi.h
> @@ -0,0 +1,7 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __HUAWEI_WMI_H__
> +#define __HUAWEI_WMI_H__
> +
> +int huawei_wmi_micmute_led_set(bool on);
> +
> +#endif
> diff --git a/sound/pci/hda/huawei_wmi_helper.c b/sound/pci/hda/huawei_wmi_helper.c
> new file mode 100644
> index 000000000000..57256f51fd88
> --- /dev/null
> +++ b/sound/pci/hda/huawei_wmi_helper.c
> @@ -0,0 +1,66 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Helper functions for Huawei WMI Mic Mute LED;
> + * to be included from codec driver
> + */
> +
> +#if IS_ENABLED(CONFIG_HUAWEI_LAPTOP)
> +#include <linux/huawei_wmi.h>
> +
> +static int (*huawei_wmi_micmute_led_set_func)(bool);
> +
> +static void update_huawei_wmi_micmute_led(struct hda_codec *codec,
> +					  struct snd_kcontrol *kcontrol,
> +					  struct snd_ctl_elem_value *ucontrol)
> +{
> +	if (!ucontrol || !huawei_wmi_micmute_led_set_func)
> +		return;
> +	if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) {
> +		/* TODO: How do I verify if it's a mono or stereo here? */
> +		bool val = ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1];
> +		huawei_wmi_micmute_led_set_func(!val);
> +	}
> +}
> +
> +static void alc_fixup_huawei_wmi(struct hda_codec *codec,
> +				   const struct hda_fixup *fix, int action)
> +{
> +	struct hda_gen_spec *spec = codec->spec;
> +	bool removefunc = false;
> +
> +	codec_info(codec, "In alc_fixup_huawei_wmi\n");
> +
> +	if (action == HDA_FIXUP_ACT_PROBE) {
> +		if (!huawei_wmi_micmute_led_set_func)
> +			huawei_wmi_micmute_led_set_func = symbol_request(huawei_wmi_micmute_led_set);
> +		if (!huawei_wmi_micmute_led_set_func) {
> +			codec_warn(codec, "Failed to find huawei_wmi symbol huawei_wmi_micmute_led_set\n");
> +			return;
> +		}
> +
> +		removefunc = true;
> +		if (huawei_wmi_micmute_led_set_func(false) >= 0) {
> +			if (spec->num_adc_nids > 1 && !spec->dyn_adc_switch)
> +				codec_dbg(codec, "Skipping micmute LED control due to several ADCs");
> +			else {
> +				spec->cap_sync_hook = update_huawei_wmi_micmute_led;
> +				removefunc = false;
> +			}
> +		}
> +		codec_info(codec, "In alc_fixup_huawei_wmi IF\n");
> +
> +	}
> +
> +	if (huawei_wmi_micmute_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
> +		symbol_put(huawei_wmi_micmute_led_set);
> +		huawei_wmi_micmute_led_set_func = NULL;
> +	}
> +}

There is a new snd_hda_gen_add_micmute_led() helper.  Please use it
instead.


> @@ -6610,6 +6620,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
>  	SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
>  	SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
>  	SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MBXP", ALC256_FIXUP_HUAWEI_MBXP_PINS),
> +	SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MBXP", ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED),

You must not have two entries with the very same ID.
And this implies that you didn't test the latest patches.  In the
quirk list, only the first matching is applied, so this WMI hook won't
be executed at all.

Anyways: the submission is confusing at this time since you posted in
may times by some reason, once mixed up all, once incomplete patchset,
etc.

At the next submission, could you give a proper cover letter (PATCH
0/3) and submit together with other patches?  git-format-patch will
give you a nice template with --cover-letter option.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 3/3] ALSA:hda: add support for Huawei WMI MicMute LED
@ 2018-10-31 19:20 Ayman Bagabas
  2018-11-01  7:37 ` Takashi Iwai
  0 siblings, 1 reply; 5+ messages in thread
From: Ayman Bagabas @ 2018-10-31 19:20 UTC (permalink / raw)
  To: Jaroslav Kysela, Takashi Iwai, Ayman Bagabas, Kailang Yang,
	Hui Wang, linux-kernel, alsa-devel

Some of Huawei laptops come with a LED in the mic mute key. This patch
enables and disable this LED when the internal microphone status is
changed.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 include/linux/huawei_wmi.h        |  7 ++++
 sound/pci/hda/huawei_wmi_helper.c | 66 +++++++++++++++++++++++++++++++
 sound/pci/hda/patch_realtek.c     | 12 ++++++
 3 files changed, 85 insertions(+)
 create mode 100644 include/linux/huawei_wmi.h
 create mode 100644 sound/pci/hda/huawei_wmi_helper.c

diff --git a/include/linux/huawei_wmi.h b/include/linux/huawei_wmi.h
new file mode 100644
index 000000000000..69b656c5029b
--- /dev/null
+++ b/include/linux/huawei_wmi.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __HUAWEI_WMI_H__
+#define __HUAWEI_WMI_H__
+
+int huawei_wmi_micmute_led_set(bool on);
+
+#endif
diff --git a/sound/pci/hda/huawei_wmi_helper.c b/sound/pci/hda/huawei_wmi_helper.c
new file mode 100644
index 000000000000..57256f51fd88
--- /dev/null
+++ b/sound/pci/hda/huawei_wmi_helper.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Helper functions for Huawei WMI Mic Mute LED;
+ * to be included from codec driver
+ */
+
+#if IS_ENABLED(CONFIG_HUAWEI_LAPTOP)
+#include <linux/huawei_wmi.h>
+
+static int (*huawei_wmi_micmute_led_set_func)(bool);
+
+static void update_huawei_wmi_micmute_led(struct hda_codec *codec,
+					  struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	if (!ucontrol || !huawei_wmi_micmute_led_set_func)
+		return;
+	if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) {
+		/* TODO: How do I verify if it's a mono or stereo here? */
+		bool val = ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1];
+		huawei_wmi_micmute_led_set_func(!val);
+	}
+}
+
+static void alc_fixup_huawei_wmi(struct hda_codec *codec,
+				   const struct hda_fixup *fix, int action)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	bool removefunc = false;
+
+	codec_info(codec, "In alc_fixup_huawei_wmi\n");
+
+	if (action == HDA_FIXUP_ACT_PROBE) {
+		if (!huawei_wmi_micmute_led_set_func)
+			huawei_wmi_micmute_led_set_func = symbol_request(huawei_wmi_micmute_led_set);
+		if (!huawei_wmi_micmute_led_set_func) {
+			codec_warn(codec, "Failed to find huawei_wmi symbol huawei_wmi_micmute_led_set\n");
+			return;
+		}
+
+		removefunc = true;
+		if (huawei_wmi_micmute_led_set_func(false) >= 0) {
+			if (spec->num_adc_nids > 1 && !spec->dyn_adc_switch)
+				codec_dbg(codec, "Skipping micmute LED control due to several ADCs");
+			else {
+				spec->cap_sync_hook = update_huawei_wmi_micmute_led;
+				removefunc = false;
+			}
+		}
+		codec_info(codec, "In alc_fixup_huawei_wmi IF\n");
+
+	}
+
+	if (huawei_wmi_micmute_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
+		symbol_put(huawei_wmi_micmute_led_set);
+		huawei_wmi_micmute_led_set_func = NULL;
+	}
+}
+
+#else
+
+static void hda_fixup_huawei_wmi(struct hda_codec *codec,
+				   const struct hda_fixup *fix, int action)
+{
+}
+
+#endif
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4f7a39c7883c..0dab00c0df50 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -5371,6 +5371,9 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
 /* for dell wmi mic mute led */
 #include "dell_wmi_helper.c"
 
+/* for huawei wmi mic mute led */
+#include "huawei_wmi_helper.c"
+
 /* for alc295_fixup_hp_top_speakers */
 #include "hp_x360_helper.c"
 
@@ -5494,6 +5497,7 @@ enum {
 	ALC255_FIXUP_DUMMY_LINEOUT_VERB,
 	ALC255_FIXUP_DELL_HEADSET_MIC,
 	ALC256_FIXUP_HUAWEI_MBXP_PINS,
+	ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED,
 	ALC295_FIXUP_HP_X360,
 	ALC221_FIXUP_HP_HEADSET_MIC,
 };
@@ -6348,6 +6352,10 @@ static const struct hda_fixup alc269_fixups[] = {
 		.chained = true,
 		.chain_id = ALC269_FIXUP_HEADSET_MIC
 	},
+	[ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_huawei_wmi,
+	},
 	[ALC256_FIXUP_HUAWEI_MBXP_PINS] = {
 		.type = HDA_FIXUP_PINS,
 		.v.pins = (const struct hda_pintbl[]) {
@@ -6363,6 +6371,8 @@ static const struct hda_fixup alc269_fixups[] = {
 			{0x21, 0x04211020},
 			{ },
 		},
+		.chained = true,
+		.chain_id = ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED
 	},
 	[ALC295_FIXUP_HP_X360] = {
 		.type = HDA_FIXUP_FUNC,
@@ -6610,6 +6620,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
 	SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MBXP", ALC256_FIXUP_HUAWEI_MBXP_PINS),
+	SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MBXP", ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED),
 	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
 	SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
 	SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
@@ -6775,6 +6786,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
 	{.id = ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, .name = "alc274-dell-aio"},
 	{.id = ALC255_FIXUP_DUMMY_LINEOUT_VERB, .name = "alc255-dummy-lineout"},
 	{.id = ALC255_FIXUP_DELL_HEADSET_MIC, .name = "alc255-dell-headset"},
+	{.id = ALC256_FIXUP_HUAWEI_WMI_MICMUTE_LED, .name = "alc256-huawei-micmute"},
 	{.id = ALC295_FIXUP_HP_X360, .name = "alc295-hp-x360"},
 	{}
 };
-- 
2.17.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2018-11-01  7:39 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-31 15:59 [PATCH 3/3] ALSA:hda: add support for Huawei WMI MicMute LED ab24580
2018-10-31 16:06 ` ayman.bagabas
2018-10-31 19:20 Ayman Bagabas
2018-11-01  7:37 ` Takashi Iwai
2018-11-01  7:39   ` Takashi Iwai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).