platform/x86: asus-wmi: Add support for SW_TABLET_MODE on UX360

The UX360CA has a WMI device id 0x00060062, which reports whether the
lid is flipped in tablet mode (1) or in normal laptop mode (0).

Add a quirk (quirk_asus_use_lid_flip_devid) for devices on which this
WMI device should be used to figure out the SW_TABLET_MODE state, as
opposed to the quirk_asus_use_kbd_dock_devid.

Additionally, the device needs to be queried on resume and restore
because the firmware does not generate an event if the laptop is put to
sleep while in tablet mode, flipped to normal mode, and later awoken.

It is assumed other UX360* models have the same WMI device. As such, the
quirk is applied to devices with DMI_MATCH(DMI_PRODUCT_NAME, "UX360").
More devices with this feature need to be tested and added accordingly.

The reason for using an allowlist via the quirk mechanism is that the new
WMI device (0x00060062) is also present on some models which do not have
a 360 degree hinge (at least FX503VD and GL503VD from Hans' DSTS
collection) and therefore its presence cannot be relied on.

Signed-off-by: Samuel Čavoj <samuel@cavoj.net>
Cc: Hans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20201020220944.1075530-1-samuel@cavoj.net
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
Samuel Čavoj 2020-10-21 00:09:44 +02:00 committed by Hans de Goede
parent 6198219362
commit ea856ec266
4 changed files with 57 additions and 0 deletions

View File

@ -119,6 +119,11 @@ static struct quirk_entry quirk_asus_use_kbd_dock_devid = {
.use_kbd_dock_devid = true, .use_kbd_dock_devid = true,
}; };
static struct quirk_entry quirk_asus_use_lid_flip_devid = {
.wmi_backlight_set_devstate = true,
.use_lid_flip_devid = true,
};
static int dmi_matched(const struct dmi_system_id *dmi) static int dmi_matched(const struct dmi_system_id *dmi)
{ {
pr_info("Identified laptop model '%s'\n", dmi->ident); pr_info("Identified laptop model '%s'\n", dmi->ident);
@ -520,6 +525,16 @@ static const struct dmi_system_id asus_quirks[] = {
}, },
.driver_data = &quirk_asus_use_kbd_dock_devid, .driver_data = &quirk_asus_use_kbd_dock_devid,
}, },
{
.callback = dmi_matched,
.ident = "ASUS ZenBook Flip UX360",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
/* Match UX360* */
DMI_MATCH(DMI_PRODUCT_NAME, "UX360"),
},
.driver_data = &quirk_asus_use_lid_flip_devid,
},
{}, {},
}; };

View File

@ -63,6 +63,7 @@ MODULE_LICENSE("GPL");
#define NOTIFY_KBD_BRTTOGGLE 0xc7 #define NOTIFY_KBD_BRTTOGGLE 0xc7
#define NOTIFY_KBD_FBM 0x99 #define NOTIFY_KBD_FBM 0x99
#define NOTIFY_KBD_TTP 0xae #define NOTIFY_KBD_TTP 0xae
#define NOTIFY_LID_FLIP 0xfa
#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0) #define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)
@ -375,6 +376,20 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
} }
} }
if (asus->driver->quirks->use_lid_flip_devid) {
result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP);
if (result < 0)
asus->driver->quirks->use_lid_flip_devid = 0;
if (result >= 0) {
input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
} else if (result == -ENODEV) {
pr_err("This device has lid_flip quirk but got ENODEV checking it. This is a bug.");
} else {
pr_err("Error checking for lid-flip: %d\n", result);
}
}
err = input_register_device(asus->inputdev); err = input_register_device(asus->inputdev);
if (err) if (err)
goto err_free_dev; goto err_free_dev;
@ -394,6 +409,18 @@ static void asus_wmi_input_exit(struct asus_wmi *asus)
asus->inputdev = NULL; asus->inputdev = NULL;
} }
/* Tablet mode ****************************************************************/
static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus)
{
int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP);
if (result >= 0) {
input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
input_sync(asus->inputdev);
}
}
/* Battery ********************************************************************/ /* Battery ********************************************************************/
/* The battery maximum charging percentage */ /* The battery maximum charging percentage */
@ -2128,6 +2155,11 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
return; return;
} }
if (asus->driver->quirks->use_lid_flip_devid && code == NOTIFY_LID_FLIP) {
lid_flip_tablet_mode_get_state(asus);
return;
}
if (asus->fan_boost_mode_available && code == NOTIFY_KBD_FBM) { if (asus->fan_boost_mode_available && code == NOTIFY_KBD_FBM) {
fan_boost_mode_switch_next(asus); fan_boost_mode_switch_next(asus);
return; return;
@ -2719,6 +2751,10 @@ static int asus_hotk_resume(struct device *device)
if (asus_wmi_has_fnlock_key(asus)) if (asus_wmi_has_fnlock_key(asus))
asus_wmi_fnlock_update(asus); asus_wmi_fnlock_update(asus);
if (asus->driver->quirks->use_lid_flip_devid)
lid_flip_tablet_mode_get_state(asus);
return 0; return 0;
} }
@ -2757,6 +2793,10 @@ static int asus_hotk_restore(struct device *device)
if (asus_wmi_has_fnlock_key(asus)) if (asus_wmi_has_fnlock_key(asus))
asus_wmi_fnlock_update(asus); asus_wmi_fnlock_update(asus);
if (asus->driver->quirks->use_lid_flip_devid)
lid_flip_tablet_mode_get_state(asus);
return 0; return 0;
} }

View File

@ -34,6 +34,7 @@ struct quirk_entry {
bool wmi_backlight_set_devstate; bool wmi_backlight_set_devstate;
bool wmi_force_als_set; bool wmi_force_als_set;
bool use_kbd_dock_devid; bool use_kbd_dock_devid;
bool use_lid_flip_devid;
int wapf; int wapf;
/* /*
* For machines with AMD graphic chips, it will send out WMI event * For machines with AMD graphic chips, it will send out WMI event

View File

@ -62,6 +62,7 @@
/* Misc */ /* Misc */
#define ASUS_WMI_DEVID_CAMERA 0x00060013 #define ASUS_WMI_DEVID_CAMERA 0x00060013
#define ASUS_WMI_DEVID_LID_FLIP 0x00060062
/* Storage */ /* Storage */
#define ASUS_WMI_DEVID_CARDREADER 0x00080013 #define ASUS_WMI_DEVID_CARDREADER 0x00080013