[PATCH v2] platform/x86: thinkpad_acpi: Handle keyboard cover attach/detach events

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



ThinkPad X1 Tablets emit HKEY 0x4012 and 0x4013 events when a keyboard
cover is attached/detached or folded to the back of the device. They are
used to switch from normal to tablet mode in userspace; e.g., to offer
touch keyboard choices when focus goes to a text box and no keyboard is
attached, or to enable autorotation of the display according to the
built-in orientation sensor.

This patch handles the two events by issuing corresponding
SW_TABLET_MODE notifications to the ACPI userspace.

Tested as working on a ThinkPad X1 Tablet Gen 2, 20JCS00C00, and as
non-interfering with a ThinkPad X1 Carbon 7th, 20QESABM02 (normal
clamshell, so it does not have a keyboard cover).

Signed-off-by: Alexander Kobel <a-kobel@xxxxxxxxxx>
---
 drivers/platform/x86/thinkpad_acpi.c | 91 +++++++++++++++++++++++++++-
 1 file changed, 90 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index c404706379d9..8c1ff555f10b 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -174,6 +174,11 @@ enum tpacpi_hkey_event_t {
 						     or port replicator */
 	TP_HKEY_EV_HOTPLUG_UNDOCK	= 0x4011, /* undocked from hotplug
 						     dock or port replicator */
+	/* Thinkpad X1 Tablet series (and probably other GTOP type 4) emit 0x4012 and 0x4013
+	 * when keyboard cover is attached, detached or folded onto the back
+	 */
+	TP_HKEY_EV_KBD_COVER_ATTACH	= 0x4012, /* keyboard cover attached */
+	TP_HKEY_EV_KBD_COVER_DETACH	= 0x4013, /* keyboard cover detached or folded back */
 
 	/* User-interface events */
 	TP_HKEY_EV_LID_CLOSE		= 0x5001, /* laptop lid closed */
@@ -308,6 +313,8 @@ static struct {
 		TP_HOTKEY_TABLET_NONE = 0,
 		TP_HOTKEY_TABLET_USES_MHKG,
 		TP_HOTKEY_TABLET_USES_GMMS,
+		TP_HOTKEY_TABLET_USES_GTOP_ANY_TYPE,
+		TP_HOTKEY_TABLET_USES_GTOP_X1_TABLET_TYPE,
 	} hotkey_tablet;
 	u32 kbdlight:1;
 	u32 light:1;
@@ -2166,11 +2173,32 @@ static int hotkey_gmms_get_tablet_mode(int s, int *has_tablet_mode)
 	return !!(mode & TP_ACPI_MULTI_MODE_TABLET_LIKE);
 }
 
+static int hotkey_gtop_any_type_get_tablet_mode(int s)
+{
+	return !(s & 0x1);
+}
+
+static int hotkey_gtop_x1_tablet_type_get_tablet_mode(int s)
+{
+	return (!(s & 0x1) /* keyboard NOT attached */
+		|| ((s >> 16) & 0x1) /* or folded onto the back */);
+}
+
 static int hotkey_get_tablet_mode(int *status)
 {
 	int s;
 
 	switch (tp_features.hotkey_tablet) {
+	case TP_HOTKEY_TABLET_USES_GTOP_ANY_TYPE:
+		if (!acpi_evalf(hkey_handle, &s, "GTOP", "dd", 0x0200))
+			return -EIO;
+		*status = hotkey_gtop_any_type_get_tablet_mode(s);
+		break;
+	case TP_HOTKEY_TABLET_USES_GTOP_X1_TABLET_TYPE:
+		if (!acpi_evalf(hkey_handle, &s, "GTOP", "dd", 0x0200))
+			return -EIO;
+		*status = hotkey_gtop_x1_tablet_type_get_tablet_mode(s);
+		break;
 	case TP_HOTKEY_TABLET_USES_MHKG:
 		if (!acpi_evalf(hkey_handle, &s, "MHKG", "d"))
 			return -EIO;
@@ -3213,7 +3241,62 @@ static int hotkey_init_tablet_mode(void)
 	int in_tablet_mode = 0, res;
 	char *type = NULL;
 
-	if (acpi_evalf(hkey_handle, &res, "GMMS", "qdd", 0)) {
+	if (acpi_evalf(hkey_handle, &res, "GTOP", "qdd", 0x0000)
+	    && res >= 0x0103
+	    && acpi_evalf(hkey_handle, &res, "GTOP", "qdd", 0x0100)) {
+		/*
+		 * GTOP ("Get Tablet OPtion") state ASL method definition:
+		 * - Input: 0x0000: Query version
+		 *   Output: 0x0103 (version 1.03)
+		 * - Input: 0x0100: Query interface type
+		 *   Output: DWORD But 31-0 Interface type
+		 *     0: Reserved
+		 *     1: Any type
+		 *     2: ThinkPad Helix series
+		 *     3: ThinkPad 10 series
+		 *     4: ThinkPad X1 Tablet series
+		 * - Input: 0x0200: Get attach option
+		 *   Output: Option attach state
+		 *     (0: detached, 1: attached)
+		 *     version >= 1.03 and interface type 1:
+		 *       Bit 0: Any option attach state
+		 *       Bit 31-1: Reserved(0)
+		 *     version >= 1.03 and interface type 4:
+		 *       Bit 0: Thin-KBD attach state
+		 *       Bit 1: Pro-Cartridge attach state
+		 *       Bit 3-2: Pico-Cartridge attach state
+		 *         00: detached
+		 *         01: attached
+		 *         10: attached with battery error
+		 *         11: Reserved
+		 *       Bit 4: 3D Cartridge attach state
+		 *       Bit 5: Reserve 1 attach state
+		 *       Bit 6: Reserve 2 attach state
+		 *       Bit 15-7: Reserved(0)
+		 *       Bit 16: Folio keyboard location
+		 *         (valid if folio attached)
+		 *         0: keyboard is NOT folded onto the back
+		 *         1: keyboard is folded onto the back of the system
+		 *       Bit 31-17: Reserved(0)
+		 */
+		switch (res) {
+		case 1:
+			tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_GTOP_ANY_TYPE;
+			if (acpi_evalf(hkey_handle, &res, "GTOP", "qdd", 0x200))
+				in_tablet_mode = hotkey_gtop_any_type_get_tablet_mode(res);
+			type = "GTOP";
+			break;
+		case 4:
+			tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_GTOP_X1_TABLET_TYPE;
+			if (acpi_evalf(hkey_handle, &res, "GTOP", "qdd", 0x200))
+				in_tablet_mode = hotkey_gtop_x1_tablet_type_get_tablet_mode(res);
+			type = "GTOP";
+			break;
+		default:
+			pr_err("unsupported GTOP type, please report this to %s\n", TPACPI_MAIL);
+			break;
+		}
+	} else if (acpi_evalf(hkey_handle, &res, "GMMS", "qdd", 0)) {
 		int has_tablet_mode;
 
 		in_tablet_mode = hotkey_gmms_get_tablet_mode(res,
@@ -3989,6 +4072,12 @@ static bool hotkey_notify_dockevent(const u32 hkey,
 	case TP_HKEY_EV_HOTPLUG_UNDOCK: /* undocked from port replicator */
 		pr_info("undocked from hotplug port replicator\n");
 		return true;
+	case TP_HKEY_EV_KBD_COVER_ATTACH:
+	case TP_HKEY_EV_KBD_COVER_DETACH:
+		tpacpi_input_send_tabletsw();
+		hotkey_tablet_mode_notify_change();
+		*send_acpi_ev = false;
+		return true;
 
 	default:
 		return false;
-- 
2.30.1


Attachment: smime.p7s
Description: S/MIME Cryptographic Signature


[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux