Linux USB
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Fix initialization for Generic Clone X-Input Gamepads
@ 2026-07-26 17:14 Ishaan Dandekar
  2026-07-26 17:14 ` [PATCH v2 1/2] usbcore: Add quirk for 255-bytes initial config read Ishaan Dandekar
  2026-07-26 17:14 ` [PATCH v2 2/2] usb: quirks: Add ShanWan gamepad to quirk list Ishaan Dandekar
  0 siblings, 2 replies; 3+ messages in thread
From: Ishaan Dandekar @ 2026-07-26 17:14 UTC (permalink / raw)
  To: linux-usb; +Cc: gregkh, nikhilsolanke5, Ishaan Dandekar

This patch series fixes a hardware panic preventing certain generic X-Input
clone controllers (specifically 0283:0001) from functioning correctly
in Linux. 

When the controller is plugged in, the USB core requests its configuration 
using a 9-byte request. The controller's firmware fails, disconnects, and 
shape-shifts into a fallback Android mode, completely losing its X-Input 
capabilities and haptic feedback (rumble).

Patch 1 (by Nikhil Solanke) builds the underlying core logic to allow 
a 255-byte config request (mimicking Windows behavior).
Patch 2 adds this specific controller's hardware ID to the new quirk list, 
preventing the crash and locking it in X-Input mode.

Note: While these USB patches keep the device stable in X-Input mode, a 
companion patch is being submitted separately to the linux-input subsystem 
(drivers/input/joystick/xpad.c) to ensure the device is routed correctly 
and retains full haptic feedback and functionality.

Changes in v2:
- Added missing Signed-off-by from transmitter to Patch 1.
- Wrapped commit message in Patch 2 to 72 columns.
- Removed trailing whitespace in Patch 2.
- Dropped the Input/xpad routing patch (sent separately to linux-input)

Ishaan Dandekar (1):
  usb: quirks: Add ShanWan gamepad to quirk list

Nikhil Solanke (1):
  usbcore: Add quirk for 255-bytes initial config read

 .../admin-guide/kernel-parameters.txt         | 10 +++++
 drivers/usb/core/config.c                     | 39 +++++++++++++++----
 drivers/usb/core/quirks.c                     |  7 ++++
 include/linux/usb/quirks.h                    |  3 ++
 4 files changed, 52 insertions(+), 7 deletions(-)

-- 
2.34.1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v2 1/2] usbcore: Add quirk for 255-bytes initial config read
  2026-07-26 17:14 [PATCH v2 0/2] Fix initialization for Generic Clone X-Input Gamepads Ishaan Dandekar
@ 2026-07-26 17:14 ` Ishaan Dandekar
  2026-07-26 17:14 ` [PATCH v2 2/2] usb: quirks: Add ShanWan gamepad to quirk list Ishaan Dandekar
  1 sibling, 0 replies; 3+ messages in thread
From: Ishaan Dandekar @ 2026-07-26 17:14 UTC (permalink / raw)
  To: linux-usb
  Cc: gregkh, nikhilsolanke5, Alan Stern, Michal Pecio, stable,
	Ishaan Dandekar

From: Nikhil Solanke <nikhilsolanke5@gmail.com>

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>
Signed-off-by: Ishaan Dandekar <ishaan.dandekar@gmail.com>
---
 .../admin-guide/kernel-parameters.txt         | 10 +++++
 drivers/usb/core/config.c                     | 39 +++++++++++++++----
 drivers/usb/core/quirks.c                     |  4 ++
 include/linux/usb/quirks.h                    |  3 ++
 4 files changed, 49 insertions(+), 7 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index b5493a7f8..14121458a 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -8169,6 +8169,16 @@ 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. 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 45e20c6d7..442c15f92 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -912,6 +912,17 @@ int usb_get_configuration(struct usb_device *dev)
 	unsigned char *bigbuffer;
 	struct usb_config_descriptor *desc;
 	int result;
+	size_t usb_config_req_size;
+
+	/*
+	 * Devices with quirky firmware will stall or reset when the initial
+	 * config descriptor request uses wLength=9. 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 +949,19 @@ 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 */
+		/*
+		 * Normally we request only the configuration descriptor header
+		 * so we can determine the total configuration length. For
+		 * devices with USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE set, try to
+		 * grab the full descriptor set instead.
+		 */
 		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,9 +971,8 @@ 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, need at least %i)\n",
+			    cfgno, usb_config_req_size, result, 4);
 			result = -EINVAL;
 			goto err;
 		}
@@ -972,6 +986,16 @@ int usb_get_configuration(struct usb_device *dev)
 			goto err;
 		}
 
+		/*
+		 * If the device returns the full configuration descriptor set,
+		 * skip the second read. Otherwise, send a second request
+		 * asking for the full set.
+		 */
+		if (result >= length) {
+			memcpy(bigbuffer, desc, length);
+			goto store_and_parse;
+		}
+
 		if (dev->quirks & USB_QUIRK_DELAY_INIT)
 			msleep(200);
 
@@ -989,6 +1013,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 87ee2d938..f5a60ccf2 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 b3cc7beab..a4043b33c 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.34.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2 2/2] usb: quirks: Add ShanWan gamepad to quirk list
  2026-07-26 17:14 [PATCH v2 0/2] Fix initialization for Generic Clone X-Input Gamepads Ishaan Dandekar
  2026-07-26 17:14 ` [PATCH v2 1/2] usbcore: Add quirk for 255-bytes initial config read Ishaan Dandekar
@ 2026-07-26 17:14 ` Ishaan Dandekar
  1 sibling, 0 replies; 3+ messages in thread
From: Ishaan Dandekar @ 2026-07-26 17:14 UTC (permalink / raw)
  To: linux-usb; +Cc: gregkh, nikhilsolanke5, Ishaan Dandekar

The ShanWan Wireless Gamepad (dongle ID 2563:0575) crashes with a -71
EPROTO error during standard enumeration because it expects a 255-byte
initial configuration request. Add this device to the quirk list to
use the USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE flag.

Signed-off-by: Ishaan Dandekar <ishaan.dandekar@gmail.com>
---
 drivers/usb/core/quirks.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index f5a60ccf2..b5b577f0b 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -593,6 +593,9 @@ static const struct usb_device_id usb_quirk_list[] = {
 
 	{ USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM },
 
+	/* ShanWan Wireless Gamepad */
+	{ USB_DEVICE(0x2563, 0x0575), .driver_info = USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE },
+
 	/* UGREEN 35871 - BOS descriptor fetch hangs at SuperSpeed Plus */
 	{ USB_DEVICE(0x2b89, 0x5871), .driver_info = USB_QUIRK_NO_BOS },
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-07-26 17:14 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-26 17:14 [PATCH v2 0/2] Fix initialization for Generic Clone X-Input Gamepads Ishaan Dandekar
2026-07-26 17:14 ` [PATCH v2 1/2] usbcore: Add quirk for 255-bytes initial config read Ishaan Dandekar
2026-07-26 17:14 ` [PATCH v2 2/2] usb: quirks: Add ShanWan gamepad to quirk list Ishaan Dandekar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox