From patchwork Thu Feb 11 07:35:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Kobel X-Patchwork-Id: 12082429 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.2 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 41F26C433DB for ; Thu, 11 Feb 2021 07:36:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 12D6764E25 for ; Thu, 11 Feb 2021 07:36:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229538AbhBKHgI (ORCPT ); Thu, 11 Feb 2021 02:36:08 -0500 Received: from ganymed.uberspace.de ([185.26.156.242]:43052 "EHLO ganymed.uberspace.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229559AbhBKHgE (ORCPT ); Thu, 11 Feb 2021 02:36:04 -0500 Received: (qmail 30408 invoked from network); 11 Feb 2021 07:35:18 -0000 Received: from localhost (HELO localhost) (127.0.0.1) by ganymed.uberspace.de with SMTP; 11 Feb 2021 07:35:18 -0000 From: Alexander Kobel Subject: [PATCH v4] platform/x86: thinkpad_acpi: Handle keyboard cover attach/detach events To: Hans de Goede , Nitin Joshi1 , "platform-driver-x86@vger.kernel.org" , Mark Pearson , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= Message-ID: Date: Thu, 11 Feb 2021 08:35:11 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.7.1 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org 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 --- 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..09adcaf49fe8 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 = 0x0200, +}; + +#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;