platform/x86: thinkpad_acpi: suppress warning about palm detection
[sfrench/cifs-2.6.git] / drivers / platform / x86 / thinkpad_acpi.c
index 3887dfeafc964522e43c077534bf62e0747f7dcf..d5eaf3b1edba91d53723fddd0c2b49125fd64b9d 100644 (file)
@@ -214,6 +214,10 @@ enum tpacpi_hkey_event_t {
        /* AC-related events */
        TP_HKEY_EV_AC_CHANGED           = 0x6040, /* AC status changed */
 
+       /* Further user-interface events */
+       TP_HKEY_EV_PALM_DETECTED        = 0x60b0, /* palm hoveres keyboard */
+       TP_HKEY_EV_PALM_UNDETECTED      = 0x60b1, /* palm removed */
+
        /* Misc */
        TP_HKEY_EV_RFKILL_CHANGED       = 0x7000, /* rfkill switch changed */
 };
@@ -310,8 +314,7 @@ static struct {
        enum {
                TP_HOTKEY_TABLET_NONE = 0,
                TP_HOTKEY_TABLET_USES_MHKG,
-               /* X1 Yoga 2016, seen on BIOS N1FET44W */
-               TP_HOTKEY_TABLET_USES_CMMD,
+               TP_HOTKEY_TABLET_USES_GMMS,
        } hotkey_tablet;
        u32 kbdlight:1;
        u32 light:1;
@@ -2044,8 +2047,28 @@ static void hotkey_poll_setup(const bool may_warn);
 
 /* HKEY.MHKG() return bits */
 #define TP_HOTKEY_TABLET_MASK (1 << 3)
-/* ThinkPad X1 Yoga (2016) */
-#define TP_EC_CMMD_TABLET_MODE 0x6
+enum {
+       TP_ACPI_MULTI_MODE_INVALID      = 0,
+       TP_ACPI_MULTI_MODE_UNKNOWN      = 1 << 0,
+       TP_ACPI_MULTI_MODE_LAPTOP       = 1 << 1,
+       TP_ACPI_MULTI_MODE_TABLET       = 1 << 2,
+       TP_ACPI_MULTI_MODE_FLAT         = 1 << 3,
+       TP_ACPI_MULTI_MODE_STAND        = 1 << 4,
+       TP_ACPI_MULTI_MODE_TENT         = 1 << 5,
+       TP_ACPI_MULTI_MODE_STAND_TENT   = 1 << 6,
+};
+
+enum {
+       /* The following modes are considered tablet mode for the purpose of
+        * reporting the status to userspace. i.e. in all these modes it makes
+        * sense to disable the laptop input devices such as touchpad and
+        * keyboard.
+        */
+       TP_ACPI_MULTI_MODE_TABLET_LIKE  = TP_ACPI_MULTI_MODE_TABLET |
+                                         TP_ACPI_MULTI_MODE_STAND |
+                                         TP_ACPI_MULTI_MODE_TENT |
+                                         TP_ACPI_MULTI_MODE_STAND_TENT,
+};
 
 static int hotkey_get_wlsw(void)
 {
@@ -2066,6 +2089,88 @@ static int hotkey_get_wlsw(void)
        return (status) ? TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
 }
 
+static int hotkey_gmms_get_tablet_mode(int s, int *has_tablet_mode)
+{
+       int type = (s >> 16) & 0xffff;
+       int value = s & 0xffff;
+       int mode = TP_ACPI_MULTI_MODE_INVALID;
+       int valid_modes = 0;
+
+       if (has_tablet_mode)
+               *has_tablet_mode = 0;
+
+       switch (type) {
+       case 1:
+               valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
+                             TP_ACPI_MULTI_MODE_TABLET |
+                             TP_ACPI_MULTI_MODE_STAND_TENT;
+               break;
+       case 2:
+               valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
+                             TP_ACPI_MULTI_MODE_FLAT |
+                             TP_ACPI_MULTI_MODE_TABLET |
+                             TP_ACPI_MULTI_MODE_STAND |
+                             TP_ACPI_MULTI_MODE_TENT;
+               break;
+       case 3:
+               valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
+                             TP_ACPI_MULTI_MODE_FLAT;
+               break;
+       case 4:
+       case 5:
+               /* In mode 4, FLAT is not specified as a valid mode. However,
+                * it can be seen at least on the X1 Yoga 2nd Generation.
+                */
+               valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
+                             TP_ACPI_MULTI_MODE_FLAT |
+                             TP_ACPI_MULTI_MODE_TABLET |
+                             TP_ACPI_MULTI_MODE_STAND |
+                             TP_ACPI_MULTI_MODE_TENT;
+               break;
+       default:
+               pr_err("Unknown multi mode status type %d with value 0x%04X, please report this to %s\n",
+                      type, value, TPACPI_MAIL);
+               return 0;
+       }
+
+       if (has_tablet_mode && (valid_modes & TP_ACPI_MULTI_MODE_TABLET_LIKE))
+               *has_tablet_mode = 1;
+
+       switch (value) {
+       case 1:
+               mode = TP_ACPI_MULTI_MODE_LAPTOP;
+               break;
+       case 2:
+               mode = TP_ACPI_MULTI_MODE_FLAT;
+               break;
+       case 3:
+               mode = TP_ACPI_MULTI_MODE_TABLET;
+               break;
+       case 4:
+               if (type == 1)
+                       mode = TP_ACPI_MULTI_MODE_STAND_TENT;
+               else
+                       mode = TP_ACPI_MULTI_MODE_STAND;
+               break;
+       case 5:
+               mode = TP_ACPI_MULTI_MODE_TENT;
+               break;
+       default:
+               if (type == 5 && value == 0xffff) {
+                       pr_warn("Multi mode status is undetected, assuming laptop\n");
+                       return 0;
+               }
+       }
+
+       if (!(mode & valid_modes)) {
+               pr_err("Unknown/reserved multi mode value 0x%04X for type %d, please report this to %s\n",
+                      value, type, TPACPI_MAIL);
+               return 0;
+       }
+
+       return !!(mode & TP_ACPI_MULTI_MODE_TABLET_LIKE);
+}
+
 static int hotkey_get_tablet_mode(int *status)
 {
        int s;
@@ -2077,11 +2182,11 @@ static int hotkey_get_tablet_mode(int *status)
 
                *status = ((s & TP_HOTKEY_TABLET_MASK) != 0);
                break;
-       case TP_HOTKEY_TABLET_USES_CMMD:
-               if (!acpi_evalf(ec_handle, &s, "CMMD", "d"))
+       case TP_HOTKEY_TABLET_USES_GMMS:
+               if (!acpi_evalf(hkey_handle, &s, "GMMS", "dd", 0))
                        return -EIO;
 
-               *status = (s == TP_EC_CMMD_TABLET_MODE);
+               *status = hotkey_gmms_get_tablet_mode(s, NULL);
                break;
        default:
                break;
@@ -3113,16 +3218,19 @@ static int hotkey_init_tablet_mode(void)
        int in_tablet_mode = 0, res;
        char *type = NULL;
 
-       if (acpi_evalf(hkey_handle, &res, "MHKG", "qd")) {
+       if (acpi_evalf(hkey_handle, &res, "GMMS", "qdd", 0)) {
+               int has_tablet_mode;
+
+               in_tablet_mode = hotkey_gmms_get_tablet_mode(res,
+                                                            &has_tablet_mode);
+               if (has_tablet_mode)
+                       tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_GMMS;
+               type = "GMMS";
+       } else if (acpi_evalf(hkey_handle, &res, "MHKG", "qd")) {
                /* For X41t, X60t, X61t Tablets... */
                tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_MHKG;
                in_tablet_mode = !!(res & TP_HOTKEY_TABLET_MASK);
                type = "MHKG";
-       } else if (acpi_evalf(ec_handle, &res, "CMMD", "qd")) {
-               /* For X1 Yoga (2016) */
-               tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_CMMD;
-               in_tablet_mode = res == TP_EC_CMMD_TABLET_MODE;
-               type = "CMMD";
        }
 
        if (!tp_features.hotkey_tablet)
@@ -3973,6 +4081,12 @@ static bool hotkey_notify_6xxx(const u32 hkey,
                *send_acpi_ev = false;
                break;
 
+       case TP_HKEY_EV_PALM_DETECTED:
+       case TP_HKEY_EV_PALM_UNDETECTED:
+               /* palm detected hovering the keyboard, forward to user-space
+                * via netlink for consumption */
+               return true;
+
        default:
                pr_warn("unknown possible thermal alarm or keyboard event received\n");
                known = false;