Commit d7604ff0 authored by Guido Kiener's avatar Guido Kiener Committed by Greg Kroah-Hartman

usb: usbtmc: Optimize usbtmc_read

Use new usbtmc_generic_read function to maximize bandwidth
during long data transfer. Also fix reading of zero length
packet (ZLP) or trailing short packet.
The maximum input transfer size is limited to INT_MAX (=2GB).
Also remove redundant return in send_request_dev_dep_msg_in().
Signed-off-by: default avatarGuido Kiener <guido.kiener@rohde-schwarz.com>
Reviewed-by: default avatarSteve Bayless <steve_bayless@keysight.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4d5e18d9
...@@ -1293,7 +1293,7 @@ static ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data, ...@@ -1293,7 +1293,7 @@ static ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data,
* Also updates bTag_last_write. * Also updates bTag_last_write.
*/ */
static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data, static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data,
size_t transfer_size) u32 transfer_size)
{ {
struct usbtmc_device_data *data = file_data->data; struct usbtmc_device_data *data = file_data->data;
int retval; int retval;
...@@ -1336,12 +1336,11 @@ static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data, ...@@ -1336,12 +1336,11 @@ static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data,
data->bTag++; data->bTag++;
kfree(buffer); kfree(buffer);
if (retval < 0) { if (retval < 0)
dev_err(&data->intf->dev, "usb_bulk_msg in send_request_dev_dep_msg_in() returned %d\n", retval); dev_err(&data->intf->dev, "%s returned %d\n",
return retval; __func__, retval);
}
return 0; return retval;
} }
static ssize_t usbtmc_read(struct file *filp, char __user *buf, static ssize_t usbtmc_read(struct file *filp, char __user *buf,
...@@ -1350,20 +1349,20 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, ...@@ -1350,20 +1349,20 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
struct usbtmc_file_data *file_data; struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data; struct usbtmc_device_data *data;
struct device *dev; struct device *dev;
const u32 bufsize = USBTMC_BUFSIZE;
u32 n_characters; u32 n_characters;
u8 *buffer; u8 *buffer;
int actual; int actual;
size_t done; u32 done = 0;
size_t remaining; u32 remaining;
int retval; int retval;
size_t this_part;
/* Get pointer to private data structure */ /* Get pointer to private data structure */
file_data = filp->private_data; file_data = filp->private_data;
data = file_data->data; data = file_data->data;
dev = &data->intf->dev; dev = &data->intf->dev;
buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); buffer = kmalloc(bufsize, GFP_KERNEL);
if (!buffer) if (!buffer)
return -ENOMEM; return -ENOMEM;
...@@ -1373,7 +1372,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, ...@@ -1373,7 +1372,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
goto exit; goto exit;
} }
dev_dbg(dev, "usb_bulk_msg_in: count(%zu)\n", count); if (count > INT_MAX)
count = INT_MAX;
dev_dbg(dev, "%s(count:%zu)\n", __func__, count);
retval = send_request_dev_dep_msg_in(file_data, count); retval = send_request_dev_dep_msg_in(file_data, count);
...@@ -1385,114 +1387,100 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, ...@@ -1385,114 +1387,100 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
/* Loop until we have fetched everything we requested */ /* Loop until we have fetched everything we requested */
remaining = count; remaining = count;
this_part = remaining;
done = 0;
while (remaining > 0) {
/* Send bulk URB */
retval = usb_bulk_msg(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev,
data->bulk_in),
buffer, USBTMC_SIZE_IOBUFFER, &actual,
file_data->timeout);
dev_dbg(dev, "usb_bulk_msg: retval(%u), done(%zu), remaining(%zu), actual(%d)\n", retval, done, remaining, actual);
/* Store bTag (in case we need to abort) */ /* Send bulk URB */
data->bTag_last_read = data->bTag; retval = usb_bulk_msg(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev,
if (retval < 0) { data->bulk_in),
dev_dbg(dev, "Unable to read data, error %d\n", retval); buffer, bufsize, &actual,
if (file_data->auto_abort) file_data->timeout);
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
/* Parse header in first packet */ dev_dbg(dev, "%s: bulk_msg retval(%u), actual(%d)\n",
if (done == 0) { __func__, retval, actual);
/* Sanity checks for the header */
if (actual < USBTMC_HEADER_SIZE) {
dev_err(dev, "Device sent too small first packet: %u < %u\n", actual, USBTMC_HEADER_SIZE);
if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
if (buffer[0] != 2) { /* Store bTag (in case we need to abort) */
dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", buffer[0]); data->bTag_last_read = data->bTag;
if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
if (buffer[1] != data->bTag_last_write) { if (retval < 0) {
dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", buffer[1], data->bTag_last_write); if (file_data->auto_abort)
if (file_data->auto_abort) usbtmc_ioctl_abort_bulk_in(data);
usbtmc_ioctl_abort_bulk_in(data); goto exit;
goto exit; }
}
/* How many characters did the instrument send? */ /* Sanity checks for the header */
n_characters = buffer[4] + if (actual < USBTMC_HEADER_SIZE) {
(buffer[5] << 8) + dev_err(dev, "Device sent too small first packet: %u < %u\n",
(buffer[6] << 16) + actual, USBTMC_HEADER_SIZE);
(buffer[7] << 24); if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
file_data->bmTransferAttributes = buffer[8]; if (buffer[0] != 2) {
dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n",
buffer[0]);
if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
if (n_characters > this_part) { if (buffer[1] != data->bTag_last_write) {
dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", n_characters, count); dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n",
if (file_data->auto_abort) buffer[1], data->bTag_last_write);
usbtmc_ioctl_abort_bulk_in(data); if (file_data->auto_abort)
goto exit; usbtmc_ioctl_abort_bulk_in(data);
} goto exit;
}
/* Remove the USBTMC header */ /* How many characters did the instrument send? */
actual -= USBTMC_HEADER_SIZE; n_characters = buffer[4] +
(buffer[5] << 8) +
(buffer[6] << 16) +
(buffer[7] << 24);
/* Check if the message is smaller than requested */ file_data->bmTransferAttributes = buffer[8];
if (remaining > n_characters)
remaining = n_characters;
/* Remove padding if it exists */
if (actual > remaining)
actual = remaining;
dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n", n_characters, buffer[8]); dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n",
n_characters, buffer[8]);
remaining -= actual; if (n_characters > remaining) {
dev_err(dev, "Device wants to return more data than requested: %u > %zu\n",
n_characters, count);
if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
/* Terminate if end-of-message bit received from device */ print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
if ((buffer[8] & 0x01) && (actual >= n_characters)) 16, 1, buffer, actual, true);
remaining = 0;
dev_dbg(dev, "Bulk-IN header: remaining(%zu), buf(%p), buffer(%p) done(%zu)\n", remaining,buf,buffer,done); remaining = n_characters;
/* Remove the USBTMC header */
actual -= USBTMC_HEADER_SIZE;
/* Copy buffer to user space */ /* Remove padding if it exists */
if (copy_to_user(buf + done, &buffer[USBTMC_HEADER_SIZE], actual)) { if (actual > remaining)
/* There must have been an addressing problem */ actual = remaining;
retval = -EFAULT;
goto exit;
}
done += actual;
}
else {
if (actual > remaining)
actual = remaining;
remaining -= actual; remaining -= actual;
dev_dbg(dev, "Bulk-IN header cont: actual(%u), done(%zu), remaining(%zu), buf(%p), buffer(%p)\n", actual, done, remaining,buf,buffer); /* Copy buffer to user space */
if (copy_to_user(buf, &buffer[USBTMC_HEADER_SIZE], actual)) {
/* There must have been an addressing problem */
retval = -EFAULT;
goto exit;
}
/* Copy buffer to user space */ if ((actual + USBTMC_HEADER_SIZE) == bufsize) {
if (copy_to_user(buf + done, buffer, actual)) { retval = usbtmc_generic_read(file_data, buf + actual,
/* There must have been an addressing problem */ remaining,
retval = -EFAULT; &done,
goto exit; USBTMC_FLAG_IGNORE_TRAILER);
} if (retval < 0)
done += actual; goto exit;
}
} }
done += actual;
/* Update file position value */ /* Update file position value */
*f_pos = *f_pos + done; *f_pos = *f_pos + done;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment