Re: usb hid descriptor requirements are rejecting hardware (ZWO EFWmini, 03c3:1f01)

Benjamin Tissoires
2025-12-15T12:25:05Z

On Dec 15, 2025, Sam Halliday wrote:
> Hi Ben,
>
> In answer to your logging request, this is the output after running
>
> echo 'file drivers/hid/usbhid/hid-core.c +p' | sudo tee /sys/kernel/debug/dynamic_debug/control
>
> and plugging in the device (with the debian kernel, not my patched one)
>
> [ 371.897694] usb 1-2: new full-speed USB device number 8 using xhci_hcd
> [ 372.036133] usb 1-2: New USB device found, idVendor=03c3, idProduct=1f01, bcdDevice= 0.00
> [ 372.036145] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
> [ 372.036149] usb 1-2: Product: ZWO EFW
> [ 372.036152] usb 1-2: Manufacturer: ZW0
> [ 372.043375] drivers/hid/usbhid/hid-core.c: HID probe called for ifnum 0
> [ 372.043404] drivers/hid/usbhid/hid-core.c: hid descriptor invalid, bLen=9 bNum=2

Looks like the length is shorter than expected. However, after looking
more carefully into the code, it seems we can bypass the check as long
as the provided length is greater than sizeof(*hdesc), because later in
the code we simply ignore any optional HID class descriptors.

Would you mind testing the following patch?:

---
From 07020d68764a29a9e5d4e95be1820e0c75a4216a Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <bentiss@kernel.org>
Date: Mon, 15 Dec 2025 12:57:21 +0100
Subject: [PATCH] HID: usbhid: paper over wrong bNumDescriptor field

Some faulty devices (ZWO EFWmini) have a wrong optional HID class
descriptor count compared to the provided length.

Given that we plainly ignore those optional descriptor, we can attempt
to fix the provided number so we do not lock out those devices.

Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
drivers/hid/usbhid/hid-core.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index aac0051a2cf6..758eb21430cd 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -985,6 +985,7 @@ static int usbhid_parse(struct hid_device *hid)
struct usb_device *dev = interface_to_usbdev (intf);
struct hid_descriptor *hdesc;
struct hid_class_descriptor *hcdesc;
+ __u8 fixed_opt_descriptors_size;
u32 quirks = 0;
unsigned int rsize = 0;
char *rdesc;
@@ -1015,7 +1016,21 @@ static int usbhid_parse(struct hid_device *hid)
(hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) {
dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n",
hdesc->bLength, hdesc->bNumDescriptors);
- return -EINVAL;
+
+ /*
+ * Some devices may expose a wrong number of descriptors compared
+ * to the provided length.
+ * However, we ignore the optional hid class descriptors entirely
+ * so we can safely recompute the proper field.
+ */
+ if (hdesc->bLength >= sizeof(*hdesc)) {
+ fixed_opt_descriptors_size = hdesc->bLength - sizeof(*hdesc);
+
+ hid_warn(intf, "fixing wrong optional hid class descriptors count\n");
+ hdesc->bNumDescriptors = fixed_opt_descriptors_size / sizeof(*hcdesc) + 1;
+ } else {
+ return -EINVAL;
+ }
}

hid->version = le16_to_cpu(hdesc->bcdHID);
--
2.51.1

---

Cheers,
Benjamin

> [ 372.043409] usbhid 1-2:1.0: can't add hid device: -22
> [ 372.043422] usbhid 1-2:1.0: probe with driver usbhid failed with error -22
>
> Also here is a more detailed lsusb output
>
>
> Bus 001 Device 008: ID 03c3:1f01 ZWO ZWO EFW
> Negotiated speed: Full Speed (12Mbps)
> Device Descriptor:
> bLength 18
> bDescriptorType 1
> bcdUSB 1.10
> bDeviceClass 0 [unknown]
> bDeviceSubClass 0 [unknown]
> bDeviceProtocol 0
> bMaxPacketSize0 16
> idVendor 0x03c3 ZWO
> idProduct 0x1f01 ZWO EFW
> bcdDevice 0.00
> iManufacturer 1 ZW0
> iProduct 2 ZWO EFW
> iSerial 0
> bNumConfigurations 1
> Configuration Descriptor:
> bLength 9
> bDescriptorType 2
> wTotalLength 0x0029
> bNumInterfaces 1
> bConfigurationValue 1
> iConfiguration 0
> bmAttributes 0x80
> (Bus Powered)
> MaxPower 64mA
> Interface Descriptor:
> bLength 9
> bDescriptorType 4
> bInterfaceNumber 0
> bAlternateSetting 0
> bNumEndpoints 2
> bInterfaceClass 3 Human Interface Device
> bInterfaceSubClass 0 [unknown]
> bInterfaceProtocol 0
> iInterface 0
> Warning: Descriptor too short
> HID Device Descriptor:
> bLength 9
> bDescriptorType 33
> bcdHID 1.01
> bCountryCode 0 Not supported
> bNumDescriptors 2
> bDescriptorType 34 (null)
> wDescriptorLength 68
> bDescriptorType 0 (null)
> wDescriptorLength 0
> Report Descriptor: (length is 68)
> Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
> (null)
> Item(Local ): (null), data= [ 0x01 ] 1
> (null)
> Item(Main ): (null), data= [ 0x01 ] 1
> Application
> Item(Global): (null), data= [ 0x01 ] 1
> Item(Global): (null), data= [ 0x0f ] 15
> Item(Global): (null), data= [ 0x08 ] 8
> Item(Global): (null), data= [ 0xff 0x00 ] 255
> Item(Global): (null), data= [ 0x00 ] 0
> Item(Local ): (null), data= [ 0x01 ] 1
> (null)
> Item(Main ): (null), data= [ 0x02 ] 2
> Data Variable Absolute No_Wrap Linear
> Preferred_State No_Null_Position Non_Volatile Bitfield
> Item(Global): (null), data= [ 0x02 ] 2
> Item(Global): (null), data= [ 0x0f ] 15
> Item(Global): (null), data= [ 0x08 ] 8
> Item(Global): (null), data= [ 0xff 0x00 ] 255
> Item(Global): (null), data= [ 0x00 ] 0
> Item(Local ): (null), data= [ 0x01 ] 1
> (null)
> Item(Main ): (null), data= [ 0x02 ] 2
> Data Variable Absolute No_Wrap Linear
> Preferred_State No_Null_Position Non_Volatile Bitfield
> Item(Global): (null), data= [ 0x03 ] 3
> Item(Global): (null), data= [ 0x0f ] 15
> Item(Global): (null), data= [ 0x08 ] 8
> Item(Global): (null), data= [ 0xff 0x00 ] 255
> Item(Global): (null), data= [ 0x00 ] 0
> Item(Local ): (null), data= [ 0x01 ] 1
> (null)
> Item(Main ): (null), data= [ 0x02 ] 2
> Data Variable Absolute No_Wrap Linear
> Preferred_State No_Null_Position Non_Volatile Bitfield
> Item(Global): (null), data= [ 0x04 ] 4
> Item(Global): (null), data= [ 0x0f ] 15
> Item(Global): (null), data= [ 0x08 ] 8
> Item(Global): (null), data= [ 0xff 0x00 ] 255
> Item(Global): (null), data= [ 0x00 ] 0
> Item(Local ): (null), data= [ 0x01 ] 1
> (null)
> Item(Main ): (null), data= [ 0x02 ] 2
> Data Variable Absolute No_Wrap Linear
> Preferred_State No_Null_Position Non_Volatile Bitfield
> Item(Main ): (null), data=none
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x81 EP 1 IN
> bmAttributes 3
> Transfer Type Interrupt
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0010 1x 16 bytes
> bInterval 10
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x01 EP 1 OUT
> bmAttributes 3
> Transfer Type Interrupt
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0010 1x 16 bytes
> bInterval 10
> Device Status: 0x0000
>
>
> (Bus Powered)> On Dec 15 2025, Benjamin Tissoires wrote:
> > On Dec 14 2025, Salvatore Bonaccorso wrote:
> > > Hi Sam,
> > >
> > > Jiri, Benjamin, this is about a report originally done in Debian as
> > > https://bugs.debian.org/1122193 where Sam's device, a ZWO EFWmini with
> > > vendor and product id's as 03c3:1f01 is not working, usbhid not
> > > loaded.
> > >
> > > On Mon, Dec 08, 2025 at 03:03:49PM +0000, Sam Halliday wrote:
> > > > Package: linux-image-amd64
> > > > Version: 6.12.57-1
> > > > Severity: normal
> > > > Tags: patch
> > > > X-Debbugs-Cc: debian-amd64@lists.debian.org
> > > > User: debian-amd64@lists.debian.org
> > > > Usertags: amd64
> > > >
> > > > Dear Maintainer,
> > > >
> > > > I propose a patch to workaround USB HID descriptor requirements that
> > > > are stopping users from being able to use astrophotography
> > > > equipment.
> > > >
> > > > I have a usb device (an ZWO EFWmini, used for astronomy) which has
> > > > the following vendor information: 03c3:1f01 ZWO ZWO EFW
> > > >
> > > > This device is known to offer a suboptimal descriptor, e.g. see the lsusb output
> > > >
> > > > Warning: Descriptor too short
> > > > HID Device Descriptor:
> > > > bLength 9
> > > > bDescriptorType 33
> > > > bcdHID 1.01
> > > > bCountryCode 0 Not supported
> > > > bNumDescriptors 2
> > > > bDescriptorType 34 (null)
> > > > wDescriptorLength 68
> > > > bDescriptorType 0 (null)
> > > > wDescriptorLength 0
> > > > Report Descriptors:
> > > > ** UNAVAILABLE **
> > > >
> > > > My software (I write it, it is GPLv3, I'm the only user, but it isn't particularly relevant...) runs primarilly on a raspberry pi, which accepts this with kernel 6.12.25-1+rpt1, and I've also done some desktop development on archlinux (unknown kernel versions but up to at least 6 months ago). I only access the hardware for development from a debian desktop computer.
> > > >
> > > > Since moving to Debian 13, my hardware no longer works, with dmesg showing the following error:
> > > >
> > > > [ 14.182522] usb 1-2.2: new full-speed USB device number 10 using xhci_hcd
> > > > [ 14.276921] usb 1-2.2: New USB device found, idVendor=03c3, idProduct=1f01, bcdDevice= 0.00
> > > > [ 14.276930] usb 1-2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
> > > > [ 14.276933] usb 1-2.2: Product: ZWO EFW
> > > > [ 14.276935] usb 1-2.2: Manufacturer: ZW0
> > > > [ 14.282951] usbhid 1-2.2:1.0: can't add hid device: -22
> > > > [ 14.282963] usbhid 1-2.2:1.0: probe with driver usbhid failed with error -22
> > > >
> > > > I have tried going back as far as debian's kernel from bullseye (5.10), bookworm (6.1), trixie (6.12) and backports (6.17) but it's the same error every time.
> > > >
> > > > Communicating with the ZWO (the device manufacturer) support team, they recommended patching the kernel, which I did, and it now works.
> > > >
> > > > I applied the following patch and built my own kernel
> > > >
> > > > ===========================================================================
> > > > --- drivers/hid/usbhid/hid-core.c.orig 2025-12-08 13:15:08.657917762 +0000
> > > > +++ drivers/hid/usbhid/hid-core.c 2025-12-08 13:16:24.293959487 +0000
> > > > @@ -1015,7 +1015,7 @@
> > > > (hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) {
> > > > dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n",
> > > > hdesc->bLength, hdesc->bNumDescriptors);
> > > > - return -EINVAL;
> > > > + // return -EINVAL;
> >
> > That looks like the wrong thing to do, especialy because the 2 previous
> > commits introducing that check are to protect against out of bound
> > errors:
> > See fe7f7ac8e0c7 ("HID: usbhid: Eliminate recurrent out-of-bounds bug in usbhid_parse()")
> >
> > Can we get the debug output from the line above (or just add plain
> > printks in the running kernel)? I suspect we might losen the test with a
> > '<' instead of an '!='.
> >
> > > > }
> > > >
> > > > hid->version = le16_to_cpu(hdesc->bcdHID);
> > > > ===========================================================================
> > > >
> > > > The new dmesg output is
> > > >
> > > > [ 366.477628] usbhid 1-2:1.0: 1 unsupported optional hid class descriptors
> > > > [ 366.478327] hid-generic 0003:03C3:1F01.0006: hiddev1,hidraw4: USB HID v1.01 Device [ZW0 ZWO EFW] on usb-000
> > > >
> > > >
> > > > Apologies but I don't think I'm giving you a particularly good patch
> > > > because the author of this code clearly intended for a -EINVAL
> > > > failure. A kernel dev may prefer to create a hardware quirk (which
> > > > ideally should be enabled for 03c3:1f01 by default) to exit if the
> > > > descriptor isn't valid. I'm not a kernel developer so that's beyond
> > > > me.
> > > >
> > > > The device works perfectly fine despite the descriptor not meeting
> > > > the kernel's current requirements. And I don't believe a firmware
> > > > upgrade is possible... it's just a little motor that turns a wheel
> > > > containing photographic filters.
> > >
> > > I suspect your case can be a candidate for HID-BPF, cf.
> > > https://docs.kernel.org/hid/hid-bpf.html and you might try to fixup
> > > the required descriptors.
> >
> > Unfortunatelly no. HID-BPF works for fixing HID protocol errors, but in
> > this case the device is not presented by the transport layer, so we can
> > not do anything there :(
> >
> > >
> > > But I'm not entirely sure. Jiri and Benjamin is that something we
> > > could have quirk for the device or the problem tackled in some other
> > > way?
> >
> > Quirking seems the wrong approach. I would be curious to know the length
> > of the binary descriptor. I suspect there is some mismatch and the end
> > is filled with 0. If the length is shorter, that's going to be a bigger
> > problem to solve.
> >
> > Cheers,
> > Benjamin
> >
> > >
> > > Regards,
> > > Salvatore