From 06501b557faec7c4aa1a3188e14c8c3d1e6e15de Mon Sep 17 00:00:00 2001 From: Ionut Nechita Date: Wed, 7 Jan 2026 17:42:18 +0200 Subject: [PATCH 1/5] HID: asus: Replace magic number with HID_UP_ASUSVENDOR constant Use the existing HID_UP_ASUSVENDOR constant instead of the magic number 0xff310000 for better code clarity and maintainability. Reviewed-by: Denis Benato Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Ionut Nechita Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index a444d41e53b6..9a969f5c5c90 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -316,7 +316,7 @@ static int asus_e1239t_event(struct asus_drvdata *drvdat, u8 *data, int size) static int asus_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value) { - if ((usage->hid & HID_USAGE_PAGE) == 0xff310000 && + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR && (usage->hid & HID_USAGE) != 0x00 && (usage->hid & HID_USAGE) != 0xff && !usage->type) { hid_warn(hdev, "Unmapped Asus vendor usagepage code 0x%02x\n", From 7fe565fb83ba7074dca1d25696f1d30116555528 Mon Sep 17 00:00:00 2001 From: Ionut Nechita Date: Wed, 7 Jan 2026 17:42:20 +0200 Subject: [PATCH 2/5] HID: asus: Filter spurious HID vendor codes on ROG laptops On Asus ROG laptops, several HID vendor usage codes (0xea, 0xec, 0x02, 0x8a, 0x9e) are sent during normal operation without a clear purpose, generating unwanted "Unmapped Asus vendor usagepage code" warnings in dmesg. Add definitions for these codes and filter them out in asus_raw_event() to prevent kernel log spam. Tested on Asus ROG series laptops. Reviewed-by: Denis Benato Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Ionut Nechita Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 9a969f5c5c90..49ffed0f6e9e 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -56,6 +56,13 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define ROG_ALLY_X_MIN_MCU 313 #define ROG_ALLY_MIN_MCU 319 +/* Spurious HID codes sent by QUIRK_ROG_NKEY_KEYBOARD devices */ +#define ASUS_SPURIOUS_CODE_0XEA 0xea +#define ASUS_SPURIOUS_CODE_0XEC 0xec +#define ASUS_SPURIOUS_CODE_0X02 0x02 +#define ASUS_SPURIOUS_CODE_0X8A 0x8a +#define ASUS_SPURIOUS_CODE_0X9E 0x9e + #define SUPPORT_KBD_BACKLIGHT BIT(0) #define MAX_TOUCH_MAJOR 8 @@ -347,6 +354,21 @@ static int asus_raw_event(struct hid_device *hdev, if (report->id == FEATURE_KBD_LED_REPORT_ID1 || report->id == FEATURE_KBD_LED_REPORT_ID2) return -1; if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { + /* + * ASUS ROG laptops send these codes during normal operation + * with no discernable reason. Filter them out to avoid + * unmapped warning messages. + */ + if (report->id == FEATURE_KBD_REPORT_ID) { + if (data[1] == ASUS_SPURIOUS_CODE_0XEA || + data[1] == ASUS_SPURIOUS_CODE_0XEC || + data[1] == ASUS_SPURIOUS_CODE_0X02 || + data[1] == ASUS_SPURIOUS_CODE_0X8A || + data[1] == ASUS_SPURIOUS_CODE_0X9E) { + return -1; + } + } + /* * G713 and G733 send these codes on some keypresses, depending on * the key pressed it can trigger a shutdown event if not caught. From c888d0bd055b57688534a884f8f210a91d15e00f Mon Sep 17 00:00:00 2001 From: Ionut Nechita Date: Wed, 7 Jan 2026 17:42:22 +0200 Subject: [PATCH 3/5] HID: asus: Add WMI communication infrastructure Add infrastructure for the HID driver to communicate with the asus-wmi driver for handling special keys that require WMI communication. This includes: - Define ASUS_WMI_METHODID_NOTIF method ID in asus-wmi.h - Implement asus_wmi_send_event() function to send events to asus-wmi Reviewed-by: Denis Benato Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Ionut Nechita Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 24 ++++++++++++++++++++++ include/linux/platform_data/x86/asus-wmi.h | 1 + 2 files changed, 25 insertions(+) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 49ffed0f6e9e..f778387c3c55 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -23,6 +23,7 @@ /* */ +#include #include #include #include @@ -320,6 +321,29 @@ static int asus_e1239t_event(struct asus_drvdata *drvdat, u8 *data, int size) return 0; } +/* + * Send events to asus-wmi driver for handling special keys + */ +static int asus_wmi_send_event(struct asus_drvdata *drvdata, u8 code) +{ + int err; + u32 retval; + + err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, + ASUS_WMI_METHODID_NOTIF, code, &retval); + if (err) { + pr_warn("Failed to notify asus-wmi: %d\n", err); + return err; + } + + if (retval != 0) { + pr_warn("Failed to notify asus-wmi (retval): 0x%x\n", retval); + return -EIO; + } + + return 0; +} + static int asus_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value) { diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 8a515179113d..e23b481ab118 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -27,6 +27,7 @@ #define ASUS_WMI_METHODID_KBFT 0x5446424B /* KeyBoard FilTer */ #define ASUS_WMI_METHODID_INIT 0x54494E49 /* INITialize */ #define ASUS_WMI_METHODID_HKEY 0x59454B48 /* Hot KEY ?? */ +#define ASUS_WMI_METHODID_NOTIF 0x00100021 /* Notify method */ #define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE From 1489a34e97efebf583ff08e506ecf9f7d44537d3 Mon Sep 17 00:00:00 2001 From: Ionut Nechita Date: Wed, 7 Jan 2026 17:42:24 +0200 Subject: [PATCH 4/5] HID: asus: Implement Fn+F5 fan control key handler On Asus ROG laptops, the Fn+F5 key (HID code 0xae) is used to cycle through fan modes. This key press needs to be forwarded to the asus-wmi driver to actually change the fan mode. Add ASUS_FAN_CTRL_KEY_CODE define and implement the handler in asus_raw_event() to send WMI events when this key is pressed. When asus-wmi successfully handles the event, it is blocked from reaching userspace. If asus-wmi is unavailable or fails, the event is passed to userspace via evdev, allowing userspace implementations of fan control. Tested on Asus ROG G14/G15 series laptops. Reviewed-by: Denis Benato Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Ionut Nechita Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index f778387c3c55..7d2189916565 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -64,6 +64,9 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define ASUS_SPURIOUS_CODE_0X8A 0x8a #define ASUS_SPURIOUS_CODE_0X9E 0x9e +/* Special key codes */ +#define ASUS_FAN_CTRL_KEY_CODE 0xae + #define SUPPORT_KBD_BACKLIGHT BIT(0) #define MAX_TOUCH_MAJOR 8 @@ -378,12 +381,34 @@ static int asus_raw_event(struct hid_device *hdev, if (report->id == FEATURE_KBD_LED_REPORT_ID1 || report->id == FEATURE_KBD_LED_REPORT_ID2) return -1; if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { - /* - * ASUS ROG laptops send these codes during normal operation - * with no discernable reason. Filter them out to avoid - * unmapped warning messages. - */ if (report->id == FEATURE_KBD_REPORT_ID) { + /* + * Fn+F5 fan control key - try to send WMI event to toggle fan mode. + * If successful, block the event from reaching userspace. + * If asus-wmi is unavailable or the call fails, let the event + * pass to userspace so it can implement its own fan control. + */ + if (data[1] == ASUS_FAN_CTRL_KEY_CODE) { + int ret = asus_wmi_send_event(drvdata, ASUS_FAN_CTRL_KEY_CODE); + + if (ret == 0) { + /* Successfully handled by asus-wmi, block event */ + return -1; + } + + /* + * Warn if asus-wmi failed (but not if it's unavailable). + * Let the event reach userspace in all failure cases. + */ + if (ret != -ENODEV) + hid_warn(hdev, "Failed to notify asus-wmi: %d\n", ret); + } + + /* + * ASUS ROG laptops send these codes during normal operation + * with no discernable reason. Filter them out to avoid + * unmapped warning messages. + */ if (data[1] == ASUS_SPURIOUS_CODE_0XEA || data[1] == ASUS_SPURIOUS_CODE_0XEC || data[1] == ASUS_SPURIOUS_CODE_0X02 || From f631011e36b87b173b71c7592b558ad05d791228 Mon Sep 17 00:00:00 2001 From: Connor Belli Date: Mon, 8 Dec 2025 19:00:08 -0500 Subject: [PATCH 5/5] HID: hid-asus: Implement fn lock for Asus ProArt P16 This patch implements support for the fn lock key on the 2025 Asus ProArt P16. The implementation for this is based on how fn lock is implemented in the hid-lenovo driver. Signed-off-by: Connor Belli Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 7d2189916565..6180217139d8 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -100,6 +100,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define QUIRK_ROG_NKEY_KEYBOARD BIT(11) #define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12) #define QUIRK_ROG_ALLY_XPAD BIT(13) +#define QUIRK_HID_FN_LOCK BIT(14) #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ QUIRK_NO_INIT_REPORTS | \ @@ -143,6 +144,8 @@ struct asus_drvdata { int battery_stat; bool battery_in_query; unsigned long battery_next_query; + struct work_struct fn_lock_sync_work; + bool fn_lock; }; static int asus_report_battery(struct asus_drvdata *, u8 *, int); @@ -350,6 +353,8 @@ static int asus_wmi_send_event(struct asus_drvdata *drvdata, u8 code) static int asus_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value) { + struct asus_drvdata *drvdata = hid_get_drvdata(hdev); + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR && (usage->hid & HID_USAGE) != 0x00 && (usage->hid & HID_USAGE) != 0xff && !usage->type) { @@ -357,6 +362,12 @@ static int asus_event(struct hid_device *hdev, struct hid_field *field, usage->hid & HID_USAGE); } + if (drvdata->quirks & QUIRK_HID_FN_LOCK && + usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) { + drvdata->fn_lock = !drvdata->fn_lock; + schedule_work(&drvdata->fn_lock_sync_work); + } + return 0; } @@ -528,6 +539,21 @@ static int asus_kbd_disable_oobe(struct hid_device *hdev) return 0; } +static int asus_kbd_set_fn_lock(struct hid_device *hdev, bool enabled) +{ + u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xd0, 0x4e, !!enabled }; + + return asus_kbd_set_report(hdev, buf, sizeof(buf)); +} + +static void asus_sync_fn_lock(struct work_struct *work) +{ + struct asus_drvdata *drvdata = + container_of(work, struct asus_drvdata, fn_lock_sync_work); + + asus_kbd_set_fn_lock(drvdata->hdev, drvdata->fn_lock); +} + static void asus_schedule_work(struct asus_kbd_leds *led) { unsigned long flags; @@ -999,6 +1025,12 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) asus_kbd_register_leds(hdev)) hid_warn(hdev, "Failed to initialize backlight.\n"); + if (drvdata->quirks & QUIRK_HID_FN_LOCK) { + drvdata->fn_lock = true; + INIT_WORK(&drvdata->fn_lock_sync_work, asus_sync_fn_lock); + asus_kbd_set_fn_lock(hdev, true); + } + return 0; } @@ -1330,6 +1362,9 @@ static void asus_remove(struct hid_device *hdev) cancel_work_sync(&drvdata->kbd_backlight->work); } + if (drvdata->quirks & QUIRK_HID_FN_LOCK) + cancel_work_sync(&drvdata->fn_lock_sync_work); + hid_hw_stop(hdev); } @@ -1457,7 +1492,7 @@ static const struct hid_device_id asus_devices[] = { QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2), - QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_HID_FN_LOCK }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR), QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },