From nobody Sat May 30 10:31:53 2026 Received: from smtp-out1.simply.com (smtp-out1.simply.com [94.231.106.240]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 68A4C396B96; Thu, 7 May 2026 09:29:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=94.231.106.240 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778146158; cv=none; b=dDCL7WUHAef3WUagbGGw0Tb/EVeCZCZuRVEOP7ZiOuoia5JQisySfmWusXRGy0MGPLyWICpjysf3zEsW6WiR08Cz2U9USdb3esP69p+bKTj0akCVk9Dq8URZGUwN+1FJXAw8NJBeJpuB7eefMUJPvnS+Eq8sPTugcxHaTM/22Fw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778146158; c=relaxed/simple; bh=WmBA/cdts7TpWshnugPsPP4SKjn7Xg2bogioVbUvU1M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=LIO6Enn7O1X6PqZlotE1r9EGrJiCDSjndnRONY1kSDlNyHsfVtyNFt7rECWIJrZMchBRsU/83K9wJOeHSJibvNq240c4nTeD1LDpXnajqONgpe4LHfI1kzTiy2MZvRTNs2b333/h3BRe92ZajcLawSNvPRuy4lczJ1uVLsMKCdM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grenangen.se; spf=pass smtp.mailfrom=grenangen.se; dkim=pass (2048-bit key) header.d=grenangen.se header.i=@grenangen.se header.b=CsB14cwp; arc=none smtp.client-ip=94.231.106.240 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grenangen.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=grenangen.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=grenangen.se header.i=@grenangen.se header.b="CsB14cwp" Received: from localhost (localhost [127.0.0.1]) by smtp.simply.com (Simply.com) with ESMTP id 4gB6QJ4Ymvz1FXZf; Thu, 7 May 2026 11:29:12 +0200 (CEST) Received: from localhost (h-217-27-171-125.A498.priv.bahnhof.se [217.27.171.125]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (Client did not present a certificate) by smtp.simply.com (Simply.com) with ESMTPSA id 4gB6QJ1n7Rz1FXZc; Thu, 7 May 2026 11:29:12 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=grenangen.se; s=simplycom2; t=1778146152; bh=aiQQKgFgDvBFT8PPKxdPbvvpVBQA2jWnQMNIjzW2a7E=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=CsB14cwpFGsT1317COWITaK+M3BdN4oKMha0SgjMhX/Am1RSO7faBcddLXxuYip8s 1kS1mZgtka8v7n2crkYRzG3VG9atakzB1cqMAMi3mr77MyrJShwYVZZhBc3/7bzopX i3ZsmjnetTGXj5PSDTqUp0Oavd/adITvD/opO0N1ZbPd4ccsOBoNKDsl0206I4IIgF Z4+x1RadcAPPZDI3e0ZESN+nNXP4Z7yl2COflgY2QKwbmwIxXlobkFiD4tfNl5f5mr iI3ecOE4gdZFj3MGpsZPyVNsxRnv3zbj1Y0PbvFKbu7UcdkkXAyxbI7O2ZEv+daXDx oCRdVIYf3Wbkw== From: =?UTF-8?q?Marcus=20Gren=C3=A4ngen?= To: platform-driver-x86@vger.kernel.org, denis.benato@linux.dev Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, luke@ljones.dev, hansg@kernel.org, ilpo.jarvinen@linux.intel.com, jikos@kernel.org, bentiss@kernel.org, corentin.chary@gmail.com, marcus@grenangen.se Subject: [PATCH v3 1/3] HID: asus: export asus_hid_fnlock_set() for direct fn-lock control Date: Thu, 7 May 2026 11:29:09 +0200 Message-ID: <20260507092911.8855-2-marcus@grenangen.se> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260507092911.8855-1-marcus@grenangen.se> References: <9b568ce0-93f7-4a7f-98e4-625e910f8a1d@linux.dev> <20260507092911.8855-1-marcus@grenangen.se> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable 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=C3=A4ngen --- 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); } =20 +/* + * Module-level reference to the HID device that handles fn-lock via featu= re + * report. Set at probe and cleared at remove for QUIRK_HID_FN_LOCK device= s. + * 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 repo= rt. + * @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 pres= ent. + */ +int asus_hid_fnlock_set(bool enabled) +{ + int ret; + + guard(mutex)(&fnlock_hdev_lock); + if (!fnlock_hdev) + return -ENODEV; + + ret =3D 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 *hd= ev, struct hid_input *hi) drvdata->fn_lock =3D 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 =3D hdev; } =20 if (drvdata->tp) { @@ -1008,6 +1043,8 @@ static int asus_input_configured(struct hid_device *h= dev, struct hid_input *hi) drvdata->fn_lock =3D 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 =3D hdev; } =20 return 0; @@ -1362,8 +1399,13 @@ static void asus_remove(struct hid_device *hdev) cancel_work_sync(&drvdata->kbd_backlight->work); } =20 - if (drvdata->quirks & QUIRK_HID_FN_LOCK) + if (drvdata->quirks & QUIRK_HID_FN_LOCK) { + scoped_guard(mutex, &fnlock_hdev_lock) { + if (fnlock_hdev =3D=3D hdev) + fnlock_hdev =3D NULL; + } cancel_work_sync(&drvdata->fn_lock_sync_work); + } =20 hid_hw_stop(hdev); } diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/pla= tform_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 { =20 #define ASUS_EV_MAX_BRIGHTNESS 3 =20 +#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, u= 32 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 e= vent) { return -ENODEV; } + +static inline int asus_hid_fnlock_set(bool enabled) +{ + return -ENODEV; +} #endif =20 #endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */ --=20 2.54.0 From nobody Sat May 30 10:31:53 2026 Received: from smtp-out1.simply.com (smtp-out1.simply.com [94.231.106.240]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ECA7E3C1414; Thu, 7 May 2026 09:29:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=94.231.106.240 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778146159; cv=none; b=hoB5K93Xt8rstBmGuTfEe5mSaaIZz4imELQkvWEAe+frN5UvqlUb+KmTgVbiRM8lt4adJH5Ixe7seeQqkTsRuLWev43o6zrpoPleB7I7Y8j+YMoU2LH+jXcOVYJh7KCGCwyJYfT44StOzf1/Vwag4Z5AbOqGJ/sW1CrULxe1VBw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778146159; c=relaxed/simple; bh=H/tScrmyvamiUhGLeRMOmsQhhFV2sCrdw6L2HUZ1k8o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=GJrue1TuNd6hjz9wMaYPV2Q3P1vN2mOlJtl1lC/scEp3xxidby5UWmt09C/aEKvERUAsRCSKu6nZZZPrSgtPhuTMGOcyNT8fMKFRse9AFOMgkxHKA5WXURwOEOwYvqDQPBf+Xr/+dCCtlNfzl19dCUGBZohcxuVqawk9/JdAo5o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grenangen.se; spf=pass smtp.mailfrom=grenangen.se; dkim=pass (2048-bit key) header.d=grenangen.se header.i=@grenangen.se header.b=VksDSn6g; arc=none smtp.client-ip=94.231.106.240 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grenangen.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=grenangen.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=grenangen.se header.i=@grenangen.se header.b="VksDSn6g" Received: from localhost (localhost [127.0.0.1]) by smtp.simply.com (Simply.com) with ESMTP id 4gB6QK1pw1z1FQVX; Thu, 7 May 2026 11:29:13 +0200 (CEST) Received: from localhost (h-217-27-171-125.A498.priv.bahnhof.se [217.27.171.125]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (Client did not present a certificate) by smtp.simply.com (Simply.com) with ESMTPSA id 4gB6QJ5VFqz1FQVM; Thu, 7 May 2026 11:29:12 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=grenangen.se; s=simplycom2; t=1778146152; bh=FpCphwls28tEQgBfDnPaU5ckJ/fIPJvTY6hjNF0Fqdw=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=VksDSn6gWODo9iEN5KQkJgMXp10iuvUe4rflAiRu5B9IvZKDs4RsSCJpwk6UPHvOH BDux5qEhhujmjyKd6FLbB9hpmS+anLiq/OvhZ6q8p+3a/J9SpmeFmE4ANIImSNBtgy zL1EzFf0TwvnOLKq/XHZa4EhLtoCKKzUh7ouHroh+Jf4iK4h7vYNPivrl3EJw+wlX+ qFMDz2o+kdl1x65csoCll9HvrEl/2JUDcsrxFZfbiKZXSwVagsH5XhggwQsHQ5pbUA IEeFJwE8ADX6FdGNeEGNctbL9DftJ//5Sli2a0U/kkdm0a7Pj3dAalMzJ3/nHVszQ3 vqsRrSBNjFEQw== From: =?UTF-8?q?Marcus=20Gren=C3=A4ngen?= To: platform-driver-x86@vger.kernel.org, denis.benato@linux.dev Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, luke@ljones.dev, hansg@kernel.org, ilpo.jarvinen@linux.intel.com, jikos@kernel.org, bentiss@kernel.org, corentin.chary@gmail.com, marcus@grenangen.se Subject: [PATCH v3 2/3] platform/x86: asus-nb-wmi: add fnlock_use_hid quirk and asus_wmi_fnlock_use_hid() Date: Thu, 7 May 2026 11:29:10 +0200 Message-ID: <20260507092911.8855-3-marcus@grenangen.se> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260507092911.8855-1-marcus@grenangen.se> References: <9b568ce0-93f7-4a7f-98e4-625e910f8a1d@linux.dev> <20260507092911.8855-1-marcus@grenangen.se> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable 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=C3=A4ngen --- 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 =3D { .tablet_switch_mode =3D asus_wmi_kbd_dock_devid, }; =20 +static struct quirk_entry quirk_asus_proart_p16 =3D { + .fnlock_use_hid =3D 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[] =3D { }, .driver_data =3D &quirk_asus_z13, }, + { + .callback =3D dmi_matched, + .ident =3D "ASUS ProArt P16", + .matches =3D { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_FAMILY, "ProArt P16"), + }, + .driver_data =3D &quirk_asus_proart_p16, + }, {}, }; =20 diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wm= i.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); =20 +/** + * asus_wmi_fnlock_use_hid() - Return true if fn-lock must use the HID pat= h. + * + * 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 =3D 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-wm= i.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; }; =20 struct asus_wmi_driver { diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/pla= tform_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, u= 32 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 ev= ent) return -ENODEV; } =20 -static inline int asus_hid_fnlock_set(bool enabled) +static inline bool asus_wmi_fnlock_use_hid(void) { - return -ENODEV; + return false; } #endif =20 --=20 2.54.0 From nobody Sat May 30 10:31:53 2026 Received: from smtp-out1.simply.com (smtp-out1.simply.com [94.231.106.240]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4115D37BE8A; Thu, 7 May 2026 09:29:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=94.231.106.240 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778146158; cv=none; b=Dfqt0UNBb7b2DvSyQtUAcUuZcfhNEjZwonn9d2jJkTqosCSY0ghJ9GFsMzenMiy65SlGJ4JKKXvui7FbZ66CVvZ1CkOHD2Ec7tQnJ0GE6v7L5qWyfSu7PvVvda7ToT/kSlyMvZhx5IXfpl85N0qyn+PAUFb4Wk5373V5X4cV5Xs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778146158; c=relaxed/simple; bh=VHu51KCain/DYYn3gz1hBFd8nOopB5zUykVRUjuUlzQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Lz8mGiSjl+m/Ix7cyZv7ejJwwPESUfYAbZaYtSrIfa2TJ9G43ZITTL9MLd7odh498H9HFJJczMFg/o5iR3JGJK5J3lndSJZuDHnkV2xBP5+xUSHlfE91oMlFrnAcBw5D1hIA7fQhN2Y+1/eEhtIkn+SY9PMLru8jYjC4cLAaePg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grenangen.se; spf=pass smtp.mailfrom=grenangen.se; dkim=pass (2048-bit key) header.d=grenangen.se header.i=@grenangen.se header.b=O0ZNERNp; arc=none smtp.client-ip=94.231.106.240 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grenangen.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=grenangen.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=grenangen.se header.i=@grenangen.se header.b="O0ZNERNp" Received: from localhost (localhost [127.0.0.1]) by smtp.simply.com (Simply.com) with ESMTP id 4gB6QK5Jl4z1FXZw; Thu, 7 May 2026 11:29:13 +0200 (CEST) Received: from localhost (h-217-27-171-125.A498.priv.bahnhof.se [217.27.171.125]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (Client did not present a certificate) by smtp.simply.com (Simply.com) with ESMTPSA id 4gB6QK25Kwz1FXZy; Thu, 7 May 2026 11:29:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=grenangen.se; s=simplycom2; t=1778146153; bh=GofJ4cjc5NMrTAg/sjY16rkR1YSplZlsMbdB5r1HUwo=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=O0ZNERNpcCslwTmEtsKj6m0xfuOh3TC7RQ0SMgXfkMNsBmtAZ4eoCfeXPVxuDdEbS E7kQ+Z8S2lEVeRPOiP6dFJwBEPfK60y+IGixlcL7nyTmtKVXKOJmRgJNJrtAEE9Frf 5NCGOoDSCuqPFbLIVWOXAc7f3TgqVt3+crCM7Qxjn01yz9NQtT3CQGqL0hnPafPxWD ypn59k3e4jyuhoZCtlgpVAy4H6WzdHA8Lf+4XLBNstWAsMXOnA193lQsVrI2w9rDqx Anzjsqqoc7d9MGU+CfM8uqadCU0GCN7e9utcOg8O6BkCFEbXw74t6nrW/YwLxQl20a 8D3pL21vLZGdQ== From: =?UTF-8?q?Marcus=20Gren=C3=A4ngen?= To: platform-driver-x86@vger.kernel.org, denis.benato@linux.dev Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, luke@ljones.dev, hansg@kernel.org, ilpo.jarvinen@linux.intel.com, jikos@kernel.org, bentiss@kernel.org, corentin.chary@gmail.com, marcus@grenangen.se Subject: [PATCH v3 3/3] platform/x86: asus-armoury: add fn_lock firmware attribute Date: Thu, 7 May 2026 11:29:11 +0200 Message-ID: <20260507092911.8855-4-marcus@grenangen.se> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260507092911.8855-1-marcus@grenangen.se> References: <9b568ce0-93f7-4a7f-98e4-625e910f8a1d@linux.dev> <20260507092911.8855-1-marcus@grenangen.se> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable 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=C3=A4ngen --- 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/asu= s-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 { =20 u32 mini_led_dev_id; u32 gpu_mux_dev_id; + bool fn_lock_registered; }; =20 static struct asus_armoury_priv asus_armoury =3D { @@ -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"); =20 +/* + * 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 =3D 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 =3D kstrtobool(buf, &enable); + if (err) + return err; + + if (asus_wmi_fnlock_use_hid()) { + err =3D asus_hid_fnlock_set(enable); + if (err) + return err; + } else { + err =3D 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[] =3D { { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED }, @@ -926,6 +979,17 @@ static int asus_fw_attr_add(void) } } =20 + if (asus_wmi_fnlock_use_hid() || + armoury_has_devstate(ASUS_WMI_DEVID_FNLOCK)) { + err =3D 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 =3D true; + } + for (i =3D 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); =20 + 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); =20 --=20 2.54.0