* [PATCH v2 0/3] platform/x86: fix fn-lock on ASUS ProArt P16 (WMI DEVS no-op) [not found] <458d9e6c-8702-4cbc-9c4f-33cbd1175e67@linux.dev> @ 2026-05-06 19:33 ` Marcus Grenängen 2026-05-06 19:33 ` [PATCH v2 1/3] HID: asus: export asus_hid_fnlock_notify() for direct fn-lock control Marcus Grenängen ` (2 more replies) 0 siblings, 3 replies; 11+ messages in thread From: Marcus Grenängen @ 2026-05-06 19:33 UTC (permalink / raw) To: platform-driver-x86, denis.benato Cc: linux-input, linux-kernel, luke, hansg, ilpo.jarvinen, jikos, bentiss, corentin.chary, marcus This is v2 of the fn-lock fix for ASUS laptops where the WMI DEVS call for DEVID 0x00100023 is silently non-functional. Changes since v1: - Split into three patches as requested: hid-asus export, nb-wmi quirk, asus-armoury attribute (the NULL-ptr fix for brightness_set is folded into patch 1 where the second listener type is introduced) - Moved the sysfs attribute to asus-armoury's firmware-attributes interface (fn_lock under /sys/class/firmware-attributes/asus-armoury/) instead of asus-wmi, as suggested - asus-armoury now calls asus_hid_fnlock_notify() directly rather than routing through asus-wmi; this avoids touching asus-wmi.c entirely - Dropped the asus_hid_listener::fnlock_set callback and the asus_hid_set_fnlock() / asus_hid_has_fnlock_listener() machinery from asus-wmi.c — the direct export from hid-asus is simpler and avoids the module init ordering issue described below Regarding Denis's question about auto-detection: unfortunately it is not feasible. On the ProArt P16, DSTS reports DEVID 0x00100023 as present (ASUS_WMI_DSTS_PRESENCE_BIT set), so the existing WMI probe path finds it. There is no distinguishing bit in the DSTS result between "WMI works" and "WMI is silently a no-op". Attempting a test write at probe time would be unreliable (no readback available on HID-path platforms — the fn_lock show function intentionally returns -EOPNOTSUPP). A DMI quirk is the cleanest approach. Note on module init ordering: asus-armoury and asus-nb-wmi are both compiled as loadable modules at the same init level. When asus-armoury initialises it cannot safely dereference asus_ref.asus (set by asus-wmi) to read the quirk flags, because asus-nb-wmi may not have probed yet. asus-armoury therefore uses dmi_match() directly rather than an exported accessor through asus-wmi. Tested on ASUS ProArt P16 (H7606WI, N-Key keyboard 0B05:19B6): - fn_lock attribute appears under firmware-attributes/asus-armoury/ - Writing 0/1 to current_value correctly toggles fn-lock state via HID - asusctl fn-lock -s true/false works end-to-end via asusd Marcus Grenängen (3): HID: asus: export asus_hid_fnlock_notify() for direct fn-lock control platform/x86: asus-nb-wmi: add fnlock_use_hid quirk for ProArt P16 platform/x86: asus-armoury: add fn_lock firmware attribute drivers/hid/hid-asus.c | 43 +++++++++++++- drivers/platform/x86/asus-armoury.c | 69 ++++++++++++++++++++++ drivers/platform/x86/asus-nb-wmi.c | 13 ++++ drivers/platform/x86/asus-wmi.h | 5 ++ include/linux/platform_data/x86/asus-wmi.h | 5 ++ 5 files changed, 134 insertions(+), 1 deletion(-) -- 2.54.0 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 1/3] HID: asus: export asus_hid_fnlock_notify() for direct fn-lock control 2026-05-06 19:33 ` [PATCH v2 0/3] platform/x86: fix fn-lock on ASUS ProArt P16 (WMI DEVS no-op) Marcus Grenängen @ 2026-05-06 19:33 ` Marcus Grenängen 2026-05-06 22:00 ` Randy Dunlap 2026-05-06 22:17 ` Denis Benato 2026-05-06 19:33 ` [PATCH v2 2/3] platform/x86: asus-nb-wmi: add fnlock_use_hid quirk for ProArt P16 Marcus Grenängen 2026-05-06 19:33 ` [PATCH v2 3/3] platform/x86: asus-armoury: add fn_lock firmware attribute Marcus Grenängen 2 siblings, 2 replies; 11+ messages in thread From: Marcus Grenängen @ 2026-05-06 19:33 UTC (permalink / raw) To: platform-driver-x86, denis.benato Cc: linux-input, linux-kernel, luke, hansg, ilpo.jarvinen, jikos, bentiss, corentin.chary, marcus Some ASUS platforms cannot control fn-lock via WMI DEVS and must send a HID feature report directly to the N-Key keyboard device instead. Add a module-level fnlock_hdev pointer (protected by a mutex) that is set at probe time for devices with QUIRK_HID_FN_LOCK and cleared at remove. Export asus_hid_fnlock_notify(bool) so that asus-armoury can call into hid-asus without a circular dependency. Signed-off-by: Marcus Grenängen <marcus@grenangen.se> --- drivers/hid/hid-asus.c | 43 +++++++++++++++++++++- include/linux/platform_data/x86/asus-wmi.h | 5 +++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index d34d74df3dc0..8a51dacf35eb 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -584,6 +584,38 @@ static void asus_sync_fn_lock(struct work_struct *work) asus_kbd_set_fn_lock(drvdata->hdev, drvdata->fn_lock); } +/* + * Module-level reference to the HID device that handles fn-lock via feature + * report. Set at probe and cleared at remove for QUIRK_HID_FN_LOCK devices. + * Protected by fnlock_hdev_lock. + */ +static DEFINE_MUTEX(fnlock_hdev_lock); +static struct hid_device *fnlock_hdev; + +/** + * asus_hid_fnlock_notify() - Set fn-lock state directly via HID feature report. + * @enabled: true to lock fn (F1-F12 primary), false to unlock. + * + * Called by asus-armoury on platforms where the WMI DEVS path for fn-lock is + * non-functional (e.g. ASUS ProArt P16, N-Key keyboard product ID 0x19B6). + * + * Returns 0 on success, -ENODEV if no fn-lock capable HID device is present. + */ +int asus_hid_fnlock_notify(bool enabled) +{ + int ret = -ENODEV; + + guard(mutex)(&fnlock_hdev_lock); + if (fnlock_hdev) { + ret = asus_kbd_set_fn_lock(fnlock_hdev, enabled); + /* hid_hw_raw_request returns byte count on success; normalise to 0 */ + if (ret > 0) + ret = 0; + } + return ret; +} +EXPORT_SYMBOL_GPL(asus_hid_fnlock_notify); + static void asus_schedule_work(struct asus_kbd_leds *led) { unsigned long flags; @@ -969,6 +1001,8 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) drvdata->fn_lock = true; INIT_WORK(&drvdata->fn_lock_sync_work, asus_sync_fn_lock); asus_kbd_set_fn_lock(hdev, true); + guard(mutex)(&fnlock_hdev_lock); + fnlock_hdev = hdev; } if (drvdata->tp) { @@ -1008,6 +1042,8 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) drvdata->fn_lock = true; INIT_WORK(&drvdata->fn_lock_sync_work, asus_sync_fn_lock); asus_kbd_set_fn_lock(hdev, true); + guard(mutex)(&fnlock_hdev_lock); + fnlock_hdev = hdev; } return 0; @@ -1362,8 +1398,13 @@ static void asus_remove(struct hid_device *hdev) cancel_work_sync(&drvdata->kbd_backlight->work); } - if (drvdata->quirks & QUIRK_HID_FN_LOCK) + if (drvdata->quirks & QUIRK_HID_FN_LOCK) { + scoped_guard(mutex, &fnlock_hdev_lock) { + if (fnlock_hdev == hdev) + fnlock_hdev = NULL; + } cancel_work_sync(&drvdata->fn_lock_sync_work); + } hid_hw_stop(hdev); } diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 554f41b827e1..20facd5da74e 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -196,6 +196,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval); int asus_hid_register_listener(struct asus_hid_listener *cdev); void asus_hid_unregister_listener(struct asus_hid_listener *cdev); int asus_hid_event(enum asus_hid_event event); +int asus_hid_fnlock_notify(bool enabled); #else static inline void set_ally_mcu_hack(enum asus_ally_mcu_hack status) { @@ -227,6 +228,10 @@ static inline int asus_hid_event(enum asus_hid_event event) { return -ENODEV; } +static inline int asus_hid_fnlock_notify(bool enabled) +{ + return -ENODEV; +} #endif #endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */ -- 2.54.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v2 1/3] HID: asus: export asus_hid_fnlock_notify() for direct fn-lock control 2026-05-06 19:33 ` [PATCH v2 1/3] HID: asus: export asus_hid_fnlock_notify() for direct fn-lock control Marcus Grenängen @ 2026-05-06 22:00 ` Randy Dunlap 2026-05-06 22:17 ` Denis Benato 1 sibling, 0 replies; 11+ messages in thread From: Randy Dunlap @ 2026-05-06 22:00 UTC (permalink / raw) To: Marcus Grenängen, platform-driver-x86, denis.benato Cc: linux-input, linux-kernel, luke, hansg, ilpo.jarvinen, jikos, bentiss, corentin.chary On 5/6/26 12:33 PM, Marcus Grenängen wrote: > +/** > + * asus_hid_fnlock_notify() - Set fn-lock state directly via HID feature report. > + * @enabled: true to lock fn (F1-F12 primary), false to unlock. > + * > + * Called by asus-armoury on platforms where the WMI DEVS path for fn-lock is > + * non-functional (e.g. ASUS ProArt P16, N-Key keyboard product ID 0x19B6). > + * > + * Returns 0 on success, -ENODEV if no fn-lock capable HID device is present. * Returns: ... > + */ > +int asus_hid_fnlock_notify(bool enabled) > +{ -- ~Randy ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 1/3] HID: asus: export asus_hid_fnlock_notify() for direct fn-lock control 2026-05-06 19:33 ` [PATCH v2 1/3] HID: asus: export asus_hid_fnlock_notify() for direct fn-lock control Marcus Grenängen 2026-05-06 22:00 ` Randy Dunlap @ 2026-05-06 22:17 ` Denis Benato 2026-05-07 9:29 ` [PATCH v3 0/3] platform/x86: fix fn-lock on ASUS ProArt P16 (WMI DEVS no-op) Marcus Grenängen 1 sibling, 1 reply; 11+ messages in thread From: Denis Benato @ 2026-05-06 22:17 UTC (permalink / raw) To: Marcus Grenängen, platform-driver-x86 Cc: linux-input, linux-kernel, luke, hansg, ilpo.jarvinen, jikos, bentiss, corentin.chary On 5/6/26 21:33, Marcus Grenängen wrote: > Some ASUS platforms cannot control fn-lock via WMI DEVS and must send a > HID feature report directly to the N-Key keyboard device instead. > > Add a module-level fnlock_hdev pointer (protected by a mutex) that is set > at probe time for devices with QUIRK_HID_FN_LOCK and cleared at remove. > Export asus_hid_fnlock_notify(bool) so that asus-armoury can call into > hid-asus without a circular dependency. > > Signed-off-by: Marcus Grenängen <marcus@grenangen.se> > --- > drivers/hid/hid-asus.c | 43 +++++++++++++++++++++- > include/linux/platform_data/x86/asus-wmi.h | 5 +++ > 2 files changed, 47 insertions(+), 1 deletion(-) > > diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c > index d34d74df3dc0..8a51dacf35eb 100644 > --- a/drivers/hid/hid-asus.c > +++ b/drivers/hid/hid-asus.c > @@ -584,6 +584,38 @@ static void asus_sync_fn_lock(struct work_struct *work) > asus_kbd_set_fn_lock(drvdata->hdev, drvdata->fn_lock); > } > > +/* > + * Module-level reference to the HID device that handles fn-lock via feature > + * report. Set at probe and cleared at remove for QUIRK_HID_FN_LOCK devices. > + * Protected by fnlock_hdev_lock. > + */ > +static DEFINE_MUTEX(fnlock_hdev_lock); > +static struct hid_device *fnlock_hdev; > + > +/** > + * asus_hid_fnlock_notify() - Set fn-lock state directly via HID feature report. > + * @enabled: true to lock fn (F1-F12 primary), false to unlock. > + * > + * Called by asus-armoury on platforms where the WMI DEVS path for fn-lock is > + * non-functional (e.g. ASUS ProArt P16, N-Key keyboard product ID 0x19B6). > + * > + * Returns 0 on success, -ENODEV if no fn-lock capable HID device is present. > + */ > +int asus_hid_fnlock_notify(bool enabled) Generally I see _notify naming being used for internal kernel messaging or to notify the sysfs of a change, can you change the name of this to something like asus_hid_fnlock_enable() or asys_hid_fnlock_set()? > +{ > + int ret = -ENODEV; > + > + guard(mutex)(&fnlock_hdev_lock); > + if (fnlock_hdev) { > + ret = asus_kbd_set_fn_lock(fnlock_hdev, enabled); > + /* hid_hw_raw_request returns byte count on success; normalise to 0 */ The pattern I see most ofter used is ret = operation() if (ret < 0) return ret; return 0; IMHO much easier to read and doesn't need a comment to explain. > + if (ret > 0) > + ret = 0; > + } > + return ret; > +} > +EXPORT_SYMBOL_GPL(asus_hid_fnlock_notify); > + > static void asus_schedule_work(struct asus_kbd_leds *led) > { > unsigned long flags; > @@ -969,6 +1001,8 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) > drvdata->fn_lock = true; > INIT_WORK(&drvdata->fn_lock_sync_work, asus_sync_fn_lock); > asus_kbd_set_fn_lock(hdev, true); > + guard(mutex)(&fnlock_hdev_lock); > + fnlock_hdev = hdev; > } > > if (drvdata->tp) { > @@ -1008,6 +1042,8 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) > drvdata->fn_lock = true; > INIT_WORK(&drvdata->fn_lock_sync_work, asus_sync_fn_lock); > asus_kbd_set_fn_lock(hdev, true); > + guard(mutex)(&fnlock_hdev_lock); > + fnlock_hdev = hdev; > } > > return 0; > @@ -1362,8 +1398,13 @@ static void asus_remove(struct hid_device *hdev) > cancel_work_sync(&drvdata->kbd_backlight->work); > } > > - if (drvdata->quirks & QUIRK_HID_FN_LOCK) > + if (drvdata->quirks & QUIRK_HID_FN_LOCK) { > + scoped_guard(mutex, &fnlock_hdev_lock) { > + if (fnlock_hdev == hdev) > + fnlock_hdev = NULL; > + } > cancel_work_sync(&drvdata->fn_lock_sync_work); > + } > > hid_hw_stop(hdev); > } > diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h > index 554f41b827e1..20facd5da74e 100644 > --- a/include/linux/platform_data/x86/asus-wmi.h > +++ b/include/linux/platform_data/x86/asus-wmi.h > @@ -196,6 +196,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval); > int asus_hid_register_listener(struct asus_hid_listener *cdev); > void asus_hid_unregister_listener(struct asus_hid_listener *cdev); > int asus_hid_event(enum asus_hid_event event); > +int asus_hid_fnlock_notify(bool enabled); > #else > static inline void set_ally_mcu_hack(enum asus_ally_mcu_hack status) > { > @@ -227,6 +228,10 @@ static inline int asus_hid_event(enum asus_hid_event event) > { > return -ENODEV; > } > +static inline int asus_hid_fnlock_notify(bool enabled) > +{ > + return -ENODEV; > +} > #endif > > #endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */ ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 0/3] platform/x86: fix fn-lock on ASUS ProArt P16 (WMI DEVS no-op) 2026-05-06 22:17 ` Denis Benato @ 2026-05-07 9:29 ` Marcus Grenängen 2026-05-07 9:29 ` [PATCH v3 1/3] HID: asus: export asus_hid_fnlock_set() for direct fn-lock control Marcus Grenängen ` (2 more replies) 0 siblings, 3 replies; 11+ messages in thread From: Marcus Grenängen @ 2026-05-07 9:29 UTC (permalink / raw) To: platform-driver-x86, denis.benato Cc: linux-input, linux-kernel, luke, hansg, ilpo.jarvinen, jikos, bentiss, corentin.chary, marcus Changes since v2 (addressing Denis's and Randy's review): Patch 1 (HID: asus): - Renamed asus_hid_fnlock_notify() to asus_hid_fnlock_set() (Denis) - Replaced "if (ret > 0) ret = 0" with "if (ret < 0) return ret; return 0;" pattern (Denis) - Fixed Returns tag format to "Returns:" (Randy) - Added #if IS_REACHABLE(CONFIG_HID_ASUS) guard for asus_hid_fnlock_set() declaration in asus-wmi.h so asus-wmi.c can call it without a missing prototype warning Patch 2 (asus-nb-wmi): - Added asus_wmi_fnlock_use_hid() export so asus-armoury can query the quirk flag without reading the quirk struct directly, keeping DMI and quirk knowledge inside asus-wmi (Denis) - Fixed Returns tag format to "Returns:" (Randy) Patch 3 (asus-armoury): - Replaced the stored fnlock_use_hid flag and dmi_match() call with asus_wmi_fnlock_use_hid(), routing the DMI/quirk check through asus-wmi as Denis suggested - Added fn_lock_registered bool to properly guard sysfs_remove_group in both the error unwind path and __exit, mirroring the gpu_mux/mini_led pattern (Denis) - NOTE/Question: Since we have proper fn+esc hardware key handling working now we could eliminate this patch completely if we don't care about being able to control the fn state from user space eg. asusctl and/or rog control center? The nice thing of having it controllable via asusctl is the scripting possibilibilities like setting prefered mode when starting a DE as one example. Regarding the if/else dispatch in fn_lock_current_value_store: Denis suggested routing everything through a single asus_wmi_fnlock_set() exported from asus-wmi. This was implemented but had to be reverted: it introduced a module dependency cycle (hid_asus -> asus_wmi -> hid_asus) that depmod detects and rejects. asus-armoury therefore retains the if/else, calling asus_hid_fnlock_set() on HID-path platforms and armoury_set_devstate() on WMI-path platforms. The asus-armoury -> hid-asus dependency is a soft one (the stub in asus-wmi.h returns -ENODEV when CONFIG_HID_ASUS is not reachable). But since I'm new to this maybe I'm missing something critical here? Marcus Grenängen (3): HID: asus: export asus_hid_fnlock_set() for direct fn-lock control platform/x86: asus-nb-wmi: add fnlock_use_hid quirk and asus_wmi_fnlock_use_hid() platform/x86: asus-armoury: add fn_lock firmware attribute drivers/hid/hid-asus.c | 44 ++++++++++++++++++- drivers/platform/x86/asus-armoury.c | 70 ++++++++++++++++++++++++++++++ drivers/platform/x86/asus-nb-wmi.c | 13 ++++++ drivers/platform/x86/asus-wmi.c | 22 ++++++++++ drivers/platform/x86/asus-wmi.h | 5 +++ include/linux/platform_data/x86/asus-wmi.h | 15 +++++++ 6 files changed, 168 insertions(+), 1 deletion(-) -- 2.54.0 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 1/3] HID: asus: export asus_hid_fnlock_set() for direct fn-lock control 2026-05-07 9:29 ` [PATCH v3 0/3] platform/x86: fix fn-lock on ASUS ProArt P16 (WMI DEVS no-op) Marcus Grenängen @ 2026-05-07 9:29 ` Marcus Grenängen 2026-05-07 9:29 ` [PATCH v3 2/3] platform/x86: asus-nb-wmi: add fnlock_use_hid quirk and asus_wmi_fnlock_use_hid() Marcus Grenängen 2026-05-07 9:29 ` [PATCH v3 3/3] platform/x86: asus-armoury: add fn_lock firmware attribute Marcus Grenängen 2 siblings, 0 replies; 11+ messages in thread From: Marcus Grenängen @ 2026-05-07 9:29 UTC (permalink / raw) To: platform-driver-x86, denis.benato Cc: linux-input, linux-kernel, luke, hansg, ilpo.jarvinen, jikos, bentiss, corentin.chary, marcus Some ASUS platforms cannot control fn-lock via WMI DEVS and must send a HID feature report directly to the N-Key keyboard device instead. Add a module-level fnlock_hdev pointer (protected by a mutex) that is set at probe time for devices with QUIRK_HID_FN_LOCK and cleared at remove. Export asus_hid_fnlock_set(bool) so that asus-armoury can call into hid-asus without a circular dependency. Signed-off-by: Marcus Grenängen <marcus@grenangen.se> --- drivers/hid/hid-asus.c | 44 +++++++++++++++++++++- include/linux/platform_data/x86/asus-wmi.h | 15 ++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index d34d74df3dc0..402ba9d5e982 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -584,6 +584,39 @@ static void asus_sync_fn_lock(struct work_struct *work) asus_kbd_set_fn_lock(drvdata->hdev, drvdata->fn_lock); } +/* + * Module-level reference to the HID device that handles fn-lock via feature + * report. Set at probe and cleared at remove for QUIRK_HID_FN_LOCK devices. + * Protected by fnlock_hdev_lock. + */ +static DEFINE_MUTEX(fnlock_hdev_lock); +static struct hid_device *fnlock_hdev; + +/** + * asus_hid_fnlock_set() - Set fn-lock state directly via HID feature report. + * @enabled: true to lock fn (F1-F12 primary), false to unlock. + * + * Called by asus-armoury on platforms where the WMI DEVS path for fn-lock is + * non-functional (e.g. ASUS ProArt P16, N-Key keyboard product ID 0x19B6). + * + * Returns: 0 on success, -ENODEV if no fn-lock capable HID device is present. + */ +int asus_hid_fnlock_set(bool enabled) +{ + int ret; + + guard(mutex)(&fnlock_hdev_lock); + if (!fnlock_hdev) + return -ENODEV; + + ret = asus_kbd_set_fn_lock(fnlock_hdev, enabled); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL_GPL(asus_hid_fnlock_set); + static void asus_schedule_work(struct asus_kbd_leds *led) { unsigned long flags; @@ -969,6 +1002,8 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) drvdata->fn_lock = true; INIT_WORK(&drvdata->fn_lock_sync_work, asus_sync_fn_lock); asus_kbd_set_fn_lock(hdev, true); + guard(mutex)(&fnlock_hdev_lock); + fnlock_hdev = hdev; } if (drvdata->tp) { @@ -1008,6 +1043,8 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) drvdata->fn_lock = true; INIT_WORK(&drvdata->fn_lock_sync_work, asus_sync_fn_lock); asus_kbd_set_fn_lock(hdev, true); + guard(mutex)(&fnlock_hdev_lock); + fnlock_hdev = hdev; } return 0; @@ -1362,8 +1399,13 @@ static void asus_remove(struct hid_device *hdev) cancel_work_sync(&drvdata->kbd_backlight->work); } - if (drvdata->quirks & QUIRK_HID_FN_LOCK) + if (drvdata->quirks & QUIRK_HID_FN_LOCK) { + scoped_guard(mutex, &fnlock_hdev_lock) { + if (fnlock_hdev == hdev) + fnlock_hdev = NULL; + } cancel_work_sync(&drvdata->fn_lock_sync_work); + } hid_hw_stop(hdev); } diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 554f41b827e1..a88bf03f9c4d 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -187,6 +187,15 @@ enum asus_hid_event { #define ASUS_EV_MAX_BRIGHTNESS 3 +#if IS_REACHABLE(CONFIG_HID_ASUS) +int asus_hid_fnlock_set(bool enabled); +#else +static inline int asus_hid_fnlock_set(bool enabled) +{ + return -ENODEV; +} +#endif + #if IS_REACHABLE(CONFIG_ASUS_WMI) void set_ally_mcu_hack(enum asus_ally_mcu_hack status); void set_ally_mcu_powersave(bool enabled); @@ -196,6 +205,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval); int asus_hid_register_listener(struct asus_hid_listener *cdev); void asus_hid_unregister_listener(struct asus_hid_listener *cdev); int asus_hid_event(enum asus_hid_event event); +int asus_hid_fnlock_set(bool enabled); #else static inline void set_ally_mcu_hack(enum asus_ally_mcu_hack status) { @@ -227,6 +237,11 @@ static inline int asus_hid_event(enum asus_hid_event event) { return -ENODEV; } + +static inline int asus_hid_fnlock_set(bool enabled) +{ + return -ENODEV; +} #endif #endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */ -- 2.54.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 2/3] platform/x86: asus-nb-wmi: add fnlock_use_hid quirk and asus_wmi_fnlock_use_hid() 2026-05-07 9:29 ` [PATCH v3 0/3] platform/x86: fix fn-lock on ASUS ProArt P16 (WMI DEVS no-op) Marcus Grenängen 2026-05-07 9:29 ` [PATCH v3 1/3] HID: asus: export asus_hid_fnlock_set() for direct fn-lock control Marcus Grenängen @ 2026-05-07 9:29 ` Marcus Grenängen 2026-05-07 9:29 ` [PATCH v3 3/3] platform/x86: asus-armoury: add fn_lock firmware attribute Marcus Grenängen 2 siblings, 0 replies; 11+ messages in thread From: Marcus Grenängen @ 2026-05-07 9:29 UTC (permalink / raw) To: platform-driver-x86, denis.benato Cc: linux-input, linux-kernel, luke, hansg, ilpo.jarvinen, jikos, bentiss, corentin.chary, marcus The ASUS ProArt P16 (N-Key keyboard 0B05:19B6) advertises the WMI fn-lock DEVID (0x00100023) as present via DSTS, but the DEVS call has no effect. Fn-lock must instead be toggled via a HID feature report sent to the N-Key keyboard (handled by hid-asus). Add a fnlock_use_hid flag to struct quirk_entry and set it for the ProArt P16 via a DMI match on DMI_PRODUCT_FAMILY. Export asus_wmi_fnlock_use_hid() so that asus-armoury can query whether the HID path is required without reading the quirk struct directly. This keeps the DMI and quirk knowledge inside asus-wmi. Signed-off-by: Marcus Grenängen <marcus@grenangen.se> --- drivers/platform/x86/asus-nb-wmi.c | 13 +++++++++++++ drivers/platform/x86/asus-wmi.c | 22 ++++++++++++++++++++++ drivers/platform/x86/asus-wmi.h | 5 +++++ include/linux/platform_data/x86/asus-wmi.h | 6 +++--- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index b4677c5bba5b..44e4cf68ff70 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -155,6 +155,10 @@ static struct quirk_entry quirk_asus_z13 = { .tablet_switch_mode = asus_wmi_kbd_dock_devid, }; +static struct quirk_entry quirk_asus_proart_p16 = { + .fnlock_use_hid = true, +}; + static int dmi_matched(const struct dmi_system_id *dmi) { pr_info("Identified laptop model '%s'\n", dmi->ident); @@ -553,6 +557,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_z13, }, + { + .callback = dmi_matched, + .ident = "ASUS ProArt P16", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_FAMILY, "ProArt P16"), + }, + .driver_data = &quirk_asus_proart_p16, + }, {}, }; diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 80144c412b90..d4d742b9983d 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1759,6 +1759,28 @@ int asus_hid_event(enum asus_hid_event event) } EXPORT_SYMBOL_GPL(asus_hid_event); +/** + * asus_wmi_fnlock_use_hid() - Return true if fn-lock must use the HID path. + * + * On some platforms (e.g. ASUS ProArt P16) the WMI DEVS call for fn-lock is + * silently a no-op. The fnlock_use_hid quirk flag marks these platforms so + * that callers can select the HID feature-report path instead. + * + * Returns: true if the HID path should be used, false otherwise. + */ +bool asus_wmi_fnlock_use_hid(void) +{ + struct asus_wmi *asus; + + guard(spinlock_irqsave)(&asus_ref.lock); + asus = asus_ref.asus; + if (!asus) + return false; + + return asus->driver->quirks->fnlock_use_hid; +} +EXPORT_SYMBOL_NS_GPL(asus_wmi_fnlock_use_hid, "ASUS_WMI"); + /* * These functions actually update the LED's, and are called from a * workqueue. By doing this as separate work rather than when the LED diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 5cd4392b964e..6c50b11860e8 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -52,6 +52,11 @@ struct quirk_entry { */ int no_display_toggle; u32 xusb2pr; + /* + * Some platforms report WMI DEVID_FNLOCK as present but the DEVS call + * is a no-op. Force the HID feature report path via hid-asus instead. + */ + bool fnlock_use_hid; }; struct asus_wmi_driver { diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index a88bf03f9c4d..199179266363 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -205,7 +205,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval); int asus_hid_register_listener(struct asus_hid_listener *cdev); void asus_hid_unregister_listener(struct asus_hid_listener *cdev); int asus_hid_event(enum asus_hid_event event); -int asus_hid_fnlock_set(bool enabled); +bool asus_wmi_fnlock_use_hid(void); #else static inline void set_ally_mcu_hack(enum asus_ally_mcu_hack status) { @@ -238,9 +238,9 @@ static inline int asus_hid_event(enum asus_hid_event event) return -ENODEV; } -static inline int asus_hid_fnlock_set(bool enabled) +static inline bool asus_wmi_fnlock_use_hid(void) { - return -ENODEV; + return false; } #endif -- 2.54.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 3/3] platform/x86: asus-armoury: add fn_lock firmware attribute 2026-05-07 9:29 ` [PATCH v3 0/3] platform/x86: fix fn-lock on ASUS ProArt P16 (WMI DEVS no-op) Marcus Grenängen 2026-05-07 9:29 ` [PATCH v3 1/3] HID: asus: export asus_hid_fnlock_set() for direct fn-lock control Marcus Grenängen 2026-05-07 9:29 ` [PATCH v3 2/3] platform/x86: asus-nb-wmi: add fnlock_use_hid quirk and asus_wmi_fnlock_use_hid() Marcus Grenängen @ 2026-05-07 9:29 ` Marcus Grenängen 2 siblings, 0 replies; 11+ messages in thread From: Marcus Grenängen @ 2026-05-07 9:29 UTC (permalink / raw) To: platform-driver-x86, denis.benato Cc: linux-input, linux-kernel, luke, hansg, ilpo.jarvinen, jikos, bentiss, corentin.chary, marcus Add a fn_lock attribute to the asus-armoury firmware-attributes interface, allowing userspace to read and set the Fn-lock state (whether F1-F12 keys are primary or media/system keys are primary). On most ASUS laptops fn-lock is backed by WMI DEVID 0x00100023. On platforms where that DEVS call is a no-op (fnlock_use_hid quirk), the store path dispatches via asus_wmi_fnlock_set(), which selects the HID feature-report path internally. The show path returns -EOPNOTSUPP on such platforms as the hardware provides no readback. The attribute is only registered when the platform actually supports fn-lock, either via the HID quirk (asus_wmi_fnlock_use_hid()) or a functional WMI DEVID (armoury_has_devstate(ASUS_WMI_DEVID_FNLOCK)). Registration state is tracked in fn_lock_registered so that removal in the exit path is symmetric. Signed-off-by: Marcus Grenängen <marcus@grenangen.se> --- drivers/platform/x86/asus-armoury.c | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c index 5b0987ccc270..fb8ad3b14aad 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c @@ -93,6 +93,7 @@ struct asus_armoury_priv { u32 mini_led_dev_id; u32 gpu_mux_dev_id; + bool fn_lock_registered; }; static struct asus_armoury_priv asus_armoury = { @@ -778,6 +779,58 @@ ASUS_ATTR_GROUP_ROG_TUNABLE(nv_tgp, "nv_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(nv_base_tgp, ATTR_NV_BASE_TGP, ASUS_WMI_DEVID_DGPU_BASE_TGP, "Read the base TGP value"); +/* + * fn_lock: toggle whether Fn key is locked (F1-F12 primary) or unlocked + * (media/system keys primary). + * + * On most ASUS laptops this is backed by WMI DEVID 0x00100023. On some + * platforms (e.g. ProArt P16) that DEVS call is a no-op and the state must + * be sent as a HID feature report to the N-Key keyboard via hid-asus. + */ +static ssize_t fn_lock_current_value_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + u32 result; + int err; + + if (asus_wmi_fnlock_use_hid()) + return -EOPNOTSUPP; + + err = armoury_get_devstate(attr, &result, ASUS_WMI_DEVID_FNLOCK); + if (err) + return err; + + return sysfs_emit(buf, "%u\n", result & 1); +} + +static ssize_t fn_lock_current_value_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + bool enable; + int err; + + err = kstrtobool(buf, &enable); + if (err) + return err; + + if (asus_wmi_fnlock_use_hid()) { + err = asus_hid_fnlock_set(enable); + if (err) + return err; + } else { + err = armoury_set_devstate(attr, enable ? 1 : 0, NULL, + ASUS_WMI_DEVID_FNLOCK); + if (err) + return err; + } + + sysfs_notify(kobj, NULL, attr->attr.name); + return count; +} + +ASUS_ATTR_GROUP_BOOL(fn_lock, "fn_lock", "Set the Fn-lock state"); + /* If an attribute does not require any special case handling add it here */ static const struct asus_attr_group armoury_attr_groups[] = { { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED }, @@ -926,6 +979,17 @@ static int asus_fw_attr_add(void) } } + if (asus_wmi_fnlock_use_hid() || + armoury_has_devstate(ASUS_WMI_DEVID_FNLOCK)) { + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, + &fn_lock_attr_group); + if (err) { + pr_err("Failed to create sysfs-group for fn_lock\n"); + goto err_remove_gpu_mux_group; + } + asus_armoury.fn_lock_registered = true; + } + for (i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) { if (!armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) continue; @@ -963,6 +1027,9 @@ static int asus_fw_attr_add(void) sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, armoury_attr_groups[i].attr_group); } + if (asus_armoury.fn_lock_registered) + sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &fn_lock_attr_group); +err_remove_gpu_mux_group: if (asus_armoury.gpu_mux_dev_id) sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); err_remove_mini_led_group: @@ -1138,6 +1205,9 @@ static void __exit asus_fw_exit(void) if (asus_armoury.gpu_mux_dev_id) sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); + if (asus_armoury.fn_lock_registered) + sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &fn_lock_attr_group); + if (asus_armoury.mini_led_dev_id) sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr_group); -- 2.54.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 2/3] platform/x86: asus-nb-wmi: add fnlock_use_hid quirk for ProArt P16 2026-05-06 19:33 ` [PATCH v2 0/3] platform/x86: fix fn-lock on ASUS ProArt P16 (WMI DEVS no-op) Marcus Grenängen 2026-05-06 19:33 ` [PATCH v2 1/3] HID: asus: export asus_hid_fnlock_notify() for direct fn-lock control Marcus Grenängen @ 2026-05-06 19:33 ` Marcus Grenängen 2026-05-06 19:33 ` [PATCH v2 3/3] platform/x86: asus-armoury: add fn_lock firmware attribute Marcus Grenängen 2 siblings, 0 replies; 11+ messages in thread From: Marcus Grenängen @ 2026-05-06 19:33 UTC (permalink / raw) To: platform-driver-x86, denis.benato Cc: linux-input, linux-kernel, luke, hansg, ilpo.jarvinen, jikos, bentiss, corentin.chary, marcus The ASUS ProArt P16 (N-Key keyboard 0B05:19B6) advertises the WMI fn-lock DEVID (0x00100023) as present via DSTS, but the DEVS call has no effect. Fn-lock must instead be toggled via a HID feature report sent to the N-Key keyboard (handled by hid-asus). Add a fnlock_use_hid flag to struct quirk_entry and set it for the ProArt P16 via a DMI match on DMI_PRODUCT_FAMILY. This flag is consumed by asus-armoury to select the HID path instead of WMI DEVS. Signed-off-by: Marcus Grenängen <marcus@grenangen.se> --- drivers/platform/x86/asus-nb-wmi.c | 13 +++++++++++++ drivers/platform/x86/asus-wmi.h | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index b4677c5bba5b..44e4cf68ff70 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -155,6 +155,10 @@ static struct quirk_entry quirk_asus_z13 = { .tablet_switch_mode = asus_wmi_kbd_dock_devid, }; +static struct quirk_entry quirk_asus_proart_p16 = { + .fnlock_use_hid = true, +}; + static int dmi_matched(const struct dmi_system_id *dmi) { pr_info("Identified laptop model '%s'\n", dmi->ident); @@ -553,6 +557,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_z13, }, + { + .callback = dmi_matched, + .ident = "ASUS ProArt P16", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_FAMILY, "ProArt P16"), + }, + .driver_data = &quirk_asus_proart_p16, + }, {}, }; diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 5cd4392b964e..6c50b11860e8 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -52,6 +52,11 @@ struct quirk_entry { */ int no_display_toggle; u32 xusb2pr; + /* + * Some platforms report WMI DEVID_FNLOCK as present but the DEVS call + * is a no-op. Force the HID feature report path via hid-asus instead. + */ + bool fnlock_use_hid; }; struct asus_wmi_driver { -- 2.54.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 3/3] platform/x86: asus-armoury: add fn_lock firmware attribute 2026-05-06 19:33 ` [PATCH v2 0/3] platform/x86: fix fn-lock on ASUS ProArt P16 (WMI DEVS no-op) Marcus Grenängen 2026-05-06 19:33 ` [PATCH v2 1/3] HID: asus: export asus_hid_fnlock_notify() for direct fn-lock control Marcus Grenängen 2026-05-06 19:33 ` [PATCH v2 2/3] platform/x86: asus-nb-wmi: add fnlock_use_hid quirk for ProArt P16 Marcus Grenängen @ 2026-05-06 19:33 ` Marcus Grenängen 2026-05-06 22:10 ` Denis Benato 2 siblings, 1 reply; 11+ messages in thread From: Marcus Grenängen @ 2026-05-06 19:33 UTC (permalink / raw) To: platform-driver-x86, denis.benato Cc: linux-input, linux-kernel, luke, hansg, ilpo.jarvinen, jikos, bentiss, corentin.chary, marcus Add a fn_lock attribute to the asus-armoury firmware-attributes interface, allowing userspace to read and set the Fn-lock state (whether F1-F12 keys are primary or media/system keys are primary). On most ASUS laptops fn-lock is backed by WMI DEVID 0x00100023 and the attribute uses armoury_get/set_devstate() as normal. On platforms where the WMI DEVS call is a no-op (fnlock_use_hid quirk, e.g. ProArt P16), the store path calls asus_hid_fnlock_notify() to send the feature report directly to the N-Key keyboard via hid-asus. The show path returns -EOPNOTSUPP on such platforms as the hardware provides no readback. The fnlock_use_hid flag is detected at init time via dmi_match() on DMI_PRODUCT_FAMILY. A direct DMI check is used rather than reading the asus-nb-wmi quirk flag because asus-armoury and asus-nb-wmi are both loadable modules at the same init level, so the asus_ref pointer set by asus-wmi may not yet be valid when asus-armoury initialises. Signed-off-by: Marcus Grenängen <marcus@grenangen.se> --- drivers/platform/x86/asus-armoury.c | 69 +++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c index 5b0987ccc270..9d7646eff944 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c @@ -93,6 +93,7 @@ struct asus_armoury_priv { u32 mini_led_dev_id; u32 gpu_mux_dev_id; + bool fnlock_use_hid; }; static struct asus_armoury_priv asus_armoury = { @@ -778,6 +779,58 @@ ASUS_ATTR_GROUP_ROG_TUNABLE(nv_tgp, "nv_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(nv_base_tgp, ATTR_NV_BASE_TGP, ASUS_WMI_DEVID_DGPU_BASE_TGP, "Read the base TGP value"); +/* + * fn_lock: toggle whether Fn key is locked (F1-F12 primary) or unlocked + * (media/system keys primary). + * + * On most ASUS laptops this is backed by WMI DEVID 0x00100023. On some + * platforms (e.g. ProArt P16) that DEVS call is a no-op and the state must + * be sent as a HID feature report to the N-Key keyboard via hid-asus. + */ +static ssize_t fn_lock_current_value_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + u32 result; + int err; + + if (asus_armoury.fnlock_use_hid) + return -EOPNOTSUPP; + + err = armoury_get_devstate(attr, &result, ASUS_WMI_DEVID_FNLOCK); + if (err) + return err; + + return sysfs_emit(buf, "%u\n", result & 1); +} + +static ssize_t fn_lock_current_value_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + bool enable; + int err; + + err = kstrtobool(buf, &enable); + if (err) + return err; + + if (asus_armoury.fnlock_use_hid) { + err = asus_hid_fnlock_notify(enable); + if (err) + return err; + } else { + err = armoury_set_devstate(attr, enable ? 1 : 0, NULL, + ASUS_WMI_DEVID_FNLOCK); + if (err) + return err; + } + + sysfs_notify(kobj, NULL, attr->attr.name); + return count; +} + +ASUS_ATTR_GROUP_BOOL(fn_lock, "fn_lock", "Set the Fn-lock state"); + /* If an attribute does not require any special case handling add it here */ static const struct asus_attr_group armoury_attr_groups[] = { { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED }, @@ -926,6 +979,16 @@ static int asus_fw_attr_add(void) } } + if (asus_armoury.fnlock_use_hid || + armoury_has_devstate(ASUS_WMI_DEVID_FNLOCK)) { + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, + &fn_lock_attr_group); + if (err) { + pr_err("Failed to create sysfs-group for fn_lock\n"); + goto err_remove_gpu_mux_group; + } + } + for (i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) { if (!armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) continue; @@ -963,6 +1026,8 @@ static int asus_fw_attr_add(void) sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, armoury_attr_groups[i].attr_group); } + sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &fn_lock_attr_group); +err_remove_gpu_mux_group: if (asus_armoury.gpu_mux_dev_id) sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); err_remove_mini_led_group: @@ -1121,6 +1186,8 @@ static int __init asus_fw_init(void) init_rog_tunables(); + asus_armoury.fnlock_use_hid = dmi_match(DMI_PRODUCT_FAMILY, "ProArt P16"); + /* Must always be last step to ensure data is available */ return asus_fw_attr_add(); } @@ -1138,6 +1205,8 @@ static void __exit asus_fw_exit(void) if (asus_armoury.gpu_mux_dev_id) sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); + sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &fn_lock_attr_group); + if (asus_armoury.mini_led_dev_id) sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr_group); -- 2.54.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v2 3/3] platform/x86: asus-armoury: add fn_lock firmware attribute 2026-05-06 19:33 ` [PATCH v2 3/3] platform/x86: asus-armoury: add fn_lock firmware attribute Marcus Grenängen @ 2026-05-06 22:10 ` Denis Benato 0 siblings, 0 replies; 11+ messages in thread From: Denis Benato @ 2026-05-06 22:10 UTC (permalink / raw) To: Marcus Grenängen, platform-driver-x86 Cc: linux-input, linux-kernel, luke, hansg, ilpo.jarvinen, jikos, bentiss, corentin.chary On 5/6/26 21:33, Marcus Grenängen wrote: > Add a fn_lock attribute to the asus-armoury firmware-attributes interface, > allowing userspace to read and set the Fn-lock state (whether F1-F12 keys > are primary or media/system keys are primary). > > On most ASUS laptops fn-lock is backed by WMI DEVID 0x00100023 and the > attribute uses armoury_get/set_devstate() as normal. On platforms where > the WMI DEVS call is a no-op (fnlock_use_hid quirk, e.g. ProArt P16), the > store path calls asus_hid_fnlock_notify() to send the feature report > directly to the N-Key keyboard via hid-asus. The show path returns > -EOPNOTSUPP on such platforms as the hardware provides no readback. > > The fnlock_use_hid flag is detected at init time via dmi_match() on > DMI_PRODUCT_FAMILY. A direct DMI check is used rather than reading the > asus-nb-wmi quirk flag because asus-armoury and asus-nb-wmi are both > loadable modules at the same init level, so the asus_ref pointer set by > asus-wmi may not yet be valid when asus-armoury initialises. > > Signed-off-by: Marcus Grenängen <marcus@grenangen.se> > --- > drivers/platform/x86/asus-armoury.c | 69 +++++++++++++++++++++++++++++ > 1 file changed, 69 insertions(+) > > diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c > index 5b0987ccc270..9d7646eff944 100644 > --- a/drivers/platform/x86/asus-armoury.c > +++ b/drivers/platform/x86/asus-armoury.c > @@ -93,6 +93,7 @@ struct asus_armoury_priv { > > u32 mini_led_dev_id; > u32 gpu_mux_dev_id; > + bool fnlock_use_hid; > }; > > static struct asus_armoury_priv asus_armoury = { > @@ -778,6 +779,58 @@ ASUS_ATTR_GROUP_ROG_TUNABLE(nv_tgp, "nv_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, > ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(nv_base_tgp, ATTR_NV_BASE_TGP, ASUS_WMI_DEVID_DGPU_BASE_TGP, > "Read the base TGP value"); > > +/* > + * fn_lock: toggle whether Fn key is locked (F1-F12 primary) or unlocked > + * (media/system keys primary). > + * > + * On most ASUS laptops this is backed by WMI DEVID 0x00100023. On some > + * platforms (e.g. ProArt P16) that DEVS call is a no-op and the state must > + * be sent as a HID feature report to the N-Key keyboard via hid-asus. > + */ > +static ssize_t fn_lock_current_value_show(struct kobject *kobj, > + struct kobj_attribute *attr, char *buf) > +{ > + u32 result; > + int err; > + > + if (asus_armoury.fnlock_use_hid) > + return -EOPNOTSUPP; > + > + err = armoury_get_devstate(attr, &result, ASUS_WMI_DEVID_FNLOCK); > + if (err) > + return err; > + > + return sysfs_emit(buf, "%u\n", result & 1); > +} > + > +static ssize_t fn_lock_current_value_store(struct kobject *kobj, > + struct kobj_attribute *attr, > + const char *buf, size_t count) > +{ > + bool enable; > + int err; > + > + err = kstrtobool(buf, &enable); > + if (err) > + return err; > + > + if (asus_armoury.fnlock_use_hid) { > + err = asus_hid_fnlock_notify(enable); Doing this would introduce a dependency from asus-armoury to hid-asus, let's not do that. Instead only show this attribute if it's actually doing something, you can check it from asus-wmi: asus-armoury already depends on it. Edit: you are actually already registering this only if fnlock_use_hid is true, so the else looks dead code to me. I think there is something not right here. > + if (err) > + return err; > + } else { > + err = armoury_set_devstate(attr, enable ? 1 : 0, NULL, > + ASUS_WMI_DEVID_FNLOCK); > + if (err) > + return err; > + } > + > + sysfs_notify(kobj, NULL, attr->attr.name); > + return count; > +} > + > +ASUS_ATTR_GROUP_BOOL(fn_lock, "fn_lock", "Set the Fn-lock state"); > + > /* If an attribute does not require any special case handling add it here */ > static const struct asus_attr_group armoury_attr_groups[] = { > { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED }, > @@ -926,6 +979,16 @@ static int asus_fw_attr_add(void) > } > } > > + if (asus_armoury.fnlock_use_hid || > + armoury_has_devstate(ASUS_WMI_DEVID_FNLOCK)) { > + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, > + &fn_lock_attr_group); > + if (err) { > + pr_err("Failed to create sysfs-group for fn_lock\n"); > + goto err_remove_gpu_mux_group; > + } > + } > + > for (i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) { > if (!armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) > continue; > @@ -963,6 +1026,8 @@ static int asus_fw_attr_add(void) > sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, > armoury_attr_groups[i].attr_group); > } > + sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &fn_lock_attr_group); > +err_remove_gpu_mux_group: > if (asus_armoury.gpu_mux_dev_id) > sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); > err_remove_mini_led_group: > @@ -1121,6 +1186,8 @@ static int __init asus_fw_init(void) > > init_rog_tunables(); > > + asus_armoury.fnlock_use_hid = dmi_match(DMI_PRODUCT_FAMILY, "ProArt P16"); Perhaps you can reuse something from asus-wmi instead of re-doing the dmi_match again in this driver. > + > /* Must always be last step to ensure data is available */ > return asus_fw_attr_add(); > } > @@ -1138,6 +1205,8 @@ static void __exit asus_fw_exit(void) > if (asus_armoury.gpu_mux_dev_id) > sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); > > + sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &fn_lock_attr_group); Not guarded the same way as the sysfs_create_group therefore will trigger on hardware that doesn't need this. > + > if (asus_armoury.mini_led_dev_id) > sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr_group); > ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-05-07 9:29 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <458d9e6c-8702-4cbc-9c4f-33cbd1175e67@linux.dev>
2026-05-06 19:33 ` [PATCH v2 0/3] platform/x86: fix fn-lock on ASUS ProArt P16 (WMI DEVS no-op) Marcus Grenängen
2026-05-06 19:33 ` [PATCH v2 1/3] HID: asus: export asus_hid_fnlock_notify() for direct fn-lock control Marcus Grenängen
2026-05-06 22:00 ` Randy Dunlap
2026-05-06 22:17 ` Denis Benato
2026-05-07 9:29 ` [PATCH v3 0/3] platform/x86: fix fn-lock on ASUS ProArt P16 (WMI DEVS no-op) Marcus Grenängen
2026-05-07 9:29 ` [PATCH v3 1/3] HID: asus: export asus_hid_fnlock_set() for direct fn-lock control Marcus Grenängen
2026-05-07 9:29 ` [PATCH v3 2/3] platform/x86: asus-nb-wmi: add fnlock_use_hid quirk and asus_wmi_fnlock_use_hid() Marcus Grenängen
2026-05-07 9:29 ` [PATCH v3 3/3] platform/x86: asus-armoury: add fn_lock firmware attribute Marcus Grenängen
2026-05-06 19:33 ` [PATCH v2 2/3] platform/x86: asus-nb-wmi: add fnlock_use_hid quirk for ProArt P16 Marcus Grenängen
2026-05-06 19:33 ` [PATCH v2 3/3] platform/x86: asus-armoury: add fn_lock firmware attribute Marcus Grenängen
2026-05-06 22:10 ` Denis Benato
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox