diff options
-rw-r--r-- | drivers/platform/x86/asus-wmi.c | 37 | ||||
-rw-r--r-- | include/linux/platform_data/x86/asus-wmi.h | 1 |
2 files changed, 38 insertions, 0 deletions
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index ee1fa93708ec..f94691615881 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -66,10 +66,13 @@ MODULE_LICENSE("GPL"); #define NOTIFY_BRNUP_MAX 0x1f #define NOTIFY_BRNDOWN_MIN 0x20 #define NOTIFY_BRNDOWN_MAX 0x2e +#define NOTIFY_FNLOCK_TOGGLE 0x4e #define NOTIFY_KBD_BRTUP 0xc4 #define NOTIFY_KBD_BRTDWN 0xc5 #define NOTIFY_KBD_BRTTOGGLE 0xc7 +#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0) + #define ASUS_FAN_DESC "cpu_fan" #define ASUS_FAN_MFUN 0x13 #define ASUS_FAN_SFUN_READ 0x06 @@ -177,6 +180,8 @@ struct asus_wmi { struct workqueue_struct *hotplug_workqueue; struct work_struct hotplug_work; + bool fnlock_locked; + struct asus_wmi_debug debug; struct asus_wmi_driver *driver; @@ -1619,6 +1624,23 @@ static int is_display_toggle(int code) return 0; } +static bool asus_wmi_has_fnlock_key(struct asus_wmi *asus) +{ + u32 result; + + asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FNLOCK, &result); + + return (result & ASUS_WMI_DSTS_PRESENCE_BIT) && + !(result & ASUS_WMI_FNLOCK_BIOS_DISABLED); +} + +static void asus_wmi_fnlock_update(struct asus_wmi *asus) +{ + int mode = asus->fnlock_locked; + + asus_wmi_set_devstate(ASUS_WMI_DEVID_FNLOCK, mode, NULL); +} + static void asus_wmi_notify(u32 value, void *context) { struct asus_wmi *asus = context; @@ -1680,6 +1702,12 @@ static void asus_wmi_notify(u32 value, void *context) goto exit; } + if (code == NOTIFY_FNLOCK_TOGGLE) { + asus->fnlock_locked = !asus->fnlock_locked; + asus_wmi_fnlock_update(asus); + goto exit; + } + if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle) goto exit; @@ -2134,6 +2162,11 @@ static int asus_wmi_add(struct platform_device *pdev) } else err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL); + if (asus_wmi_has_fnlock_key(asus)) { + asus->fnlock_locked = true; + asus_wmi_fnlock_update(asus); + } + status = wmi_install_notify_handler(asus->driver->event_guid, asus_wmi_notify, asus); if (ACPI_FAILURE(status)) { @@ -2213,6 +2246,8 @@ static int asus_hotk_resume(struct device *device) if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) kbd_led_update(asus); + if (asus_wmi_has_fnlock_key(asus)) + asus_wmi_fnlock_update(asus); return 0; } @@ -2249,6 +2284,8 @@ static int asus_hotk_restore(struct device *device) if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) kbd_led_update(asus); + if (asus_wmi_has_fnlock_key(asus)) + asus_wmi_fnlock_update(asus); return 0; } diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 53dfc2541960..bfba245636a7 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -67,6 +67,7 @@ /* Input */ #define ASUS_WMI_DEVID_TOUCHPAD 0x00100011 #define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012 +#define ASUS_WMI_DEVID_FNLOCK 0x00100023 /* Fan, Thermal */ #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011 |