]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
HID: huawei: fix CD30 keyboard report descriptor issue
authorMiao Li <limiao@kylinos.cn>
Wed, 18 Mar 2026 09:12:49 +0000 (17:12 +0800)
committerJiri Kosina <jkosina@suse.com>
Thu, 9 Apr 2026 15:56:46 +0000 (17:56 +0200)
When the Huawei CD30 USB keyboard undergoes 500 reboot cycles,
initialization may fail due to a report descriptor problem.
The error log is as follows:
[pid:175,cpu0,kworker/0:1,6]usb 1-1.2.2: new low-speed USB device number 6 using xhci-hcd
[pid:175,cpu0,kworker/0:1,9]usb 1-1.2.2: New USB device found, idVendor=12d1, idProduct=109b, bcdDevice= 1.03
[pid:175,cpu0,kworker/0:1,0]usb 1-1.2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[pid:175,cpu0,kworker/0:1,1]usb 1-1.2.2: Product: HUAWEI USB Wired Keyboard
[pid:175,cpu0,kworker/0:1,2]usb 1-1.2.2: Manufacturer: HUAWEI
[pid:175,cpu0,kworker/0:1,4]input: HUAWEI HUAWEI USB Wired Keyboard as /devices/platform/efc00000.hisi_usb/efc00000.dwc3/xhci-hcd.1.auto/usb1/1-1/1-1.2/1-1.2.2/1-1.2.2:1.0/0003:12D1:109B.0002/input/input6
[pid:175,cpu0,kworker/0:1,5]hid-generic 0003:12D1:109B.0002: input,hidraw1: USB HID v1.10 Keyboard [HUAWEI HUAWEI USB Wired Keyboard] on usb-xhci-hcd.1.auto-1.2.2/input0
[pid:175,cpu0,kworker/0:1,9]hid-generic 0003:12D1:109B.0003: collection stack underflow
[pid:175,cpu0,kworker/0:1,0]hid-generic 0003:12D1:109B.0003: item 0 0 0 12 parsing failed
[pid:175,cpu0,kworker/0:1,1]hid-generic: probe of 0003:12D1:109B.0003 failed with error -22
...
When encountering such a situation, fix it with the correct report descriptor.

Signed-off-by: Miao Li <limiao@kylinos.cn>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-huawei.c [new file with mode: 0644]
drivers/hid/hid-ids.h

index c1d9f7c6a5f234ed97c716fe5d174aa640e62f0e..2fab4964d21ca805c9c751f6475749ce19f549d3 100644 (file)
@@ -1435,6 +1435,13 @@ config HID_KUNIT_TEST
 
          If in doubt, say "N".
 
+config HID_HUAWEI
+       tristate "Huawei HID devices support"
+       depends on USB_HID
+       help
+         Support for huawei cd30 keyboard or other hid devices
+         that need fix-ups to work properly.
+
 endmenu
 
 source "drivers/hid/bpf/Kconfig"
index e01838239ae64ca2d9b25534c890589476499830..616ff21852ca01c0e4c9465b91de4b95fd7d4cfc 100644 (file)
@@ -152,6 +152,7 @@ obj-$(CONFIG_HID_ZEROPLUS)  += hid-zpff.o
 obj-$(CONFIG_HID_ZYDACRON)     += hid-zydacron.o
 obj-$(CONFIG_HID_VIEWSONIC)    += hid-viewsonic.o
 obj-$(CONFIG_HID_VRC2)         += hid-vrc2.o
+obj-$(CONFIG_HID_HUAWEI)       += hid-huawei.o
 
 wacom-objs                     := wacom_wac.o wacom_sys.o
 obj-$(CONFIG_HID_WACOM)                += wacom.o
diff --git a/drivers/hid/hid-huawei.c b/drivers/hid/hid-huawei.c
new file mode 100644 (file)
index 0000000..6a616bf
--- /dev/null
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  HID driver for some huawei "special" devices
+ *
+ * Copyright (c) 2026 Miao Li <limiao@kylinos.cn>
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+static const __u8 huawei_cd30_kbd_rdesc_fixed[] = {
+       0x05, 0x01,             /* Usage Page (Generic Desktop)         */
+       0x09, 0x80,             /* Usage (System Control)               */
+       0xa1, 0x01,             /* Collection (Application)             */
+       0x85, 0x01,             /*   Report ID (1)                      */
+       0x19, 0x81,             /*   Usage Minimum (System Power Down)  */
+       0x29, 0x83,             /*   Usage Maximum (System Wake Up)     */
+       0x15, 0x00,             /*   Logical Minimum (0)                */
+       0x25, 0x01,             /*   Logical Maximum (1)                */
+       0x75, 0x01,             /*   Report Size (1 bit)                */
+       0x95, 0x03,             /*   Report Count (3)                   */
+       0x81, 0x02,             /*   Input (Data,Var,Abs)               */
+       0x95, 0x05,             /*   Report Count (5)                   */
+       0x81, 0x01,             /*   Input (Cnst,Ary,Abs)               */
+       0xc0,                   /* End Collection                       */
+       0x05, 0x0c,             /* Usage Page (Consumer)                */
+       0x09, 0x01,             /* Usage (Consumer Control)             */
+       0xa1, 0x01,             /* Collection (Application)             */
+       0x85, 0x02,             /*   Report ID (2)                      */
+       0x19, 0x00,             /*   Usage Minimum (0)                  */
+       0x2a, 0x3c, 0x02,       /*   Usage Maximum (0x023C)             */
+       0x15, 0x00,             /*   Logical Minimum (0)                */
+       0x26, 0x3c, 0x02,       /*   Logical Maximum (0x023C)           */
+       0x95, 0x01,             /*   Report Count (1)                   */
+       0x75, 0x10,             /*   Report Size (16 bits)              */
+       0x81, 0x00,             /*   Input (Data,Ary,Abs)               */
+       0xc0                    /* End Collection                       */
+};
+
+static const __u8 *huawei_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+                                 unsigned int *rsize)
+{
+       struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+
+       switch (hdev->product) {
+       case USB_DEVICE_ID_HUAWEI_CD30KBD:
+               if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
+                       if (*rsize != sizeof(huawei_cd30_kbd_rdesc_fixed) ||
+                               memcmp(huawei_cd30_kbd_rdesc_fixed, rdesc,
+                                       sizeof(huawei_cd30_kbd_rdesc_fixed)) != 0) {
+                               hid_info(hdev, "Replacing Huawei cd30 keyboard report descriptor.\n");
+                               *rsize = sizeof(huawei_cd30_kbd_rdesc_fixed);
+                               return huawei_cd30_kbd_rdesc_fixed;
+                       }
+               }
+               break;
+       }
+
+       return rdesc;
+}
+
+static const struct hid_device_id huawei_devices[] = {
+       /* HUAWEI cd30 keyboard */
+       { HID_USB_DEVICE(USB_VENDOR_ID_HUAWEI, USB_DEVICE_ID_HUAWEI_CD30KBD)},
+       { }
+};
+MODULE_DEVICE_TABLE(hid, huawei_devices);
+
+static struct hid_driver huawei_driver = {
+       .name = "huawei",
+       .id_table = huawei_devices,
+       .report_fixup = huawei_report_fixup,
+};
+module_hid_driver(huawei_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Miao Li <limiao@kylinos.cn>");
+MODULE_DESCRIPTION("HID driver for some huawei \"special\" devices");
index c1e4a6ce96317ab4df75b2e795d739e9cfd1ff32..91d650afdff36af57f901e0232c75072267ffb28 100644 (file)
 #define USB_VENDOR_ID_JIELI_SDK_DEFAULT                0x4c4a
 #define USB_DEVICE_ID_JIELI_SDK_4155           0x4155
 
+#define USB_VENDOR_ID_HUAWEI                   0x12d1
+#define USB_DEVICE_ID_HUAWEI_CD30KBD           0x109b
+
 #endif