All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alex Hung <alex.hung@canonical.com>
To: alex.hung@canonical.com, dvhart@infradead.org,
	platform-driver-x86@vger.kernel.org
Subject: [PATCH][V2] intel-hid: support 5 array button
Date: Thu, 26 Jan 2017 15:33:01 +0800	[thread overview]
Message-ID: <1485415981-20487-1-git-send-email-alex.hung@canonical.com> (raw)

New firmwares include a feature called 5 button array that supports
super key, volume up/down, rotation lock and power button. Especially,
support for this feature is required to fix power button on some recent
systems.

This patch was tested on a Dell Latitude 7280.

Signed-off-by: Alex Hung <alex.hung@canonical.com>
---
 drivers/platform/x86/intel-hid.c | 107 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 102 insertions(+), 5 deletions(-)

diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c
index cb3ab2b..6e796a5 100644
--- a/drivers/platform/x86/intel-hid.c
+++ b/drivers/platform/x86/intel-hid.c
@@ -1,5 +1,5 @@
 /*
- *  Intel HID event driver for Windows 8
+ *  Intel HID event & 5 button array driver
  *
  *  Copyright (C) 2015 Alex Hung <alex.hung@canonical.com>
  *  Copyright (C) 2015 Andrew Lutomirski <luto@kernel.org>
@@ -57,8 +57,24 @@ static const struct key_entry intel_hid_keymap[] = {
 	{ KE_END },
 };
 
+/* 5 button array notification value. */
+static const struct key_entry intel_array_keymap[] = {
+	{ KE_KEY,    0xC2, { KEY_LEFTMETA} },                /* Press */
+	{ KE_IGNORE, 0xC3, { KEY_LEFTMETA} },                /* Release */
+	{ KE_KEY,    0xC4, { KEY_VOLUMEUP} },                /* Press */
+	{ KE_IGNORE, 0xC5, { KEY_VOLUMEUP} },                /* Release */
+	{ KE_KEY,    0xC6, { KEY_VOLUMEDOWN} },              /* Press */
+	{ KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN} },	             /* Release */
+	{ KE_SW,     0xC8, { .sw = {SW_ROTATE_LOCK, 1} } },   /* Press */
+	{ KE_SW,     0xC9, { .sw = {SW_ROTATE_LOCK, 0} } },   /* Release */
+	{ KE_KEY,    0xCE, { KEY_POWER} },                   /* Press */
+	{ KE_IGNORE, 0xCF, { KEY_POWER} },                   /* Release */
+	{ KE_END },
+};
+
 struct intel_hid_priv {
 	struct input_dev *input_dev;
+	struct input_dev *array;
 };
 
 static int intel_hid_set_enable(struct device *device, int enable)
@@ -78,15 +94,43 @@ static int intel_hid_set_enable(struct device *device, int enable)
 	return 0;
 }
 
+static void intel_button_array_enable(struct device *device, int enable)
+{
+	struct intel_hid_priv *priv = dev_get_drvdata(device);
+	acpi_handle handle = ACPI_HANDLE(device);
+	unsigned long long button_cap;
+	acpi_status status;
+
+	if (!priv->array)
+		return;
+
+	/* Query supported platform features */
+	status = acpi_evaluate_integer(handle, "BTNC", NULL, &button_cap);
+	if (ACPI_FAILURE(status)) {
+		dev_warn(device, "failed to get button capability\n");
+		return;
+	}
+
+	/* Enable|disable features - power button is always enabled */
+	status = acpi_execute_simple_method(handle, "BTNE",
+					    enable ? button_cap : 1);
+	if (ACPI_FAILURE(status))
+		dev_warn(device, "failed to set button capability\n");
+}
+
 static int intel_hid_pl_suspend_handler(struct device *device)
 {
 	intel_hid_set_enable(device, 0);
+	intel_button_array_enable(device, 0);
+
 	return 0;
 }
 
 static int intel_hid_pl_resume_handler(struct device *device)
 {
 	intel_hid_set_enable(device, 1);
+	intel_button_array_enable(device, 1);
+
 	return 0;
 }
 
@@ -126,11 +170,43 @@ static int intel_hid_input_setup(struct platform_device *device)
 	return ret;
 }
 
+static int intel_button_array_input_setup(struct platform_device *device)
+{
+	struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
+	int ret;
+
+	/* Setup input device for 5 button array */
+	priv->array = input_allocate_device();
+	if (!priv->array)
+		return -ENOMEM;
+
+	ret = sparse_keymap_setup(priv->array, intel_array_keymap, NULL);
+	if (ret)
+		goto err_free_array_device;
+
+	priv->array->dev.parent = &device->dev;
+	priv->array->name = "Intel HID 5 button array";
+	priv->array->id.bustype = BUS_HOST;
+
+	ret = input_register_device(priv->array);
+	if (ret)
+		goto err_free_array_device;
+
+	return 0;
+
+err_free_array_device:
+	input_free_device(priv->array);
+	return ret;
+}
+
 static void intel_hid_input_destroy(struct platform_device *device)
 {
 	struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
 
 	input_unregister_device(priv->input_dev);
+
+	if (priv->array)
+		input_unregister_device(priv->array);
 }
 
 static void notify_handler(acpi_handle handle, u32 event, void *context)
@@ -140,10 +216,11 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
 	unsigned long long ev_index;
 	acpi_status status;
 
-	/* The platform spec only defines one event code: 0xC0. */
+	/* 0xC0 is for HID events, other values are for 5 button array */
 	if (event != 0xc0) {
-		dev_warn(&device->dev, "received unknown event (0x%x)\n",
-			 event);
+		if (!priv->array ||
+		    !sparse_keymap_report_event(priv->array, event, 1, true))
+			dev_info(&device->dev, "unknown event 0x%x\n", event);
 		return;
 	}
 
@@ -161,8 +238,8 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
 static int intel_hid_probe(struct platform_device *device)
 {
 	acpi_handle handle = ACPI_HANDLE(&device->dev);
+	unsigned long long event_cap, mode;
 	struct intel_hid_priv *priv;
-	unsigned long long mode;
 	acpi_status status;
 	int err;
 
@@ -193,6 +270,15 @@ static int intel_hid_probe(struct platform_device *device)
 		return err;
 	}
 
+	/* Setup 5 button array */
+	status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap);
+	if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) {
+		dev_info(&device->dev, "platform supports 5 button array\n");
+		err = intel_button_array_input_setup(device);
+		if (err)
+			pr_err("Failed to setup Intel 5 button array hotkeys\n");
+	}
+
 	status = acpi_install_notify_handler(handle,
 					     ACPI_DEVICE_NOTIFY,
 					     notify_handler,
@@ -206,6 +292,16 @@ static int intel_hid_probe(struct platform_device *device)
 	if (err)
 		goto err_remove_notify;
 
+	if (priv->array) {
+		intel_button_array_enable(&device->dev, 1);
+
+		/* Call button load method to enable HID power button */
+		status = acpi_evaluate_object(handle, "BTNL", NULL, NULL);
+		if (ACPI_FAILURE(status))
+			dev_warn(&device->dev,
+				 "failed to enable HID power button\n");
+	}
+
 	return 0;
 
 err_remove_notify:
@@ -224,6 +320,7 @@ static int intel_hid_remove(struct platform_device *device)
 	acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
 	intel_hid_input_destroy(device);
 	intel_hid_set_enable(&device->dev, 0);
+	intel_button_array_enable(&device->dev, 0);
 
 	/*
 	 * Even if we failed to shut off the event stream, we can still
-- 
2.7.4

             reply	other threads:[~2017-01-26  7:33 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-26  7:33 Alex Hung [this message]
2017-01-27 14:16 ` [PATCH][V2] intel-hid: support 5 array button Michał Kępień
2017-02-04  1:14 ` Darren Hart
2017-02-04  1:26   ` Darren Hart
2017-02-04 16:06     ` Pali Rohár
2017-02-08  7:21       ` Michał Kępień
2017-02-08  8:17         ` Pali Rohár
2017-02-08  9:05           ` Alex Hung
2017-02-08  9:07             ` Pali Rohár
2017-02-04 14:58   ` Andy Shevchenko
2017-02-09  2:22     ` Darren Hart
2017-02-09  3:09       ` Alex Hung
2017-02-09 19:56         ` Andy Shevchenko
2017-02-17  2:43           ` Darren Hart
2017-02-08  8:54   ` Alex Hung
2017-02-13 11:43     ` Michał Kępień
2017-02-13 23:23       ` Andy Shevchenko
2017-02-14  0:06         ` Alex Hung

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1485415981-20487-1-git-send-email-alex.hung@canonical.com \
    --to=alex.hung@canonical.com \
    --cc=dvhart@infradead.org \
    --cc=platform-driver-x86@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.