[PATCH 1/4] usb: usbtmc: handle undersized high-speed bulk IN packets
From: Nicolai Buchwitz
Date: Tue Oct 20 2026 - 10:58:16 EST
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@xxxxxxxxxxxxxxx
Signed-off-by: Nicolai Buchwitz <nb@xxxxxxxxxxx>
---
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