* [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
@ 2026-06-23 16:10 Nikhil Solanke
2026-06-23 18:35 ` Randy Dunlap
2026-06-23 20:24 ` Alan Stern
0 siblings, 2 replies; 5+ messages in thread
From: Nikhil Solanke @ 2026-06-23 16:10 UTC (permalink / raw)
To: linux-usb
Cc: gregkh, linux-kernel, stern, michal.pecio, stable, corbet, skhan,
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_CONFIG_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 v2:
- Add Documentation
- Naming changes
- Refactored to have a better flow with existing code.
.../admin-guide/kernel-parameters.txt | 9 +++
drivers/usb/core/config.c | 61 ++++++++++++++-----
drivers/usb/core/hub.c | 6 +-
drivers/usb/core/quirks.c | 4 ++
include/linux/usb/quirks.h | 3 +
5 files changed, 67 insertions(+), 16 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 97007f4f69d4..af4bf0ef2c7b 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -8158,6 +8158,15 @@ 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 desciptor request. Ask
+ for 255-bytes request instead to mirror
+ Windows' behavior. This quirk is originally
+ meant to fix some quirky gamepads that refuse
+ to connect in their XInput mode. But it can also
+ potentially fix issues with other USB devices
+ that work on Windows but not on Linux)
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..4fc3145404d6 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -19,6 +19,9 @@
#define USB_MAXCONFIG 8 /* Arbitrary limit */
+/* config req size if USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE is set */
+#define USB_CONFIG_WINDOWS_REQ_SIZE 255
+
static int find_next_descriptor(unsigned char *buffer, int size,
int dt1, int dt2, int *num_skipped)
{
@@ -912,6 +915,13 @@ int usb_get_configuration(struct usb_device *dev)
unsigned char *bigbuffer;
struct usb_config_descriptor *desc;
int result;
+ /*
+ * Devices with quirky firmware will stall or reset when asked only for
+ * the configuration header. This variable decides which size to use in
+ * that case, if the quirk for that device was set.
+ */
+ size_t usb_config_req_size = (dev->quirks & USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE)
+ ? USB_CONFIG_WINDOWS_REQ_SIZE : USB_DT_CONFIG_SIZE;
if (ncfg > USB_MAXCONFIG) {
dev_notice(ddev, "too many configurations: %d, "
@@ -938,18 +948,27 @@ 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 */
+
+ if (dev->quirks & USB_QUIRK_DELAY_INIT)
+ msleep(200);
+
+ /*
+ * Grab just the first descriptor so we know how long the whole
+ * configuration is. In case of quirky firmware, try to grab the
+ * whole thing in one go by asking for a 255-bytes sized buffer
+ * mirroring Windows behavior.
+ */
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);
+ "descriptor/%s: %d\n", cfgno, "start", result);
if (result != -EPIPE)
goto err;
dev_notice(ddev, "chopping to %d config(s)\n", cfgno);
@@ -957,13 +976,25 @@ int usb_get_configuration(struct usb_device *dev)
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);
+ "(asked for %zu, got %i, expected at least %i)\n",
+ cfgno, usb_config_req_size, result, 4);
result = -EINVAL;
goto err;
}
+
length = max_t(int, le16_to_cpu(desc->wTotalLength),
- USB_DT_CONFIG_SIZE);
+ USB_DT_CONFIG_SIZE);
+
+ /*
+ * If the device returns the full length configuration
+ * descriptor, skip the second read. Otherwise, send a second
+ * request asking for the full length.
+ */
+ if (result >= le16_to_cpu(desc->wTotalLength)) {
+ bigbuffer = (unsigned char *) desc;
+ desc = NULL;
+ goto store_and_parse;
+ }
/* Now that we know the length, get the whole thing */
bigbuffer = kmalloc(length, GFP_KERNEL);
@@ -972,23 +1003,25 @@ int usb_get_configuration(struct usb_device *dev)
goto err;
}
- if (dev->quirks & USB_QUIRK_DELAY_INIT)
- msleep(200);
-
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
- bigbuffer, length);
+ bigbuffer, length);
+
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
- "descriptor/%s\n", cfgno, "all");
+ "descriptor/%s\n", cfgno, "all");
kfree(bigbuffer);
goto err;
}
+
if (result < length) {
dev_notice(ddev, "config index %d descriptor too short "
- "(expected %i, got %i)\n", cfgno, length, result);
+ "(asked for %i, got %i)\n",
+ cfgno, length, result);
length = result;
}
+store_and_parse:
+ krealloc(bigbuffer, length, GFP_KERNEL);
dev->rawdescriptors[cfgno] = bigbuffer;
result = usb_parse_configuration(dev, cfgno,
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 24960ba9caa9..9acd278666fc 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2527,8 +2527,10 @@ static int usb_enumerate_device(struct usb_device *udev)
err = usb_get_configuration(udev);
if (err < 0) {
if (err != -ENODEV)
- dev_err(&udev->dev, "can't read configurations, error %d\n",
- err);
+ dev_err(&udev->dev, "can't read configurations, "
+ "for device %04x:%04x, error %d\n",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct), err);
return err;
}
}
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 87810eff974e..df670b0b66fe 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] 5+ messages in thread
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
2026-06-23 16:10 [PATCH v2] usbcore: Add quirk for 255-bytes initial config read Nikhil Solanke
@ 2026-06-23 18:35 ` Randy Dunlap
2026-06-23 19:08 ` Nikhil Solanke
2026-06-23 20:24 ` Alan Stern
1 sibling, 1 reply; 5+ messages in thread
From: Randy Dunlap @ 2026-06-23 18:35 UTC (permalink / raw)
To: Nikhil Solanke, linux-usb
Cc: gregkh, linux-kernel, stern, michal.pecio, stable, corbet, skhan,
linux-doc
On 6/23/26 9:10 AM, 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_CONFIG_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 v2:
> - Add Documentation
> - Naming changes
> - Refactored to have a better flow with existing code.
>
> .../admin-guide/kernel-parameters.txt | 9 +++
> drivers/usb/core/config.c | 61 ++++++++++++++-----
> drivers/usb/core/hub.c | 6 +-
> drivers/usb/core/quirks.c | 4 ++
> include/linux/usb/quirks.h | 3 +
> 5 files changed, 67 insertions(+), 16 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 97007f4f69d4..af4bf0ef2c7b 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -8158,6 +8158,15 @@ 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 desciptor request. Ask
descriptor
> + for 255-bytes request instead to mirror
> + Windows' behavior. This quirk is originally
> + meant to fix some quirky gamepads that refuse
> + to connect in their XInput mode. But it can also
> + potentially fix issues with other USB devices
> + that work on Windows but not on Linux)
add ending '.'
For all lines added here, use tabs instead of spaces for indentation.
> Example: quirks=0781:5580:bk,0a5c:5834:gij
>
> usbhid.mousepoll=
--
~Randy
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
2026-06-23 18:35 ` Randy Dunlap
@ 2026-06-23 19:08 ` Nikhil Solanke
0 siblings, 0 replies; 5+ messages in thread
From: Nikhil Solanke @ 2026-06-23 19:08 UTC (permalink / raw)
To: Randy Dunlap
Cc: linux-usb, gregkh, linux-kernel, stern, michal.pecio, stable,
corbet, skhan, linux-doc
> add ending '.'
>
> For all lines added here, use tabs instead of spaces for indentation.
Done! Waiting for any other changes before submitting v3
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
2026-06-23 16:10 [PATCH v2] usbcore: Add quirk for 255-bytes initial config read Nikhil Solanke
2026-06-23 18:35 ` Randy Dunlap
@ 2026-06-23 20:24 ` Alan Stern
2026-06-23 21:14 ` Nikhil Solanke
1 sibling, 1 reply; 5+ messages in thread
From: Alan Stern @ 2026-06-23 20:24 UTC (permalink / raw)
To: Nikhil Solanke
Cc: linux-usb, gregkh, linux-kernel, michal.pecio, stable, corbet,
skhan, linux-doc
This is looking better. A few more things to mention below, but
otherwise okay.
On Tue, Jun 23, 2026 at 09:40:35PM +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_CONFIG_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>
Normally people don't leave a blank line before their Signed-off-by:
(unless it's the first tag to appear). But I don't think it makes any
difference, especially if the checkpatch.pl script doesn't object.
> ---
> Changes in v2:
> - Add Documentation
> - Naming changes
> - Refactored to have a better flow with existing code.
>
> .../admin-guide/kernel-parameters.txt | 9 +++
> drivers/usb/core/config.c | 61 ++++++++++++++-----
> drivers/usb/core/hub.c | 6 +-
> drivers/usb/core/quirks.c | 4 ++
> include/linux/usb/quirks.h | 3 +
> 5 files changed, 67 insertions(+), 16 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 97007f4f69d4..af4bf0ef2c7b 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -8158,6 +8158,15 @@ 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 desciptor request. Ask
> + for 255-bytes request instead to mirror
> + Windows' behavior. This quirk is originally
> + meant to fix some quirky gamepads that refuse
> + to connect in their XInput mode. But it can also
> + potentially fix issues with other USB devices
> + that work on Windows but not on Linux)
> Example: quirks=0781:5580:bk,0a5c:5834:gij
As Randy said, use tabs instead of spaces. And this new entry should be
aligned with all the preceding entries, and it should end with a ';'
like they do.
I would leave out the two sentences of explanation, but that's more of a
personal choice. We'll see if Greg KH objects.
>
> usbhid.mousepoll=
> diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
> index 45e20c6d76c0..4fc3145404d6 100644
> --- a/drivers/usb/core/config.c
> +++ b/drivers/usb/core/config.c
> @@ -19,6 +19,9 @@
>
> #define USB_MAXCONFIG 8 /* Arbitrary limit */
>
> +/* config req size if USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE is set */
> +#define USB_CONFIG_WINDOWS_REQ_SIZE 255
> +
> static int find_next_descriptor(unsigned char *buffer, int size,
> int dt1, int dt2, int *num_skipped)
> {
> @@ -912,6 +915,13 @@ int usb_get_configuration(struct usb_device *dev)
> unsigned char *bigbuffer;
> struct usb_config_descriptor *desc;
> int result;
> + /*
> + * Devices with quirky firmware will stall or reset when asked only for
> + * the configuration header. This variable decides which size to use in
> + * that case, if the quirk for that device was set.
> + */
> + size_t usb_config_req_size = (dev->quirks & USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE)
> + ? USB_CONFIG_WINDOWS_REQ_SIZE : USB_DT_CONFIG_SIZE;
It's a little unusual to have a multiline comment in the middle of a
bunch of variable definitions. The alternative is to do the assignment
later on and move the comment there.
>
> if (ncfg > USB_MAXCONFIG) {
> dev_notice(ddev, "too many configurations: %d, "
> @@ -938,18 +948,27 @@ 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 */
> +
> + if (dev->quirks & USB_QUIRK_DELAY_INIT)
> + msleep(200);
Moving this delay up here changes the behavior when the quirk flag isn't
set. While it agrees with the intention of the USB_QUIRK_DELAY_INIT
flag, such a change should be mentioned in the patch description.
> +
> + /*
> + * Grab just the first descriptor so we know how long the whole
> + * configuration is. In case of quirky firmware, try to grab the
> + * whole thing in one go by asking for a 255-bytes sized buffer
> + * mirroring Windows behavior.
> + */
This needs to be rewritten, as it is self-contradictory. When the quirk
flag is set we issue a 255-byte request to mimic the Windows behavior,
and only when the flag isn't set do we grab just the first descriptor.
> result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
> - desc, USB_DT_CONFIG_SIZE);
> + desc, usb_config_req_size);
Don't make extraneous changes to the existing indentation (or whitespace
in general), here and below.
> if (result < 0) {
> dev_err(ddev, "unable to read config index %d "
> - "descriptor/%s: %d\n", cfgno, "start", result);
> + "descriptor/%s: %d\n", cfgno, "start", result);
At the time this code was originally written, the policy for kernel code
was to break lines before 80 columns. Since then the policy has changed
to avoid splitting long literal strings into pieces, even when that
means exceeding 80 columns. So your new string here should all go on
one line.
> if (result != -EPIPE)
> goto err;
> dev_notice(ddev, "chopping to %d config(s)\n", cfgno);
> @@ -957,13 +976,25 @@ int usb_get_configuration(struct usb_device *dev)
> 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);
> + "(asked for %zu, got %i, expected at least %i)\n",
> + cfgno, usb_config_req_size, result, 4);
> result = -EINVAL;
> goto err;
> }
> +
> length = max_t(int, le16_to_cpu(desc->wTotalLength),
> - USB_DT_CONFIG_SIZE);
> + USB_DT_CONFIG_SIZE);
This is another example of a change that has nothing to do with the
purpose of the patch.
> +
> + /*
> + * If the device returns the full length configuration
> + * descriptor, skip the second read. Otherwise, send a second
Strictly speaking, the configuration descriptor is only 9 bytes long.
What you mean here is the entire configuration descriptor set.
> + * request asking for the full length.
> + */
> + if (result >= le16_to_cpu(desc->wTotalLength)) {
Shouldn't this be: result >= length? No point in repeating the
le16_to_cpu calculation.
> + bigbuffer = (unsigned char *) desc;
> + desc = NULL;
> + goto store_and_parse;
> + }
>
> /* Now that we know the length, get the whole thing */
> bigbuffer = kmalloc(length, GFP_KERNEL);
> @@ -972,23 +1003,25 @@ int usb_get_configuration(struct usb_device *dev)
> goto err;
> }
>
> - if (dev->quirks & USB_QUIRK_DELAY_INIT)
> - msleep(200);
> -
> result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
> - bigbuffer, length);
> + bigbuffer, length);
> +
> if (result < 0) {
> dev_err(ddev, "unable to read config index %d "
> - "descriptor/%s\n", cfgno, "all");
> + "descriptor/%s\n", cfgno, "all");
> kfree(bigbuffer);
> goto err;
> }
> +
More examples of unnecessary whitespace changes.
> if (result < length) {
> dev_notice(ddev, "config index %d descriptor too short "
> - "(expected %i, got %i)\n", cfgno, length, result);
> + "(asked for %i, got %i)\n",
> + cfgno, length, result);
> length = result;
> }
>
> +store_and_parse:
> + krealloc(bigbuffer, length, GFP_KERNEL);
> dev->rawdescriptors[cfgno] = bigbuffer;
>
> result = usb_parse_configuration(dev, cfgno,
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index 24960ba9caa9..9acd278666fc 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -2527,8 +2527,10 @@ static int usb_enumerate_device(struct usb_device *udev)
> err = usb_get_configuration(udev);
> if (err < 0) {
> if (err != -ENODEV)
> - dev_err(&udev->dev, "can't read configurations, error %d\n",
> - err);
> + dev_err(&udev->dev, "can't read configurations, "
> + "for device %04x:%04x, error %d\n",
Like above, this string should all be on one line.
Alan Stern
> + le16_to_cpu(udev->descriptor.idVendor),
> + le16_to_cpu(udev->descriptor.idProduct), err);
> return err;
> }
> }
> diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
> index 87810eff974e..df670b0b66fe 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 [flat|nested] 5+ messages in thread
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
2026-06-23 20:24 ` Alan Stern
@ 2026-06-23 21:14 ` Nikhil Solanke
0 siblings, 0 replies; 5+ messages in thread
From: Nikhil Solanke @ 2026-06-23 21:14 UTC (permalink / raw)
To: Alan Stern
Cc: linux-usb, gregkh, linux-kernel, michal.pecio, stable, corbet,
skhan, linux-doc
> Moving this delay up here changes the behavior when the quirk flag isn't
> set. While it agrees with the intention of the USB_QUIRK_DELAY_INIT
> flag, such a change should be mentioned in the patch description.
How should I mention it then? Nothing comes to mind besides the
obvious: "Also move the USB_QUIRK_DELAY_INIT sleep to before the
initial descriptor read, so the delay applies consistently regardless
of whether USB_QUIRK_CONFIG_SIZE is set.". Or should i revert it back
to original position?
> > +
> > + /*
> > + * Grab just the first descriptor so we know how long the whole
> > + * configuration is. In case of quirky firmware, try to grab the
> > + * whole thing in one go by asking for a 255-bytes sized buffer
> > + * mirroring Windows behavior.
> > + */
>
> This needs to be rewritten, as it is self-contradictory. When the quirk
> flag is set we issue a 255-byte request to mimic the Windows behavior,
> and only when the flag isn't set do we grab just the first descriptor.
I am sorry I didn't understand how it is self contradictory. The
comment does say, "in case of quirky firmware..."? Am i missing
something?
> > result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
> > - desc, USB_DT_CONFIG_SIZE);
> > + desc, usb_config_req_size);
>
> Don't make extraneous changes to the existing indentation (or whitespace
> in general), here and below.
Well the linux coding style guidelines mention that those descendants
should preferably be aligned with the function open parenthesis. Since
i did "touch" that line/part of code I though might as well indent it
a bit accordingly. Should i revert the indent then (in this and the
other place)?
> > if (result != -EPIPE)
> > goto err;
> > dev_notice(ddev, "chopping to %d config(s)\n", cfgno);
> > @@ -957,13 +976,25 @@ int usb_get_configuration(struct usb_device *dev)
> > 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);
> > + "(asked for %zu, got %i, expected at least %i)\n",
> > + cfgno, usb_config_req_size, result, 4);
> > result = -EINVAL;
> > goto err;
> > }
> > +
> > length = max_t(int, le16_to_cpu(desc->wTotalLength),
> > - USB_DT_CONFIG_SIZE);
> > + USB_DT_CONFIG_SIZE);
>
> This is another example of a change that has nothing to do with the
> purpose of the patch.
Isn't that what you told me to change? So the logs are accurate? I
made that change because you suggested it. :')
> > +
> > + /*
> > + * If the device returns the full length configuration
> > + * descriptor, skip the second read. Otherwise, send a second
>
> Strictly speaking, the configuration descriptor is only 9 bytes long.
> What you mean here is the entire configuration descriptor set.
Alright i'll reword it.
> > + * request asking for the full length.
> > + */
> > + if (result >= le16_to_cpu(desc->wTotalLength)) {
>
> Shouldn't this be: result >= length? No point in repeating the
> le16_to_cpu calculation.
Yess. initially the length assignment was happening afterwards in my
patch. then i decided to move it before the "if" statement since the
outcome of length was going to be similar in any case (within if and
after if). but then i forgot to modify the if too. Will fix it.
> Like above, this string should all be on one line.
Will fix all the strings as well
Nikhil Solanke
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-06-23 21:14 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-23 16:10 [PATCH v2] usbcore: Add quirk for 255-bytes initial config read Nikhil Solanke
2026-06-23 18:35 ` Randy Dunlap
2026-06-23 19:08 ` Nikhil Solanke
2026-06-23 20:24 ` Alan Stern
2026-06-23 21:14 ` Nikhil Solanke
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox