[PATCH] HID: asus: add support for the ASUS Zenbook Duo built-in keyboard
Rebecca Mara Müller <[email protected]> Tue, 11 Aug 2026 12:56:42 +0000
| Newsgroups | org.kernel.vger.linux-input,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
The detachable keyboard of the ASUS Zenbook Duo (2026, UX8407) is a Primax-built combo device (USB 0b05:1cd7 when docked, Bluetooth 0b05:1cd8 when detached) whose hotkeys need several fixes to work: - The hotkey interface wraps its vendor input report (ID 0x5a) in a single bogus usage 0x76, the same descriptor bug the T100CHI family fixup handles. Rewrite the usage into a usage range on both transports so the hotkey codes map to their key definitions. - On USB the hotkey interface only exposes vendor usage collections, which do not count as input applications, so hid-input would not bind to it. Force the connect. - When docked, the keyboard powers up in F-key mode and needs the well-known "ASUS Tech.Inc." handshake to emit hotkeys at all. The handshake sent from probe is lost again because configuring the touchpad on the sibling USB interface (handled by hid-multitouch) resets the keyboard to F-key mode. Re-send the handshake from delayed work two seconds after probe. - Bind by group like the ROG Z13 Folio so hid-multitouch keeps handling the touchpad interfaces. Tested on an ASUS Zenbook Duo UX8407AA in both docked (USB) and detached (Bluetooth) modes: brightness keys emit BRIGHTNESSDOWN/UP, the other hotkeys (volume, mute, print screen, display toggle) keep working, and both keyboard typing and the touchpad are unaffected. Signed-off-by: Rebecca Mara Müller <[email protected]> --- Tested on an ASUS Zenbook Duo UX8407AA (Pop!_OS 24.04). The change was validated as a backport on kernel 7.0.11 (repeated dock/undock cycles, alternating brightness levels between mode switches to rule out state-dependent behaviour) and compile-tested against this tree. The failure analysis (raw HID captures, descriptor decoding, and the discovery of the touchpad-init interaction) and the initial patch draft were done with AI assistance; I reviewed the change and did all testing on the real hardware myself. drivers/hid/hid-asus.c | 94 +++++++++++++++++++++++++++++++++++++++++- drivers/hid/hid-ids.h | 2 + 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 3f5e96900..8c1e54a8c 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -99,6 +99,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12) #define QUIRK_ROG_ALLY_XPAD BIT(13) #define QUIRK_HID_FN_LOCK BIT(14) +#define QUIRK_ZENBOOK_DUO_KEYBOARD BIT(15) #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ QUIRK_NO_INIT_REPORTS | \ @@ -143,6 +144,7 @@ struct asus_drvdata { unsigned long battery_next_query; struct work_struct fn_lock_sync_work; bool fn_lock; + struct delayed_work reinit_work; }; static int asus_report_battery(struct asus_drvdata *, u8 *, int); @@ -1191,6 +1193,22 @@ 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; + + /* + * The Zenbook Duo keyboard drops out of hotkey mode when the + * touchpad on its sibling USB interface is configured after us. + * Re-send the handshake once the dust has settled. + */ + ret = asus_kbd_init(drvdata->hdev, FEATURE_KBD_REPORT_ID); + if (ret < 0) + hid_warn(drvdata->hdev, "Asus re-init failed: %d\n", ret); +} + static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct hid_report_enum *rep_enum; @@ -1288,7 +1306,16 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) is_vendor = true; } - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + /* + * The Zenbook Duo keyboard hotkey interface only exposes vendor + * usage collections, which do not count as input applications. + * Force hid-input to bind so the hotkeys reach userspace. + */ + if (drvdata->quirks & QUIRK_ZENBOOK_DUO_KEYBOARD) + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | + HID_CONNECT_HIDINPUT_FORCE); + else + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { hid_err(hdev, "Asus hw start failed: %d\n", ret); return ret; @@ -1309,6 +1336,13 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) (asus_kbd_register_leds(hdev))) hid_warn(hdev, "Failed to initialize backlight.\n"); + if (is_vendor && (drvdata->quirks & QUIRK_ZENBOOK_DUO_KEYBOARD) && + hdev->bus == BUS_USB) { + INIT_DELAYED_WORK(&drvdata->reinit_work, asus_reinit_work); + schedule_delayed_work(&drvdata->reinit_work, + msecs_to_jiffies(2000)); + } + /* * For ROG keyboards, skip rename for consistency and ->input check as * some devices do not have inputs. @@ -1346,6 +1380,9 @@ static void asus_remove(struct hid_device *hdev) struct asus_drvdata *drvdata = hid_get_drvdata(hdev); unsigned long flags; + if (drvdata->quirks & QUIRK_ZENBOOK_DUO_KEYBOARD) + cancel_delayed_work_sync(&drvdata->reinit_work); + if (drvdata->kbd_backlight) { asus_hid_unregister_listener(&drvdata->kbd_backlight->listener); @@ -1384,6 +1421,51 @@ 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; } + /* + * The Zenbook Duo keyboard uses the same bogus single-usage (0x76) + * vendor input report as the T100CHI family, on both its USB and + * Bluetooth interfaces. Rewrite the usage into a usage range so the + * hotkey codes map to their key definitions. + */ + if (drvdata->quirks & QUIRK_ZENBOOK_DUO_KEYBOARD) { + static const __u8 bogus[] = { + 0xa1, 0x01, /* Collection (Application) */ + 0x85, 0x5a, /* Report ID (0x5a) */ + 0x09, 0x76, /* Usage (0x76) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x26, 0xff, 0x00, /* Logical Maximum (255) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x05, /* Report Count (5) */ + 0x81, 0x02, /* Input (Data,Var,Abs) */ + }; + __u8 *new_rdesc; + unsigned int i; + + for (i = 0; *rsize >= sizeof(bogus) && i <= *rsize - sizeof(bogus); i++) { + if (memcmp(rdesc + i, bogus, sizeof(bogus)) != 0) + continue; + + new_rdesc = devm_kzalloc(&hdev->dev, *rsize + 3, GFP_KERNEL); + if (!new_rdesc) + return rdesc; + + hid_info(hdev, "Fixing up Zenbook Duo keyboard report descriptor\n"); + memcpy(new_rdesc, rdesc, i + 4); + /* Usage (76h) -> Usage Minimum (00h), Usage Maximum (FFh) */ + new_rdesc[i + 4] = 0x19; + new_rdesc[i + 5] = 0x00; + new_rdesc[i + 6] = 0x2a; + new_rdesc[i + 7] = 0xff; + new_rdesc[i + 8] = 0x00; + memcpy(new_rdesc + i + 9, rdesc + i + 6, *rsize - (i + 6)); + /* Input (Data,Var,Abs) -> Input (Data,Arr,Abs) */ + new_rdesc[i + 19] = 0x00; + *rsize += 3; + rdesc = new_rdesc; + break; + } + } + /* For the T100CHI/T90CHI keyboard dock */ if (drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) { int rsize_orig; @@ -1534,6 +1616,16 @@ 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) }, + /* + * The Zenbook Duo keyboard also binds by group so that + * hid-multitouch.c keeps handling the touchpad interfaces. + */ + { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, + USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_KEYBOARD), + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ZENBOOK_DUO_KEYBOARD }, + { HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_GENERIC, + USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_KEYBOARD_BT), + 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 1059922ba..b030df014 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -225,6 +225,8 @@ #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837 #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866 +#define USB_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_KEYBOARD 0x1cd7 +#define USB_DEVICE_ID_ASUSTEK_ZENBOOK_DUO_KEYBOARD_BT 0x1cd8 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 0x19b6 #define USB_DEVICE_ID_ASUSTEK_ROG_Z13_FOLIO 0x1a30 #define USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR 0x18c6 -- 2.43.0