All of lore.kernel.org
 help / color / mirror / Atom feed
From: Elia Devito <eliadevito@gmail.com>
To: unlisted-recipients:; (no To-header on input)
Cc: mario.limonciello@dell.com, Elia Devito <eliadevito@gmail.com>,
	Alex Hung <alex.hung@canonical.com>,
	Hans de Goede <hdegoede@redhat.com>,
	Mark Gross <mgross@linux.intel.com>,
	platform-driver-x86@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH 1/3] intel-hid: add support for SW_TABLET_MODE
Date: Tue,  1 Dec 2020 20:55:05 +0100	[thread overview]
Message-ID: <20201201195504.22296-1-eliadevito@gmail.com> (raw)

Add support for SW_TABLET_MODE for convertibles notebook.

Exactly as intel-vbtn driver, the event code 0xcc is emitted by
convertibles when entering tablet mode and 0xcd when return to
laptop mode.

Signed-off-by: Elia Devito <eliadevito@gmail.com>
---
more info: https://bugzilla.kernel.org/show_bug.cgi?id=207433
 
 drivers/platform/x86/intel-hid.c | 84 ++++++++++++++++++++++++++++++--
 1 file changed, 80 insertions(+), 4 deletions(-)

diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c
index 86261970bd8f..5093c57102cf 100644
--- a/drivers/platform/x86/intel-hid.c
+++ b/drivers/platform/x86/intel-hid.c
@@ -15,6 +15,9 @@
 #include <linux/platform_device.h>
 #include <linux/suspend.h>
 
+/* When NOT in tablet mode, VGBS returns with the flag 0x40 */
+#define TABLET_MODE_FLAG 0x40
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alex Hung");
 
@@ -61,7 +64,11 @@ static const struct key_entry intel_array_keymap[] = {
 	{ KE_IGNORE, 0xC9, { KEY_ROTATE_LOCK_TOGGLE } },      /* Release */
 	{ KE_KEY,    0xCE, { KEY_POWER } },                   /* Press */
 	{ KE_IGNORE, 0xCF, { KEY_POWER } },                   /* Release */
-	{ KE_END },
+};
+
+static const struct key_entry intel_array_switches[] = {
+	{ KE_SW, 0xCC, { .sw = { SW_TABLET_MODE, 1 } } },  /* Tablet */
+	{ KE_SW, 0xCD, { .sw = { SW_TABLET_MODE, 0 } } },  /* Laptop */
 };
 
 static const struct dmi_system_id button_array_table[] = {
@@ -89,9 +96,23 @@ static const struct dmi_system_id button_array_table[] = {
 	{ }
 };
 
+static const struct dmi_system_id button_array_switches_table[] = {
+	{
+		.matches = {
+			DMI_EXACT_MATCH(DMI_CHASSIS_TYPE, "31" /* Convertible */),
+		},
+	},
+	{ }
+};
+
+#define KEYMAP_LEN \
+	(ARRAY_SIZE(intel_array_keymap) + ARRAY_SIZE(intel_array_switches) + 1)
+
 struct intel_hid_priv {
+	struct key_entry keymap[KEYMAP_LEN];
 	struct input_dev *input_dev;
 	struct input_dev *array;
+	bool has_switches;
 	bool wakeup_mode;
 };
 
@@ -327,23 +348,54 @@ static int intel_hid_input_setup(struct platform_device *device)
 	return input_register_device(priv->input_dev);
 }
 
+static void detect_tablet_mode(struct platform_device *device)
+{
+	struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
+	acpi_handle handle = ACPI_HANDLE(&device->dev);
+	unsigned long long vgbs;
+	int m;
+
+	if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_VGBS_FN, &vgbs))
+		return;
+
+	m = !(vgbs & TABLET_MODE_FLAG);
+	input_report_switch(priv->array, SW_TABLET_MODE, m);
+}
+
 static int intel_button_array_input_setup(struct platform_device *device)
 {
 	struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
-	int ret;
+	int ret, keymap_len = 0;
 
 	/* Setup input device for 5 button array */
 	priv->array = devm_input_allocate_device(&device->dev);
 	if (!priv->array)
 		return -ENOMEM;
 
-	ret = sparse_keymap_setup(priv->array, intel_array_keymap, NULL);
+	memcpy(&priv->keymap[keymap_len], intel_array_keymap,
+		       ARRAY_SIZE(intel_array_keymap) *
+		       sizeof(struct key_entry));
+	keymap_len += ARRAY_SIZE(intel_array_keymap);
+
+	if (priv->has_switches) {
+		memcpy(&priv->keymap[keymap_len], intel_array_switches,
+		       ARRAY_SIZE(intel_array_switches) *
+		       sizeof(struct key_entry));
+		keymap_len += ARRAY_SIZE(intel_array_switches);
+	}
+
+	priv->keymap[keymap_len].type = KE_END;
+
+	ret = sparse_keymap_setup(priv->array, priv->keymap, NULL);
 	if (ret)
 		return ret;
 
 	priv->array->name = "Intel HID 5 button array";
 	priv->array->id.bustype = BUS_HOST;
 
+	if (priv->has_switches)
+		detect_tablet_mode(device);
+
 	return input_register_device(priv->array);
 }
 
@@ -352,7 +404,10 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
 	struct platform_device *device = context;
 	struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
 	unsigned long long ev_index;
+	unsigned int val = !(event & 1); /* Even=press, Odd=release */
+	const struct key_entry *ke;
 
+	dev_info(&device->dev, "event 0x%x\n", event);
 	if (priv->wakeup_mode) {
 		/*
 		 * Needed for wakeup from suspend-to-idle to work on some
@@ -367,13 +422,19 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
 		if (event == 0xc0 || !priv->array)
 			return;
 
-		if (!sparse_keymap_entry_from_scancode(priv->array, event)) {
+		ke = sparse_keymap_entry_from_scancode(priv->array, event);
+		if (!ke) {
 			dev_info(&device->dev, "unknown event 0x%x\n", event);
 			return;
 		}
 
 wakeup:
 		pm_wakeup_hard_event(&device->dev);
+
+		/* report the new switch position to the input subsystem. */
+		if (ke && ke->type == KE_SW)
+			sparse_keymap_report_event(priv->array, event, val, 0);
+
 		return;
 	}
 
@@ -441,6 +502,20 @@ static bool button_array_present(struct platform_device *device)
 	return false;
 }
 
+static bool intel_button_array_has_switches(struct platform_device *device)
+{
+	acpi_handle handle = ACPI_HANDLE(&device->dev);
+	unsigned long long vgbs;
+
+	if (!dmi_check_system(button_array_switches_table))
+		return false;
+
+	if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_VGBS_FN, &vgbs))
+		return false;
+
+	return true;
+}
+
 static int intel_hid_probe(struct platform_device *device)
 {
 	acpi_handle handle = ACPI_HANDLE(&device->dev);
@@ -479,6 +554,7 @@ static int intel_hid_probe(struct platform_device *device)
 
 	/* Setup 5 button array */
 	if (button_array_present(device)) {
+		priv->has_switches = intel_button_array_has_switches(device);
 		dev_info(&device->dev, "platform supports 5 button array\n");
 		err = intel_button_array_input_setup(device);
 		if (err)
-- 
2.28.0


             reply	other threads:[~2020-12-01 19:57 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-01 19:55 Elia Devito [this message]
2020-12-01 21:23 ` [PATCH 1/3] intel-hid: add support for SW_TABLET_MODE Hans de Goede
2020-12-03 21:20   ` [PATCH v2 1/2] " Elia Devito
2020-12-04 16:01     ` [PATCH v3 " Elia Devito
2020-12-07 16:49       ` Hans de Goede
2020-12-04 16:02     ` [PATCH v3 2/2] intel-hid: add alternative method to enable switches Elia Devito
2020-12-03 21:21   ` [PATCH v2 " Elia Devito
2020-12-03 23:45     ` Barnabás Pőcze
2020-12-03 23:52       ` Barnabás Pőcze
2020-12-04 15:22       ` Elia Devito

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=20201201195504.22296-1-eliadevito@gmail.com \
    --to=eliadevito@gmail.com \
    --cc=alex.hung@canonical.com \
    --cc=hdegoede@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mario.limonciello@dell.com \
    --cc=mgross@linux.intel.com \
    --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.