* [PATCH 0/4] usb: usbtmc: fix undersized high-speed bulk packets on xHCI
@ 2026-10-20 14:33 Nicolai Buchwitz
2026-10-20 14:33 ` [PATCH 1/4] usb: usbtmc: handle undersized high-speed bulk IN packets Nicolai Buchwitz
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Nicolai Buchwitz @ 2026-10-20 14:33 UTC (permalink / raw)
To: Greg Kroah-Hartman, Steve Bayless, Guido Kiener
Cc: linux-usb, linux-kernel, Nicolai Buchwitz, stable
The Siglent SDM4065A-SC, Rigol DP800 and Rigol DS1000Z (and probably
others) advertise 64-byte bulk endpoints at high speed. USB 2.0 only
allows 512, which xHCI correctly implements. Unfortunately this breaks
usbtmc on these devices. Reads stop after the first packet, and longer
writes also fail or hang the OUT endpoint until a USB reset:
usb 1-1.3: config 1 interface 0 altsetting 0 bulk endpoint 0x81 has invalid maxpacket 64
usbtmc 1-1.3:1.0: Device sent too small first packet: 8 < 12
usbtmc 1-1.3:1.0: Unable to send data, error -110
We ran into this in our factory once we switched some test PCs from
dwc2 based hardware to xHCI based ones. dwc2 uses the advertised 64
bytes, so the devices worked fine before.
This series adds a quirk table to usbtmc and moves one packet per URB
for the devices in it. The DP800 also wants a ZLP after a write that
ends on a packet boundary. Only read() and write() change, the ioctls
behave as before. More devices can go into the table as they turn up.
The Rigols still have one issue I can't work around. They split replies
over 500 bytes into several transfers, and a follow-on transfer that
ends exactly on a packet boundary never arrives. Raw libusb shows the
same, so I guess it's another firmware bug. Should be fine for most use
cases though.
Tested on a Raspberry Pi CM4S (BCM2711 xHCI) and a CM5 (RP1 xHCI).
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
---
Nicolai Buchwitz (4):
usb: usbtmc: handle undersized high-speed bulk IN packets
usb: usbtmc: handle undersized high-speed bulk OUT packets
usb: usbtmc: add Rigol DP800 and DS1000Z to the packet I/O quirk table
usb: usbtmc: send a ZLP after a full last packet in packet I/O mode
drivers/usb/class/usbtmc.c | 87 ++++++++++++++++++++++++++++++++++++++++------
1 file changed, 76 insertions(+), 11 deletions(-)
---
base-commit: a90ee4305c4a5df72c11b31dacfdc76e00fcf78a
change-id: 20261020-fix-usbtmc-short-packets-1c4e233ae407
Best regards,
--
Nicolai Buchwitz <nb@tipi-net.de>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/4] usb: usbtmc: handle undersized high-speed bulk IN packets
2026-10-20 14:33 [PATCH 0/4] usb: usbtmc: fix undersized high-speed bulk packets on xHCI Nicolai Buchwitz
@ 2026-10-20 14:33 ` Nicolai Buchwitz
2026-10-20 14:33 ` [PATCH 2/4] usb: usbtmc: handle undersized high-speed bulk OUT packets Nicolai Buchwitz
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Nicolai Buchwitz @ 2026-10-20 14:33 UTC (permalink / raw)
To: Greg Kroah-Hartman, Steve Bayless, Guido Kiener
Cc: linux-usb, linux-kernel, Nicolai Buchwitz, stable
The Siglent SDM4065A-SC advertises 64-byte bulk endpoints at high
speed. USB 2.0 requires 512 bytes there, and xHCI uses 512. The device
still sends 64-byte packets, so each packet ends the transfer and
usbtmc_read() returns only the first one. The rest is read as the next
reply:
usbtmc 1-1.3:1.0: Device sent too small first packet: 8 < 12
usbtmc 1-1.3:1.0: Device sent reply with wrong bTag: 4 != 6
Read one packet per URB in usbtmc_read() on this device. Also check for
a full first transfer before stripping the alignment bytes, otherwise a
reply whose padding fills that transfer leaves its trailing ZLP behind.
The existing 4096-byte path had the same problem.
Fixes: d7604ff0dc01 ("usb: usbtmc: Optimize usbtmc_read")
Cc: stable@vger.kernel.org
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
---
drivers/usb/class/usbtmc.c | 60 ++++++++++++++++++++++++++++++++++++++++------
1 file changed, 53 insertions(+), 7 deletions(-)
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 51cd9320a7366..7a2ea14aa524b 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -54,6 +54,16 @@ static const struct usb_device_id usbtmc_devices[] = {
};
MODULE_DEVICE_TABLE(usb, usbtmc_devices);
+/*
+ * Devices advertising high-speed bulk packets smaller than the 512 bytes
+ * xHCI uses. Transfers are limited to one advertised packet so the
+ * device's packet boundaries are preserved.
+ */
+static const struct usb_device_id usbtmc_packet_io_devices[] = {
+ { USB_DEVICE(0xf4ec, 0x1220) }, /* Siglent SDM4065A-SC */
+ { } /* terminating entry */
+};
+
/*
* This structure is the capabilities for the device
* See section 4.2.1.8 of the USBTMC specification,
@@ -84,6 +94,10 @@ struct usbtmc_device_data {
/* packet size of IN bulk */
u16 wMaxPacketSize;
+ /* packet size of OUT bulk */
+ u16 out_wMaxPacketSize;
+ /* one URB per advertised bulk packet */
+ bool packet_io;
/* data for interrupt in endpoint handling */
u8 bNotify1;
@@ -826,13 +840,13 @@ static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data,
void __user *user_buffer,
u32 transfer_size,
u32 *transferred,
- u32 flags)
+ u32 flags, bool packet_mode)
{
struct usbtmc_device_data *data = file_data->data;
struct device *dev = &data->intf->dev;
+ const u32 bufsize = packet_mode ? data->wMaxPacketSize : USBTMC_BUFSIZE;
u32 done = 0;
u32 remaining;
- const u32 bufsize = USBTMC_BUFSIZE;
int retval = 0;
u32 max_transfer_size;
unsigned long expire;
@@ -852,7 +866,13 @@ static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data,
* packet
*/
remaining = transfer_size;
- if ((max_transfer_size % data->wMaxPacketSize) == 0)
+ /*
+ * Packet-sized reads must also consume a trailing short packet
+ * when alignment bytes fill the last data packet.
+ */
+ if (packet_mode)
+ max_transfer_size += data->wMaxPacketSize;
+ else if ((max_transfer_size % data->wMaxPacketSize) == 0)
max_transfer_size += (data->wMaxPacketSize - 1);
} else {
/* round down to bufsize to avoid truncated data left */
@@ -899,6 +919,12 @@ static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data,
bufcount = MAX_URBS_IN_FLIGHT -
file_data->in_urbs_used;
}
+ /*
+ * Queue one URB at a time. A trailer URB queued ahead would be
+ * killed after most replies and log -ENOENT.
+ */
+ if (packet_mode)
+ bufcount = min(bufcount, 1);
}
spin_unlock_irq(&file_data->err_lock);
@@ -1072,7 +1098,7 @@ static ssize_t usbtmc_ioctl_generic_read(struct usbtmc_file_data *file_data,
retval = usbtmc_generic_read(file_data, msg.message,
msg.transfer_size, &msg.transferred,
- msg.flags);
+ msg.flags, false);
if (put_user(msg.transferred,
&((struct usbtmc_message __user *)arg)->transferred))
@@ -1377,7 +1403,8 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data;
struct device *dev;
- const u32 bufsize = USBTMC_BUFSIZE;
+ u32 bufsize = USBTMC_BUFSIZE;
+ bool full_buffer;
u32 n_characters;
u8 *buffer;
int actual;
@@ -1390,6 +1417,9 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
data = file_data->data;
dev = &data->intf->dev;
+ if (data->packet_io)
+ bufsize = data->wMaxPacketSize;
+
buffer = kmalloc(bufsize, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
@@ -1488,6 +1518,8 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
remaining = n_characters;
+ full_buffer = actual == bufsize;
+
/* Remove the USBTMC header */
actual -= USBTMC_HEADER_SIZE;
@@ -1504,11 +1536,12 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
goto exit;
}
- if ((actual + USBTMC_HEADER_SIZE) == bufsize) {
+ if (full_buffer) {
retval = usbtmc_generic_read(file_data, buf + actual,
remaining,
&done,
- USBTMC_FLAG_IGNORE_TRAILER);
+ USBTMC_FLAG_IGNORE_TRAILER,
+ data->packet_io);
if (retval < 0)
goto exit;
}
@@ -2378,6 +2411,12 @@ static void usbtmc_free_int(struct usbtmc_device_data *data)
kref_put(&data->kref, usbtmc_delete);
}
+static bool usbtmc_packet_io_ok(u16 maxpacket)
+{
+ return maxpacket >= USBTMC_HEADER_SIZE && maxpacket < 512 &&
+ !(maxpacket & 3);
+}
+
static int usbtmc_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -2429,8 +2468,15 @@ static int usbtmc_probe(struct usb_interface *intf,
dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", data->bulk_in);
data->bulk_out = bulk_out->bEndpointAddress;
+ data->out_wMaxPacketSize = usb_endpoint_maxp(bulk_out);
dev_dbg(&intf->dev, "Found Bulk out endpoint at %u\n", data->bulk_out);
+ /* Packets must carry the header and keep writes 32-bit aligned */
+ data->packet_io = usb_match_id(intf, usbtmc_packet_io_devices) &&
+ data->usb_dev->speed == USB_SPEED_HIGH &&
+ usbtmc_packet_io_ok(data->wMaxPacketSize) &&
+ usbtmc_packet_io_ok(data->out_wMaxPacketSize);
+
/* Find int endpoint */
retcode = usb_find_int_in_endpoint(iface_desc, &int_in);
if (!retcode) {
--
2.53.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/4] usb: usbtmc: handle undersized high-speed bulk OUT packets
2026-10-20 14:33 [PATCH 0/4] usb: usbtmc: fix undersized high-speed bulk packets on xHCI Nicolai Buchwitz
2026-10-20 14:33 ` [PATCH 1/4] usb: usbtmc: handle undersized high-speed bulk IN packets Nicolai Buchwitz
@ 2026-10-20 14:33 ` Nicolai Buchwitz
2026-10-20 14:33 ` [PATCH 3/4] usb: usbtmc: add Rigol DP800 and DS1000Z to the packet I/O quirk table Nicolai Buchwitz
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Nicolai Buchwitz @ 2026-10-20 14:33 UTC (permalink / raw)
To: Greg Kroah-Hartman, Steve Bayless, Guido Kiener
Cc: linux-usb, linux-kernel, Nicolai Buchwitz, stable
The Siglent SDM4065A-SC hangs its OUT endpoint when xHCI sends a packet
larger than the 64 bytes it advertises. Every transfer after that times
out until a USB reset:
usbtmc 1-1.3:1.0: Unable to send data, error -110
usbtmc 1-1.3:1.0: send_request_dev_dep_msg_in returned -110
Limit usbtmc_write() to URBs of the advertised packet size on this
device and send them one at a time. Some devices with this bug also
stall on back-to-back OUT packets.
Cc: stable@vger.kernel.org
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
---
The write path never handled this device, so there is no Fixes: target.
---
drivers/usb/class/usbtmc.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 7a2ea14aa524b..679ab5908e203 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1145,14 +1145,15 @@ static ssize_t usbtmc_generic_write(struct usbtmc_file_data *file_data,
const void __user *user_buffer,
u32 transfer_size,
u32 *transferred,
- u32 flags)
+ u32 flags, bool packet_mode)
{
struct usbtmc_device_data *data = file_data->data;
+ const u32 bufsize = packet_mode ? data->out_wMaxPacketSize :
+ USBTMC_BUFSIZE;
struct device *dev;
u32 done = 0;
u32 remaining;
unsigned long expire;
- const u32 bufsize = USBTMC_BUFSIZE;
struct urb *urb = NULL;
int retval = 0;
u32 timeout;
@@ -1190,6 +1191,14 @@ static ssize_t usbtmc_generic_write(struct usbtmc_file_data *file_data,
u32 this_part, aligned;
u8 *buffer = NULL;
+ /* Some packet mode devices stall on back-to-back OUT packets */
+ if (packet_mode &&
+ !usb_wait_anchor_empty_timeout(&file_data->submitted,
+ timeout)) {
+ retval = -ETIMEDOUT;
+ goto error;
+ }
+
if (flags & USBTMC_FLAG_ASYNC) {
if (down_trylock(&file_data->limit_write_sem)) {
retval = (done)?(0):(-EAGAIN);
@@ -1309,7 +1318,7 @@ static ssize_t usbtmc_ioctl_generic_write(struct usbtmc_file_data *file_data,
retval = usbtmc_generic_write(file_data, msg.message,
msg.transfer_size, &msg.transferred,
- msg.flags);
+ msg.flags, false);
if (put_user(msg.transferred,
&((struct usbtmc_message __user *)arg)->transferred))
@@ -1605,6 +1614,9 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
buffer = urb->transfer_buffer;
buflen = urb->transfer_buffer_length;
+ if (data->packet_io)
+ buflen = data->out_wMaxPacketSize;
+
if (count > INT_MAX) {
transfersize = INT_MAX;
buffer[8] = 0;
@@ -1671,7 +1683,7 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
/* call generic_write even when remaining = 0 */
retval = usbtmc_generic_write(file_data, buf + transfersize, remaining,
- &done, USBTMC_FLAG_APPEND);
+ &done, USBTMC_FLAG_APPEND, data->packet_io);
/* truncate alignment bytes */
if (done > remaining)
done = remaining;
--
2.53.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 3/4] usb: usbtmc: add Rigol DP800 and DS1000Z to the packet I/O quirk table
2026-10-20 14:33 [PATCH 0/4] usb: usbtmc: fix undersized high-speed bulk packets on xHCI Nicolai Buchwitz
2026-10-20 14:33 ` [PATCH 1/4] usb: usbtmc: handle undersized high-speed bulk IN packets Nicolai Buchwitz
2026-10-20 14:33 ` [PATCH 2/4] usb: usbtmc: handle undersized high-speed bulk OUT packets Nicolai Buchwitz
@ 2026-10-20 14:33 ` Nicolai Buchwitz
2026-10-20 14:33 ` [PATCH 4/4] usb: usbtmc: send a ZLP after a full last packet in packet I/O mode Nicolai Buchwitz
2026-10-20 16:42 ` [PATCH 0/4] usb: usbtmc: fix undersized high-speed bulk packets on xHCI Michal Pecio
4 siblings, 0 replies; 7+ messages in thread
From: Nicolai Buchwitz @ 2026-10-20 14:33 UTC (permalink / raw)
To: Greg Kroah-Hartman, Steve Bayless, Guido Kiener
Cc: linux-usb, linux-kernel, Nicolai Buchwitz, stable
The Rigol DP800 power supply and DS1000Z oscilloscope families also
advertise 64-byte bulk endpoints at high speed. Replies are cut off
after the first packet, and writes larger than 64 bytes fail on the
DP800:
usbtmc 1-1.3:1.0: Unable to send data, error -71
Tested on a DP832A and a DS1054Z.
Cc: stable@vger.kernel.org
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
---
drivers/usb/class/usbtmc.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 679ab5908e203..861913b9de918 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -60,6 +60,8 @@ MODULE_DEVICE_TABLE(usb, usbtmc_devices);
* device's packet boundaries are preserved.
*/
static const struct usb_device_id usbtmc_packet_io_devices[] = {
+ { USB_DEVICE(0x1ab1, 0x04ce) }, /* Rigol DS1000Z family */
+ { USB_DEVICE(0x1ab1, 0x0e11) }, /* Rigol DP800 family */
{ USB_DEVICE(0xf4ec, 0x1220) }, /* Siglent SDM4065A-SC */
{ } /* terminating entry */
};
--
2.53.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 4/4] usb: usbtmc: send a ZLP after a full last packet in packet I/O mode
2026-10-20 14:33 [PATCH 0/4] usb: usbtmc: fix undersized high-speed bulk packets on xHCI Nicolai Buchwitz
` (2 preceding siblings ...)
2026-10-20 14:33 ` [PATCH 3/4] usb: usbtmc: add Rigol DP800 and DS1000Z to the packet I/O quirk table Nicolai Buchwitz
@ 2026-10-20 14:33 ` Nicolai Buchwitz
2026-10-20 16:42 ` [PATCH 0/4] usb: usbtmc: fix undersized high-speed bulk packets on xHCI Michal Pecio
4 siblings, 0 replies; 7+ messages in thread
From: Nicolai Buchwitz @ 2026-10-20 14:33 UTC (permalink / raw)
To: Greg Kroah-Hartman, Steve Bayless, Guido Kiener
Cc: linux-usb, linux-kernel, Nicolai Buchwitz, stable
The Rigol DP800 waits for a short packet before it handles a command.
A message that ends exactly on a 64-byte boundary is never processed.
The read times out, and once the next message gets appended the device
shows "command incorrect".
Send a zero-length packet after a full last packet in usbtmc_write()
on quirked devices.
Tested on a DP832A, a DS1054Z and an SDM4065A-SC.
Cc: stable@vger.kernel.org
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
---
drivers/usb/class/usbtmc.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 861913b9de918..101d4f9fff6b5 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1259,6 +1259,8 @@ static ssize_t usbtmc_generic_write(struct usbtmc_file_data *file_data,
usb_sndbulkpipe(data->usb_dev, data->bulk_out),
urb->transfer_buffer, aligned,
usbtmc_write_bulk_cb, file_data);
+ if (packet_mode && this_part == remaining)
+ urb->transfer_flags |= URB_ZERO_PACKET;
usb_anchor_urb(urb, &file_data->submitted);
retval = usb_submit_urb(urb, GFP_KERNEL);
@@ -1666,6 +1668,9 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
usb_sndbulkpipe(data->usb_dev, data->bulk_out),
urb->transfer_buffer, aligned,
usbtmc_write_bulk_cb, file_data);
+ /* Some devices only end a transfer on a short packet */
+ if (data->packet_io && transfersize == remaining)
+ urb->transfer_flags |= URB_ZERO_PACKET;
usb_anchor_urb(urb, &file_data->submitted);
retval = usb_submit_urb(urb, GFP_KERNEL);
--
2.53.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 0/4] usb: usbtmc: fix undersized high-speed bulk packets on xHCI
2026-10-20 14:33 [PATCH 0/4] usb: usbtmc: fix undersized high-speed bulk packets on xHCI Nicolai Buchwitz
` (3 preceding siblings ...)
2026-10-20 14:33 ` [PATCH 4/4] usb: usbtmc: send a ZLP after a full last packet in packet I/O mode Nicolai Buchwitz
@ 2026-10-20 16:42 ` Michal Pecio
2026-10-20 18:33 ` Nicolai Buchwitz
4 siblings, 1 reply; 7+ messages in thread
From: Michal Pecio @ 2026-10-20 16:42 UTC (permalink / raw)
To: Nicolai Buchwitz
Cc: Greg Kroah-Hartman, Steve Bayless, Guido Kiener, linux-usb,
linux-kernel, stable
On Tue, 20 Oct 2026 16:33:37 +0200, Nicolai Buchwitz wrote:
> The Siglent SDM4065A-SC, Rigol DP800 and Rigol DS1000Z (and probably
> others) advertise 64-byte bulk endpoints at high speed. USB 2.0 only
> allows 512, which xHCI correctly implements. Unfortunately this breaks
> usbtmc on these devices. Reads stop after the first packet, and longer
> writes also fail or hang the OUT endpoint until a USB reset:
>
> usb 1-1.3: config 1 interface 0 altsetting 0 bulk endpoint 0x81 has invalid maxpacket 64
> usbtmc 1-1.3:1.0: Device sent too small first packet: 8 < 12
> usbtmc 1-1.3:1.0: Unable to send data, error -110
Fascinating.
But SDM4065A is apparently pretty modern (2025) gear marketed for
"automatic production lines", so it's odd that it has such issues.
Has anyone looked if the same out-of-spec descriptor shows up on
Windows or (don't laught at my optimism) consulted vendor support?
Maybe Windows xHCI driver tries to enable out-of-spec maxpacket?
We could do that too, though IIRC not all controllers are happy,
so a SW workaround may be unavoidable.
And xHCI doesn't support URB_SHORT_NOT_OK, for the record.
> We ran into this in our factory once we switched some test PCs from
> dwc2 based hardware to xHCI based ones. dwc2 uses the advertised 64
> bytes, so the devices worked fine before.
>
> This series adds a quirk table to usbtmc and moves one packet per URB
> for the devices in it. The DP800 also wants a ZLP after a write that
> ends on a packet boundary. Only read() and write() change, the ioctls
> behave as before. More devices can go into the table as they turn up.
>
> The Rigols still have one issue I can't work around. They split
> replies over 500 bytes into several transfers, and a follow-on
> transfer that ends exactly on a packet boundary never arrives. Raw
> libusb shows the same, so I guess it's another firmware bug. Should
> be fine for most use cases though.
What exactly is the sequence of URBs you see vs would want to see?
>
> Tested on a Raspberry Pi CM4S (BCM2711 xHCI) and a CM5 (RP1 xHCI).
>
> Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
> ---
> Nicolai Buchwitz (4):
> usb: usbtmc: handle undersized high-speed bulk IN packets
> usb: usbtmc: handle undersized high-speed bulk OUT packets
> usb: usbtmc: add Rigol DP800 and DS1000Z to the packet I/O quirk table
> usb: usbtmc: send a ZLP after a full last packet in packet I/O mode
>
> drivers/usb/class/usbtmc.c | 87 ++++++++++++++++++++++++++++++++++++++++------
> 1 file changed, 76 insertions(+), 11 deletions(-)
> ---
> base-commit: a90ee4305c4a5df72c11b31dacfdc76e00fcf78a
> change-id: 20261020-fix-usbtmc-short-packets-1c4e233ae407
>
> Best regards,
> --
> Nicolai Buchwitz <nb@tipi-net.de>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 0/4] usb: usbtmc: fix undersized high-speed bulk packets on xHCI
2026-10-20 16:42 ` [PATCH 0/4] usb: usbtmc: fix undersized high-speed bulk packets on xHCI Michal Pecio
@ 2026-10-20 18:33 ` Nicolai Buchwitz
0 siblings, 0 replies; 7+ messages in thread
From: Nicolai Buchwitz @ 2026-10-20 18:33 UTC (permalink / raw)
To: Michal Pecio
Cc: Greg Kroah-Hartman, Steve Bayless, Guido Kiener, linux-usb,
linux-kernel, stable
Hi Michal
On 20.10.2026 18:42, Michal Pecio wrote:
> [...]
> But SDM4065A is apparently pretty modern (2025) gear marketed for
> "automatic production lines", so it's odd that it has such issues.
> Has anyone looked if the same out-of-spec descriptor shows up on
> Windows or (don't laught at my optimism) consulted vendor support?
Not yet, but I'll check on Windows. The vendor(s) don't really seem to
care about the bug (surprise!). It is known for quite a while and even
not fixed with the latest 2026 firmware for the siglent. This makes me
assume that either most of the professional users a) use Windows or b)
use the lan interface (which we do for most of the stations).
>
> Maybe Windows xHCI driver tries to enable out-of-spec maxpacket?
> We could do that too, though IIRC not all controllers are happy,
> so a SW workaround may be unavoidable.
Did some quick tests and it looks good so far. If the usb maintainers
can agree on making it less restrictive (/ compliant) it would save
lots of efforts and the quirk would be down to the ZLP patch. In my
tests all three devices worked with
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 8a8636279e844..c4306482874eb 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1505,7 +1505,9 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
err_count = 3;
/* HS bulk max packet should be 512, FS bulk supports 8, 16, 32
or 64 */
if (usb_endpoint_xfer_bulk(&ep->desc)) {
- if (udev->speed == USB_SPEED_HIGH)
+ if (udev->speed == USB_SPEED_HIGH && max_packet != 512)
+ xhci_warn(xhci, "EXPERIMENT: keeping HS bulk
maxp %u\n", max_packet);
+ else if (udev->speed == USB_SPEED_HIGH)
max_packet = 512;
if (udev->speed == USB_SPEED_FULL) {
max_packet = rounddown_pow_of_two(max_packet);
So this looks like the better fix. How would we want it gated, a USB
core quirk flag per device, or per controller?
> [...]
>> The Rigols still have one issue I can't work around. They split
>> replies over 500 bytes into several transfers, and a follow-on
>> transfer that ends exactly on a packet boundary never arrives. Raw
>> libusb shows the same, so I guess it's another firmware bug. Should
>> be fine for most use cases though.
>
> What exactly is the sequence of URBs you see vs would want to see?
The Rigols split anything over 500 bytes into two transfers:
REQUEST_DEV_DEP_MSG_IN #1
IN: 8 x 64 bytes (12 byte header + 500 data), then a ZLP
REQUEST_DEV_DEP_MSG_IN #2
IN: header + the rest
That works fine, unless the second transfer happens to end exactly on
a 64 byte boundary (e.g. 640 bytes). Then the device just never answers
request #2 and the first IN times out. I also tried leaving the ZLP
from #1 pending until after request #2. That fixes the boundary case,
but then the device randomly ignores request #2 instead (roughly 1 in
5). Raw libusb behaves the same, also with maxpacket 64 in xHCI, so I'm
pretty sure it's just another firmware bug. What I'd want to see is
simply the second transfer arriving :)
> [...]
Thanks,
Nicolai
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-20 18:33 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-20 14:33 [PATCH 0/4] usb: usbtmc: fix undersized high-speed bulk packets on xHCI Nicolai Buchwitz
2026-10-20 14:33 ` [PATCH 1/4] usb: usbtmc: handle undersized high-speed bulk IN packets Nicolai Buchwitz
2026-10-20 14:33 ` [PATCH 2/4] usb: usbtmc: handle undersized high-speed bulk OUT packets Nicolai Buchwitz
2026-10-20 14:33 ` [PATCH 3/4] usb: usbtmc: add Rigol DP800 and DS1000Z to the packet I/O quirk table Nicolai Buchwitz
2026-10-20 14:33 ` [PATCH 4/4] usb: usbtmc: send a ZLP after a full last packet in packet I/O mode Nicolai Buchwitz
2026-10-20 16:42 ` [PATCH 0/4] usb: usbtmc: fix undersized high-speed bulk packets on xHCI Michal Pecio
2026-10-20 18:33 ` Nicolai Buchwitz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®