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 | 100 ++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index c404706379d9..c3e805f478a3 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -145,6 +145,45 @@ enum { TP_ACPI_WGSV_STATE_UWBPWR = 0x0020, /* UWB radio enabled */ }; +/* ThinkPad GTOP ("Get Tablet OPtion") methods */ +enum { + TP_GTOP_CMD_QUERY_VERSION = 0x0000, + TP_GTOP_CMD_QUERY_INTERFACE_TYPE = 0x0100, + TP_GTOP_CMD_GET_ATTACH_OPTION = 0x2000, +}; + +#define TP_GTOP_MINIMUM_VERSION 0x0103 + +enum { + TP_GTOP_INTERFACE_TYPE_RESERVED = 0, + TP_GTOP_INTERFACE_TYPE_ANY_TYPE = 1, + TP_GTOP_INTERFACE_TYPE_TP_HELIX = 2, + TP_GTOP_INTERFACE_TYPE_TP10 = 3, + TP_GTOP_INTERFACE_TYPE_TP_X1_TAB = 4, +}; + +/* Attach option states for GTOP Type 1 interfaces ("Any type") */ +#define TP_GTOP_ANY_TYPE_STATE_ANY_OPTION_ATTACHED BIT(0) + +/* + * Attach option states for GTOP Type 4 interfaces ("ThinkPad X1 Tablet series") + * 0: detached, 1: attached + * except for special meanings for Pico cartridge and folio keyboard cover location + */ +#define TP_GTOP_TP_X1_TAB_STATE_THIN_KBD_ATTACHED BIT(0) +#define TP_GTOP_TP_X1_TAB_STATE_PRO_CARTRIDGE_ATTACHED BIT(1) +#define TP_GTOP_TP_X1_TAB_STATE_PICO_CARTRIDGE_ATTACH_MASK GENMASK(3, 2) +#define TP_GTOP_TP_X1_TAB_STATE_3D_CARTRIDGE_ATTACHED BIT(4) +#define TP_GTOP_TP_X1_TAB_STATE_RESERVE1_ATTACHED BIT(5) +#define TP_GTOP_TP_X1_TAB_STATE_RESERVE2_ATTACHED BIT(6) +#define TP_GTOP_TP_X1_TAB_STATE_FOLIO_KBD_FOLDED_ONTO_BACK BIT(16) + +/* Special values for Pico cartridge state (bits 3-2) */ +#define TP_GTOP_TP_X1_TAB_STATE_PICO_CARTRIDGE_DETACHED 0 +#define TP_GTOP_TP_X1_TAB_STATE_PICO_CARTRIDGE_ATTACHED BIT(2) +#define TP_GTOP_TP_X1_TAB_STATE_PICO_CARTRIDGE_BATTERY_ERROR BIT(3) +#define TP_GTOP_TP_X1_TAB_STATE_PICO_CARTRIDGE_RESERVED (BIT(2) | BIT(3)) + /* HKEY events */ enum tpacpi_hkey_event_t { /* Hotkey-related */ @@ -174,6 +213,12 @@ 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 devices 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 +353,10 @@ 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_TP_HELIX, + TP_HOTKEY_TABLET_USES_GTOP_TP10, + TP_HOTKEY_TABLET_USES_GTOP_TP_X1_TAB, } hotkey_tablet; u32 kbdlight:1; u32 light:1; @@ -2166,11 +2215,32 @@ static int hotkey_gmms_get_tablet_mode(int s, int *has_tablet_mode) return !!(mode & TP_ACPI_MULTI_MODE_TABLET_LIKE); } +static bool hotkey_gtop_any_type_get_tablet_mode(int s) +{ + return !(s & TP_GTOP_ANY_TYPE_STATE_ANY_OPTION_ATTACHED); +} + +static bool hotkey_gtop_tp_x1_tab_get_tablet_mode(int s) +{ + return (!(s & TP_GTOP_TP_X1_TAB_STATE_THIN_KBD_ATTACHED) || + (s & TP_GTOP_TP_X1_TAB_STATE_FOLIO_KBD_FOLDED_ONTO_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", TP_GTOP_CMD_GET_ATTACH_OPTION)) + return -EIO; + *status = hotkey_gtop_any_type_get_tablet_mode(s); + break; + case TP_HOTKEY_TABLET_USES_GTOP_TP_X1_TAB: + if (!acpi_evalf(hkey_handle, &s, "GTOP", "dd", TP_GTOP_CMD_GET_ATTACH_OPTION)) + return -EIO; + *status = hotkey_gtop_tp_x1_tab_get_tablet_mode(s); + break; case TP_HOTKEY_TABLET_USES_MHKG: if (!acpi_evalf(hkey_handle, &s, "MHKG", "d")) return -EIO; @@ -3213,7 +3283,29 @@ 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", TP_GTOP_CMD_QUERY_VERSION) && + res >= TP_GTOP_MINIMUM_VERSION && + acpi_evalf(hkey_handle, &res, "GTOP", "qdd", TP_GTOP_CMD_QUERY_INTERFACE_TYPE)) { + switch (res) { + case TP_GTOP_INTERFACE_TYPE_ANY_TYPE: + tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_GTOP_ANY_TYPE; + if (acpi_evalf(hkey_handle, &res, "GTOP", "qdd", + TP_GTOP_CMD_GET_ATTACH_OPTION)) + in_tablet_mode = hotkey_gtop_any_type_get_tablet_mode(res); + type = "GTOP"; + break; + case TP_GTOP_INTERFACE_TYPE_TP_X1_TAB: + tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_GTOP_TP_X1_TAB; + if (acpi_evalf(hkey_handle, &res, "GTOP", "qdd", + TP_GTOP_CMD_GET_ATTACH_OPTION)) + in_tablet_mode = hotkey_gtop_tp_x1_tab_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 +4081,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