* [PATCH v2 1/7] HID: asus: Fix up Zenbook Duo report descriptors
2026-10-09 15:34 [PATCH v2 0/7] HID: asus: ASUS Zenbook Duo keyboard support Paolo Pisati
@ 2026-10-09 15:34 ` Paolo Pisati
2026-10-09 15:34 ` [PATCH v2 2/7] HID: asus: Add missing Zenbook Duo hotkeys Paolo Pisati
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Paolo Pisati @ 2026-10-09 15:34 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Joshua Leivenzon, linux-input, linux-kernel, Luke Jones,
Ivan Levchenko, Rebecca Mara Müller, Nathan Chancellor,
Denis Benato
From: Joshua Leivenzon <hacker1024@users.sourceforge.net>
The Zenbook Duo keyboards (UX8406MA, UX8406CA, UX8407AA) ship the same
broken vendor hotkey collection as the T100CHI/T90CHI keyboard docks:
the Input item of report 0x5a is preceded by a single Usage (76h)
instead of a Usage Minimum/Maximum range, so none of the hotkey codes
get mapped and every key press logs
Unmapped Asus vendor usagepage code 0x76
Extend the T100CHI/T90CHI fixup to the Zenbook Duo: the descriptor is
90 bytes long with the bogus usage at offset 66 on the USB hotkey
interface, and 257 bytes long with the usage at offset 176 over
Bluetooth.
The dock fixup only moves the 12 bytes between the usage and the End
Collection item, as nothing but a bogus trailing 0 byte follows them.
That is not true of the Zenbook Duo: the collection goes on with a 15
byte feature report (also ID 0x5a) after the Input item, and over
Bluetooth a further collection follows it, which a 12 byte move
corrupts, leaving stray 0 bytes at the end. Move everything after the
usage instead, after dropping any trailing 0 bytes, and allocate the
two bytes the usage range adds. The result for the T100CHI/T90CHI is
unchanged.
Signed-off-by: Joshua Leivenzon <hacker1024@users.sourceforge.net>
[pisati: fold the USB offsets and the padding removal into this patch,
bound the padding removal, move the whole tail of the descriptor, and
end the branch chain with a plain else so clang does not warn that
rsize_orig may be uninitialized]
Assisted-by: LLM
Signed-off-by: Paolo Pisati <p.pisati@gmail.com>
---
drivers/hid/hid-asus.c | 38 ++++++++++++++++++++++++++------------
1 file changed, 26 insertions(+), 12 deletions(-)
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index bd46aba6622a..34739198d90e 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_ALLY_XPAD BIT(13)
#define QUIRK_HID_FN_LOCK BIT(14)
#define QUIRK_FILTER_CAMERA_COMPANION BIT(15)
+#define QUIRK_ZENBOOK_DUO_KEYBOARD BIT(16)
#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
QUIRK_NO_INIT_REPORTS | \
@@ -1579,43 +1580,56 @@ static const __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
hid_info(hdev, "Fixing up Asus T100 keyb report descriptor\n");
rdesc[74] &= ~HID_MAIN_ITEM_CONSTANT;
}
- /* For the T100CHI/T90CHI keyboard dock */
- if (drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) {
+ /* For the T100CHI/T90CHI keyboard dock and Zenbook Duo keyboards */
+ if (drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI | QUIRK_ZENBOOK_DUO_KEYBOARD)) {
int rsize_orig;
int offs;
if (drvdata->quirks & QUIRK_T100CHI) {
rsize_orig = 403;
offs = 388;
- } else {
+ } else if (drvdata->quirks & QUIRK_T90CHI) {
rsize_orig = 306;
offs = 291;
+ } else if (hid_is_usb(hdev)) { /* QUIRK_ZENBOOK_DUO_KEYBOARD */
+ rsize_orig = 90;
+ offs = 66;
+ } else { /* QUIRK_ZENBOOK_DUO_KEYBOARD over Bluetooth */
+ rsize_orig = 257;
+ offs = 176;
}
/*
* Change Usage (76h) to Usage Minimum (00h), Usage Maximum
- * (FFh) and clear the flags in the Input() byte.
- * Note the descriptor has a bogus 0 byte at the end so we
- * only need 1 extra byte.
+ * (FFh) and clear the flags in the Input() byte, shifting
+ * the rest of the descriptor by the 2 bytes that adds. Drop
+ * the bogus 0 bytes some descriptors end with first, but
+ * never the Input() item that follows the usage.
*/
if (*rsize == rsize_orig &&
rdesc[offs] == 0x09 && rdesc[offs + 1] == 0x76) {
+ unsigned int new_rsize = rsize_orig;
__u8 *new_rdesc;
- new_rdesc = devm_kzalloc(&hdev->dev, rsize_orig + 1,
+ while (new_rsize > offs + 14 && rdesc[new_rsize - 1] == 0)
+ --new_rsize;
+
+ new_rdesc = devm_kzalloc(&hdev->dev, new_rsize + 2,
GFP_KERNEL);
if (!new_rdesc)
return rdesc;
hid_info(hdev, "Fixing up %s keyb report descriptor\n",
- drvdata->quirks & QUIRK_T100CHI ?
- "T100CHI" : "T90CHI");
+ drvdata->quirks & QUIRK_T100CHI ? "T100CHI" :
+ drvdata->quirks & QUIRK_T90CHI ? "T90CHI" :
+ "Zenbook Duo");
- memcpy(new_rdesc, rdesc, rsize_orig);
- *rsize = rsize_orig + 1;
+ memcpy(new_rdesc, rdesc, new_rsize);
+ *rsize = new_rsize + 2;
rdesc = new_rdesc;
- memmove(rdesc + offs + 4, rdesc + offs + 2, 12);
+ memmove(rdesc + offs + 4, rdesc + offs + 2,
+ new_rsize - (offs + 2));
rdesc[offs] = 0x19;
rdesc[offs + 1] = 0x00;
rdesc[offs + 2] = 0x29;
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 2/7] HID: asus: Add missing Zenbook Duo hotkeys
2026-10-09 15:34 [PATCH v2 0/7] HID: asus: ASUS Zenbook Duo keyboard support Paolo Pisati
2026-10-09 15:34 ` [PATCH v2 1/7] HID: asus: Fix up Zenbook Duo report descriptors Paolo Pisati
@ 2026-10-09 15:34 ` Paolo Pisati
2026-10-09 15:34 ` [PATCH v2 3/7] HID: asus: Force hid-input to bind to the Zenbook Duo hotkey interface Paolo Pisati
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Paolo Pisati @ 2026-10-09 15:34 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Joshua Leivenzon, linux-input, linux-kernel, Luke Jones,
Ivan Levchenko, Rebecca Mara Müller, Nathan Chancellor,
Denis Benato
From: Joshua Leivenzon <hacker1024@users.sourceforge.net>
Map the Zenbook Duo "screen swap" hotkey (vendor usage 0x9c) to
KEY_F19, like the other ASUS vendor keys that have no dedicated
keycode, so that userspace can bind it.
The mappings from the ROG Ally onwards belong to devices with built-in
keyboards and can share keycodes freely. The Zenbook Duo keyboard
cannot: it is a standard USB/Bluetooth device and can be connected to
another ASUS machine handled by this driver. Document that above the
ROG Ally mappings.
Signed-off-by: Joshua Leivenzon <hacker1024@users.sourceforge.net>
[pisati: drop the MyASUS key (0x86) mapping, 2061075360182 ("HID:
asus: support the Zenbook A16 (UX3607OA) keyboard") maps it to
KEY_PROG1 like asus-nb-wmi does]
Assisted-by: LLM
Signed-off-by: Paolo Pisati <p.pisati@gmail.com>
---
drivers/hid/hid-asus.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 34739198d90e..242e273e4cb3 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -1264,6 +1264,19 @@ static int asus_input_mapping(struct hid_device *hdev,
case 0xb3: asus_map_key_clear(KEY_PROG3); break; /* Fn+Left next aura */
case 0x6a: asus_map_key_clear(KEY_F13); break; /* Screenpad toggle */
case 0x4b: asus_map_key_clear(KEY_F14); break; /* Arrows/Pg-Up/Dn toggle */
+ case 0x9c: asus_map_key_clear(KEY_F19); break; /* Screen swap */
+
+ /*
+ * Mutually exclusive section: Special keys from different devices
+ * can bind to the same keycodes without concern, as they will never
+ * conflict.
+ *
+ * Note that devices with removable keyboards that connect over a
+ * standard interface (e.g. Zenbook Duo UX8406 with USB/Bluetooth) do
+ * not belong in this section, as such keyboards can be connected to
+ * another ASUS device that also uses this driver for its own keyboard.
+ */
+ /* ROG Ally */
case 0xa5: asus_map_key_clear(KEY_F15); break; /* ROG Ally left back */
case 0xa6: asus_map_key_clear(KEY_F16); break; /* ROG Ally QAM button */
case 0xa7: asus_map_key_clear(KEY_F17); break; /* ROG Ally ROG long-press */
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 3/7] HID: asus: Force hid-input to bind to the Zenbook Duo hotkey interface
2026-10-09 15:34 [PATCH v2 0/7] HID: asus: ASUS Zenbook Duo keyboard support Paolo Pisati
2026-10-09 15:34 ` [PATCH v2 1/7] HID: asus: Fix up Zenbook Duo report descriptors Paolo Pisati
2026-10-09 15:34 ` [PATCH v2 2/7] HID: asus: Add missing Zenbook Duo hotkeys Paolo Pisati
@ 2026-10-09 15:34 ` Paolo Pisati
2026-10-09 15:34 ` [PATCH v2 4/7] HID: asus: Cycle the platform profile from the Zenbook Duo profile key Paolo Pisati
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Paolo Pisati @ 2026-10-09 15:34 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Joshua Leivenzon, linux-input, linux-kernel, Luke Jones,
Ivan Levchenko, Rebecca Mara Müller, Nathan Chancellor,
Denis Benato
From: Joshua Leivenzon <hacker1024@users.sourceforge.net>
The Zenbook Duo USB keyboard reports its hotkeys on a dedicated
interface, separate from the keyboard and consumer control ones, that
only contains ASUS vendor usage collections. hid-input does not
consider those an input application and never binds to the interface,
so the hotkeys are never mapped.
Pass HID_CONNECT_HIDINPUT_FORCE for the interface of Zenbook Duo
keyboards that carries the ASUS vendor collection, which skips that
check, so the vendor usages go through asus_input_mapping() like on
any other ASUS keyboard. The other interfaces either have a proper
input application or nothing worth an input device.
Signed-off-by: Joshua Leivenzon <hacker1024@users.sourceforge.net>
[pisati: use HID_CONNECT_HIDINPUT_FORCE on the vendor interface instead
of injecting a fake keyboard collection into its report descriptor]
Assisted-by: LLM
Signed-off-by: Paolo Pisati <p.pisati@gmail.com>
---
drivers/hid/hid-asus.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 242e273e4cb3..d69431615c27 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -1405,6 +1405,7 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
struct asus_drvdata *drvdata;
struct hid_report *rep;
bool is_vendor = false;
+ unsigned int connect_mask;
int ret;
drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
@@ -1500,7 +1501,18 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
}
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ /*
+ * The Zenbook Duo keyboard reports its hotkeys on a dedicated USB
+ * interface that only has vendor usage collections, which hid-input
+ * does not consider an input application. Make it bind to the
+ * interface carrying the ASUS vendor collection anyway so the
+ * hotkeys get mapped.
+ */
+ connect_mask = HID_CONNECT_DEFAULT;
+ if ((drvdata->quirks & QUIRK_ZENBOOK_DUO_KEYBOARD) && is_vendor)
+ connect_mask |= HID_CONNECT_HIDINPUT_FORCE;
+
+ ret = hid_hw_start(hdev, connect_mask);
if (ret) {
asus_worker_stop(drvdata->worker);
hid_err(hdev, "Asus hw start failed: %d\n", ret);
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 4/7] HID: asus: Cycle the platform profile from the Zenbook Duo profile key
2026-10-09 15:34 [PATCH v2 0/7] HID: asus: ASUS Zenbook Duo keyboard support Paolo Pisati
` (2 preceding siblings ...)
2026-10-09 15:34 ` [PATCH v2 3/7] HID: asus: Force hid-input to bind to the Zenbook Duo hotkey interface Paolo Pisati
@ 2026-10-09 15:34 ` Paolo Pisati
2026-10-09 15:34 ` [PATCH v2 5/7] HID: asus: Do not send feature reports larger than declared Paolo Pisati
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Paolo Pisati @ 2026-10-09 15:34 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Joshua Leivenzon, linux-input, linux-kernel, Luke Jones,
Ivan Levchenko, Rebecca Mara Müller, Nathan Chancellor,
Denis Benato
From: Joshua Leivenzon <hacker1024@users.sourceforge.net>
The Zenbook Duo keyboard reports Fn+F, the performance mode key, as
vendor usage 0x9d. On the built-in keyboards of other ASUS laptops the
same key arrives through asus-wmi, which cycles the platform profile
in response. Do the same here so the key works on the detachable
keyboard too.
asus_event() runs from the HID input path, which for USB is the URB
completion handler, while platform_profile_cycle() takes a mutex, so
run it from the driver's worker like the Fn-lock toggle, and consume
the event. Only call it when the platform profile class is reachable:
it is not built on architectures without ACPI, where HID_ASUS still
is, and it may be a module while HID_ASUS is built in.
Signed-off-by: Joshua Leivenzon <hacker1024@users.sourceforge.net>
[pisati: defer platform_profile_cycle() to the worker, return 1 from
asus_event() instead of propagating its return value, and guard the
call with IS_REACHABLE(CONFIG_ACPI_PLATFORM_PROFILE)]
Assisted-by: LLM
Signed-off-by: Paolo Pisati <p.pisati@gmail.com>
---
drivers/hid/hid-asus.c | 53 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index d69431615c27..d8a931290c9a 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -29,6 +29,7 @@
#include <linux/input/mt.h>
#include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */
#include <linux/power_supply.h>
+#include <linux/platform_profile.h>
#include <linux/leds.h>
#include "hid-ids.h"
@@ -115,6 +116,7 @@ enum asus_work_action_type {
FN_LOCK_SYNC,
BRIGHTNESS_SET,
WMI_FAN,
+ PLATFORM_PROFILE_CYCLE,
};
struct hid_raw_event_data {
@@ -423,6 +425,28 @@ static int asus_kbd_fn_lock_set(struct asus_drvdata *drvdata, bool enabled)
return 0;
}
+static int asus_platform_profile_cycle(struct asus_drvdata *drvdata)
+{
+ struct asus_work_action *action;
+ unsigned long flags;
+
+ if (!IS_REACHABLE(CONFIG_ACPI_PLATFORM_PROFILE))
+ return 0;
+
+ action = kzalloc_obj(struct asus_work_action, GFP_ATOMIC);
+ if (!action)
+ return -ENOMEM;
+
+ action->type = PLATFORM_PROFILE_CYCLE;
+ INIT_LIST_HEAD(&action->node);
+
+ spin_lock_irqsave(&drvdata->worker->lock, flags);
+ asus_worker_schedule(drvdata->worker, action);
+ spin_unlock_irqrestore(&drvdata->worker->lock, flags);
+
+ return 0;
+}
+
static int asus_kbd_wmi_fan_send(struct asus_drvdata *drvdata, u8 *report_data,
size_t report_size)
{
@@ -459,8 +483,25 @@ static int asus_event(struct hid_device *hdev, struct hid_field *field,
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",
- usage->hid & HID_USAGE);
+ /*
+ * Some vendor usages do not map to a key and need special
+ * handling.
+ */
+ switch (usage->hid & HID_USAGE) {
+ case 0x9d: /* Zenbook Duo Fn+F: cycle the platform profile */
+ if (value) {
+ ret = asus_platform_profile_cycle(drvdata);
+ if (ret) {
+ hid_err(hdev, "Failed to cycle the platform profile: %d\n",
+ ret);
+ return ret;
+ }
+ }
+ return 1;
+ default:
+ hid_warn(hdev, "Unmapped Asus vendor usagepage code 0x%02x\n",
+ usage->hid & HID_USAGE);
+ }
}
if (usage->type == EV_KEY && value) {
@@ -765,6 +806,7 @@ static void asus_work(struct work_struct *work)
struct asus_worker *worker = container_of(work, struct asus_worker, work);
struct asus_work_action *action = NULL;
unsigned long flags;
+ int ret;
/* Save the action to be performed and clear the flag */
spin_lock_irqsave(&worker->lock, flags);
@@ -788,6 +830,13 @@ static void asus_work(struct work_struct *work)
case WMI_FAN:
asus_kbd_wmi_fan(worker->hdev, &action->data.fan_hid_data);
break;
+ case PLATFORM_PROFILE_CYCLE:
+ if (!IS_REACHABLE(CONFIG_ACPI_PLATFORM_PROFILE))
+ break;
+ ret = platform_profile_cycle();
+ if (ret)
+ hid_dbg(worker->hdev, "Failed to cycle the platform profile: %d\n", ret);
+ break;
default:
hid_err(worker->hdev, "Invalid action type: %d\n", action->type);
break;
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 5/7] HID: asus: Do not send feature reports larger than declared
2026-10-09 15:34 [PATCH v2 0/7] HID: asus: ASUS Zenbook Duo keyboard support Paolo Pisati
` (3 preceding siblings ...)
2026-10-09 15:34 ` [PATCH v2 4/7] HID: asus: Cycle the platform profile from the Zenbook Duo profile key Paolo Pisati
@ 2026-10-09 15:34 ` Paolo Pisati
2026-10-09 15:34 ` [PATCH v2 6/7] HID: asus: add prod-id, quirk for Zenbook Duo keyboard Paolo Pisati
2026-10-09 15:34 ` [PATCH v2 7/7] HID: asus: Re-send the Zenbook Duo keyboard handshake after probe Paolo Pisati
6 siblings, 0 replies; 8+ messages in thread
From: Paolo Pisati @ 2026-10-09 15:34 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: linux-input, linux-kernel, Luke Jones, Joshua Leivenzon,
Ivan Levchenko, Rebecca Mara Müller, Nathan Chancellor,
Denis Benato
The keyboard backlight and Fn-lock commands are sent as 64 byte
feature reports, the size of report 0x5a on the ROG keyboards. The
Zenbook Duo keyboards declare report 0x5a as a 15 byte feature report
and do not answer writes larger than that: the control transfer times
out over USB and fails with -EIO over Bluetooth, so the backlight
cannot be set, while the 16 byte handshake goes through.
Cap feature report writes at the length the device declares for the
report, when it declares it.
Assisted-by: LLM
Signed-off-by: Paolo Pisati <p.pisati@gmail.com>
---
drivers/hid/hid-asus.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index d8a931290c9a..9e80a2bb54c3 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -618,6 +618,17 @@ static int asus_raw_event(struct hid_device *hdev,
static int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size)
{
+ struct hid_report *report;
+
+ /*
+ * Do not send more than the declared size of the report: the
+ * Zenbook Duo keyboards declare report 0x5a as 15 bytes long and
+ * do not answer the 64 byte writes sized for the ROG keyboards.
+ */
+ report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[buf[0]];
+ if (report)
+ buf_size = min_t(size_t, buf_size, hid_report_len(report));
+
u8 *dmabuf __free(kfree) = kmemdup(buf, buf_size, GFP_KERNEL);
if (!dmabuf)
return -ENOMEM;
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 6/7] HID: asus: add prod-id, quirk for Zenbook Duo keyboard
2026-10-09 15:34 [PATCH v2 0/7] HID: asus: ASUS Zenbook Duo keyboard support Paolo Pisati
` (4 preceding siblings ...)
2026-10-09 15:34 ` [PATCH v2 5/7] HID: asus: Do not send feature reports larger than declared Paolo Pisati
@ 2026-10-09 15:34 ` Paolo Pisati
2026-10-09 15:34 ` [PATCH v2 7/7] HID: asus: Re-send the Zenbook Duo keyboard handshake after probe Paolo Pisati
6 siblings, 0 replies; 8+ messages in thread
From: Paolo Pisati @ 2026-10-09 15:34 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Luke Jones, linux-input, linux-kernel, Joshua Leivenzon,
Ivan Levchenko, Rebecca Mara Müller, Nathan Chancellor,
Denis Benato
From: Luke Jones <luke@ljones.dev>
The 2024/2025/2026 ASUS Zenbook Duo has a similar keyboard setup as
many of the ROG range of laptops, with the same init sequence and
control for backlight. Enable the keyboard control and backlight by:
- adding the product ID for 2024/2025/2026 Zenbook Duo keyboard MCU
- adding the Bluetooth Zenbook Duo keyboard IDs
Intended for the UX8406-style product line with the fully removable
keyboard.
The USB keyboard also exposes its touchpad as interfaces of the same
device, so bind the USB IDs to the HID_GROUP_GENERIC group only, like
the ROG Z13 Folio, and leave the touchpad to hid-multitouch.
Fn-lock is left out for now: with QUIRK_HID_FN_LOCK the Fn-lock report
is sent to every interface of the device, before the handshake, and on
the UX8407AA that stalled the hotkey interface for good. It can be
added back once the driver only sends it where and when it belongs.
Signed-off-by: Luke Jones <luke@ljones.dev>
Signed-off-by: Joshua Leivenzon <hacker1024@users.sourceforge.net>
Signed-off-by: Ivan Levchenko <me@livan.pro>
[pisati: bind the USB IDs to HID_GROUP_GENERIC only, drop
QUIRK_HID_FN_LOCK]
Assisted-by: LLM
Signed-off-by: Paolo Pisati <p.pisati@gmail.com>
---
drivers/hid/hid-asus.c | 23 +++++++++++++++++++++++
drivers/hid/hid-ids.h | 6 ++++++
2 files changed, 29 insertions(+)
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 9e80a2bb54c3..a0a04ddb30af 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -1834,6 +1834,29 @@ static const struct hid_device_id asus_devices[] = {
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T101HA_KEYBOARD) },
+ /*
+ * Zenbook Duo detachable keyboards. Bind the USB IDs to the
+ * HID_GROUP_GENERIC group only, like the ROG Z13 Folio, so that
+ * hid-multitouch keeps handling the touchpad interfaces.
+ */
+ { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_ASUSTEK,
+ USB_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_UX8406MA_KEYBOARD),
+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ZENBOOK_DUO_KEYBOARD },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK,
+ BT_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_UX8406MA_KEYBOARD),
+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ZENBOOK_DUO_KEYBOARD },
+ { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_ASUSTEK,
+ USB_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_UX8406CA_KEYBOARD),
+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ZENBOOK_DUO_KEYBOARD },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK,
+ BT_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_UX8406CA_KEYBOARD),
+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ZENBOOK_DUO_KEYBOARD },
+ { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_ASUSTEK,
+ USB_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_UX8407AA_KEYBOARD),
+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ZENBOOK_DUO_KEYBOARD },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK,
+ BT_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_UX8407AA_KEYBOARD),
+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ZENBOOK_DUO_KEYBOARD },
{ }
};
MODULE_DEVICE_TABLE(hid, asus_devices);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index b3aca5aa9176..59f44204d738 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -228,6 +228,12 @@
#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866
#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 0x19b6
#define USB_DEVICE_ID_ASUSTEK_ROG_Z13_FOLIO 0x1a30
+#define USB_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_UX8406MA_KEYBOARD 0x1b2c
+#define BT_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_UX8406MA_KEYBOARD 0x1b2d
+#define USB_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_UX8406CA_KEYBOARD 0x1bf2
+#define BT_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_UX8406CA_KEYBOARD 0x1bf3
+#define USB_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_UX8407AA_KEYBOARD 0x1cd7
+#define BT_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_UX8407AA_KEYBOARD 0x1cd8
#define USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR 0x18c6
#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY 0x1abe
#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X 0x1b4c
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 7/7] HID: asus: Re-send the Zenbook Duo keyboard handshake after probe
2026-10-09 15:34 [PATCH v2 0/7] HID: asus: ASUS Zenbook Duo keyboard support Paolo Pisati
` (5 preceding siblings ...)
2026-10-09 15:34 ` [PATCH v2 6/7] HID: asus: add prod-id, quirk for Zenbook Duo keyboard Paolo Pisati
@ 2026-10-09 15:34 ` Paolo Pisati
6 siblings, 0 replies; 8+ messages in thread
From: Paolo Pisati @ 2026-10-09 15:34 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Rebecca Mara Müller, linux-input, linux-kernel, Luke Jones,
Joshua Leivenzon, Ivan Levchenko, Nathan Chancellor,
Denis Benato
From: Rebecca Mara Müller <rebecca.mara@posteo.de>
When docked, the Zenbook Duo keyboard powers up in F-key mode and
needs the "ASUS Tech.Inc." handshake to emit hotkeys at all. The
handshake sent from probe is lost again when hid-multitouch configures
the touchpad on the sibling USB interface, which resets the keyboard
to F-key mode, so the hotkeys stop working as soon as the touchpad is
set up.
Re-send the handshake from delayed work two seconds after probe.
Signed-off-by: Rebecca Mara Müller <rebecca.mara@posteo.de>
Link: https://lore.kernel.org/r/20260811125548.1975748-1-rebecca.mara@posteo.de
[pisati: taken from Rebecca's standalone UX8407AA patch and adapted to
the current driver; initialize and cancel the work unconditionally]
Assisted-by: LLM
Signed-off-by: Paolo Pisati <p.pisati@gmail.com>
---
drivers/hid/hid-asus.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index a0a04ddb30af..f60f9a8fafbd 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -173,6 +173,7 @@ struct asus_drvdata {
unsigned long battery_next_query;
struct asus_hid_listener listener;
bool fn_lock;
+ struct delayed_work reinit_work;
};
static int asus_report_battery(struct asus_drvdata *, u8 *, int);
@@ -1459,6 +1460,17 @@ static int __maybe_unused asus_reset_resume(struct hid_device *hdev)
return 0;
}
+static void asus_reinit_work(struct work_struct *work)
+{
+ struct asus_drvdata *drvdata = container_of(work, struct asus_drvdata,
+ reinit_work.work);
+ int ret;
+
+ ret = asus_kbd_init(drvdata->hdev, FEATURE_KBD_REPORT_ID);
+ if (ret < 0)
+ hid_warn(drvdata->hdev, "Failed to re-initialize the keyboard: %d\n", ret);
+}
+
static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct hid_report_enum *rep_enum;
@@ -1555,6 +1567,8 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
is_vendor = true;
}
+ INIT_DELAYED_WORK(&drvdata->reinit_work, asus_reinit_work);
+
ret = asus_worker_create(hdev, drvdata);
if (ret) {
hid_warn(hdev, "Failed to initialize worker: %d\n", ret);
@@ -1590,6 +1604,16 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
}
+ /*
+ * When docked, the Zenbook Duo keyboard drops back to F-key mode when
+ * hid-multitouch configures the touchpad on the sibling USB interface,
+ * which can happen after the handshake above. Send it again once the
+ * dust has settled.
+ */
+ if (is_vendor && (drvdata->quirks & QUIRK_ZENBOOK_DUO_KEYBOARD) &&
+ hid_is_usb(hdev))
+ schedule_delayed_work(&drvdata->reinit_work, msecs_to_jiffies(2000));
+
/* Laptops keyboard backlight is always at 0x5a */
if (is_vendor && (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT) &&
(asus_has_report_id(hdev, FEATURE_KBD_REPORT_ID)) &&
@@ -1624,6 +1648,7 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
return 0;
err_stop_hw:
+ cancel_delayed_work_sync(&drvdata->reinit_work);
if (drvdata->listener.brightness_set)
asus_hid_unregister_listener(&drvdata->listener);
@@ -1639,6 +1664,7 @@ static void asus_remove(struct hid_device *hdev)
if (drvdata->listener.brightness_set)
asus_hid_unregister_listener(&drvdata->listener);
+ cancel_delayed_work_sync(&drvdata->reinit_work);
asus_worker_stop(drvdata->worker);
hid_hw_stop(hdev);
}
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread