X86 platform drivers
 help / color / mirror / Atom feed
* [PATCH] Add IdeaPad WMI Fn Keys driver
@ 2022-09-11 16:04 Philipp Jungkamp
  2022-09-11 16:18 ` Hans de Goede
  0 siblings, 1 reply; 19+ messages in thread
From: Philipp Jungkamp @ 2022-09-11 16:04 UTC (permalink / raw)
  To: Hans de Goede, Mark Gross; +Cc: platform-driver-x86, Philipp Jungkamp

Create an input device for WMI events corresponding to some special
keys on the 'Lenovo Yoga' line.

This include the 3 keys to the right on the 'Lenovo Yoga9 14IAP7' and
additionally the 'Lenovo Support' and 'Lenovo Favorites' (star with 'S'
inside) in the fn key row as well as the event emitted on 'Fn+R' which
toggles between 60Hz and 90Hz display refresh rate on windows.

Signed-off-by: Philipp Jungkamp <p.jungkamp@gmx.net>
---
I found this patch by poking in the DSDT. I have not submitted any
notable patches yet and hope you can help me improve in case I make
unfortunate choices during submission.

Thank you for your time!
Philipp Jungkamp

 drivers/platform/x86/Kconfig       |  13 +++
 drivers/platform/x86/Makefile      |   1 +
 drivers/platform/x86/ideapad-wmi.c | 153 +++++++++++++++++++++++++++++
 3 files changed, 167 insertions(+)
 create mode 100644 drivers/platform/x86/ideapad-wmi.c

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index f2f98e942cf2..e7c5148e5cb4 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -140,6 +140,19 @@ config YOGABOOK_WMI
 	  To compile this driver as a module, choose M here: the module will
 	  be called lenovo-yogabook-wmi.

+config IDEAPAD_WMI
+	tristate "Lenovo IdeaPad WMI Fn Keys"
+	depends on ACPI_WMI
+	depends on INPUT
+	select INPUT_SPARSEKMAP
+	help
+	  Say Y here if you want to receive key presses from some lenovo
+	  specific keys. (Star Key, Support Key, Virtual Background,
+	  Dark Mode Toggle, ...)
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called ideapad-wmi.
+
 config ACERHDF
 	tristate "Acer Aspire One temperature and fan driver"
 	depends on ACPI && THERMAL
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 5a428caa654a..d8bec884d6bc 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_PEAQ_WMI)			+= peaq-wmi.o
 obj-$(CONFIG_XIAOMI_WMI)		+= xiaomi-wmi.o
 obj-$(CONFIG_GIGABYTE_WMI)		+= gigabyte-wmi.o
 obj-$(CONFIG_YOGABOOK_WMI)		+= lenovo-yogabook-wmi.o
+obj-$(CONFIG_IDEAPAD_WMI)		+= ideapad-wmi.o

 # Acer
 obj-$(CONFIG_ACERHDF)		+= acerhdf.o
diff --git a/drivers/platform/x86/ideapad-wmi.c b/drivers/platform/x86/ideapad-wmi.c
new file mode 100644
index 000000000000..38f7b3d0c171
--- /dev/null
+++ b/drivers/platform/x86/ideapad-wmi.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ideapad-wmi.c - Ideapad WMI fn keys driver
+ *
+ * Copyright (C) 2022 Philipp Jungkamp <p.jungkamp@gmx.net>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/acpi.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/wmi.h>
+
+#define IDEAPAD_FN_KEY_EVENT_GUID	"8FC0DE0C-B4E4-43FD-B0F3-8871711C1294"
+
+struct ideapad_wmi_private {
+	struct wmi_device *wmi_device;
+	struct input_dev *input_dev;
+};
+
+static const struct key_entry ideapad_wmi_fn_key_keymap[] = {
+	/* FnLock (handled by the firmware) */
+	{ KE_IGNORE,	0x02 },
+	/* Customizable Lenovo Hotkey ("star" with 'S' inside) */
+	{ KE_KEY,	0x01, { KEY_FAVORITES } },
+	/* Dark mode toggle */
+	{ KE_KEY,	0x13, { KEY_PROG1 } },
+	/* Sound profile switch */
+	{ KE_KEY,	0x12, { KEY_PROG2 } },
+	/* Lenovo Virtual Background application */
+	{ KE_KEY,	0x28, { KEY_PROG3 } },
+	/* Lenovo Support */
+	{ KE_KEY,	0x27, { KEY_HELP } },
+	/* Refresh Rate Toggle */
+	{ KE_KEY,	0x0a, { KEY_DISPLAYTOGGLE } },
+	{ KE_END },
+};
+
+static int ideapad_wmi_input_init(struct ideapad_wmi_private *priv)
+{
+	struct input_dev *input_dev;
+	int err;
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		return -ENOMEM;
+	}
+
+	input_dev->name = "Ideapad WMI Fn Keys";
+	input_dev->phys = IDEAPAD_FN_KEY_EVENT_GUID "/input0";
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->dev.parent = &priv->wmi_device->dev;
+
+	err = sparse_keymap_setup(input_dev, ideapad_wmi_fn_key_keymap, NULL);
+	if (err) {
+		dev_err(&priv->wmi_device->dev,
+			"Could not set up input device keymap: %d\n", err);
+		goto err_free_dev;
+	}
+
+	err = input_register_device(input_dev);
+	if (err) {
+		dev_err(&priv->wmi_device->dev,
+			"Could not register input device: %d\n", err);
+		goto err_free_dev;
+	}
+
+	priv->input_dev = input_dev;
+	return 0;
+
+err_free_dev:
+	input_free_device(input_dev);
+	return err;
+}
+
+static void ideapad_wmi_input_exit(struct ideapad_wmi_private *priv)
+{
+	input_unregister_device(priv->input_dev);
+	priv->input_dev = NULL;
+}
+
+static void ideapad_wmi_input_report(struct ideapad_wmi_private *priv,
+				     unsigned int scancode)
+{
+	sparse_keymap_report_event(priv->input_dev, scancode, 1, true);
+}
+
+static int ideapad_wmi_probe(struct wmi_device *wdev, const void *ctx)
+{
+	struct ideapad_wmi_private *priv;
+	int err;
+
+	priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dev_set_drvdata(&wdev->dev, priv);
+
+	priv->wmi_device = wdev;
+
+	err = ideapad_wmi_input_init(priv);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static void ideapad_wmi_remove(struct wmi_device *wdev)
+{
+	struct ideapad_wmi_private *priv = dev_get_drvdata(&wdev->dev);
+
+	ideapad_wmi_input_exit(priv);
+}
+
+static void ideapad_wmi_notify(struct wmi_device *wdev, union acpi_object *data)
+{
+	struct ideapad_wmi_private *priv = dev_get_drvdata(&wdev->dev);
+
+	if(data->type != ACPI_TYPE_INTEGER) {
+		dev_warn(&priv->wmi_device->dev,
+			"WMI event data is not an integer\n");
+		return;
+	}
+
+	ideapad_wmi_input_report(priv, data->integer.value);
+}
+
+static const struct wmi_device_id ideapad_wmi_id_table[] = {
+	{	/* Special Keys on the Yoga 9 14IAP7 */
+		.guid_string = IDEAPAD_FN_KEY_EVENT_GUID
+	},
+	{ }
+};
+
+static struct wmi_driver ideapad_wmi_driver = {
+	.driver = {
+		.name = "ideapad-wmi",
+	},
+	.id_table = ideapad_wmi_id_table,
+	.probe = ideapad_wmi_probe,
+	.remove = ideapad_wmi_remove,
+	.notify = ideapad_wmi_notify,
+};
+
+module_wmi_driver(ideapad_wmi_driver);
+
+MODULE_DEVICE_TABLE(wmi, ideapad_wmi_id_table);
+MODULE_AUTHOR("Philipp Jungkamp <p.jungkamp@gmx.net>");
+MODULE_DESCRIPTION("Ideapad WMI fn keys driver");
+MODULE_LICENSE("GPL");
--
2.37.3


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

end of thread, other threads:[~2022-11-16 14:44 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-09-11 16:04 [PATCH] Add IdeaPad WMI Fn Keys driver Philipp Jungkamp
2022-09-11 16:18 ` Hans de Goede
2022-09-19  7:54   ` Hans de Goede
2022-11-10 20:02     ` Philipp Jungkamp
2022-11-10 21:02       ` Hans de Goede
2022-11-13 12:12         ` [PATCH v2 1/2] platform/x86: wmi: Disambiguate WMI event data on some ACPI tables Philipp Jungkamp
2022-11-13 12:12           ` [PATCH v2 2/2] platform/x86: ideapad-laptop: support for more special keys in WMI Philipp Jungkamp
2022-11-13 20:30           ` [PATCH v2 1/2] platform/x86: wmi: Disambiguate WMI event data on some ACPI tables Armin Wolf
2022-11-13 21:42             ` Philipp Jungkamp
2022-11-13 23:02               ` Armin Wolf
2022-11-14 14:41                 ` [PATCH v3] platform/x86: ideapad-laptop: support for more special keys in WMI Philipp Jungkamp
2022-11-14 16:15                   ` Hans de Goede
2022-11-14 16:41                   ` Hans de Goede
2022-11-15  0:09                     ` [PATCH v4] " Philipp Jungkamp
2022-11-15 21:19                       ` Hans de Goede
2022-11-16 11:06                         ` [PATCH v5] " Philipp Jungkamp
2022-11-16 14:43                           ` Hans de Goede
2022-11-15  2:27                     ` [PATCH v3] " Armin Wolf
2022-11-15 11:19                       ` Hans de Goede

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox