Commit d2ddce37 authored by Alexandre Peixoto Ferreira's avatar Alexandre Peixoto Ferreira Committed by Greg Kroah-Hartman

USB: usbtmc: usbtmc_read sends multiple TMC header based on rigol_quirk

These patches implement a modification of the USBTMC
protocol to allow operation with Rigol equipment. The usbtmc_read function is
modified so if the quirk is active, the TMC header is sent with the size of
the data as the whole size of the request. If the quirk is inactive, the TMC
request is sent once per bulk transfer and with size limited to the bulk
transfer size. In the case of the quirk, only the first response contains the
TMC header and the others are just data.
Signed-off-by: default avatarAlexandre Peixoto Ferreira <alexandref75@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c2e31483
...@@ -455,12 +455,29 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, ...@@ -455,12 +455,29 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
goto exit; goto exit;
} }
if (data->rigol_quirk) {
dev_dbg(dev, "usb_bulk_msg_in: count(%zu)\n", count);
retval = send_request_dev_dep_msg_in(data, count);
if (retval < 0) {
if (data->auto_abort)
usbtmc_ioctl_abort_bulk_out(data);
goto exit;
}
}
/* Loop until we have fetched everything we requested */
remaining = count; remaining = count;
this_part = remaining;
done = 0; done = 0;
while (remaining > 0) { while (remaining > 0) {
if (remaining > USBTMC_SIZE_IOBUFFER - 12 - 3) if (!(data->rigol_quirk)) {
this_part = USBTMC_SIZE_IOBUFFER - 12 - 3; dev_dbg(dev, "usb_bulk_msg_in: remaining(%zu), count(%zu)\n", remaining, count);
if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3)
this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3;
else else
this_part = remaining; this_part = remaining;
...@@ -471,6 +488,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, ...@@ -471,6 +488,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
usbtmc_ioctl_abort_bulk_out(data); usbtmc_ioctl_abort_bulk_out(data);
goto exit; goto exit;
} }
}
/* Send bulk URB */ /* Send bulk URB */
retval = usb_bulk_msg(data->usb_dev, retval = usb_bulk_msg(data->usb_dev,
...@@ -479,11 +497,37 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, ...@@ -479,11 +497,37 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
buffer, USBTMC_SIZE_IOBUFFER, &actual, buffer, USBTMC_SIZE_IOBUFFER, &actual,
USBTMC_TIMEOUT); USBTMC_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) */ /* Store bTag (in case we need to abort) */
data->bTag_last_read = data->bTag; data->bTag_last_read = data->bTag;
if (retval < 0) { if (retval < 0) {
dev_err(dev, "Unable to read data, error %d\n", retval); dev_dbg(dev, "Unable to read data, error %d\n", retval);
if (data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
/* Parse header in first packet */
if ((done == 0) || (!(data->rigol_quirk))) {
/* 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 (data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
if (buffer[0] != 2) {
dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", buffer[0]);
if (data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
if (buffer[1] != data->bTag_last_write) {
dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", buffer[1], data->bTag_last_write);
if (data->auto_abort) if (data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data); usbtmc_ioctl_abort_bulk_in(data);
goto exit; goto exit;
...@@ -495,35 +539,67 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, ...@@ -495,35 +539,67 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
(buffer[6] << 16) + (buffer[6] << 16) +
(buffer[7] << 24); (buffer[7] << 24);
/* Ensure the instrument doesn't lie about it */ if (n_characters > this_part) {
if(n_characters > actual - 12) { dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", n_characters, count);
dev_err(dev, "Device lies about message size: %u > %d\n", n_characters, actual - 12); if (data->auto_abort)
n_characters = actual - 12; usbtmc_ioctl_abort_bulk_in(data);
goto exit;
} }
/* Ensure the instrument doesn't send more back than requested */ /* Remove the USBTMC header */
if(n_characters > this_part) { actual -= USBTMC_HEADER_SIZE;
dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part);
n_characters = this_part; /* Check if the message is smaller than requested */
if (data->rigol_quirk) {
if (remaining > n_characters)
remaining = n_characters;
/* Remove padding if it exists */
if (actual > remaining)
actual = remaining;
}
else {
if (this_part > n_characters)
this_part = n_characters;
/* Remove padding if it exists */
if (actual > this_part)
actual = this_part;
} }
/* Bound amount of data received by amount of data requested */ dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n", n_characters, buffer[8]);
if (n_characters > this_part)
n_characters = this_part; remaining -= actual;
/* Terminate if end-of-message bit received from device */
if ((buffer[8] & 0x01) && (actual >= n_characters))
remaining = 0;
dev_dbg(dev, "Bulk-IN header: remaining(%zu), buf(%p), buffer(%p) done(%zu)\n", remaining,buf,buffer,done);
/* Copy buffer to user space */ /* Copy buffer to user space */
if (copy_to_user(buf + done, &buffer[12], n_characters)) { if (copy_to_user(buf + done, &buffer[USBTMC_HEADER_SIZE], actual)) {
/* There must have been an addressing problem */ /* There must have been an addressing problem */
retval = -EFAULT; retval = -EFAULT;
goto exit; goto exit;
} }
done += actual;
}
else {
if (actual > remaining)
actual = remaining;
done += n_characters; remaining -= actual;
/* Terminate if end-of-message bit received from device */
if ((buffer[8] & 0x01) && (actual >= n_characters + 12)) dev_dbg(dev, "Bulk-IN header cont: actual(%u), done(%zu), remaining(%zu), buf(%p), buffer(%p)\n", actual, done, remaining,buf,buffer);
remaining = 0;
else /* Copy buffer to user space */
remaining -= n_characters; if (copy_to_user(buf + done, buffer, actual)) {
/* There must have been an addressing problem */
retval = -EFAULT;
goto exit;
}
done += actual;
}
} }
/* Update file position value */ /* Update file position value */
......
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