Skip to content

Commit 520ee4e

Browse files
Jorge Lopezjwrdegoede
authored andcommitted
platform/x86: hp-wmi: Fix SW_TABLET_MODE detection method
The purpose of this patch is to introduce a fix and removal of the current hack when determining tablet mode status. Determining the tablet mode status requires reading Byte 0 bit 2 as reported by HPWMI_HARDWARE_QUERY. The investigation identified the failure was rooted in two areas: HPWMI_HARDWARE_QUERY failure (0x05) and reading Byte 0, bit 2 only to determine the table mode status. HPWMI_HARDWARE_QUERY WMI failure also rendered the dock state value invalid. The latest changes use SMBIOS Type 3 (chassis type) and WMI Command 0x40 (device_mode_status) information to determine if the device is in tablet mode or not. hp_wmi_hw_state function was split into two functions; hp_wmi_get_dock_state and hp_wmi_get_tablet_mode. The new functions separate how dock_state and tablet_mode is handled in a cleaner manner. All changes were validated on a HP ZBook Workstation notebook, HP EliteBook x360, and HP EliteBook 850 G8. Signed-off-by: Jorge Lopez <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Hans de Goede <[email protected]> Signed-off-by: Hans de Goede <[email protected]>
1 parent 12b19f1 commit 520ee4e

File tree

1 file changed

+52
-19
lines changed

1 file changed

+52
-19
lines changed

drivers/platform/x86/hp-wmi.c

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@ MODULE_LICENSE("GPL");
3535
MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
3636
MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
3737

38-
static int enable_tablet_mode_sw = -1;
39-
module_param(enable_tablet_mode_sw, int, 0444);
40-
MODULE_PARM_DESC(enable_tablet_mode_sw, "Enable SW_TABLET_MODE reporting (-1=auto, 0=no, 1=yes)");
41-
4238
#define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
4339
#define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
4440
#define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
@@ -107,6 +103,7 @@ enum hp_wmi_commandtype {
107103
HPWMI_FEATURE2_QUERY = 0x0d,
108104
HPWMI_WIRELESS2_QUERY = 0x1b,
109105
HPWMI_POSTCODEERROR_QUERY = 0x2a,
106+
HPWMI_SYSTEM_DEVICE_MODE = 0x40,
110107
HPWMI_THERMAL_PROFILE_QUERY = 0x4c,
111108
};
112109

@@ -217,6 +214,19 @@ struct rfkill2_device {
217214
static int rfkill2_count;
218215
static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
219216

217+
/*
218+
* Chassis Types values were obtained from SMBIOS reference
219+
* specification version 3.00. A complete list of system enclosures
220+
* and chassis types is available on Table 17.
221+
*/
222+
static const char * const tablet_chassis_types[] = {
223+
"30", /* Tablet*/
224+
"31", /* Convertible */
225+
"32" /* Detachable */
226+
};
227+
228+
#define DEVICE_MODE_TABLET 0x06
229+
220230
/* map output size to the corresponding WMI method id */
221231
static inline int encode_outsize_for_pvsz(int outsize)
222232
{
@@ -345,14 +355,39 @@ static int hp_wmi_read_int(int query)
345355
return val;
346356
}
347357

348-
static int hp_wmi_hw_state(int mask)
358+
static int hp_wmi_get_dock_state(void)
349359
{
350360
int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY);
351361

352362
if (state < 0)
353363
return state;
354364

355-
return !!(state & mask);
365+
return !!(state & HPWMI_DOCK_MASK);
366+
}
367+
368+
static int hp_wmi_get_tablet_mode(void)
369+
{
370+
char system_device_mode[4] = { 0 };
371+
const char *chassis_type;
372+
bool tablet_found;
373+
int ret;
374+
375+
chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
376+
if (!chassis_type)
377+
return -ENODEV;
378+
379+
tablet_found = match_string(tablet_chassis_types,
380+
ARRAY_SIZE(tablet_chassis_types),
381+
chassis_type) >= 0;
382+
if (!tablet_found)
383+
return -ENODEV;
384+
385+
ret = hp_wmi_perform_query(HPWMI_SYSTEM_DEVICE_MODE, HPWMI_READ,
386+
system_device_mode, 0, sizeof(system_device_mode));
387+
if (ret < 0)
388+
return ret;
389+
390+
return system_device_mode[0] == DEVICE_MODE_TABLET;
356391
}
357392

358393
static int omen_thermal_profile_set(int mode)
@@ -568,7 +603,7 @@ static ssize_t als_show(struct device *dev, struct device_attribute *attr,
568603
static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
569604
char *buf)
570605
{
571-
int value = hp_wmi_hw_state(HPWMI_DOCK_MASK);
606+
int value = hp_wmi_get_dock_state();
572607
if (value < 0)
573608
return value;
574609
return sprintf(buf, "%d\n", value);
@@ -577,7 +612,7 @@ static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
577612
static ssize_t tablet_show(struct device *dev, struct device_attribute *attr,
578613
char *buf)
579614
{
580-
int value = hp_wmi_hw_state(HPWMI_TABLET_MASK);
615+
int value = hp_wmi_get_tablet_mode();
581616
if (value < 0)
582617
return value;
583618
return sprintf(buf, "%d\n", value);
@@ -699,10 +734,10 @@ static void hp_wmi_notify(u32 value, void *context)
699734
case HPWMI_DOCK_EVENT:
700735
if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
701736
input_report_switch(hp_wmi_input_dev, SW_DOCK,
702-
hp_wmi_hw_state(HPWMI_DOCK_MASK));
737+
hp_wmi_get_dock_state());
703738
if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
704739
input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
705-
hp_wmi_hw_state(HPWMI_TABLET_MASK));
740+
hp_wmi_get_tablet_mode());
706741
input_sync(hp_wmi_input_dev);
707742
break;
708743
case HPWMI_PARK_HDD:
@@ -780,19 +815,17 @@ static int __init hp_wmi_input_setup(void)
780815
__set_bit(EV_SW, hp_wmi_input_dev->evbit);
781816

782817
/* Dock */
783-
val = hp_wmi_hw_state(HPWMI_DOCK_MASK);
818+
val = hp_wmi_get_dock_state();
784819
if (!(val < 0)) {
785820
__set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
786821
input_report_switch(hp_wmi_input_dev, SW_DOCK, val);
787822
}
788823

789824
/* Tablet mode */
790-
if (enable_tablet_mode_sw > 0) {
791-
val = hp_wmi_hw_state(HPWMI_TABLET_MASK);
792-
if (val >= 0) {
793-
__set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
794-
input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val);
795-
}
825+
val = hp_wmi_get_tablet_mode();
826+
if (!(val < 0)) {
827+
__set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
828+
input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val);
796829
}
797830

798831
err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
@@ -1227,10 +1260,10 @@ static int hp_wmi_resume_handler(struct device *device)
12271260
if (hp_wmi_input_dev) {
12281261
if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
12291262
input_report_switch(hp_wmi_input_dev, SW_DOCK,
1230-
hp_wmi_hw_state(HPWMI_DOCK_MASK));
1263+
hp_wmi_get_dock_state());
12311264
if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
12321265
input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
1233-
hp_wmi_hw_state(HPWMI_TABLET_MASK));
1266+
hp_wmi_get_tablet_mode());
12341267
input_sync(hp_wmi_input_dev);
12351268
}
12361269

0 commit comments

Comments
 (0)