* [PATCH v4 0/2] usb: core: Add quirk for 255-byte initial config read
@ 2026-07-27 19:54 Nikhil Solanke
2026-07-27 19:54 ` [PATCH v4 1/2] usb: core: Add quirk for 255-bytes " Nikhil Solanke
2026-07-27 19:54 ` [PATCH v4 2/2] usb: hub: Split announce_device() to log device identity before enumeration Nikhil Solanke
0 siblings, 2 replies; 6+ messages in thread
From: Nikhil Solanke @ 2026-07-27 19:54 UTC (permalink / raw)
To: linux-usb
Cc: gregkh, linux-kernel, stern, michal.pecio, corbet, skhan, stable,
linux-doc, Nikhil Solanke
This series adds a quirk for USB devices that fail enumeration when
the initial GET_DESCRIPTOR(CONFIGURATION) request uses wLength=9.
Patch 1 adds USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE which causes
usb_get_configuration() to use wLength=255 for the initial config
descriptor request, mirroring long-standing Windows behavior.
Patch 2 splits announce_device() to log device identity before
enumeration, improving failure diagnosis.
Nikhil Solanke (2):
usb: core: Add quirk for 255-bytes initial config read
usb: hub: Split announce_device() to log device identity before
enumeration
Changes in v4:
- Reworded comments and messages
- Moved the memcpy() block that skips the second read after USB_QUIRK_DELAY_INIT
.../admin-guide/kernel-parameters.txt | 5 +++
drivers/usb/core/config.c | 32 ++++++++++++++-----
drivers/usb/core/hub.c | 16 +++++++---
drivers/usb/core/quirks.c | 4 +++
include/linux/usb/quirks.h | 3 ++
5 files changed, 48 insertions(+), 12 deletions(-)
--
2.54.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v4 1/2] usb: core: Add quirk for 255-bytes initial config read 2026-07-27 19:54 [PATCH v4 0/2] usb: core: Add quirk for 255-byte initial config read Nikhil Solanke @ 2026-07-27 19:54 ` Nikhil Solanke 2026-07-28 1:59 ` Alan Stern 2026-07-27 19:54 ` [PATCH v4 2/2] usb: hub: Split announce_device() to log device identity before enumeration Nikhil Solanke 1 sibling, 1 reply; 6+ messages in thread From: Nikhil Solanke @ 2026-07-27 19:54 UTC (permalink / raw) To: linux-usb Cc: gregkh, linux-kernel, stern, michal.pecio, corbet, skhan, stable, linux-doc, Nikhil Solanke Certain third-party USB game controllers exposing (or spoofing) an Xbox 360-compatible interface (VID:PID 045e:028e) fail to enumerate under Linux. The device disconnects from the bus without responding to the initial GET_DESCRIPTOR(CONFIGURATION) request, and the kernel logs 'unable to read config index 0 descriptor/start: -71'. The device then falls back to a secondary Android HID mode (with a different VID:PID), losing XInput functionality including rumble support. The failure reproduces across multiple machines, host controller types, and kernel versions including current mainline and LTS. The device enumerates correctly and remains in XInput mode under Windows. Notably, the device enumerates correctly in Android mode when the same 9-byte request is issued for that mode's configuration descriptor, confirming the firmware bug is specific to the XInput mode. usbmon traces from Linux and Wireshark/USBPcap traces from Windows are identical up to the point of failure, with no visible protocol-level difference explaining the divergence. The root cause was identified when Michal Pecio discovered via a QEMU bus-level capture that Windows does not use wLength=9 for the initial config descriptor request; it uses wLength=255. Alan Stern subsequently confirmed this with a bus analyzer on a different USB 2.0 device, and Michal verified the behavior goes back to Windows 95 OSR2.1. So, add a new quirk flag USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE which causes usb_get_configuration() to issue a 255 byte sized configuration request instead of USB_DT_CONFIG_SIZE (9) for the initial GET_DESCRIPTOR(CONFIGURATION) request, mimicking long-standing Windows behavior. Suggested-by: Alan Stern <stern@rowland.harvard.edu> Suggested-by: Michal Pecio <michal.pecio@gmail.com> Closes: https://lore.kernel.org/linux-usb/CAFgddh+JWdT4LLwMc5qjM8q_pBu-fRo2qADR5ovAKoGHWMQrRw@mail.gmail.com/ Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Nikhil Solanke <nikhilsolanke5@gmail.com> --- Changes in v4: - Reworded comments and messages - Moved the memcpy() block that skips the second read after USB_QUIRK_DELAY_INIT .../admin-guide/kernel-parameters.txt | 5 +++ drivers/usb/core/config.c | 32 ++++++++++++++----- drivers/usb/core/quirks.c | 4 +++ include/linux/usb/quirks.h | 3 ++ 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index b5493a7f8f22..3d35270dddef 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -8169,6 +8169,11 @@ Kernel parameters q = USB_QUIRK_FORCE_ONE_CONFIG (Device claims zero configurations, forcing to 1); + r = USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE (Device + fails during initialization when asked for + 9-bytes configuration descriptor request. + Ask for 255-bytes request instead to mirror + Windows' behavior); Example: quirks=0781:5580:bk,0a5c:5834:gij usbhid.mousepoll= diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 45e20c6d76c0..346a2faa9bb8 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -912,6 +912,18 @@ int usb_get_configuration(struct usb_device *dev) unsigned char *bigbuffer; struct usb_config_descriptor *desc; int result; + size_t usb_config_req_size; + + /* + * We usually start by grabbing the first 9-bytes descriptor so we know + * how long the whole configuration is. Some devices with quirky + * firmware will fail enumeration, so if the quirk is set, use 255 instead, + * mirroring the behavior of Windows. + */ + if (dev->quirks & USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE) + usb_config_req_size = 255; + else + usb_config_req_size = USB_DT_CONFIG_SIZE; if (ncfg > USB_MAXCONFIG) { dev_notice(ddev, "too many configurations: %d, " @@ -938,15 +950,13 @@ int usb_get_configuration(struct usb_device *dev) if (!dev->rawdescriptors) return -ENOMEM; - desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL); + desc = kmalloc(usb_config_req_size, GFP_KERNEL); if (!desc) return -ENOMEM; for (cfgno = 0; cfgno < ncfg; cfgno++) { - /* We grab just the first descriptor so we know how long - * the whole configuration is */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, - desc, USB_DT_CONFIG_SIZE); + desc, usb_config_req_size); if (result < 0) { dev_err(ddev, "unable to read config index %d " "descriptor/%s: %d\n", cfgno, "start", result); @@ -956,16 +966,14 @@ int usb_get_configuration(struct usb_device *dev) dev->descriptor.bNumConfigurations = cfgno; break; } else if (result < 4) { - dev_err(ddev, "config index %d descriptor too short " - "(expected %i, got %i)\n", cfgno, - USB_DT_CONFIG_SIZE, result); + dev_err(ddev, "config index %d descriptor too short (asked for %zu, got %i)\n", + cfgno, usb_config_req_size, result); result = -EINVAL; goto err; } length = max_t(int, le16_to_cpu(desc->wTotalLength), USB_DT_CONFIG_SIZE); - /* Now that we know the length, get the whole thing */ bigbuffer = kmalloc(length, GFP_KERNEL); if (!bigbuffer) { result = -ENOMEM; @@ -975,6 +983,13 @@ int usb_get_configuration(struct usb_device *dev) if (dev->quirks & USB_QUIRK_DELAY_INIT) msleep(200); + /* Skip the second read if we already got everything */ + if (result >= length) { + memcpy(bigbuffer, desc, length); + goto store_and_parse; + } + + /* Get the whole thing */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length); if (result < 0) { @@ -989,6 +1004,7 @@ int usb_get_configuration(struct usb_device *dev) length = result; } +store_and_parse: dev->rawdescriptors[cfgno] = bigbuffer; result = usb_parse_configuration(dev, cfgno, diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 87ee2d938bc0..f5a60ccf21d3 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -142,6 +142,10 @@ static int quirks_param_set(const char *value, const struct kernel_param *kp) break; case 'q': flags |= USB_QUIRK_FORCE_ONE_CONFIG; + break; + case 'r': + flags |= USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE; + break; /* Ignore unrecognized flag characters */ } } diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index b3cc7beab4a3..a4043b33c2c2 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -81,4 +81,7 @@ /* Device claims zero configurations, forcing to 1 */ #define USB_QUIRK_FORCE_ONE_CONFIG BIT(18) +/* Use a 255 bytes config descriptor request mirroring windows behavior */ +#define USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE BIT(19) + #endif /* __LINUX_USB_QUIRKS_H */ -- 2.54.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v4 1/2] usb: core: Add quirk for 255-bytes initial config read 2026-07-27 19:54 ` [PATCH v4 1/2] usb: core: Add quirk for 255-bytes " Nikhil Solanke @ 2026-07-28 1:59 ` Alan Stern 2026-07-28 8:07 ` Nikhil Solanke 0 siblings, 1 reply; 6+ messages in thread From: Alan Stern @ 2026-07-28 1:59 UTC (permalink / raw) To: Nikhil Solanke Cc: linux-usb, gregkh, linux-kernel, michal.pecio, corbet, skhan, stable, linux-doc On Tue, Jul 28, 2026 at 01:24:33AM +0530, Nikhil Solanke wrote: > Certain third-party USB game controllers exposing (or spoofing) an Xbox > 360-compatible interface (VID:PID 045e:028e) fail to enumerate under Linux. > The device disconnects from the bus without responding to the initial > GET_DESCRIPTOR(CONFIGURATION) request, and the kernel logs 'unable to read > config index 0 descriptor/start: -71'. > > The device then falls back to a secondary Android HID mode (with a > different VID:PID), losing XInput functionality including rumble support. > The failure reproduces across multiple machines, host controller types, and > kernel versions including current mainline and LTS. The device enumerates > correctly and remains in XInput mode under Windows. Notably, the device > enumerates correctly in Android mode when the same 9-byte request > is issued for that mode's configuration descriptor, confirming the firmware > bug is specific to the XInput mode. > > usbmon traces from Linux and Wireshark/USBPcap traces from Windows are > identical up to the point of failure, with no visible protocol-level > difference explaining the divergence. The root cause was identified when > Michal Pecio discovered via a QEMU bus-level capture that Windows does not > use wLength=9 for the initial config descriptor request; it uses > wLength=255. Alan Stern subsequently confirmed this with a bus > analyzer on a different USB 2.0 device, and Michal verified the behavior > goes back to Windows 95 OSR2.1. > > So, add a new quirk flag USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE which causes > usb_get_configuration() to issue a 255 byte sized configuration request > instead of USB_DT_CONFIG_SIZE (9) for the initial > GET_DESCRIPTOR(CONFIGURATION) request, mimicking long-standing Windows > behavior. > > Suggested-by: Alan Stern <stern@rowland.harvard.edu> > Suggested-by: Michal Pecio <michal.pecio@gmail.com> > Closes: https://lore.kernel.org/linux-usb/CAFgddh+JWdT4LLwMc5qjM8q_pBu-fRo2qADR5ovAKoGHWMQrRw@mail.gmail.com/ > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") > Cc: stable@vger.kernel.org > Signed-off-by: Nikhil Solanke <nikhilsolanke5@gmail.com> > --- Your patches basically looks fine to me. Just a couple of things to note... Personally, I prefer to see comments that don't extend beyond the 80-column limit. But there's no hard rule about this, it's just my own preference -- you don't have to change anything if you don't want to. Also, it's odd that you add the quirk flag to the kernel without adding a new quirk entry for the Xbox 360-compatible devices. That doesn't have to be done in this patch, though; it can be done in a follow-up. (But note that without a followup this patch doesn't actually fix anything, since a true fix would require user intervention.) Finally, a really minor nit: The two patches in this series are completely independent; either one can be applied without the other. That means they don't really belong in a series, that is, they should be submitted as two separate patches. Obviously that doesn't matter at all in practice; it's just a matter of principle. Anyway, for both patches 1 and 2: Acked-by: Alan Stern <stern@rowland.harvard.edu> If you want to rewrite and resubmit them along the lines mentioned above, you can add my Acked-by to the new submissions. Alan Stern ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4 1/2] usb: core: Add quirk for 255-bytes initial config read 2026-07-28 1:59 ` Alan Stern @ 2026-07-28 8:07 ` Nikhil Solanke 2026-07-28 15:18 ` Alan Stern 0 siblings, 1 reply; 6+ messages in thread From: Nikhil Solanke @ 2026-07-28 8:07 UTC (permalink / raw) To: Alan Stern Cc: linux-usb, gregkh, linux-kernel, michal.pecio, corbet, skhan, stable, linux-doc On Tue, 28 Jul 2026 at 07:29, Alan Stern <stern@rowland.harvard.edu> wrote: > > Also, it's odd that you add the quirk flag to the kernel without adding > a new quirk entry for the Xbox 360-compatible devices. That doesn't > have to be done in this patch, though; it can be done in a follow-up. > (But note that without a followup this patch doesn't actually fix > anything, since a true fix would require user intervention.) > Well the device I am using spoofs Microsoft's device IDs directly. I avoided adding it because the official xbox controllers work out of the box. It won't break their functionality, but it kinda falls into the category of "if it ain't broken, why fix it". Other clone devices use different VID:PID pair as well, like with what happened Ishaan's device (his reply to my previous patch revision). I believe they should be added here instead. Since there are many such devices, gathering all the IDs would take considerable time and community work. Also, the kernel's own xpad module is slightly behind some changes or so I have heard. There are a few community maintained kernel modules/drivers with many changes that are required for these devices to actually function. There is some magic packet that needs to be sent after the usb device has initialized along with doing a bunch of other things like mapping out buttons, etc. These drivers are also required for a device to fully function in most cases (the builtin xpad also works in some cases). So just by adding a device to the quirk list wouldn't truly fix it. There's still a lot of issues that need to be addressed in the kernel driver space to "truly" fix Xbox 360-compatible devices (majorly, hid-generic or other drivers claim the devices before these out-of-tree modules due to race conditions). My patch is just the first step. > > Finally, a really minor nit: The two patches in this series are > completely independent; either one can be applied without the other. > That means they don't really belong in a series, that is, they should be > submitted as two separate patches. Obviously that doesn't matter at all > in practice; it's just a matter of principle. > > Anyway, for both patches 1 and 2: > > Acked-by: Alan Stern <stern@rowland.harvard.edu> > > If you want to rewrite and resubmit them along the lines mentioned > above, you can add my Acked-by to the new submissions. > > Alan Stern Thanks! I would like to know your thoughts on the above points as to what should be preferably done moving forward. If it happens that I should send in another patch, I will address the nits and add the Acked-By as well. Thanks, Nikhil Solanke ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4 1/2] usb: core: Add quirk for 255-bytes initial config read 2026-07-28 8:07 ` Nikhil Solanke @ 2026-07-28 15:18 ` Alan Stern 0 siblings, 0 replies; 6+ messages in thread From: Alan Stern @ 2026-07-28 15:18 UTC (permalink / raw) To: Nikhil Solanke Cc: linux-usb, gregkh, linux-kernel, michal.pecio, corbet, skhan, stable, linux-doc On Tue, Jul 28, 2026 at 01:37:16PM +0530, Nikhil Solanke wrote: > On Tue, 28 Jul 2026 at 07:29, Alan Stern <stern@rowland.harvard.edu> wrote: > > > > Also, it's odd that you add the quirk flag to the kernel without adding > > a new quirk entry for the Xbox 360-compatible devices. That doesn't > > have to be done in this patch, though; it can be done in a follow-up. > > (But note that without a followup this patch doesn't actually fix > > anything, since a true fix would require user intervention.) > > > > Well the device I am using spoofs Microsoft's device IDs directly. I > avoided adding it because the official xbox controllers work out of > the box. It won't break their functionality, but it kinda falls into > the category of "if it ain't broken, why fix it". Other clone devices > use different VID:PID pair as well, like with what happened Ishaan's > device (his reply to my previous patch revision). I believe they > should be added here instead. Since there are many such devices, > gathering all the IDs would take considerable time and community work. Okay. It's worth mentioning this in the patch description. > Also, the kernel's own xpad module is slightly behind some changes or > so I have heard. There are a few community maintained kernel > modules/drivers with many changes that are required for these devices > to actually function. There is some magic packet that needs to be sent > after the usb device has initialized along with doing a bunch of other > things like mapping out buttons, etc. These drivers are also required > for a device to fully function in most cases (the builtin xpad also > works in some cases). So just by adding a device to the quirk list > wouldn't truly fix it. > > There's still a lot of issues that need to be addressed in the kernel > driver space to "truly" fix Xbox 360-compatible devices (majorly, > hid-generic or other drivers claim the devices before these > out-of-tree modules due to race conditions). My patch is just the > first step. Got it. > Thanks! I would like to know your thoughts on the above points as to > what should be preferably done moving forward. If it happens that I > should send in another patch, I will address the nits and add the > Acked-By as well. That's up to you. What you have done so far is already acceptable, IMO. Alan Stern ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v4 2/2] usb: hub: Split announce_device() to log device identity before enumeration 2026-07-27 19:54 [PATCH v4 0/2] usb: core: Add quirk for 255-byte initial config read Nikhil Solanke 2026-07-27 19:54 ` [PATCH v4 1/2] usb: core: Add quirk for 255-bytes " Nikhil Solanke @ 2026-07-27 19:54 ` Nikhil Solanke 1 sibling, 0 replies; 6+ messages in thread From: Nikhil Solanke @ 2026-07-27 19:54 UTC (permalink / raw) To: linux-usb Cc: gregkh, linux-kernel, stern, michal.pecio, corbet, skhan, stable, linux-doc, Nikhil Solanke announce_device() currently logs the device VID:PID and string descriptors only after successful enumeration. This means that if enumeration fails, no identifying information about the device appears in the kernel log, making it difficult to diagnose failures. Split announce_device() into announce_device_ids(), which logs the VID:PID and bcdDevice immediately after the device descriptor is read, and announce_device_strings(), which logs the product, manufacturer, and serial number strings after successful enumeration. This ensures that a device's identity is always visible in the log regardless of whether enumeration succeeds or fails. Suggested-by: Michal Pecio <michal.pecio@gmail.com> Signed-off-by: Nikhil Solanke <nikhilsolanke5@gmail.com> --- drivers/usb/core/hub.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 5262e11c12cd..d92bf887739d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2401,7 +2401,7 @@ static void show_string(struct usb_device *udev, char *id, char *string) dev_info(&udev->dev, "%s: %s\n", id, string); } -static void announce_device(struct usb_device *udev) +static void announce_device_ids(struct usb_device *udev) { u16 bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice); @@ -2410,6 +2410,10 @@ static void announce_device(struct usb_device *udev) le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), bcdDevice >> 8, bcdDevice & 0xff); +} + +static void announce_device_strings(struct usb_device *udev) +{ dev_info(&udev->dev, "New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n", udev->descriptor.iManufacturer, @@ -2420,7 +2424,8 @@ static void announce_device(struct usb_device *udev) show_string(udev, "SerialNumber", udev->serial); } #else -static inline void announce_device(struct usb_device *udev) { } +static inline void announce_device_ids(struct usb_device *udev) { } +static inline void announce_device_strings(struct usb_device *udev) { } #endif @@ -2651,6 +2656,9 @@ int usb_new_device(struct usb_device *udev) device_init_wakeup(&udev->dev, 0); } + /* Announce the device identity */ + announce_device_ids(udev); + /* Tell the runtime-PM framework the device is active */ pm_runtime_set_active(&udev->dev); pm_runtime_get_noresume(&udev->dev); @@ -2672,8 +2680,8 @@ int usb_new_device(struct usb_device *udev) udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); - /* Tell the world! */ - announce_device(udev); + /* Announce the device's product, manufacturer and serial number */ + announce_device_strings(udev); if (udev->serial) add_device_randomness(udev->serial, strlen(udev->serial)); -- 2.54.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-07-28 15:18 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-27 19:54 [PATCH v4 0/2] usb: core: Add quirk for 255-byte initial config read Nikhil Solanke 2026-07-27 19:54 ` [PATCH v4 1/2] usb: core: Add quirk for 255-bytes " Nikhil Solanke 2026-07-28 1:59 ` Alan Stern 2026-07-28 8:07 ` Nikhil Solanke 2026-07-28 15:18 ` Alan Stern 2026-07-27 19:54 ` [PATCH v4 2/2] usb: hub: Split announce_device() to log device identity before enumeration Nikhil Solanke
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox