mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-30 07:34:12 +08:00
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 <jorge.lopez2@hp.com> Link: https://lore.kernel.org/r/20220310210853.28367-3-jorge.lopez2@hp.com Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
parent
12b19f14a2
commit
520ee4ea1c
@ -35,10 +35,6 @@ MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
|
||||
MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
|
||||
|
||||
static int enable_tablet_mode_sw = -1;
|
||||
module_param(enable_tablet_mode_sw, int, 0444);
|
||||
MODULE_PARM_DESC(enable_tablet_mode_sw, "Enable SW_TABLET_MODE reporting (-1=auto, 0=no, 1=yes)");
|
||||
|
||||
#define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
|
||||
#define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
|
||||
#define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
|
||||
@ -107,6 +103,7 @@ enum hp_wmi_commandtype {
|
||||
HPWMI_FEATURE2_QUERY = 0x0d,
|
||||
HPWMI_WIRELESS2_QUERY = 0x1b,
|
||||
HPWMI_POSTCODEERROR_QUERY = 0x2a,
|
||||
HPWMI_SYSTEM_DEVICE_MODE = 0x40,
|
||||
HPWMI_THERMAL_PROFILE_QUERY = 0x4c,
|
||||
};
|
||||
|
||||
@ -217,6 +214,19 @@ struct rfkill2_device {
|
||||
static int rfkill2_count;
|
||||
static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
|
||||
|
||||
/*
|
||||
* Chassis Types values were obtained from SMBIOS reference
|
||||
* specification version 3.00. A complete list of system enclosures
|
||||
* and chassis types is available on Table 17.
|
||||
*/
|
||||
static const char * const tablet_chassis_types[] = {
|
||||
"30", /* Tablet*/
|
||||
"31", /* Convertible */
|
||||
"32" /* Detachable */
|
||||
};
|
||||
|
||||
#define DEVICE_MODE_TABLET 0x06
|
||||
|
||||
/* map output size to the corresponding WMI method id */
|
||||
static inline int encode_outsize_for_pvsz(int outsize)
|
||||
{
|
||||
@ -345,14 +355,39 @@ static int hp_wmi_read_int(int query)
|
||||
return val;
|
||||
}
|
||||
|
||||
static int hp_wmi_hw_state(int mask)
|
||||
static int hp_wmi_get_dock_state(void)
|
||||
{
|
||||
int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY);
|
||||
|
||||
if (state < 0)
|
||||
return state;
|
||||
|
||||
return !!(state & mask);
|
||||
return !!(state & HPWMI_DOCK_MASK);
|
||||
}
|
||||
|
||||
static int hp_wmi_get_tablet_mode(void)
|
||||
{
|
||||
char system_device_mode[4] = { 0 };
|
||||
const char *chassis_type;
|
||||
bool tablet_found;
|
||||
int ret;
|
||||
|
||||
chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
|
||||
if (!chassis_type)
|
||||
return -ENODEV;
|
||||
|
||||
tablet_found = match_string(tablet_chassis_types,
|
||||
ARRAY_SIZE(tablet_chassis_types),
|
||||
chassis_type) >= 0;
|
||||
if (!tablet_found)
|
||||
return -ENODEV;
|
||||
|
||||
ret = hp_wmi_perform_query(HPWMI_SYSTEM_DEVICE_MODE, HPWMI_READ,
|
||||
system_device_mode, 0, sizeof(system_device_mode));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return system_device_mode[0] == DEVICE_MODE_TABLET;
|
||||
}
|
||||
|
||||
static int omen_thermal_profile_set(int mode)
|
||||
@ -568,7 +603,7 @@ static ssize_t als_show(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int value = hp_wmi_hw_state(HPWMI_DOCK_MASK);
|
||||
int value = hp_wmi_get_dock_state();
|
||||
if (value < 0)
|
||||
return value;
|
||||
return sprintf(buf, "%d\n", value);
|
||||
@ -577,7 +612,7 @@ static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t tablet_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int value = hp_wmi_hw_state(HPWMI_TABLET_MASK);
|
||||
int value = hp_wmi_get_tablet_mode();
|
||||
if (value < 0)
|
||||
return value;
|
||||
return sprintf(buf, "%d\n", value);
|
||||
@ -699,10 +734,10 @@ static void hp_wmi_notify(u32 value, void *context)
|
||||
case HPWMI_DOCK_EVENT:
|
||||
if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
|
||||
input_report_switch(hp_wmi_input_dev, SW_DOCK,
|
||||
hp_wmi_hw_state(HPWMI_DOCK_MASK));
|
||||
hp_wmi_get_dock_state());
|
||||
if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
|
||||
input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
|
||||
hp_wmi_hw_state(HPWMI_TABLET_MASK));
|
||||
hp_wmi_get_tablet_mode());
|
||||
input_sync(hp_wmi_input_dev);
|
||||
break;
|
||||
case HPWMI_PARK_HDD:
|
||||
@ -780,19 +815,17 @@ static int __init hp_wmi_input_setup(void)
|
||||
__set_bit(EV_SW, hp_wmi_input_dev->evbit);
|
||||
|
||||
/* Dock */
|
||||
val = hp_wmi_hw_state(HPWMI_DOCK_MASK);
|
||||
val = hp_wmi_get_dock_state();
|
||||
if (!(val < 0)) {
|
||||
__set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
|
||||
input_report_switch(hp_wmi_input_dev, SW_DOCK, val);
|
||||
}
|
||||
|
||||
/* Tablet mode */
|
||||
if (enable_tablet_mode_sw > 0) {
|
||||
val = hp_wmi_hw_state(HPWMI_TABLET_MASK);
|
||||
if (val >= 0) {
|
||||
__set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
|
||||
input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val);
|
||||
}
|
||||
val = hp_wmi_get_tablet_mode();
|
||||
if (!(val < 0)) {
|
||||
__set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
|
||||
input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val);
|
||||
}
|
||||
|
||||
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)
|
||||
if (hp_wmi_input_dev) {
|
||||
if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
|
||||
input_report_switch(hp_wmi_input_dev, SW_DOCK,
|
||||
hp_wmi_hw_state(HPWMI_DOCK_MASK));
|
||||
hp_wmi_get_dock_state());
|
||||
if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
|
||||
input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
|
||||
hp_wmi_hw_state(HPWMI_TABLET_MASK));
|
||||
hp_wmi_get_tablet_mode());
|
||||
input_sync(hp_wmi_input_dev);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user