[PATCH 3/4] usb: usbtmc: uninitialized symbol 'actual' in usbtmc_ioctl_clear

2018-09-24 Thread Guido Kiener
From: Guido Kiener 

Fix uninitialized symbol 'actual' in function usbtmc_ioctl_clear.

When symbol 'actual' is not initialized and usb_bulk_msg() fails,
the subsequent kernel debug message shows a random value.

Signed-off-by: Guido Kiener 
Fixes: dfee02ac4bce ("usb: usbtmc: Fix ioctl USBTMC_IOCTL_CLEAR")
---
 drivers/usb/class/usbtmc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 9cb90603f71f..7184fa035434 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1679,6 +1679,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
do {
dev_dbg(dev, "Reading from bulk in EP\n");
 
+   actual = 0;
rv = usb_bulk_msg(data->usb_dev,
  usb_rcvbulkpipe(data->usb_dev,
  data->bulk_in),
-- 
2.17.1



[PATCH 1/4] usb: usbtmc: Fix memory leak in usbtmc_ioctl_request

2018-09-24 Thread Guido Kiener
From: Guido Kiener 

Kernel memory is allocated twice in new function
usbtmc_ioctl_request and creates a memory leak.
This fix removes the superfluous kmalloc().

Signed-off-by: Guido Kiener 
Fixes: 658f24f4523e ("usb: usbtmc: Add ioctl for generic requests on control")
---
 drivers/usb/class/usbtmc.c | 4 
 1 file changed, 4 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 0fcb81a1399b..dfbcf418dad7 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1895,10 +1895,6 @@ static int usbtmc_ioctl_request(struct 
usbtmc_device_data *data,
if (res)
return -EFAULT;
 
-   buffer = kmalloc(request.req.wLength, GFP_KERNEL);
-   if (!buffer)
-   return -ENOMEM;
-
if (request.req.wLength > USBTMC_BUFSIZE)
return -EMSGSIZE;
 
-- 
2.17.1



[PATCH 0/4] usb: usbtmc: Fix changes for compatible IVI/VISA library

2018-09-24 Thread Guido Kiener
Fix memory leak and uninitialized symbol 'actual' in usbtmc driver of
patch series:
[v6,00/22] usb: usbtmc: Changes needed for compatible IVI/VISA library
https://patchwork.kernel.org/cover/10596935/

Two errors are reported by 0-day service (smatch tool) when testing
branch usb-testing:

1. usbtmc_ioctl_request() warn: possible memory leak of 'buffer'
https://lists.01.org/pipermail/kbuild-all/2018-September/053023.html
2. usbtmc_ioctl_abort_bulk_in_tag() error: uninitialized symbol 'actual'
https://lists.01.org/pipermail/kbuild-all/2018-September/053024.html

Additionally the unitialized symbol 'actual' can cause similar
problems and show wrong debug kernel messages in the other functions
usbtmc_read() and usbtmc_ioctl_clear().

Guido Kiener (4):
  usb: usbtmc: Fix memory leak in usbtmc_ioctl_request
  usb: usbtmc: uninitialized symbol 'actual' in usbtmc_read
  usb: usbtmc: uninitialized symbol 'actual' in usbtmc_ioctl_clear
  usb: usbtmc: uninitialized symbol 'actual' in
usbtmc_ioctl_abort_bulk_in_tag

 drivers/usb/class/usbtmc.c | 7 +++
 1 file changed, 3 insertions(+), 4 deletions(-)

-- 
2.17.1



[PATCH 4/4] usb: usbtmc: uninitialized symbol 'actual' in usbtmc_ioctl_abort_bulk_in_tag

2018-09-24 Thread Guido Kiener
From: Guido Kiener 

Fix uninitialized symbol 'actual' in function
usbtmc_ioctl_abort_bulk_in_tag().

When symbol 'actual' is not initialized and usb_bulk_msg() fails,
the subsequent kernel debug message shows invalid data.

Signed-off-by: Guido Kiener 
Fixes: cbe743f1333b ("usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_IN")
---
 drivers/usb/class/usbtmc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 7184fa035434..4942122b2346 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -321,6 +321,7 @@ static int usbtmc_ioctl_abort_bulk_in_tag(struct 
usbtmc_device_data *data,
dev_dbg(dev, "Reading from bulk in EP\n");
 
/* Data must be present. So use low timeout 300 ms */
+   actual = 0;
rv = usb_bulk_msg(data->usb_dev,
  usb_rcvbulkpipe(data->usb_dev,
  data->bulk_in),
-- 
2.17.1



[PATCH 2/4] usb: usbtmc: uninitialized symbol 'actual' in usbtmc_read

2018-09-24 Thread Guido Kiener
From: Guido Kiener 

Fix uninitialized symbol 'actual' in function usbtmc_read.

When symbol 'actual' is not initialized and usb_bulk_msg() fails,
the subsequent kernel debug message shows a random value.

Signed-off-by: Guido Kiener 
Fixes: d7604ff0dc01 ("usb: usbtmc: Optimize usbtmc_read")
---
 drivers/usb/class/usbtmc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index dfbcf418dad7..9cb90603f71f 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1370,6 +1370,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
 
/* Loop until we have fetched everything we requested */
remaining = count;
+   actual = 0;
 
/* Send bulk URB */
retval = usb_bulk_msg(data->usb_dev,
-- 
2.17.1



[PATCH v6 16/22] usb: usbtmc: Replace USBTMC_TIMEOUT macros for control messages

2018-09-12 Thread Guido Kiener
Use common timeout macro USB_CTRL_GET_TIMEOUT (=5s) for all
usb_control_msg() function calls.

The macro USBTMC_TIMEOUT should only be used as default value for
Bulk IN/OUT transfers.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 329daa7425dc..964c8e87dacb 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -521,7 +521,7 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data 
*file_data,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
data->iin_bTag,
data->ifnum,
-   buffer, 0x03, USBTMC_TIMEOUT);
+   buffer, 0x03, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "stb usb_control_msg returned %d\n", rv);
goto exit;
@@ -655,7 +655,7 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data 
*data,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
wValue,
data->ifnum,
-   buffer, 0x01, USBTMC_TIMEOUT);
+   buffer, 0x01, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "simple usb_control_msg failed %d\n", rv);
goto exit;
@@ -1802,7 +1802,7 @@ static int get_capabilities(struct usbtmc_device_data 
*data)
rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_GET_CAPABILITIES,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 0x18, USBTMC_TIMEOUT);
+0, 0, buffer, 0x18, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto err_out;
@@ -1941,7 +1941,7 @@ static int usbtmc_ioctl_indicator_pulse(struct 
usbtmc_device_data *data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INDICATOR_PULSE,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 0x01, USBTMC_TIMEOUT);
+0, 0, buffer, 0x01, USB_CTRL_GET_TIMEOUT);
 
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
-- 
2.17.1



[PATCH v6 13/22] usb: usbtmc: Fix ioctl USBTMC_IOCTL_CLEAR

2018-09-12 Thread Guido Kiener
Remove calculation of max_size (=wMaxPacketSize) and wrong
condition (actual == max_size) in while loop. A device clear
should always flush the complete Bulk-IN FIFO.

Insert a sleep of 50 ms between subsequent CHECK_CLEAR_STATUS
control requests to avoid stressing the instrument with
repeated requests.

Some instruments need time to cleanup internal I/O buffers.
Polling and nonbraked requests slow down the response time of
devices.

Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.

Check only bit 0 (field bmClear) of the CHECK_CLEAR_STATUS
response, since other bits are reserved and can change in
future versions.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 46 +++---
 1 file changed, 18 insertions(+), 28 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 26a779d0c89b..11b2c8632d91 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1632,20 +1632,17 @@ static ssize_t usbtmc_write(struct file *filp, const 
char __user *buf,
 
 static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
 {
-   struct usb_host_interface *current_setting;
-   struct usb_endpoint_descriptor *desc;
struct device *dev;
u8 *buffer;
int rv;
int n;
int actual = 0;
-   int max_size;
 
dev = >intf->dev;
 
dev_dbg(dev, "Sending INITIATE_CLEAR request\n");
 
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+   buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
 
@@ -1653,7 +1650,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INITIATE_CLEAR,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 1, USBTMC_TIMEOUT);
+0, 0, buffer, 1, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
@@ -1667,22 +1664,6 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
goto exit;
}
 
-   max_size = 0;
-   current_setting = data->intf->cur_altsetting;
-   for (n = 0; n < current_setting->desc.bNumEndpoints; n++) {
-   desc = _setting->endpoint[n].desc;
-   if (desc->bEndpointAddress == data->bulk_in)
-   max_size = usb_endpoint_maxp(desc);
-   }
-
-   if (max_size == 0) {
-   dev_err(dev, "Couldn't get wMaxPacketSize\n");
-   rv = -EPERM;
-   goto exit;
-   }
-
-   dev_dbg(dev, "wMaxPacketSize is %d\n", max_size);
-
n = 0;
 
 usbtmc_clear_check_status:
@@ -1693,7 +1674,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_CHECK_CLEAR_STATUS,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 2, USBTMC_TIMEOUT);
+0, 0, buffer, 2, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
@@ -1710,15 +1691,19 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
goto exit;
}
 
-   if (buffer[1] == 1)
+   if ((buffer[1] & 1) != 0) {
do {
dev_dbg(dev, "Reading from bulk in EP\n");
 
rv = usb_bulk_msg(data->usb_dev,
  usb_rcvbulkpipe(data->usb_dev,
  data->bulk_in),
- buffer, USBTMC_SIZE_IOBUFFER,
- , USBTMC_TIMEOUT);
+ buffer, USBTMC_BUFSIZE,
+ , USB_CTRL_GET_TIMEOUT);
+
+   print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
+16, 1, buffer, actual, true);
+
n++;
 
if (rv < 0) {
@@ -1726,10 +1711,15 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
rv);
goto exit;
}
-   } while ((actual == max_size) &&
+   } while ((actual == USBTMC_BUFSIZE) &&
  (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
+   } else {
+  

[PATCH v6 11/22] usb: usbtmc: Optimize usbtmc_write

2018-09-12 Thread Guido Kiener
Use new usbtmc_generic_write function to maximize bandwidth
during long data transfer.
The maximum output transfer size is limited to INT_MAX (=2GB).

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 176 +++--
 1 file changed, 109 insertions(+), 67 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 3ed2146fb670..c476b53b6237 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1509,94 +1509,136 @@ static ssize_t usbtmc_write(struct file *filp, const 
char __user *buf,
 {
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data;
+   struct urb *urb = NULL;
+   ssize_t retval = 0;
u8 *buffer;
-   int retval;
-   int actual;
-   unsigned long int n_bytes;
-   int remaining;
-   int done;
-   int this_part;
+   u32 remaining, done;
+   u32 transfersize, aligned, buflen;
 
file_data = filp->private_data;
data = file_data->data;
 
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
-   if (!buffer)
-   return -ENOMEM;
-
mutex_lock(>io_mutex);
+
if (data->zombie) {
retval = -ENODEV;
goto exit;
}
 
-   remaining = count;
done = 0;
 
-   while (remaining > 0) {
-   if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE) {
-   this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE;
-   buffer[8] = 0;
-   } else {
-   this_part = remaining;
-   buffer[8] = file_data->eom_val;
-   }
-
-   /* Setup IO buffer for DEV_DEP_MSG_OUT message */
-   buffer[0] = 1;
-   buffer[1] = data->bTag;
-   buffer[2] = ~data->bTag;
-   buffer[3] = 0; /* Reserved */
-   buffer[4] = this_part >> 0;
-   buffer[5] = this_part >> 8;
-   buffer[6] = this_part >> 16;
-   buffer[7] = this_part >> 24;
-   /* buffer[8] is set above... */
-   buffer[9] = 0; /* Reserved */
-   buffer[10] = 0; /* Reserved */
-   buffer[11] = 0; /* Reserved */
-
-   if (copy_from_user([USBTMC_HEADER_SIZE], buf + done, 
this_part)) {
-   retval = -EFAULT;
-   goto exit;
-   }
-
-   n_bytes = roundup(USBTMC_HEADER_SIZE + this_part, 4);
-   memset(buffer + USBTMC_HEADER_SIZE + this_part, 0, n_bytes - 
(USBTMC_HEADER_SIZE + this_part));
-
-   do {
-   retval = usb_bulk_msg(data->usb_dev,
- usb_sndbulkpipe(data->usb_dev,
- data->bulk_out),
- buffer, n_bytes,
- , file_data->timeout);
-   if (retval != 0)
-   break;
-   n_bytes -= actual;
-   } while (n_bytes);
-
-   data->bTag_last_write = data->bTag;
+   spin_lock_irq(_data->err_lock);
+   file_data->out_transfer_size = 0;
+   file_data->out_status = 0;
+   spin_unlock_irq(_data->err_lock);
+
+   if (!count)
+   goto exit;
+
+   if (down_trylock(_data->limit_write_sem)) {
+   /* previous calls were async */
+   retval = -EBUSY;
+   goto exit;
+   }
+
+   urb = usbtmc_create_urb();
+   if (!urb) {
+   retval = -ENOMEM;
+   up(_data->limit_write_sem);
+   goto exit;
+   }
+
+   buffer = urb->transfer_buffer;
+   buflen = urb->transfer_buffer_length;
+
+   if (count > INT_MAX) {
+   transfersize = INT_MAX;
+   buffer[8] = 0;
+   } else {
+   transfersize = count;
+   buffer[8] = file_data->eom_val;
+   }
+
+   /* Setup IO buffer for DEV_DEP_MSG_OUT message */
+   buffer[0] = 1;
+   buffer[1] = data->bTag;
+   buffer[2] = ~data->bTag;
+   buffer[3] = 0; /* Reserved */
+   buffer[4] = transfersize >> 0;
+   buffer[5] = transfersize >> 8;
+   buffer[6] = transfersize >> 16;
+   buffer[7] = transfersize >> 24;
+   /* buffer[8] is set above... */
+   buffer[9] = 0; /* Reserved */
+   buffer[10] = 0; /* Reserved */
+   buffer[11] = 0; /* Reserved */
+
+   remaining = transfersize;
+
+   if (transfersize + USBTMC_HEADER_SIZE > buflen) {
+   transfersize = buflen - USBTMC_HEADER_SIZE;
+   aligned = buflen;
+   } else {
+   alig

[PATCH v6 14/22] usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_IN

2018-09-12 Thread Guido Kiener
Add parameter 'tag' to function usbtmc_ioctl_abort_bulk_in_tag()
for future versions.

Remove calculation of max_size (=wMaxPacketSize) and wrong
condition (actual == max_size) in while loop. An abort operation
should always flush the complete Bulk-IN until a short packet is
received.

Return error code ENOMSG when transfer (specified by given tag)
is not in progress and device returns code
USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS.

Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.

Use common macro USB_CTRL_GET_TIMEOUT instead of USBTMC_TIMEOUT.

Check only bit 0 (field bmAbortBulkIn) of the
CHECK_ABORT_BULK_IN_STATUS response, since other bits are reserved
and can change in future versions.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 139 -
 1 file changed, 61 insertions(+), 78 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 11b2c8632d91..0b05aaa0247c 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -270,18 +270,17 @@ static int usbtmc_release(struct inode *inode, struct 
file *file)
return 0;
 }
 
-static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
+static int usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data *data,
+ u8 tag)
 {
u8 *buffer;
struct device *dev;
int rv;
int n;
int actual;
-   struct usb_host_interface *current_setting;
-   int max_size;
 
dev = >intf->dev;
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+   buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
 
@@ -289,21 +288,34 @@ static int usbtmc_ioctl_abort_bulk_in(struct 
usbtmc_device_data *data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INITIATE_ABORT_BULK_IN,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
-data->bTag_last_read, data->bulk_in,
-buffer, 2, USBTMC_TIMEOUT);
+tag, data->bulk_in,
+buffer, 2, USB_CTRL_GET_TIMEOUT);
 
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
}
 
-   dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]);
+   dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x with tag %02x\n",
+   buffer[0], buffer[1]);
 
if (buffer[0] == USBTMC_STATUS_FAILED) {
+   /* No transfer in progress and the Bulk-OUT FIFO is empty. */
rv = 0;
goto exit;
}
 
+   if (buffer[0] == USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS) {
+   /* The device returns this status if either:
+* - There is a transfer in progress, but the specified bTag
+*   does not match.
+* - There is no transfer in progress, but the Bulk-OUT FIFO
+*   is not empty.
+*/
+   rv = -ENOMSG;
+   goto exit;
+   }
+
if (buffer[0] != USBTMC_STATUS_SUCCESS) {
dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n",
buffer[0]);
@@ -311,64 +323,52 @@ static int usbtmc_ioctl_abort_bulk_in(struct 
usbtmc_device_data *data)
goto exit;
}
 
-   max_size = 0;
-   current_setting = data->intf->cur_altsetting;
-   for (n = 0; n < current_setting->desc.bNumEndpoints; n++)
-   if (current_setting->endpoint[n].desc.bEndpointAddress ==
-   data->bulk_in)
-   max_size = 
usb_endpoint_maxp(_setting->endpoint[n].desc);
-
-   if (max_size == 0) {
-   dev_err(dev, "Couldn't get wMaxPacketSize\n");
-   rv = -EPERM;
-   goto exit;
-   }
-
-   dev_dbg(>intf->dev, "wMaxPacketSize is %d\n", max_size);
-
-   n = 0;
-
-   do {
-   dev_dbg(dev, "Reading from bulk in EP\n");
-
-   rv = usb_bulk_msg(data->usb_dev,
- usb_rcvbulkpipe(data->usb_dev,
- data->bulk_in),
- buffer, USBTMC_SIZE_IOBUFFER,
- , USBTMC_TIMEOUT);
-
-   n++;
-
-   if (rv < 0) {
-   dev_err(dev, "usb_bulk_msg returned %d\n", rv);
-   goto exit;
-   }
-   } while ((actual == max_size) &&
-(n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
-
-   if (actual =

[PATCH v6 15/22] usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_OUT

2018-09-12 Thread Guido Kiener
Add parameter 'tag' to function usbtmc_ioctl_abort_bulk_out_tag()
for future versions.

Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.

Insert a sleep of 50 ms between subsequent
CHECK_ABORT_BULK_OUT_STATUS control requests to avoid stressing
the instrument with repeated requests.

Use common macro USB_CTRL_GET_TIMEOUT instead of USBTMC_TIMEOUT.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 16 
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 0b05aaa0247c..329daa7425dc 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -398,7 +398,8 @@ static int usbtmc_ioctl_abort_bulk_in(struct 
usbtmc_device_data *data)
return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read);
 }
 
-static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
+static int usbtmc_ioctl_abort_bulk_out_tag(struct usbtmc_device_data *data,
+  u8 tag)
 {
struct device *dev;
u8 *buffer;
@@ -415,8 +416,8 @@ static int usbtmc_ioctl_abort_bulk_out(struct 
usbtmc_device_data *data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
-data->bTag_last_write, data->bulk_out,
-buffer, 2, USBTMC_TIMEOUT);
+tag, data->bulk_out,
+buffer, 2, USB_CTRL_GET_TIMEOUT);
 
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
@@ -435,12 +436,14 @@ static int usbtmc_ioctl_abort_bulk_out(struct 
usbtmc_device_data *data)
n = 0;
 
 usbtmc_abort_bulk_out_check_status:
+   /* do not stress device with subsequent requests */
+   msleep(50);
rv = usb_control_msg(data->usb_dev,
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
 0, data->bulk_out, buffer, 0x08,
-USBTMC_TIMEOUT);
+USB_CTRL_GET_TIMEOUT);
n++;
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
@@ -474,6 +477,11 @@ static int usbtmc_ioctl_abort_bulk_out(struct 
usbtmc_device_data *data)
return rv;
 }
 
+static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
+{
+   return usbtmc_ioctl_abort_bulk_out_tag(data, data->bTag_last_write);
+}
+
 static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,
void __user *arg)
 {
-- 
2.17.1



[PATCH v6 18/22] usb: usbtmc: Update ioctl-number.txt

2018-09-12 Thread Guido Kiener
Reserve a suitable range of ioctl numbers for USBTMC driver.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 Documentation/ioctl/ioctl-number.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/ioctl/ioctl-number.txt 
b/Documentation/ioctl/ioctl-number.txt
index 13a7c999c04a..d05d93761653 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -201,7 +201,7 @@ Code  Seq#(hex) Include FileComments
 'X'01  linux/pktcdvd.h conflict!
 'Y'all linux/cyclades.h
 'Z'14-15   drivers/message/fusion/mptctl.h
-'['00-07   linux/usb/tmc.h USB Test and Measurement Devices
+'['00-3F   linux/usb/tmc.h USB Test and Measurement Devices
<mailto:gre...@linuxfoundation.org>
 'a'all linux/atm*.h, linux/sonet.h ATM on linux
<http://lrcwww.epfl.ch/>
-- 
2.17.1



[PATCH v6 22/22] usb: usbtmc: Remove sysfs group TermChar and auto_abort

2018-09-12 Thread Guido Kiener
As all the properties of the usbtmc driver can now be
controlled on a per file descriptor basis by ioctl functions
the sysfs interface is of limited use.
We are not aware about applications that are using the sysfs
parameter TermChar, TermCharEnabled or auto_abort.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 .../ABI/stable/sysfs-driver-usb-usbtmc| 35 
 drivers/usb/class/usbtmc.c| 84 +--
 2 files changed, 3 insertions(+), 116 deletions(-)

diff --git a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc 
b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
index e960cd027e1e..a9e123ba32cd 100644
--- a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
+++ b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
@@ -25,38 +25,3 @@ Description:
4.2.2.
 
The files are read only.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/TermChar
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file is the TermChar value to be sent to the USB TMC
-   device as described by the document, "Universal Serial Bus Test
-   and Measurement Class Specification
-   (USBTMC) Revision 1.0" as published by the USB-IF.
-
-   Note that the TermCharEnabled file determines if this value is
-   sent to the device or not.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/TermCharEnabled
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file determines if the TermChar is to be sent to the
-   device on every transaction or not.  For more details about
-   this, please see the document, "Universal Serial Bus Test and
-   Measurement Class Specification (USBTMC) Revision 1.0" as
-   published by the USB-IF.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/auto_abort
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file determines if the transaction of the USB TMC
-   device is to be automatically aborted if there is any error.
-   For more details about this, please see the document,
-   "Universal Serial Bus Test and Measurement Class Specification
-   (USBTMC) Revision 1.0" as published by the USB-IF.
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index b9e505cbe6b4..0fcb81a1399b 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -102,11 +102,6 @@ struct usbtmc_device_data {
/* coalesced usb488_caps from usbtmc_dev_capabilities */
__u8 usb488_caps;
 
-   /* attributes from the USB TMC spec for this device */
-   u8 TermChar;
-   bool TermCharEnabled;
-   bool auto_abort;
-
bool zombie; /* fd of disconnected device */
 
struct usbtmc_dev_capabilities  capabilities;
@@ -196,11 +191,10 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
 
atomic_set(_data->closing, 0);
 
-   /* copy default values from device settings */
file_data->timeout = USBTMC_TIMEOUT;
-   file_data->term_char = data->TermChar;
-   file_data->term_char_enabled = data->TermCharEnabled;
-   file_data->auto_abort = data->auto_abort;
+   file_data->term_char = '\n';
+   file_data->term_char_enabled = 0;
+   file_data->auto_abort = 0;
file_data->eom_val = 1;
 
INIT_LIST_HEAD(_data->file_elem);
@@ -1851,72 +1845,6 @@ static const struct attribute_group capability_attr_grp 
= {
.attrs = capability_attrs,
 };
 
-static ssize_t TermChar_show(struct device *dev,
-struct device_attribute *attr, char *buf)
-{
-   struct usb_interface *intf = to_usb_interface(dev);
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);
-
-   return sprintf(buf, "%c\n", data->TermChar);
-}
-
-static ssize_t TermChar_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
-   struct usb_interface *intf = to_usb_interface(dev);
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);
-
-   if (count < 1)
-   return -EINVAL;
-   data->TermChar = buf[0];
-   return count;
-}
-static DEVICE_ATTR_RW(TermChar);
-
-#define data_attribute(name)   \
-static ssize_t name##_show(struct device *dev, \
-  struct device_attribute *attr, char *buf)\
-{  \
-   struct usb_interface *intf = to_usb_interface(dev); \
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);   \
-   

[PATCH v6 12/22] usb: usbtmc: Optimize usbtmc_read

2018-09-12 Thread Guido Kiener
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: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 222 ++---
 1 file changed, 105 insertions(+), 117 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index c476b53b6237..26a779d0c89b 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1293,7 +1293,7 @@ static ssize_t usbtmc_ioctl_write_result(struct 
usbtmc_file_data *file_data,
  * Also updates bTag_last_write.
  */
 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;
int retval;
@@ -1336,12 +1336,11 @@ static int send_request_dev_dep_msg_in(struct 
usbtmc_file_data *file_data,
data->bTag++;
 
kfree(buffer);
-   if (retval < 0) {
-   dev_err(>intf->dev, "usb_bulk_msg in 
send_request_dev_dep_msg_in() returned %d\n", retval);
-   return retval;
-   }
+   if (retval < 0)
+   dev_err(>intf->dev, "%s returned %d\n",
+   __func__, retval);
 
-   return 0;
+   return retval;
 }
 
 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_device_data *data;
struct device *dev;
+   const u32 bufsize = USBTMC_BUFSIZE;
u32 n_characters;
u8 *buffer;
int actual;
-   size_t done;
-   size_t remaining;
+   u32 done = 0;
+   u32 remaining;
int retval;
-   size_t this_part;
 
/* Get pointer to private data structure */
file_data = filp->private_data;
data = file_data->data;
dev = >intf->dev;
 
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+   buffer = kmalloc(bufsize, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
 
@@ -1373,7 +1372,10 @@ static ssize_t usbtmc_read(struct file *filp, char 
__user *buf,
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);
 
@@ -1385,114 +1387,100 @@ static ssize_t usbtmc_read(struct file *filp, char 
__user *buf,
 
/* Loop until we have fetched everything we requested */
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, ,
- 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) */
-   data->bTag_last_read = data->bTag;
-
-   if (retval < 0) {
-   dev_dbg(dev, "Unable to read data, error %d\n", retval);
-   if (file_data->auto_abort)
-   usbtmc_ioctl_abort_bulk_in(data);
+
+   /* Send bulk URB */
+   retval = usb_bulk_msg(data->usb_dev,
+ usb_rcvbulkpipe(data->usb_dev,
+ data->bulk_in),
+ buffer, bufsize, ,
+ file_data->timeout);
+
+   dev_dbg(dev, "%s: bulk_msg retval(%u), actual(%d)\n",
+   __func__, retval, actual);
+
+   /* Store bTag (in case we need to abort) */
+   data->bTag_last_read = data->bTag;
+
+   if (retval < 0) {
+   if (file_data->auto_abort)
+   usbtmc_ioctl_abort_bulk_in(data);
+   goto exit;
+   }
+
+   /* 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)
+ 

[PATCH v6 06/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_CLEANUP_IO

2018-09-12 Thread Guido Kiener
The ioctl USBTMC_IOCTL_CLEANUP_IO kills all submitted urbs to OUT
and IN bulk, and clears all received data from IN bulk. Internal
transfer counters and error states are reset.

An application should use this ioctl after an asnychronous transfer
was canceled and/or error handling has finished.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 19 +++
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 20 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 0d8aa4bc3fa7..dc6c04fdfdff 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1706,6 +1706,21 @@ static int usbtmc_ioctl_cancel_io(struct 
usbtmc_file_data *file_data)
return 0;
 }
 
+static int usbtmc_ioctl_cleanup_io(struct usbtmc_file_data *file_data)
+{
+   usb_kill_anchored_urbs(_data->submitted);
+   usb_scuttle_anchored_urbs(_data->in_anchor);
+   spin_lock_irq(_data->err_lock);
+   file_data->in_status = 0;
+   file_data->in_transfer_size = 0;
+   file_data->out_status = 0;
+   file_data->out_transfer_size = 0;
+   spin_unlock_irq(_data->err_lock);
+
+   file_data->in_urbs_used = 0;
+   return 0;
+}
+
 static int get_capabilities(struct usbtmc_device_data *data)
 {
struct device *dev = >usb_dev->dev;
@@ -2130,6 +2145,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
case USBTMC_IOCTL_CANCEL_IO:
retval = usbtmc_ioctl_cancel_io(file_data);
break;
+
+   case USBTMC_IOCTL_CLEANUP_IO:
+   retval = usbtmc_ioctl_cleanup_io(file_data);
+   break;
}
 
 skip_io_on_zombie:
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 42e275d1d385..5a69d9dc967d 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -99,6 +99,7 @@ struct usbtmc_message {
 
 /* Cancel and cleanup asynchronous calls */
 #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
+#define USBTMC_IOCTL_CLEANUP_IO_IO(USBTMC_IOC_NR, 36)
 
 /* Driver encoded usb488 capabilities */
 #define USBTMC488_CAPABILITY_TRIGGER 1
-- 
2.17.1



[PATCH v6 07/22] usb: usbtmc: Fix suspend/resume

2018-09-12 Thread Guido Kiener
Submitted urbs are not allowed when system is suspended.
Thus the submitted urb waiting at interrupt pipe is killed
during suspend callback and submitted again when system resumes.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 16 +++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index dc6c04fdfdff..e4c80b44b55a 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -2306,7 +2306,9 @@ static void usbtmc_free_int(struct usbtmc_device_data 
*data)
return;
usb_kill_urb(data->iin_urb);
kfree(data->iin_buffer);
+   data->iin_buffer = NULL;
usb_free_urb(data->iin_urb);
+   data->iin_urb = NULL;
kref_put(>kref, usbtmc_delete);
 }
 
@@ -2488,13 +2490,25 @@ static int usbtmc_suspend(struct usb_interface *intf, 
pm_message_t message)
   file_elem);
usbtmc_draw_down(file_data);
}
+
+   if (data->iin_ep_present && data->iin_urb)
+   usb_kill_urb(data->iin_urb);
+
mutex_unlock(>io_mutex);
return 0;
 }
 
 static int usbtmc_resume(struct usb_interface *intf)
 {
-   return 0;
+   struct usbtmc_device_data *data = usb_get_intfdata(intf);
+   int retcode = 0;
+
+   if (data->iin_ep_present && data->iin_urb)
+   retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL);
+   if (retcode)
+   dev_err(>dev, "Failed to submit iin_urb\n");
+
+   return retcode;
 }
 
 static int usbtmc_pre_reset(struct usb_interface *intf)
-- 
2.17.1



[PATCH v6 09/22] usb: usbtmc: add ioctl USBTMC_IOCTL_MSG_IN_ATTR

2018-09-12 Thread Guido Kiener
add ioctl USBTMC_IOCTL_MSG_IN_ATTR that returns the specific
bmTransferAttributes field of the last DEV_DEP_MSG_IN Bulk-IN
header. This header is received by the read() function. The
meaning of the (u8) bitmap bmTransferAttributes is:

Bit 0 = EOM flag is set when the last transfer of a USBTMC
message is received.

Bit 1 = is set when the last byte is a termchar (e.g. '\n').
Note that this bit is always zero when the device does not support
the termchar feature or when termchar detection is not enabled
(see ioctl USBTMC_IOCTL_CONFIG_TERMCHAR).

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 8 
 include/uapi/linux/usb/tmc.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index e177bac777f4..4cda74e9e11b 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -131,6 +131,7 @@ struct usbtmc_file_data {
u8 srq_byte;
atomic_t   srq_asserted;
atomic_t   closing;
+   u8 bmTransferAttributes; /* member of DEV_DEP_MSG_IN */
 
u8 eom_val;
u8 term_char;
@@ -1435,6 +1436,8 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
   (buffer[6] << 16) +
   (buffer[7] << 24);
 
+   file_data->bmTransferAttributes = buffer[8];
+
if (n_characters > this_part) {
dev_err(dev, "Device wants to return more data 
than requested: %u > %zu\n", n_characters, count);
if (data->auto_abort)
@@ -2199,6 +2202,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
  (__u32 __user *)arg);
break;
 
+   case USBTMC_IOCTL_MSG_IN_ATTR:
+   retval = put_user(file_data->bmTransferAttributes,
+ (__u8 __user *)arg);
+   break;
+
case USBTMC_IOCTL_CANCEL_IO:
retval = usbtmc_ioctl_cancel_io(file_data);
break;
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index e228ad7fc141..55ca365b66d4 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -98,6 +98,8 @@ struct usbtmc_message {
 #define USBTMC488_IOCTL_TRIGGER_IO(USBTMC_IOC_NR, 22)
 #define USBTMC488_IOCTL_WAIT_SRQ   _IOW(USBTMC_IOC_NR, 23, __u32)
 
+#define USBTMC_IOCTL_MSG_IN_ATTR   _IOR(USBTMC_IOC_NR, 24, __u8)
+
 /* Cancel and cleanup asynchronous calls */
 #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
 #define USBTMC_IOCTL_CLEANUP_IO_IO(USBTMC_IOC_NR, 36)
-- 
2.17.1



[PATCH v6 10/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_AUTO_ABORT

2018-09-12 Thread Guido Kiener
Add ioctl USBTMC_IOCTL_AUTO_ABORT to configure auto_abort for
each specific file handle.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 23 ---
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 4cda74e9e11b..3ed2146fb670 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -136,6 +136,7 @@ struct usbtmc_file_data {
u8 eom_val;
u8 term_char;
bool   term_char_enabled;
+   bool   auto_abort;
 
spinlock_t err_lock; /* lock for errors */
 
@@ -201,6 +202,7 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
file_data->timeout = USBTMC_TIMEOUT;
file_data->term_char = data->TermChar;
file_data->term_char_enabled = data->TermCharEnabled;
+   file_data->auto_abort = data->auto_abort;
file_data->eom_val = 1;
 
INIT_LIST_HEAD(_data->file_elem);
@@ -1376,7 +1378,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
retval = send_request_dev_dep_msg_in(file_data, count);
 
if (retval < 0) {
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_out(data);
goto exit;
}
@@ -1401,7 +1403,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
 
if (retval < 0) {
dev_dbg(dev, "Unable to read data, error %d\n", retval);
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
@@ -1411,21 +1413,21 @@ static ssize_t usbtmc_read(struct file *filp, char 
__user *buf,
/* 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)
+   if (file_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)
+   if (file_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 (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
@@ -1440,7 +1442,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
 
if (n_characters > this_part) {
dev_err(dev, "Device wants to return more data 
than requested: %u > %zu\n", n_characters, count);
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
@@ -1582,7 +1584,7 @@ static ssize_t usbtmc_write(struct file *filp, const char 
__user *buf,
if (retval < 0) {
dev_err(>intf->dev,
"Unable to send data, error %d\n", retval);
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_out(data);
goto exit;
}
@@ -2091,6 +2093,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data;
int retval = -EBADRQC;
+   __u8 tmp_byte;
 
file_data = file->private_data;
data = file_data->data;
@@ -2207,6 +2210,12 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
  (__u8 __user *)arg);
break;
 
+   ca

[PATCH v6 17/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_API_VERSION

2018-09-12 Thread Guido Kiener
Add ioctl USBTMC_IOCTL_API_VERSION to get current API version
of usbtmc driver.

This is to allow an instrument library to determine whether
the driver API is compatible with the implementation.

The API may change in future versions. Therefore the macro
USBTMC_API_VERSION should be incremented when changing tmc.h
with new flags, ioctls or when changing a significant behavior
of the driver.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 9 +
 include/uapi/linux/usb/tmc.h | 1 +
 2 files changed, 10 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 964c8e87dacb..72867a97ec00 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -22,6 +22,10 @@
 #include 
 #include 
 
+/* Increment API VERSION when changing tmc.h with new flags or ioctls
+ * or when changing a significant behavior of the driver.
+ */
+#define USBTMC_API_VERSION (2)
 
 #define USBTMC_HEADER_SIZE 12
 #define USBTMC_MINOR_BASE  176
@@ -2179,6 +2183,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
   (void __user *)arg);
break;
 
+   case USBTMC_IOCTL_API_VERSION:
+   retval = put_user(USBTMC_API_VERSION,
+ (__u32 __user *)arg);
+   break;
+
case USBTMC488_IOCTL_GET_CAPS:
retval = copy_to_user((void __user *)arg,
>usb488_caps,
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 4b36108b9cca..fdd4d88a7b95 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -89,6 +89,7 @@ struct usbtmc_message {
 #define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct 
usbtmc_message)
 #define USBTMC_IOCTL_READ  _IOWR(USBTMC_IOC_NR, 14, struct 
usbtmc_message)
 #define USBTMC_IOCTL_WRITE_RESULT  _IOWR(USBTMC_IOC_NR, 15, __u32)
+#define USBTMC_IOCTL_API_VERSION   _IOR(USBTMC_IOC_NR, 16, __u32)
 
 #define USBTMC488_IOCTL_GET_CAPS   _IOR(USBTMC_IOC_NR, 17, unsigned char)
 #define USBTMC488_IOCTL_READ_STB   _IOR(USBTMC_IOC_NR, 18, unsigned char)
-- 
2.17.1



[PATCH v6 19/22] usb: usbtmc: Remove redundant code

2018-09-12 Thread Guido Kiener
Remove redundant code and fix debug messages.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 25 -
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 72867a97ec00..5b6cdb1237ab 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1745,12 +1745,9 @@ static int usbtmc_ioctl_clear_out_halt(struct 
usbtmc_device_data *data)
rv = usb_clear_halt(data->usb_dev,
usb_sndbulkpipe(data->usb_dev, data->bulk_out));
 
-   if (rv < 0) {
-   dev_err(>usb_dev->dev, "usb_control_msg returned %d\n",
-   rv);
-   return rv;
-   }
-   return 0;
+   if (rv < 0)
+   dev_err(>usb_dev->dev, "%s returned %d\n", __func__, rv);
+   return rv;
 }
 
 static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
@@ -1760,12 +1757,9 @@ static int usbtmc_ioctl_clear_in_halt(struct 
usbtmc_device_data *data)
rv = usb_clear_halt(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
 
-   if (rv < 0) {
-   dev_err(>usb_dev->dev, "usb_control_msg returned %d\n",
-   rv);
-   return rv;
-   }
-   return 0;
+   if (rv < 0)
+   dev_err(>usb_dev->dev, "%s returned %d\n", __func__, rv);
+   return rv;
 }
 
 static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data)
@@ -2189,11 +2183,8 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
break;
 
case USBTMC488_IOCTL_GET_CAPS:
-   retval = copy_to_user((void __user *)arg,
-   >usb488_caps,
-   sizeof(data->usb488_caps));
-   if (retval)
-   retval = -EFAULT;
+   retval = put_user(data->usb488_caps,
+ (unsigned char __user *)arg);
break;
 
case USBTMC488_IOCTL_READ_STB:
-- 
2.17.1



[PATCH v6 21/22] usb: usbtmc: Fix split quoted string in debug message

2018-09-12 Thread Guido Kiener
Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index ad3932ca4d8d..b9e505cbe6b4 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -2499,8 +2499,8 @@ static int usbtmc_probe(struct usb_interface *intf,
 
retcode = usb_register_dev(intf, _class);
if (retcode) {
-   dev_err(>dev, "Not able to get a minor"
-   " (base %u, slice default): %d\n", USBTMC_MINOR_BASE,
+   dev_err(>dev, "Not able to get a minor (base %u, slice 
default): %d\n",
+   USBTMC_MINOR_BASE,
retcode);
goto error_register;
}
-- 
2.17.1



[PATCH v6 08/22] usb: usbtmc: Add ioctl USBTMC488_IOCTL_WAIT_SRQ

2018-09-12 Thread Guido Kiener
Wait until an SRQ (service request) is received on the interrupt pipe
or until the given period of time is expired. In contrast to the
poll() function this ioctl does not return when other (a)synchronous
I/O operations fail with EPOLLERR.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 57 
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 58 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index e4c80b44b55a..e177bac777f4 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -130,6 +130,7 @@ struct usbtmc_file_data {
u32timeout;
u8 srq_byte;
atomic_t   srq_asserted;
+   atomic_t   closing;
 
u8 eom_val;
u8 term_char;
@@ -193,6 +194,8 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
mutex_lock(>io_mutex);
file_data->data = data;
 
+   atomic_set(_data->closing, 0);
+
/* copy default values from device settings */
file_data->timeout = USBTMC_TIMEOUT;
file_data->term_char = data->TermChar;
@@ -223,6 +226,7 @@ static int usbtmc_flush(struct file *file, fl_owner_t id)
if (file_data == NULL)
return -ENODEV;
 
+   atomic_set(_data->closing, 1);
data = file_data->data;
 
/* wait for io to stop */
@@ -576,6 +580,54 @@ static int usbtmc488_ioctl_read_stb(struct 
usbtmc_file_data *file_data,
return rv;
 }
 
+static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data,
+   __u32 __user *arg)
+{
+   struct usbtmc_device_data *data = file_data->data;
+   struct device *dev = >intf->dev;
+   int rv;
+   u32 timeout;
+   unsigned long expire;
+
+   if (!data->iin_ep_present) {
+   dev_dbg(dev, "no interrupt endpoint present\n");
+   return -EFAULT;
+   }
+
+   if (get_user(timeout, arg))
+   return -EFAULT;
+
+   expire = msecs_to_jiffies(timeout);
+
+   mutex_unlock(>io_mutex);
+
+   rv = wait_event_interruptible_timeout(
+   data->waitq,
+   atomic_read(_data->srq_asserted) != 0 ||
+   atomic_read(_data->closing),
+   expire);
+
+   mutex_lock(>io_mutex);
+
+   /* Note! disconnect or close could be called in the meantime */
+   if (atomic_read(_data->closing) || data->zombie)
+   rv = -ENODEV;
+
+   if (rv < 0) {
+   /* dev can be invalid now! */
+   pr_debug("%s - wait interrupted %d\n", __func__, rv);
+   return rv;
+   }
+
+   if (rv == 0) {
+   dev_dbg(dev, "%s - wait timed out\n", __func__);
+   return -ETIMEDOUT;
+   }
+
+   dev_dbg(dev, "%s - srq asserted\n", __func__);
+   return 0;
+}
+
 static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
void __user *arg, unsigned int cmd)
 {
@@ -2142,6 +2194,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
retval = usbtmc488_ioctl_trigger(file_data);
break;
 
+   case USBTMC488_IOCTL_WAIT_SRQ:
+   retval = usbtmc488_ioctl_wait_srq(file_data,
+ (__u32 __user *)arg);
+   break;
+
case USBTMC_IOCTL_CANCEL_IO:
retval = usbtmc_ioctl_cancel_io(file_data);
break;
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 5a69d9dc967d..e228ad7fc141 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -96,6 +96,7 @@ struct usbtmc_message {
 #define USBTMC488_IOCTL_GOTO_LOCAL _IO(USBTMC_IOC_NR, 20)
 #define USBTMC488_IOCTL_LOCAL_LOCKOUT  _IO(USBTMC_IOC_NR, 21)
 #define USBTMC488_IOCTL_TRIGGER_IO(USBTMC_IOC_NR, 22)
+#define USBTMC488_IOCTL_WAIT_SRQ   _IOW(USBTMC_IOC_NR, 23, __u32)
 
 /* Cancel and cleanup asynchronous calls */
 #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
-- 
2.17.1



[PATCH v6 05/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_CANCEL_IO

2018-09-12 Thread Guido Kiener
ioctl USBTMC_IOCTL_CANCEL_IO stops and kills all flying urbs of
last USBTMC_IOCTL_READ and USBTMC_IOCTL_WRITE function calls.
A subsequent call to USBTMC_IOCTL_READ or
USBTMC_IOCTL_WRITE_RESULT returns -ECANCELED with
information about current transferred data.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 4 
 include/uapi/linux/usb/tmc.h | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 45ccdd087d6f..0d8aa4bc3fa7 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -2126,6 +2126,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
case USBTMC488_IOCTL_TRIGGER:
retval = usbtmc488_ioctl_trigger(file_data);
break;
+
+   case USBTMC_IOCTL_CANCEL_IO:
+   retval = usbtmc_ioctl_cancel_io(file_data);
+   break;
}
 
 skip_io_on_zombie:
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index f0fd0d4334ec..42e275d1d385 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -97,6 +97,9 @@ struct usbtmc_message {
 #define USBTMC488_IOCTL_LOCAL_LOCKOUT  _IO(USBTMC_IOC_NR, 21)
 #define USBTMC488_IOCTL_TRIGGER_IO(USBTMC_IOC_NR, 22)
 
+/* Cancel and cleanup asynchronous calls */
+#define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
+
 /* Driver encoded usb488 capabilities */
 #define USBTMC488_CAPABILITY_TRIGGER 1
 #define USBTMC488_CAPABILITY_SIMPLE  2
-- 
2.17.1



[PATCH v6 01/22] usb: usbtmc: Add ioctl for generic requests on control

2018-09-12 Thread Guido Kiener
Add USBTMC_IOCTL_CTRL_REQUEST to send arbitrary requests on the
control pipe.  Used by specific applications of IVI Foundation,
Inc. to implement VISA API functions: viUsbControlIn/Out.

The maximum length of control request is set to 4k.

This ioctl does not support compatibility for 32 bit
applications running on 64 bit systems. However all other
convenient ioctls of the USBTMC driver can still be used in 32
bit applications as well. Note that 32 bit applications running
on 32 bit target systems are not affected by this limitation.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 69 
 include/uapi/linux/usb/tmc.h | 15 
 2 files changed, 84 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 83ffa5a14c3d..7e69bd05c631 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 Greg Kroah-Hartman 
+ * Copyright (C) 2018 IVI Foundation, Inc.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -36,6 +37,9 @@
 /* Default USB timeout (in milliseconds) */
 #define USBTMC_TIMEOUT 5000
 
+/* I/O buffer size used in generic read/write functions */
+#define USBTMC_BUFSIZE (4096)
+
 /*
  * Maximum number of read cycles to empty bulk in endpoint during CLEAR and
  * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short
@@ -1250,6 +1254,67 @@ static int usbtmc_ioctl_indicator_pulse(struct 
usbtmc_device_data *data)
return rv;
 }
 
+static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
+   void __user *arg)
+{
+   struct device *dev = >intf->dev;
+   struct usbtmc_ctrlrequest request;
+   u8 *buffer = NULL;
+   int rv;
+   unsigned long res;
+
+   res = copy_from_user(, arg, sizeof(struct usbtmc_ctrlrequest));
+   if (res)
+   return -EFAULT;
+
+   buffer = kmalloc(request.req.wLength, GFP_KERNEL);
+   if (!buffer)
+   return -ENOMEM;
+
+   if (request.req.wLength > USBTMC_BUFSIZE)
+   return -EMSGSIZE;
+
+   if (request.req.wLength) {
+   buffer = kmalloc(request.req.wLength, GFP_KERNEL);
+   if (!buffer)
+   return -ENOMEM;
+
+   if ((request.req.bRequestType & USB_DIR_IN) == 0) {
+   /* Send control data to device */
+   res = copy_from_user(buffer, request.data,
+request.req.wLength);
+   if (res) {
+   rv = -EFAULT;
+   goto exit;
+   }
+   }
+   }
+
+   rv = usb_control_msg(data->usb_dev,
+   usb_rcvctrlpipe(data->usb_dev, 0),
+   request.req.bRequest,
+   request.req.bRequestType,
+   request.req.wValue,
+   request.req.wIndex,
+   buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT);
+
+   if (rv < 0) {
+   dev_err(dev, "%s failed %d\n", __func__, rv);
+   goto exit;
+   }
+
+   if (rv && (request.req.bRequestType & USB_DIR_IN)) {
+   /* Read control data from device */
+   res = copy_to_user(request.data, buffer, rv);
+   if (res)
+   rv = -EFAULT;
+   }
+
+ exit:
+   kfree(buffer);
+   return rv;
+}
+
 /*
  * Get the usb timeout value
  */
@@ -1366,6 +1431,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
retval = usbtmc_ioctl_abort_bulk_in(data);
break;
 
+   case USBTMC_IOCTL_CTRL_REQUEST:
+   retval = usbtmc_ioctl_request(data, (void __user *)arg);
+   break;
+
case USBTMC_IOCTL_GET_TIMEOUT:
retval = usbtmc_ioctl_get_timeout(file_data,
  (void __user *)arg);
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 729af2f861a4..5e12928ed1e5 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -4,6 +4,7 @@
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 Greg Kroah-Hartman 
  * Copyright (C) 2015 Dave Penkler 
+ * Copyright (C) 2018 IVI Foundation, Inc.
  *
  * This file holds USB constants defined by the USB Device Class
  * and USB488 Subclass Definitions for Test and Measurement devices
@@ -40,6 +41,19 @@
 #define USBTMC488_REQUEST_GOTO_LOCAL   161
 #define USBTMC488_REQUEST_LOCAL_LOCKOUT162
 
+struct usbtmc_request {
+   __u8 bRequestType;
+   __u8 bRequest;
+   __u

[PATCH v6 00/22] usb: usbtmc: Changes needed for compatible IVI/VISA library

2018-09-12 Thread Guido Kiener
The working group "VISA for Linux" of the IVI Foundation
www.ivifoundation.org specifies common rules, shared libraries and
drivers to implement the specification of "VPP-4.3: The VISA Library"
on Linux to be compatible with implementations on other operating systems.

The USBTMC protocol is part of the "VISA Library" that is used by many
popular T applications.

Initial implementations for Linux based on libusb has been created.
However using one common USBTMC driver results in more benefits:

- Multiple applications can share access to the same instruments.
- The driver handles SRQ conflicts.
- Simplifies definition of udev rules for USBTMC devices.
- Simplifies development of applications using T instruments.

The following collaborative patches meet the requirements of the IVI
Foundation to implement the library based on the usbtmc driver.

Improvements in the data transfer rate of over 130 MByte/s for
usb 3.x connections have been measured.

V6: Using void __user* pointer again and drop 32 bit compatibility
for the following 3 iotcls: USBTMC_IOCTL_CTRL_REQUEST
USBTMC_IOCTL_WRITE, USBTMC_IOCTL_READ to simplify kernel
driver and user applications.
Note that supporting 32 bit applications running on 64 bit
target systems are not in the focus of the IVI Foundation.
However all other convenient ioctls of the USBTMC driver can
still be used in 32 bit applications as well. Note that 32
bit applications running on 32 bit target systems are not
affected by this limitation.

V5: Added this version history. No change to patches.

V4: Removed redundant #ifdef CONFIG_COMPAT.

V3: Replaced data pointer of type void* in structs 
usbtmc_ctrlrequest and usbtmc_message with data pointer of
type __u64 to avoid double implementation of ioctls with
different structure sizes for 32 and 64 bit applications.

Following patch is added to usb-next branch:
usb: usbtmc: Add support for 32 bit compat applications

V2: Split patch series into smaller patches.
Add compatible ioctls and structs to support 32 bit applications.
Incorporates feedback from reviewers.

Following patches are added to usb-next branch:
usb: usbtmc: Add ioctl for termination character
usb: usbtmc: Add ioctl for EOM bit
usb: usbtmc: Add ioctl for trigger
usb: usbtmc: Add ioctls to set/get usb timeout
usb: usbtmc: use consistent timeout error
usb: usbtmc: Support Read Status Byte with SRQ per file

V1: usb: usbtmc: Remove rigol_quirk (accepted)
https://patchwork.kernel.org/patch/10407097/

Guido Kiener, Dave Penkler, Steve Bayless (22):
  usb: usbtmc: Add ioctl for generic requests on control
  usb: usbtmc: Add ioctl for vendor specific write
  usb: usbtmc: Add ioctl USBTMC_IOCTL_WRITE_RESULT
  usb: usbtmc: Add ioctl for vendor specific read
  usb: usbtmc: Add ioctl USBTMC_IOCTL_CANCEL_IO
  usb: usbtmc: Add ioctl USBTMC_IOCTL_CLEANUP_IO
  usb: usbtmc: Fix suspend/resume
  usb: usbtmc: Add ioctl USBTMC488_IOCTL_WAIT_SRQ
  usb: usbtmc: add ioctl USBTMC_IOCTL_MSG_IN_ATTR
  usb: usbtmc: Add ioctl USBTMC_IOCTL_AUTO_ABORT
  usb: usbtmc: Optimize usbtmc_write
  usb: usbtmc: Optimize usbtmc_read
  usb: usbtmc: Fix ioctl USBTMC_IOCTL_CLEAR
  usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_IN
  usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_OUT
  usb: usbtmc: Replace USBTMC_TIMEOUT macros for control messages
  usb: usbtmc: Add ioctl USBTMC_IOCTL_API_VERSION
  usb: usbtmc: Update ioctl-number.txt
  usb: usbtmc: Remove redundant code
  usb: usbtmc: Remove redundant macro USBTMC_SIZE_IOBUFFER
  usb: usbtmc: Fix split quoted string in debug message
  usb: usbtmc: Remove sysfs group TermChar and auto_abort

 .../ABI/stable/sysfs-driver-usb-usbtmc|   35 -
 Documentation/ioctl/ioctl-number.txt  |2 +-
 drivers/usb/class/usbtmc.c| 1644 +
 include/uapi/linux/usb/tmc.h  |   41 +
 4 files changed, 1283 insertions(+), 439 deletions(-)

-- 
2.17.1



[PATCH v6 03/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_WRITE_RESULT

2018-09-12 Thread Guido Kiener
ioctl USBTMC_IOCTL_WRITE_RESULT copies current out_transfer_size
to given __u32 pointer and returns current out_status of the last
(asnynchronous) USBTMC_IOCTL_WRITE call.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 25 +
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 26 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 915c3fefc4e3..eec382ab1a44 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -893,6 +893,26 @@ static ssize_t usbtmc_ioctl_generic_write(struct 
usbtmc_file_data *file_data,
return retval;
 }
 
+/*
+ * Get the generic write result
+ */
+static ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data,
+   void __user *arg)
+{
+   u32 transferred;
+   int retval;
+
+   spin_lock_irq(_data->err_lock);
+   transferred = file_data->out_transfer_size;
+   retval = file_data->out_status;
+   spin_unlock_irq(_data->err_lock);
+
+   if (put_user(transferred, (__u32 __user *)arg))
+   return -EFAULT;
+
+   return retval;
+}
+
 /*
  * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint.
  * @transfer_size: number of bytes to request from the device.
@@ -1748,6 +1768,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
(void __user *)arg);
break;
 
+   case USBTMC_IOCTL_WRITE_RESULT:
+   retval = usbtmc_ioctl_write_result(file_data,
+  (void __user *)arg);
+   break;
+
case USBTMC488_IOCTL_GET_CAPS:
retval = copy_to_user((void __user *)arg,
>usb488_caps,
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 44dc88f3479d..0166ba5452d5 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -86,6 +86,7 @@ struct usbtmc_message {
 #define USBTMC_IOCTL_EOM_ENABLE_IOW(USBTMC_IOC_NR, 11, __u8)
 #define USBTMC_IOCTL_CONFIG_TERMCHAR   _IOW(USBTMC_IOC_NR, 12, struct 
usbtmc_termchar)
 #define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct 
usbtmc_message)
+#define USBTMC_IOCTL_WRITE_RESULT  _IOWR(USBTMC_IOC_NR, 15, __u32)
 
 #define USBTMC488_IOCTL_GET_CAPS   _IOR(USBTMC_IOC_NR, 17, unsigned char)
 #define USBTMC488_IOCTL_READ_STB   _IOR(USBTMC_IOC_NR, 18, unsigned char)
-- 
2.17.1



[PATCH v6 02/22] usb: usbtmc: Add ioctl for vendor specific write

2018-09-12 Thread Guido Kiener
The new ioctl USBTMC_IOCTL_WRITE sends a generic message to bulk OUT.
This ioctl is used for vendor specific or asynchronous I/O as well.

The message is split into chunks of 4k (page size).
Message size is aligned to 32 bit boundaries.

With flag USBTMC_FLAG_ASYNC the ioctl is non blocking.
With flag USBTMC_FLAG_APPEND additional urbs are queued and
out_status/out_transfer_size is not reset. EPOLLOUT | EPOLLWRNORM
is signaled when all submitted urbs are completed.

Flush flying urbs when file handle is closed or device is
suspended or reset.

This ioctl does not support compatibility for 32 bit
applications running on 64 bit systems. However all other
convenient ioctls of the USBTMC driver can still be used in 32
bit applications as well. Note that 32 bit applications running
on 32 bit target systems are not affected by this limitation.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 376 ++-
 include/uapi/linux/usb/tmc.h |  14 ++
 2 files changed, 388 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 7e69bd05c631..915c3fefc4e3 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -37,6 +37,8 @@
 /* Default USB timeout (in milliseconds) */
 #define USBTMC_TIMEOUT 5000
 
+/* Max number of urbs used in write transfers */
+#define MAX_URBS_IN_FLIGHT 16
 /* I/O buffer size used in generic read/write functions */
 #define USBTMC_BUFSIZE (4096)
 
@@ -125,13 +127,24 @@ struct usbtmc_file_data {
u32timeout;
u8 srq_byte;
atomic_t   srq_asserted;
+
u8 eom_val;
u8 term_char;
bool   term_char_enabled;
+
+   spinlock_t err_lock; /* lock for errors */
+
+   struct usb_anchor submitted;
+
+   /* data for generic_write */
+   struct semaphore limit_write_sem;
+   u32 out_transfer_size;
+   int out_status;
 };
 
 /* Forward declarations */
 static struct usb_driver usbtmc_driver;
+static void usbtmc_draw_down(struct usbtmc_file_data *file_data);
 
 static void usbtmc_delete(struct kref *kref)
 {
@@ -157,6 +170,10 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
if (!file_data)
return -ENOMEM;
 
+   spin_lock_init(_data->err_lock);
+   sema_init(_data->limit_write_sem, MAX_URBS_IN_FLIGHT);
+   init_usb_anchor(_data->submitted);
+
data = usb_get_intfdata(intf);
/* Protect reference to data from file structure until release */
kref_get(>kref);
@@ -182,6 +199,36 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
return 0;
 }
 
+/*
+ * usbtmc_flush - called before file handle is closed
+ */
+static int usbtmc_flush(struct file *file, fl_owner_t id)
+{
+   struct usbtmc_file_data *file_data;
+   struct usbtmc_device_data *data;
+
+   file_data = file->private_data;
+   if (file_data == NULL)
+   return -ENODEV;
+
+   data = file_data->data;
+
+   /* wait for io to stop */
+   mutex_lock(>io_mutex);
+
+   usbtmc_draw_down(file_data);
+
+   spin_lock_irq(_data->err_lock);
+   file_data->out_status = 0;
+   file_data->out_transfer_size = 0;
+   spin_unlock_irq(_data->err_lock);
+
+   wake_up_interruptible_all(>waitq);
+   mutex_unlock(>io_mutex);
+
+   return 0;
+}
+
 static int usbtmc_release(struct inode *inode, struct file *file)
 {
struct usbtmc_file_data *file_data = file->private_data;
@@ -614,6 +661,238 @@ static int usbtmc488_ioctl_trigger(struct 
usbtmc_file_data *file_data)
return 0;
 }
 
+static struct urb *usbtmc_create_urb(void)
+{
+   const size_t bufsize = USBTMC_BUFSIZE;
+   u8 *dmabuf = NULL;
+   struct urb *urb = usb_alloc_urb(0, GFP_KERNEL);
+
+   if (!urb)
+   return NULL;
+
+   dmabuf = kmalloc(bufsize, GFP_KERNEL);
+   if (!dmabuf) {
+   usb_free_urb(urb);
+   return NULL;
+   }
+
+   urb->transfer_buffer = dmabuf;
+   urb->transfer_buffer_length = bufsize;
+   urb->transfer_flags |= URB_FREE_BUFFER;
+   return urb;
+}
+
+static void usbtmc_write_bulk_cb(struct urb *urb)
+{
+   struct usbtmc_file_data *file_data = urb->context;
+   int wakeup = 0;
+   unsigned long flags;
+
+   spin_lock_irqsave(_data->err_lock, flags);
+   file_data->out_transfer_size += urb->actual_length;
+
+   /* sync/async unlink faults aren't errors */
+   if (urb->status) {
+   if (!(urb->status == -ENOENT ||
+   urb->status == -ECONNRESET ||
+   urb->status == -ESHUTDOWN))
+   dev_err(_data->data->intf->dev,
+   "%s - nonzero

[PATCH v6 20/22] usb: usbtmc: Remove redundant macro USBTMC_SIZE_IOBUFFER

2018-09-12 Thread Guido Kiener
Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 6 --
 1 file changed, 6 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 5b6cdb1237ab..ad3932ca4d8d 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -30,12 +30,6 @@
 #define USBTMC_HEADER_SIZE 12
 #define USBTMC_MINOR_BASE  176
 
-/*
- * Size of driver internal IO buffer. Must be multiple of 4 and at least as
- * large as wMaxPacketSize (which is usually 512 bytes).
- */
-#define USBTMC_SIZE_IOBUFFER   2048
-
 /* Minimum USB timeout (in milliseconds) */
 #define USBTMC_MIN_TIMEOUT 100
 /* Default USB timeout (in milliseconds) */
-- 
2.17.1



[PATCH v6 04/22] usb: usbtmc: Add ioctl for vendor specific read

2018-09-12 Thread Guido Kiener
The USBTMC_IOCTL_READ call provides for generic synchronous and
asynchronous reads on bulk IN to implement vendor specific library
routines.

Depending on transfer_size the function submits one or more urbs (up
to 16) each with a size of up to 4kB.

The flag USBTMC_FLAG_IGNORE_TRAILER can be used when the transmission
size is already known. Then the function does not truncate the
transfer_size to a multiple of 4 kB, but does reserve extra space
to receive the final short or zero length packet. Note that the
instrument is allowed to send up to wMaxPacketSize - 1 bytes at the
end of a message to avoid sending a zero length packet.

With flag USBTMC_FLAG_ASYNC the ioctl is non blocking. When no
received data is available, the read function submits as many urbs as
needed to receive transfer_size bytes. However the number of flying
urbs (=4kB) is limited to 16 even with subsequent calls of this ioctl.

Returns -EAGAIN when non blocking and no data is received.
Signals EPOLLIN | EPOLLRDNORM when asynchronous urbs are ready to
be read.

In non blocking mode the usbtmc_message.message pointer may be NULL
and the ioctl just submits urbs to initiate receiving data. However if
data is already available due to a previous non blocking call the ioctl
will return -EINVAL when the message pointer is NULL.

This ioctl does not support compatibility for 32 bit
applications running on 64 bit systems. However all other
convenient ioctls of the USBTMC driver can still be used in 32
bit applications as well. Note that 32 bit applications running
on 32 bit target systems are not affected by this limitation.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 336 ++-
 include/uapi/linux/usb/tmc.h |   2 +
 2 files changed, 337 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index eec382ab1a44..45ccdd087d6f 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -85,6 +85,9 @@ struct usbtmc_device_data {
u8 bTag_last_write; /* needed for abort */
u8 bTag_last_read;  /* needed for abort */
 
+   /* packet size of IN bulk */
+   u16wMaxPacketSize;
+
/* data for interrupt in endpoint handling */
u8 bNotify1;
u8 bNotify2;
@@ -140,6 +143,13 @@ struct usbtmc_file_data {
struct semaphore limit_write_sem;
u32 out_transfer_size;
int out_status;
+
+   /* data for generic_read */
+   u32 in_transfer_size;
+   int in_status;
+   int in_urbs_used;
+   struct usb_anchor in_anchor;
+   wait_queue_head_t wait_bulk_in;
 };
 
 /* Forward declarations */
@@ -173,6 +183,8 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
spin_lock_init(_data->err_lock);
sema_init(_data->limit_write_sem, MAX_URBS_IN_FLIGHT);
init_usb_anchor(_data->submitted);
+   init_usb_anchor(_data->in_anchor);
+   init_waitqueue_head(_data->wait_bulk_in);
 
data = usb_get_intfdata(intf);
/* Protect reference to data from file structure until release */
@@ -219,6 +231,9 @@ static int usbtmc_flush(struct file *file, fl_owner_t id)
usbtmc_draw_down(file_data);
 
spin_lock_irq(_data->err_lock);
+   file_data->in_status = 0;
+   file_data->in_transfer_size = 0;
+   file_data->in_urbs_used = 0;
file_data->out_status = 0;
file_data->out_transfer_size = 0;
spin_unlock_irq(_data->err_lock);
@@ -682,6 +697,307 @@ static struct urb *usbtmc_create_urb(void)
return urb;
 }
 
+static void usbtmc_read_bulk_cb(struct urb *urb)
+{
+   struct usbtmc_file_data *file_data = urb->context;
+   int status = urb->status;
+   unsigned long flags;
+
+   /* sync/async unlink faults aren't errors */
+   if (status) {
+   if (!(/* status == -ENOENT || */
+   status == -ECONNRESET ||
+   status == -EREMOTEIO || /* Short packet */
+   status == -ESHUTDOWN))
+   dev_err(_data->data->intf->dev,
+   "%s - nonzero read bulk status received: %d\n",
+   __func__, status);
+
+   spin_lock_irqsave(_data->err_lock, flags);
+   if (!file_data->in_status)
+   file_data->in_status = status;
+   spin_unlock_irqrestore(_data->err_lock, flags);
+   }
+
+   spin_lock_irqsave(_data->err_lock, flags);
+   file_data->in_transfer_size += urb->actual_length;
+   dev_dbg(_data->data->intf->dev,
+   "%s - total size: %u current: %d status: %d\n",
+   __func__, file_data->in_transfer_size,
+   urb->actual_length, status);
+   spin_unlock_irqrestore(_data->err_lo

[PATCH v5 18/22] usb: usbtmc: Update ioctl-number.txt

2018-08-03 Thread Guido Kiener
Reserve a suitable range of ioctl numbers for USBTMC driver.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 Documentation/ioctl/ioctl-number.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/ioctl/ioctl-number.txt 
b/Documentation/ioctl/ioctl-number.txt
index 480c8609dc58..810dd6c30296 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -200,7 +200,7 @@ Code  Seq#(hex) Include FileComments
 'X'01  linux/pktcdvd.h conflict!
 'Y'all linux/cyclades.h
 'Z'14-15   drivers/message/fusion/mptctl.h
-'['00-07   linux/usb/tmc.h USB Test and Measurement Devices
+'['00-3F   linux/usb/tmc.h USB Test and Measurement Devices
<mailto:gre...@linuxfoundation.org>
 'a'all linux/atm*.h, linux/sonet.h ATM on linux
<http://lrcwww.epfl.ch/>
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 21/22] usb: usbtmc: Fix split quoted string in debug message

2018-08-03 Thread Guido Kiener
Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 785eee3a6b89..6aef3447adcc 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -2507,8 +2507,8 @@ static int usbtmc_probe(struct usb_interface *intf,
 
retcode = usb_register_dev(intf, _class);
if (retcode) {
-   dev_err(>dev, "Not able to get a minor"
-   " (base %u, slice default): %d\n", USBTMC_MINOR_BASE,
+   dev_err(>dev, "Not able to get a minor (base %u, slice 
default): %d\n",
+   USBTMC_MINOR_BASE,
retcode);
goto error_register;
}
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 22/22] usb: usbtmc: Remove sysfs group TermChar and auto_abort

2018-08-03 Thread Guido Kiener
As all the properties of the usbtmc driver can now be
controlled on a per file descriptor basis by ioctl functions
the sysfs interface is of limited use.
We are not aware about applications that are using the sysfs
parameter TermChar, TermCharEnabled or auto_abort.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 .../ABI/stable/sysfs-driver-usb-usbtmc| 35 
 drivers/usb/class/usbtmc.c| 84 +--
 2 files changed, 3 insertions(+), 116 deletions(-)

diff --git a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc 
b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
index e960cd027e1e..a9e123ba32cd 100644
--- a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
+++ b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
@@ -25,38 +25,3 @@ Description:
4.2.2.
 
The files are read only.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/TermChar
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file is the TermChar value to be sent to the USB TMC
-   device as described by the document, "Universal Serial Bus Test
-   and Measurement Class Specification
-   (USBTMC) Revision 1.0" as published by the USB-IF.
-
-   Note that the TermCharEnabled file determines if this value is
-   sent to the device or not.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/TermCharEnabled
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file determines if the TermChar is to be sent to the
-   device on every transaction or not.  For more details about
-   this, please see the document, "Universal Serial Bus Test and
-   Measurement Class Specification (USBTMC) Revision 1.0" as
-   published by the USB-IF.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/auto_abort
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file determines if the transaction of the USB TMC
-   device is to be automatically aborted if there is any error.
-   For more details about this, please see the document,
-   "Universal Serial Bus Test and Measurement Class Specification
-   (USBTMC) Revision 1.0" as published by the USB-IF.
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 6aef3447adcc..f8391d41b13d 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -102,11 +102,6 @@ struct usbtmc_device_data {
/* coalesced usb488_caps from usbtmc_dev_capabilities */
__u8 usb488_caps;
 
-   /* attributes from the USB TMC spec for this device */
-   u8 TermChar;
-   bool TermCharEnabled;
-   bool auto_abort;
-
bool zombie; /* fd of disconnected device */
 
struct usbtmc_dev_capabilities  capabilities;
@@ -204,11 +199,10 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
 
atomic_set(_data->closing, 0);
 
-   /* copy default values from device settings */
file_data->timeout = USBTMC_TIMEOUT;
-   file_data->term_char = data->TermChar;
-   file_data->term_char_enabled = data->TermCharEnabled;
-   file_data->auto_abort = data->auto_abort;
+   file_data->term_char = '\n';
+   file_data->term_char_enabled = 0;
+   file_data->auto_abort = 0;
file_data->eom_val = 1;
 
INIT_LIST_HEAD(_data->file_elem);
@@ -1859,72 +1853,6 @@ static const struct attribute_group capability_attr_grp 
= {
.attrs = capability_attrs,
 };
 
-static ssize_t TermChar_show(struct device *dev,
-struct device_attribute *attr, char *buf)
-{
-   struct usb_interface *intf = to_usb_interface(dev);
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);
-
-   return sprintf(buf, "%c\n", data->TermChar);
-}
-
-static ssize_t TermChar_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
-   struct usb_interface *intf = to_usb_interface(dev);
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);
-
-   if (count < 1)
-   return -EINVAL;
-   data->TermChar = buf[0];
-   return count;
-}
-static DEVICE_ATTR_RW(TermChar);
-
-#define data_attribute(name)   \
-static ssize_t name##_show(struct device *dev, \
-  struct device_attribute *attr, char *buf)\
-{  \
-   struct usb_interface *intf = to_usb_interface(dev); \
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);   \
-   

[PATCH v5 20/22] usb: usbtmc: Remove redundant macro USBTMC_SIZE_IOBUFFER

2018-08-03 Thread Guido Kiener
Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 6 --
 1 file changed, 6 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 81144c0c4772..785eee3a6b89 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -30,12 +30,6 @@
 #define USBTMC_HEADER_SIZE 12
 #define USBTMC_MINOR_BASE  176
 
-/*
- * Size of driver internal IO buffer. Must be multiple of 4 and at least as
- * large as wMaxPacketSize (which is usually 512 bytes).
- */
-#define USBTMC_SIZE_IOBUFFER   2048
-
 /* Minimum USB timeout (in milliseconds) */
 #define USBTMC_MIN_TIMEOUT 100
 /* Default USB timeout (in milliseconds) */
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 19/22] usb: usbtmc: Remove redundant code

2018-08-03 Thread Guido Kiener
Remove redundant code and fix debug messages.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 25 -
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index fb49a737ea61..81144c0c4772 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1753,12 +1753,9 @@ static int usbtmc_ioctl_clear_out_halt(struct 
usbtmc_device_data *data)
rv = usb_clear_halt(data->usb_dev,
usb_sndbulkpipe(data->usb_dev, data->bulk_out));
 
-   if (rv < 0) {
-   dev_err(>usb_dev->dev, "usb_control_msg returned %d\n",
-   rv);
-   return rv;
-   }
-   return 0;
+   if (rv < 0)
+   dev_err(>usb_dev->dev, "%s returned %d\n", __func__, rv);
+   return rv;
 }
 
 static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
@@ -1768,12 +1765,9 @@ static int usbtmc_ioctl_clear_in_halt(struct 
usbtmc_device_data *data)
rv = usb_clear_halt(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
 
-   if (rv < 0) {
-   dev_err(>usb_dev->dev, "usb_control_msg returned %d\n",
-   rv);
-   return rv;
-   }
-   return 0;
+   if (rv < 0)
+   dev_err(>usb_dev->dev, "%s returned %d\n", __func__, rv);
+   return rv;
 }
 
 static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data)
@@ -2197,11 +2191,8 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
break;
 
case USBTMC488_IOCTL_GET_CAPS:
-   retval = copy_to_user((void __user *)arg,
-   >usb488_caps,
-   sizeof(data->usb488_caps));
-   if (retval)
-   retval = -EFAULT;
+   retval = put_user(data->usb488_caps,
+ (unsigned char __user *)arg);
break;
 
case USBTMC488_IOCTL_READ_STB:
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 16/22] usb: usbtmc: Replace USBTMC_TIMEOUT macros for control messages

2018-08-03 Thread Guido Kiener
Use common timeout macro USB_CTRL_GET_TIMEOUT (=5s) for all
usb_control_msg() function calls.

The macro USBTMC_TIMEOUT should only be used as default value for
Bulk IN/OUT transfers.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 4609dc0db8a8..91fb2fbf1aeb 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -529,7 +529,7 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data 
*file_data,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
data->iin_bTag,
data->ifnum,
-   buffer, 0x03, USBTMC_TIMEOUT);
+   buffer, 0x03, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "stb usb_control_msg returned %d\n", rv);
goto exit;
@@ -663,7 +663,7 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data 
*data,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
wValue,
data->ifnum,
-   buffer, 0x01, USBTMC_TIMEOUT);
+   buffer, 0x01, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "simple usb_control_msg failed %d\n", rv);
goto exit;
@@ -1810,7 +1810,7 @@ static int get_capabilities(struct usbtmc_device_data 
*data)
rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_GET_CAPABILITIES,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 0x18, USBTMC_TIMEOUT);
+0, 0, buffer, 0x18, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto err_out;
@@ -1949,7 +1949,7 @@ static int usbtmc_ioctl_indicator_pulse(struct 
usbtmc_device_data *data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INDICATOR_PULSE,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 0x01, USBTMC_TIMEOUT);
+0, 0, buffer, 0x01, USB_CTRL_GET_TIMEOUT);
 
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 00/22] usb: usbtmc: Changes needed for compatible IVI/VISA library

2018-08-03 Thread Guido Kiener
The working group "VISA for Linux" of the IVI Foundation
www.ivifoundation.org specifies common rules, shared libraries and
drivers to implement the specification of "VPP-4.3: The VISA Library"
on Linux to be compatible with implementations on other operating systems.

The USBTMC protocol is part of the "VISA Library" that is used by many
popular T applications.

Initial implementations for Linux based on libusb has been created.
However using one common USBTMC driver results in more benefits:

- Multiple applications can share access to the same instruments.
- The driver handles SRQ conflicts.
- Simplifies definition of udev rules for USBTMC devices.
- Simplifies development of applications using T instruments.

The following collaborative patches meet the requirements of the IVI
Foundation to implement the library based on the usbtmc driver.

Improvements in the data transfer rate of over 130 MByte/s for
usb 3.x connections have been measured.


V5: Added this version history. No change to patches.

V4: Removed redundant #ifdef CONFIG_COMPAT.

V3: Replaced data pointer of type void* in structs 
usbtmc_ctrlrequest and usbtmc_message with data pointer of
type __u64 to avoid double implementation of ioctls with
different structure sizes for 32 and 64 bit applications.

Following patch is added to usb-next branch:
usb: usbtmc: Add support for 32 bit compat applications

V2: Split patch series into smaller patches.
Add compatible ioctls and structs to support 32 bit applications.
Incorporates feedback from reviewers.

Following patches are added to usb-next branch:
usb: usbtmc: Add ioctl for termination character
usb: usbtmc: Add ioctl for EOM bit
usb: usbtmc: Add ioctl for trigger
usb: usbtmc: Add ioctls to set/get usb timeout
usb: usbtmc: use consistent timeout error
usb: usbtmc: Support Read Status Byte with SRQ per file

V1: usb: usbtmc: Remove rigol_quirk (accepted)
https://patchwork.kernel.org/patch/10407097/

Guido Kiener, Dave Penkler, Steve Bayless (22):
  usb: usbtmc: Add ioctl for generic requests on control
  usb: usbtmc: Add ioctl for vendor specific write
  usb: usbtmc: Add ioctl USBTMC_IOCTL_WRITE_RESULT
  usb: usbtmc: Add ioctl for vendor specific read
  usb: usbtmc: Add ioctl USBTMC_IOCTL_CANCEL_IO
  usb: usbtmc: Add ioctl USBTMC_IOCTL_CLEANUP_IO
  usb: usbtmc: Fix suspend/resume
  usb: usbtmc: Add ioctl USBTMC488_IOCTL_WAIT_SRQ
  usb: usbtmc: add ioctl USBTMC_IOCTL_MSG_IN_ATTR
  usb: usbtmc: Add ioctl USBTMC_IOCTL_AUTO_ABORT
  usb: usbtmc: Optimize usbtmc_write
  usb: usbtmc: Optimize usbtmc_read
  usb: usbtmc: Fix ioctl USBTMC_IOCTL_CLEAR
  usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_IN
  usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_OUT
  usb: usbtmc: Replace USBTMC_TIMEOUT macros for control messages
  usb: usbtmc: Add ioctl USBTMC_IOCTL_API_VERSION
  usb: usbtmc: Update ioctl-number.txt
  usb: usbtmc: Remove redundant code
  usb: usbtmc: Remove redundant macro USBTMC_SIZE_IOBUFFER
  usb: usbtmc: Fix split quoted string in debug message
  usb: usbtmc: Remove sysfs group TermChar and auto_abort


 .../ABI/stable/sysfs-driver-usb-usbtmc|   35 -
 Documentation/ioctl/ioctl-number.txt  |2 +-
 drivers/usb/class/usbtmc.c| 1652 +
 include/uapi/linux/usb/tmc.h  |   41 +
 4 files changed, 1291 insertions(+), 439 deletions(-)

-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 08/22] usb: usbtmc: Add ioctl USBTMC488_IOCTL_WAIT_SRQ

2018-08-03 Thread Guido Kiener
Wait until an SRQ (service request) is received on the interrupt pipe
or until the given period of time is expired. In contrast to the
poll() function this ioctl does not return when other (a)synchronous
I/O operations fail with EPOLLERR.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 57 
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 58 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 9953b62b7db4..15421aa71eef 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -130,6 +130,7 @@ struct usbtmc_file_data {
u32timeout;
u8 srq_byte;
atomic_t   srq_asserted;
+   atomic_t   closing;
 
u8 eom_val;
u8 term_char;
@@ -201,6 +202,8 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
mutex_lock(>io_mutex);
file_data->data = data;
 
+   atomic_set(_data->closing, 0);
+
/* copy default values from device settings */
file_data->timeout = USBTMC_TIMEOUT;
file_data->term_char = data->TermChar;
@@ -231,6 +234,7 @@ static int usbtmc_flush(struct file *file, fl_owner_t id)
if (file_data == NULL)
return -ENODEV;
 
+   atomic_set(_data->closing, 1);
data = file_data->data;
 
/* wait for io to stop */
@@ -584,6 +588,54 @@ static int usbtmc488_ioctl_read_stb(struct 
usbtmc_file_data *file_data,
return rv;
 }
 
+static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data,
+   __u32 __user *arg)
+{
+   struct usbtmc_device_data *data = file_data->data;
+   struct device *dev = >intf->dev;
+   int rv;
+   u32 timeout;
+   unsigned long expire;
+
+   if (!data->iin_ep_present) {
+   dev_dbg(dev, "no interrupt endpoint present\n");
+   return -EFAULT;
+   }
+
+   if (get_user(timeout, arg))
+   return -EFAULT;
+
+   expire = msecs_to_jiffies(timeout);
+
+   mutex_unlock(>io_mutex);
+
+   rv = wait_event_interruptible_timeout(
+   data->waitq,
+   atomic_read(_data->srq_asserted) != 0 ||
+   atomic_read(_data->closing),
+   expire);
+
+   mutex_lock(>io_mutex);
+
+   /* Note! disconnect or close could be called in the meantime */
+   if (atomic_read(_data->closing) || data->zombie)
+   rv = -ENODEV;
+
+   if (rv < 0) {
+   /* dev can be invalid now! */
+   pr_debug("%s - wait interrupted %d\n", __func__, rv);
+   return rv;
+   }
+
+   if (rv == 0) {
+   dev_dbg(dev, "%s - wait timed out\n", __func__);
+   return -ETIMEDOUT;
+   }
+
+   dev_dbg(dev, "%s - srq asserted\n", __func__);
+   return 0;
+}
+
 static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
void __user *arg, unsigned int cmd)
 {
@@ -2150,6 +2202,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
retval = usbtmc488_ioctl_trigger(file_data);
break;
 
+   case USBTMC488_IOCTL_WAIT_SRQ:
+   retval = usbtmc488_ioctl_wait_srq(file_data,
+ (__u32 __user *)arg);
+   break;
+
case USBTMC_IOCTL_CANCEL_IO:
retval = usbtmc_ioctl_cancel_io(file_data);
break;
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index d638c198c7a8..56c76a9680e5 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -96,6 +96,7 @@ struct usbtmc_message {
 #define USBTMC488_IOCTL_GOTO_LOCAL _IO(USBTMC_IOC_NR, 20)
 #define USBTMC488_IOCTL_LOCAL_LOCKOUT  _IO(USBTMC_IOC_NR, 21)
 #define USBTMC488_IOCTL_TRIGGER_IO(USBTMC_IOC_NR, 22)
+#define USBTMC488_IOCTL_WAIT_SRQ   _IOW(USBTMC_IOC_NR, 23, __u32)
 
 /* Cancel and cleanup asynchronous calls */
 #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 04/22] usb: usbtmc: Add ioctl for vendor specific read

2018-08-03 Thread Guido Kiener
The USBTMC_IOCTL_READ call provides for generic synchronous and
asynchronous reads on bulk IN to implement vendor specific library
routines.

Depending on transfer_size the function submits one or more urbs (up
to 16) each with a size of up to 4kB.

The flag USBTMC_FLAG_IGNORE_TRAILER can be used when the transmission
size is already known. Then the function does not truncate the
transfer_size to a multiple of 4 kB, but does reserve extra space
to receive the final short or zero length packet. Note that the
instrument is allowed to send up to wMaxPacketSize - 1 bytes at the
end of a message to avoid sending a zero length packet.

With flag USBTMC_FLAG_ASYNC the ioctl is non blocking. When no
received data is available, the read function submits as many urbs as
needed to receive transfer_size bytes. However the number of flying
urbs (=4kB) is limited to 16 even with subsequent calls of this ioctl.

Returns -EAGAIN when non blocking and no data is received.
Signals EPOLLIN | EPOLLRDNORM when asynchronous urbs are ready to
be read.

In non blocking mode the usbtmc_message.message pointer may be NULL
and the ioctl just submits urbs to initiate receiving data. However if
data is already available due to a previous non blocking call the ioctl
will return -EINVAL when the message pointer is NULL.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 336 ++-
 include/uapi/linux/usb/tmc.h |   2 +
 2 files changed, 337 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 32aef9e53bc5..5edb548d9122 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -85,6 +85,9 @@ struct usbtmc_device_data {
u8 bTag_last_write; /* needed for abort */
u8 bTag_last_read;  /* needed for abort */
 
+   /* packet size of IN bulk */
+   u16wMaxPacketSize;
+
/* data for interrupt in endpoint handling */
u8 bNotify1;
u8 bNotify2;
@@ -140,6 +143,13 @@ struct usbtmc_file_data {
struct semaphore limit_write_sem;
u32 out_transfer_size;
int out_status;
+
+   /* data for generic_read */
+   u32 in_transfer_size;
+   int in_status;
+   int in_urbs_used;
+   struct usb_anchor in_anchor;
+   wait_queue_head_t wait_bulk_in;
 };
 
 /* Forward declarations */
@@ -181,6 +191,8 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
spin_lock_init(_data->err_lock);
sema_init(_data->limit_write_sem, MAX_URBS_IN_FLIGHT);
init_usb_anchor(_data->submitted);
+   init_usb_anchor(_data->in_anchor);
+   init_waitqueue_head(_data->wait_bulk_in);
 
data = usb_get_intfdata(intf);
/* Protect reference to data from file structure until release */
@@ -227,6 +239,9 @@ static int usbtmc_flush(struct file *file, fl_owner_t id)
usbtmc_draw_down(file_data);
 
spin_lock_irq(_data->err_lock);
+   file_data->in_status = 0;
+   file_data->in_transfer_size = 0;
+   file_data->in_urbs_used = 0;
file_data->out_status = 0;
file_data->out_transfer_size = 0;
spin_unlock_irq(_data->err_lock);
@@ -690,6 +705,307 @@ static struct urb *usbtmc_create_urb(void)
return urb;
 }
 
+static void usbtmc_read_bulk_cb(struct urb *urb)
+{
+   struct usbtmc_file_data *file_data = urb->context;
+   int status = urb->status;
+   unsigned long flags;
+
+   /* sync/async unlink faults aren't errors */
+   if (status) {
+   if (!(/* status == -ENOENT || */
+   status == -ECONNRESET ||
+   status == -EREMOTEIO || /* Short packet */
+   status == -ESHUTDOWN))
+   dev_err(_data->data->intf->dev,
+   "%s - nonzero read bulk status received: %d\n",
+   __func__, status);
+
+   spin_lock_irqsave(_data->err_lock, flags);
+   if (!file_data->in_status)
+   file_data->in_status = status;
+   spin_unlock_irqrestore(_data->err_lock, flags);
+   }
+
+   spin_lock_irqsave(_data->err_lock, flags);
+   file_data->in_transfer_size += urb->actual_length;
+   dev_dbg(_data->data->intf->dev,
+   "%s - total size: %u current: %d status: %d\n",
+   __func__, file_data->in_transfer_size,
+   urb->actual_length, status);
+   spin_unlock_irqrestore(_data->err_lock, flags);
+   usb_anchor_urb(urb, _data->in_anchor);
+
+   wake_up_interruptible(_data->wait_bulk_in);
+   wake_up_interruptible(_data->data->waitq);
+}
+
+static inline bool usbtmc_do_transfer(struct usbtmc_file_data *file_data)
+{
+   bool data_or_error;
+
+   spin_l

[PATCH v5 10/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_AUTO_ABORT

2018-08-03 Thread Guido Kiener
Add ioctl USBTMC_IOCTL_AUTO_ABORT to configure auto_abort for
each specific file handle.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 23 ---
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 1e7a1dcfcec7..42989c7902a8 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -136,6 +136,7 @@ struct usbtmc_file_data {
u8 eom_val;
u8 term_char;
bool   term_char_enabled;
+   bool   auto_abort;
 
spinlock_t err_lock; /* lock for errors */
 
@@ -209,6 +210,7 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
file_data->timeout = USBTMC_TIMEOUT;
file_data->term_char = data->TermChar;
file_data->term_char_enabled = data->TermCharEnabled;
+   file_data->auto_abort = data->auto_abort;
file_data->eom_val = 1;
 
INIT_LIST_HEAD(_data->file_elem);
@@ -1384,7 +1386,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
retval = send_request_dev_dep_msg_in(file_data, count);
 
if (retval < 0) {
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_out(data);
goto exit;
}
@@ -1409,7 +1411,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
 
if (retval < 0) {
dev_dbg(dev, "Unable to read data, error %d\n", retval);
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
@@ -1419,21 +1421,21 @@ static ssize_t usbtmc_read(struct file *filp, char 
__user *buf,
/* 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)
+   if (file_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)
+   if (file_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 (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
@@ -1448,7 +1450,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
 
if (n_characters > this_part) {
dev_err(dev, "Device wants to return more data 
than requested: %u > %zu\n", n_characters, count);
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
@@ -1590,7 +1592,7 @@ static ssize_t usbtmc_write(struct file *filp, const char 
__user *buf,
if (retval < 0) {
dev_err(>intf->dev,
"Unable to send data, error %d\n", retval);
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_out(data);
goto exit;
}
@@ -2099,6 +2101,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data;
int retval = -EBADRQC;
+   __u8 tmp_byte;
 
file_data = file->private_data;
data = file_data->data;
@@ -2215,6 +2218,12 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
  (__u8 __user *)arg);
break;
 
+   ca

[PATCH v5 09/22] usb: usbtmc: add ioctl USBTMC_IOCTL_MSG_IN_ATTR

2018-08-03 Thread Guido Kiener
add ioctl USBTMC_IOCTL_MSG_IN_ATTR that returns the specific
bmTransferAttributes field of the last DEV_DEP_MSG_IN Bulk-IN
header. This header is received by the read() function. The
meaning of the (u8) bitmap bmTransferAttributes is:

Bit 0 = EOM flag is set when the last transfer of a USBTMC
message is received.

Bit 1 = is set when the last byte is a termchar (e.g. '\n').
Note that this bit is always zero when the device does not support
the termchar feature or when termchar detection is not enabled
(see ioctl USBTMC_IOCTL_CONFIG_TERMCHAR).

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 8 
 include/uapi/linux/usb/tmc.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 15421aa71eef..1e7a1dcfcec7 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -131,6 +131,7 @@ struct usbtmc_file_data {
u8 srq_byte;
atomic_t   srq_asserted;
atomic_t   closing;
+   u8 bmTransferAttributes; /* member of DEV_DEP_MSG_IN */
 
u8 eom_val;
u8 term_char;
@@ -1443,6 +1444,8 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
   (buffer[6] << 16) +
   (buffer[7] << 24);
 
+   file_data->bmTransferAttributes = buffer[8];
+
if (n_characters > this_part) {
dev_err(dev, "Device wants to return more data 
than requested: %u > %zu\n", n_characters, count);
if (data->auto_abort)
@@ -2207,6 +2210,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
  (__u32 __user *)arg);
break;
 
+   case USBTMC_IOCTL_MSG_IN_ATTR:
+   retval = put_user(file_data->bmTransferAttributes,
+ (__u8 __user *)arg);
+   break;
+
case USBTMC_IOCTL_CANCEL_IO:
retval = usbtmc_ioctl_cancel_io(file_data);
break;
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 56c76a9680e5..d2ed6a20de6b 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -98,6 +98,8 @@ struct usbtmc_message {
 #define USBTMC488_IOCTL_TRIGGER_IO(USBTMC_IOC_NR, 22)
 #define USBTMC488_IOCTL_WAIT_SRQ   _IOW(USBTMC_IOC_NR, 23, __u32)
 
+#define USBTMC_IOCTL_MSG_IN_ATTR   _IOR(USBTMC_IOC_NR, 24, __u8)
+
 /* Cancel and cleanup asynchronous calls */
 #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
 #define USBTMC_IOCTL_CLEANUP_IO_IO(USBTMC_IOC_NR, 36)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 11/22] usb: usbtmc: Optimize usbtmc_write

2018-08-03 Thread Guido Kiener
Use new usbtmc_generic_write function to maximize bandwidth
during long data transfer.
The maximum output transfer size is limited to INT_MAX (=2GB).

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 176 +++--
 1 file changed, 109 insertions(+), 67 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 42989c7902a8..6d5f514b3081 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1517,94 +1517,136 @@ static ssize_t usbtmc_write(struct file *filp, const 
char __user *buf,
 {
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data;
+   struct urb *urb = NULL;
+   ssize_t retval = 0;
u8 *buffer;
-   int retval;
-   int actual;
-   unsigned long int n_bytes;
-   int remaining;
-   int done;
-   int this_part;
+   u32 remaining, done;
+   u32 transfersize, aligned, buflen;
 
file_data = filp->private_data;
data = file_data->data;
 
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
-   if (!buffer)
-   return -ENOMEM;
-
mutex_lock(>io_mutex);
+
if (data->zombie) {
retval = -ENODEV;
goto exit;
}
 
-   remaining = count;
done = 0;
 
-   while (remaining > 0) {
-   if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE) {
-   this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE;
-   buffer[8] = 0;
-   } else {
-   this_part = remaining;
-   buffer[8] = file_data->eom_val;
-   }
-
-   /* Setup IO buffer for DEV_DEP_MSG_OUT message */
-   buffer[0] = 1;
-   buffer[1] = data->bTag;
-   buffer[2] = ~data->bTag;
-   buffer[3] = 0; /* Reserved */
-   buffer[4] = this_part >> 0;
-   buffer[5] = this_part >> 8;
-   buffer[6] = this_part >> 16;
-   buffer[7] = this_part >> 24;
-   /* buffer[8] is set above... */
-   buffer[9] = 0; /* Reserved */
-   buffer[10] = 0; /* Reserved */
-   buffer[11] = 0; /* Reserved */
-
-   if (copy_from_user([USBTMC_HEADER_SIZE], buf + done, 
this_part)) {
-   retval = -EFAULT;
-   goto exit;
-   }
-
-   n_bytes = roundup(USBTMC_HEADER_SIZE + this_part, 4);
-   memset(buffer + USBTMC_HEADER_SIZE + this_part, 0, n_bytes - 
(USBTMC_HEADER_SIZE + this_part));
-
-   do {
-   retval = usb_bulk_msg(data->usb_dev,
- usb_sndbulkpipe(data->usb_dev,
- data->bulk_out),
- buffer, n_bytes,
- , file_data->timeout);
-   if (retval != 0)
-   break;
-   n_bytes -= actual;
-   } while (n_bytes);
-
-   data->bTag_last_write = data->bTag;
+   spin_lock_irq(_data->err_lock);
+   file_data->out_transfer_size = 0;
+   file_data->out_status = 0;
+   spin_unlock_irq(_data->err_lock);
+
+   if (!count)
+   goto exit;
+
+   if (down_trylock(_data->limit_write_sem)) {
+   /* previous calls were async */
+   retval = -EBUSY;
+   goto exit;
+   }
+
+   urb = usbtmc_create_urb();
+   if (!urb) {
+   retval = -ENOMEM;
+   up(_data->limit_write_sem);
+   goto exit;
+   }
+
+   buffer = urb->transfer_buffer;
+   buflen = urb->transfer_buffer_length;
+
+   if (count > INT_MAX) {
+   transfersize = INT_MAX;
+   buffer[8] = 0;
+   } else {
+   transfersize = count;
+   buffer[8] = file_data->eom_val;
+   }
+
+   /* Setup IO buffer for DEV_DEP_MSG_OUT message */
+   buffer[0] = 1;
+   buffer[1] = data->bTag;
+   buffer[2] = ~data->bTag;
+   buffer[3] = 0; /* Reserved */
+   buffer[4] = transfersize >> 0;
+   buffer[5] = transfersize >> 8;
+   buffer[6] = transfersize >> 16;
+   buffer[7] = transfersize >> 24;
+   /* buffer[8] is set above... */
+   buffer[9] = 0; /* Reserved */
+   buffer[10] = 0; /* Reserved */
+   buffer[11] = 0; /* Reserved */
+
+   remaining = transfersize;
+
+   if (transfersize + USBTMC_HEADER_SIZE > buflen) {
+   transfersize = buflen - USBTMC_HEADER_SIZE;
+   aligned = buflen;
+   } else {
+   alig

[PATCH v5 03/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_WRITE_RESULT

2018-08-03 Thread Guido Kiener
ioctl USBTMC_IOCTL_WRITE_RESULT copies current out_transfer_size
to given __u32 pointer and returns current out_status of the last
(asnynchronous) USBTMC_IOCTL_WRITE call.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 25 +
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 26 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index b30935d8af6b..32aef9e53bc5 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -901,6 +901,26 @@ static ssize_t usbtmc_ioctl_generic_write(struct 
usbtmc_file_data *file_data,
return retval;
 }
 
+/*
+ * Get the generic write result
+ */
+static ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data,
+   void __user *arg)
+{
+   u32 transferred;
+   int retval;
+
+   spin_lock_irq(_data->err_lock);
+   transferred = file_data->out_transfer_size;
+   retval = file_data->out_status;
+   spin_unlock_irq(_data->err_lock);
+
+   if (put_user(transferred, (__u32 __user *)arg))
+   return -EFAULT;
+
+   return retval;
+}
+
 /*
  * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint.
  * @transfer_size: number of bytes to request from the device.
@@ -1756,6 +1776,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
(void __user *)arg);
break;
 
+   case USBTMC_IOCTL_WRITE_RESULT:
+   retval = usbtmc_ioctl_write_result(file_data,
+  (void __user *)arg);
+   break;
+
case USBTMC488_IOCTL_GET_CAPS:
retval = copy_to_user((void __user *)arg,
>usb488_caps,
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 56faeb3b5f0f..4a47b11e4a7e 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -86,6 +86,7 @@ struct usbtmc_message {
 #define USBTMC_IOCTL_EOM_ENABLE_IOW(USBTMC_IOC_NR, 11, __u8)
 #define USBTMC_IOCTL_CONFIG_TERMCHAR   _IOW(USBTMC_IOC_NR, 12, struct 
usbtmc_termchar)
 #define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct 
usbtmc_message)
+#define USBTMC_IOCTL_WRITE_RESULT  _IOWR(USBTMC_IOC_NR, 15, __u32)
 
 #define USBTMC488_IOCTL_GET_CAPS   _IOR(USBTMC_IOC_NR, 17, unsigned char)
 #define USBTMC488_IOCTL_READ_STB   _IOR(USBTMC_IOC_NR, 18, unsigned char)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 13/22] usb: usbtmc: Fix ioctl USBTMC_IOCTL_CLEAR

2018-08-03 Thread Guido Kiener
Remove calculation of max_size (=wMaxPacketSize) and wrong
condition (actual == max_size) in while loop. A device clear
should always flush the complete Bulk-IN FIFO.

Insert a sleep of 50 ms between subsequent CHECK_CLEAR_STATUS
control requests to avoid stressing the instrument with
repeated requests.

Some instruments need time to cleanup internal I/O buffers.
Polling and nonbraked requests slow down the response time of
devices.

Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.

Check only bit 0 (field bmClear) of the CHECK_CLEAR_STATUS
response, since other bits are reserved and can change in
future versions.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 46 +++---
 1 file changed, 18 insertions(+), 28 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 11225c6d6c69..1903d98f5a18 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1640,20 +1640,17 @@ static ssize_t usbtmc_write(struct file *filp, const 
char __user *buf,
 
 static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
 {
-   struct usb_host_interface *current_setting;
-   struct usb_endpoint_descriptor *desc;
struct device *dev;
u8 *buffer;
int rv;
int n;
int actual = 0;
-   int max_size;
 
dev = >intf->dev;
 
dev_dbg(dev, "Sending INITIATE_CLEAR request\n");
 
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+   buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
 
@@ -1661,7 +1658,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INITIATE_CLEAR,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 1, USBTMC_TIMEOUT);
+0, 0, buffer, 1, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
@@ -1675,22 +1672,6 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
goto exit;
}
 
-   max_size = 0;
-   current_setting = data->intf->cur_altsetting;
-   for (n = 0; n < current_setting->desc.bNumEndpoints; n++) {
-   desc = _setting->endpoint[n].desc;
-   if (desc->bEndpointAddress == data->bulk_in)
-   max_size = usb_endpoint_maxp(desc);
-   }
-
-   if (max_size == 0) {
-   dev_err(dev, "Couldn't get wMaxPacketSize\n");
-   rv = -EPERM;
-   goto exit;
-   }
-
-   dev_dbg(dev, "wMaxPacketSize is %d\n", max_size);
-
n = 0;
 
 usbtmc_clear_check_status:
@@ -1701,7 +1682,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_CHECK_CLEAR_STATUS,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 2, USBTMC_TIMEOUT);
+0, 0, buffer, 2, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
@@ -1718,15 +1699,19 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
goto exit;
}
 
-   if (buffer[1] == 1)
+   if ((buffer[1] & 1) != 0) {
do {
dev_dbg(dev, "Reading from bulk in EP\n");
 
rv = usb_bulk_msg(data->usb_dev,
  usb_rcvbulkpipe(data->usb_dev,
  data->bulk_in),
- buffer, USBTMC_SIZE_IOBUFFER,
- , USBTMC_TIMEOUT);
+ buffer, USBTMC_BUFSIZE,
+ , USB_CTRL_GET_TIMEOUT);
+
+   print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
+16, 1, buffer, actual, true);
+
n++;
 
if (rv < 0) {
@@ -1734,10 +1719,15 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
rv);
goto exit;
}
-   } while ((actual == max_size) &&
+   } while ((actual == USBTMC_BUFSIZE) &&
  (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
+   } else {
+  

[PATCH v5 12/22] usb: usbtmc: Optimize usbtmc_read

2018-08-03 Thread Guido Kiener
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: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 222 ++---
 1 file changed, 105 insertions(+), 117 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 6d5f514b3081..11225c6d6c69 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1301,7 +1301,7 @@ static ssize_t usbtmc_ioctl_write_result(struct 
usbtmc_file_data *file_data,
  * Also updates bTag_last_write.
  */
 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;
int retval;
@@ -1344,12 +1344,11 @@ static int send_request_dev_dep_msg_in(struct 
usbtmc_file_data *file_data,
data->bTag++;
 
kfree(buffer);
-   if (retval < 0) {
-   dev_err(>intf->dev, "usb_bulk_msg in 
send_request_dev_dep_msg_in() returned %d\n", retval);
-   return retval;
-   }
+   if (retval < 0)
+   dev_err(>intf->dev, "%s returned %d\n",
+   __func__, retval);
 
-   return 0;
+   return retval;
 }
 
 static ssize_t usbtmc_read(struct file *filp, char __user *buf,
@@ -1358,20 +1357,20 @@ 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 n_characters;
u8 *buffer;
int actual;
-   size_t done;
-   size_t remaining;
+   u32 done = 0;
+   u32 remaining;
int retval;
-   size_t this_part;
 
/* Get pointer to private data structure */
file_data = filp->private_data;
data = file_data->data;
dev = >intf->dev;
 
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+   buffer = kmalloc(bufsize, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
 
@@ -1381,7 +1380,10 @@ static ssize_t usbtmc_read(struct file *filp, char 
__user *buf,
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);
 
@@ -1393,114 +1395,100 @@ static ssize_t usbtmc_read(struct file *filp, char 
__user *buf,
 
/* Loop until we have fetched everything we requested */
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, ,
- 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) */
-   data->bTag_last_read = data->bTag;
-
-   if (retval < 0) {
-   dev_dbg(dev, "Unable to read data, error %d\n", retval);
-   if (file_data->auto_abort)
-   usbtmc_ioctl_abort_bulk_in(data);
+
+   /* Send bulk URB */
+   retval = usb_bulk_msg(data->usb_dev,
+ usb_rcvbulkpipe(data->usb_dev,
+ data->bulk_in),
+ buffer, bufsize, ,
+ file_data->timeout);
+
+   dev_dbg(dev, "%s: bulk_msg retval(%u), actual(%d)\n",
+   __func__, retval, actual);
+
+   /* Store bTag (in case we need to abort) */
+   data->bTag_last_read = data->bTag;
+
+   if (retval < 0) {
+   if (file_data->auto_abort)
+   usbtmc_ioctl_abort_bulk_in(data);
+   goto exit;
+   }
+
+   /* 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)
+ 

[PATCH v5 17/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_API_VERSION

2018-08-03 Thread Guido Kiener
Add ioctl USBTMC_IOCTL_API_VERSION to get current API version
of usbtmc driver.

This is to allow an instrument library to determine whether
the driver API is compatible with the implementation.

The API may change in future versions. Therefore the macro
USBTMC_API_VERSION should be incremented when changing tmc.h
with new flags, ioctls or when changing a significant behavior
of the driver.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 9 +
 include/uapi/linux/usb/tmc.h | 1 +
 2 files changed, 10 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 91fb2fbf1aeb..fb49a737ea61 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -22,6 +22,10 @@
 #include 
 #include 
 
+/* Increment API VERSION when changing tmc.h with new flags or ioctls
+ * or when changing a significant behavior of the driver.
+ */
+#define USBTMC_API_VERSION (2)
 
 #define USBTMC_HEADER_SIZE 12
 #define USBTMC_MINOR_BASE  176
@@ -2187,6 +2191,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
   (void __user *)arg);
break;
 
+   case USBTMC_IOCTL_API_VERSION:
+   retval = put_user(USBTMC_API_VERSION,
+ (__u32 __user *)arg);
+   break;
+
case USBTMC488_IOCTL_GET_CAPS:
retval = copy_to_user((void __user *)arg,
>usb488_caps,
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 2435694d3ba5..1d3373922e5e 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -89,6 +89,7 @@ struct usbtmc_message {
 #define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct 
usbtmc_message)
 #define USBTMC_IOCTL_READ  _IOWR(USBTMC_IOC_NR, 14, struct 
usbtmc_message)
 #define USBTMC_IOCTL_WRITE_RESULT  _IOWR(USBTMC_IOC_NR, 15, __u32)
+#define USBTMC_IOCTL_API_VERSION   _IOR(USBTMC_IOC_NR, 16, __u32)
 
 #define USBTMC488_IOCTL_GET_CAPS   _IOR(USBTMC_IOC_NR, 17, unsigned char)
 #define USBTMC488_IOCTL_READ_STB   _IOR(USBTMC_IOC_NR, 18, unsigned char)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 06/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_CLEANUP_IO

2018-08-03 Thread Guido Kiener
The ioctl USBTMC_IOCTL_CLEANUP_IO kills all submitted urbs to OUT
and IN bulk, and clears all received data from IN bulk. Internal
transfer counters and error states are reset.

An application should use this ioctl after an asnychronous transfer
was canceled and/or error handling has finished.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 19 +++
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 20 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index e78176ef0e42..b8a4140bd161 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1714,6 +1714,21 @@ static int usbtmc_ioctl_cancel_io(struct 
usbtmc_file_data *file_data)
return 0;
 }
 
+static int usbtmc_ioctl_cleanup_io(struct usbtmc_file_data *file_data)
+{
+   usb_kill_anchored_urbs(_data->submitted);
+   usb_scuttle_anchored_urbs(_data->in_anchor);
+   spin_lock_irq(_data->err_lock);
+   file_data->in_status = 0;
+   file_data->in_transfer_size = 0;
+   file_data->out_status = 0;
+   file_data->out_transfer_size = 0;
+   spin_unlock_irq(_data->err_lock);
+
+   file_data->in_urbs_used = 0;
+   return 0;
+}
+
 static int get_capabilities(struct usbtmc_device_data *data)
 {
struct device *dev = >usb_dev->dev;
@@ -2138,6 +2153,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
case USBTMC_IOCTL_CANCEL_IO:
retval = usbtmc_ioctl_cancel_io(file_data);
break;
+
+   case USBTMC_IOCTL_CLEANUP_IO:
+   retval = usbtmc_ioctl_cleanup_io(file_data);
+   break;
}
 
 skip_io_on_zombie:
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 934991624a28..d638c198c7a8 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -99,6 +99,7 @@ struct usbtmc_message {
 
 /* Cancel and cleanup asynchronous calls */
 #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
+#define USBTMC_IOCTL_CLEANUP_IO_IO(USBTMC_IOC_NR, 36)
 
 /* Driver encoded usb488 capabilities */
 #define USBTMC488_CAPABILITY_TRIGGER 1
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 14/22] usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_IN

2018-08-03 Thread Guido Kiener
Add parameter 'tag' to function usbtmc_ioctl_abort_bulk_in_tag()
for future versions.

Remove calculation of max_size (=wMaxPacketSize) and wrong
condition (actual == max_size) in while loop. An abort operation
should always flush the complete Bulk-IN until a short packet is
received.

Return error code ENOMSG when transfer (specified by given tag)
is not in progress and device returns code
USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS.

Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.

Use common macro USB_CTRL_GET_TIMEOUT instead of USBTMC_TIMEOUT.

Check only bit 0 (field bmAbortBulkIn) of the
CHECK_ABORT_BULK_IN_STATUS response, since other bits are reserved
and can change in future versions.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 139 -
 1 file changed, 61 insertions(+), 78 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 1903d98f5a18..c197d8c629f2 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -278,18 +278,17 @@ static int usbtmc_release(struct inode *inode, struct 
file *file)
return 0;
 }
 
-static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
+static int usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data *data,
+ u8 tag)
 {
u8 *buffer;
struct device *dev;
int rv;
int n;
int actual;
-   struct usb_host_interface *current_setting;
-   int max_size;
 
dev = >intf->dev;
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+   buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
 
@@ -297,21 +296,34 @@ static int usbtmc_ioctl_abort_bulk_in(struct 
usbtmc_device_data *data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INITIATE_ABORT_BULK_IN,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
-data->bTag_last_read, data->bulk_in,
-buffer, 2, USBTMC_TIMEOUT);
+tag, data->bulk_in,
+buffer, 2, USB_CTRL_GET_TIMEOUT);
 
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
}
 
-   dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]);
+   dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x with tag %02x\n",
+   buffer[0], buffer[1]);
 
if (buffer[0] == USBTMC_STATUS_FAILED) {
+   /* No transfer in progress and the Bulk-OUT FIFO is empty. */
rv = 0;
goto exit;
}
 
+   if (buffer[0] == USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS) {
+   /* The device returns this status if either:
+* - There is a transfer in progress, but the specified bTag
+*   does not match.
+* - There is no transfer in progress, but the Bulk-OUT FIFO
+*   is not empty.
+*/
+   rv = -ENOMSG;
+   goto exit;
+   }
+
if (buffer[0] != USBTMC_STATUS_SUCCESS) {
dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n",
buffer[0]);
@@ -319,64 +331,52 @@ static int usbtmc_ioctl_abort_bulk_in(struct 
usbtmc_device_data *data)
goto exit;
}
 
-   max_size = 0;
-   current_setting = data->intf->cur_altsetting;
-   for (n = 0; n < current_setting->desc.bNumEndpoints; n++)
-   if (current_setting->endpoint[n].desc.bEndpointAddress ==
-   data->bulk_in)
-   max_size = 
usb_endpoint_maxp(_setting->endpoint[n].desc);
-
-   if (max_size == 0) {
-   dev_err(dev, "Couldn't get wMaxPacketSize\n");
-   rv = -EPERM;
-   goto exit;
-   }
-
-   dev_dbg(>intf->dev, "wMaxPacketSize is %d\n", max_size);
-
-   n = 0;
-
-   do {
-   dev_dbg(dev, "Reading from bulk in EP\n");
-
-   rv = usb_bulk_msg(data->usb_dev,
- usb_rcvbulkpipe(data->usb_dev,
- data->bulk_in),
- buffer, USBTMC_SIZE_IOBUFFER,
- , USBTMC_TIMEOUT);
-
-   n++;
-
-   if (rv < 0) {
-   dev_err(dev, "usb_bulk_msg returned %d\n", rv);
-   goto exit;
-   }
-   } while ((actual == max_size) &&
-(n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
-
-   if (actual =

[PATCH v5 02/22] usb: usbtmc: Add ioctl for vendor specific write

2018-08-03 Thread Guido Kiener
The new ioctl USBTMC_IOCTL_WRITE sends a generic message to bulk OUT.
This ioctl is used for vendor specific or asynchronous I/O as well.

The message is split into chunks of 4k (page size).
Message size is aligned to 32 bit boundaries.

With flag USBTMC_FLAG_ASYNC the ioctl is non blocking.
With flag USBTMC_FLAG_APPEND additional urbs are queued and
out_status/out_transfer_size is not reset. EPOLLOUT | EPOLLWRNORM
is signaled when all submitted urbs are completed.

Flush flying urbs when file handle is closed or device is
suspended or reset.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 376 ++-
 include/uapi/linux/usb/tmc.h |  14 ++
 2 files changed, 388 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index f5603c835336..b30935d8af6b 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -37,6 +37,8 @@
 /* Default USB timeout (in milliseconds) */
 #define USBTMC_TIMEOUT 5000
 
+/* Max number of urbs used in write transfers */
+#define MAX_URBS_IN_FLIGHT 16
 /* I/O buffer size used in generic read/write functions */
 #define USBTMC_BUFSIZE (4096)
 
@@ -125,13 +127,24 @@ struct usbtmc_file_data {
u32timeout;
u8 srq_byte;
atomic_t   srq_asserted;
+
u8 eom_val;
u8 term_char;
bool   term_char_enabled;
+
+   spinlock_t err_lock; /* lock for errors */
+
+   struct usb_anchor submitted;
+
+   /* data for generic_write */
+   struct semaphore limit_write_sem;
+   u32 out_transfer_size;
+   int out_status;
 };
 
 /* Forward declarations */
 static struct usb_driver usbtmc_driver;
+static void usbtmc_draw_down(struct usbtmc_file_data *file_data);
 
 static void __user *u64_to_uptr(u64 value)
 {
@@ -165,6 +178,10 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
if (!file_data)
return -ENOMEM;
 
+   spin_lock_init(_data->err_lock);
+   sema_init(_data->limit_write_sem, MAX_URBS_IN_FLIGHT);
+   init_usb_anchor(_data->submitted);
+
data = usb_get_intfdata(intf);
/* Protect reference to data from file structure until release */
kref_get(>kref);
@@ -190,6 +207,36 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
return 0;
 }
 
+/*
+ * usbtmc_flush - called before file handle is closed
+ */
+static int usbtmc_flush(struct file *file, fl_owner_t id)
+{
+   struct usbtmc_file_data *file_data;
+   struct usbtmc_device_data *data;
+
+   file_data = file->private_data;
+   if (file_data == NULL)
+   return -ENODEV;
+
+   data = file_data->data;
+
+   /* wait for io to stop */
+   mutex_lock(>io_mutex);
+
+   usbtmc_draw_down(file_data);
+
+   spin_lock_irq(_data->err_lock);
+   file_data->out_status = 0;
+   file_data->out_transfer_size = 0;
+   spin_unlock_irq(_data->err_lock);
+
+   wake_up_interruptible_all(>waitq);
+   mutex_unlock(>io_mutex);
+
+   return 0;
+}
+
 static int usbtmc_release(struct inode *inode, struct file *file)
 {
struct usbtmc_file_data *file_data = file->private_data;
@@ -622,6 +669,238 @@ static int usbtmc488_ioctl_trigger(struct 
usbtmc_file_data *file_data)
return 0;
 }
 
+static struct urb *usbtmc_create_urb(void)
+{
+   const size_t bufsize = USBTMC_BUFSIZE;
+   u8 *dmabuf = NULL;
+   struct urb *urb = usb_alloc_urb(0, GFP_KERNEL);
+
+   if (!urb)
+   return NULL;
+
+   dmabuf = kmalloc(bufsize, GFP_KERNEL);
+   if (!dmabuf) {
+   usb_free_urb(urb);
+   return NULL;
+   }
+
+   urb->transfer_buffer = dmabuf;
+   urb->transfer_buffer_length = bufsize;
+   urb->transfer_flags |= URB_FREE_BUFFER;
+   return urb;
+}
+
+static void usbtmc_write_bulk_cb(struct urb *urb)
+{
+   struct usbtmc_file_data *file_data = urb->context;
+   int wakeup = 0;
+   unsigned long flags;
+
+   spin_lock_irqsave(_data->err_lock, flags);
+   file_data->out_transfer_size += urb->actual_length;
+
+   /* sync/async unlink faults aren't errors */
+   if (urb->status) {
+   if (!(urb->status == -ENOENT ||
+   urb->status == -ECONNRESET ||
+   urb->status == -ESHUTDOWN))
+   dev_err(_data->data->intf->dev,
+   "%s - nonzero write bulk status received: %d\n",
+   __func__, urb->status);
+
+   if (!file_data->out_status) {
+   file_data->out_status = urb->status;
+   wakeup = 1;
+   }
+   }
+   spin_unlock_irqrestore(_data->

[PATCH v5 01/22] usb: usbtmc: Add ioctl for generic requests on control

2018-08-03 Thread Guido Kiener
Add USBTMC_IOCTL_CTRL_REQUEST to send arbitrary requests on the
control pipe.  Used by specific applications of IVI Foundation,
Inc. to implement VISA API functions: viUsbControlIn/Out.

The maximum length of control request is set to 4k.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 77 
 include/uapi/linux/usb/tmc.h | 15 +++
 2 files changed, 92 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 83ffa5a14c3d..f5603c835336 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 Greg Kroah-Hartman 
+ * Copyright (C) 2018 IVI Foundation, Inc.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -36,6 +37,9 @@
 /* Default USB timeout (in milliseconds) */
 #define USBTMC_TIMEOUT 5000
 
+/* I/O buffer size used in generic read/write functions */
+#define USBTMC_BUFSIZE (4096)
+
 /*
  * Maximum number of read cycles to empty bulk in endpoint during CLEAR and
  * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short
@@ -129,6 +133,14 @@ struct usbtmc_file_data {
 /* Forward declarations */
 static struct usb_driver usbtmc_driver;
 
+static void __user *u64_to_uptr(u64 value)
+{
+   if (in_compat_syscall())
+   return compat_ptr(value);
+   else
+   return (void __user *)(unsigned long)value;
+}
+
 static void usbtmc_delete(struct kref *kref)
 {
struct usbtmc_device_data *data = to_usbtmc_data(kref);
@@ -1250,6 +1262,67 @@ static int usbtmc_ioctl_indicator_pulse(struct 
usbtmc_device_data *data)
return rv;
 }
 
+static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
+   void __user *arg)
+{
+   struct device *dev = >intf->dev;
+   struct usbtmc_ctrlrequest request;
+   u8 *buffer = NULL;
+   int rv;
+   unsigned long res;
+
+   res = copy_from_user(, arg, sizeof(struct usbtmc_ctrlrequest));
+   if (res)
+   return -EFAULT;
+
+   buffer = kmalloc(request.req.wLength, GFP_KERNEL);
+   if (!buffer)
+   return -ENOMEM;
+
+   if (request.req.wLength > USBTMC_BUFSIZE)
+   return -EMSGSIZE;
+
+   if (request.req.wLength) {
+   buffer = kmalloc(request.req.wLength, GFP_KERNEL);
+   if (!buffer)
+   return -ENOMEM;
+
+   if ((request.req.bRequestType & USB_DIR_IN) == 0) {
+   /* Send control data to device */
+   res = copy_from_user(buffer, u64_to_uptr(request.data),
+request.req.wLength);
+   if (res) {
+   rv = -EFAULT;
+   goto exit;
+   }
+   }
+   }
+
+   rv = usb_control_msg(data->usb_dev,
+   usb_rcvctrlpipe(data->usb_dev, 0),
+   request.req.bRequest,
+   request.req.bRequestType,
+   request.req.wValue,
+   request.req.wIndex,
+   buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT);
+
+   if (rv < 0) {
+   dev_err(dev, "%s failed %d\n", __func__, rv);
+   goto exit;
+   }
+
+   if (rv && (request.req.bRequestType & USB_DIR_IN)) {
+   /* Read control data from device */
+   res = copy_to_user(u64_to_uptr(request.data), buffer, rv);
+   if (res)
+   rv = -EFAULT;
+   }
+
+ exit:
+   kfree(buffer);
+   return rv;
+}
+
 /*
  * Get the usb timeout value
  */
@@ -1366,6 +1439,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
retval = usbtmc_ioctl_abort_bulk_in(data);
break;
 
+   case USBTMC_IOCTL_CTRL_REQUEST:
+   retval = usbtmc_ioctl_request(data, (void __user *)arg);
+   break;
+
case USBTMC_IOCTL_GET_TIMEOUT:
retval = usbtmc_ioctl_get_timeout(file_data,
  (void __user *)arg);
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 729af2f861a4..95533118ac34 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -4,6 +4,7 @@
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 Greg Kroah-Hartman 
  * Copyright (C) 2015 Dave Penkler 
+ * Copyright (C) 2018 IVI Foundation, Inc.
  *
  * This file holds USB constants defined by the USB Device Class
  * and USB488 Subclass Definitions for Test and Measurement devices
@@ -40,6 +41,19 @@
 #define USBTMC488_REQUEST_GOTO_LOCAL   161
 #define USBT

[PATCH v5 07/22] usb: usbtmc: Fix suspend/resume

2018-08-03 Thread Guido Kiener
Submitted urbs are not allowed when system is suspended.
Thus the submitted urb waiting at interrupt pipe is killed
during suspend callback and submitted again when system resumes.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 16 +++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index b8a4140bd161..9953b62b7db4 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -2314,7 +2314,9 @@ static void usbtmc_free_int(struct usbtmc_device_data 
*data)
return;
usb_kill_urb(data->iin_urb);
kfree(data->iin_buffer);
+   data->iin_buffer = NULL;
usb_free_urb(data->iin_urb);
+   data->iin_urb = NULL;
kref_put(>kref, usbtmc_delete);
 }
 
@@ -2496,13 +2498,25 @@ static int usbtmc_suspend(struct usb_interface *intf, 
pm_message_t message)
   file_elem);
usbtmc_draw_down(file_data);
}
+
+   if (data->iin_ep_present && data->iin_urb)
+   usb_kill_urb(data->iin_urb);
+
mutex_unlock(>io_mutex);
return 0;
 }
 
 static int usbtmc_resume(struct usb_interface *intf)
 {
-   return 0;
+   struct usbtmc_device_data *data = usb_get_intfdata(intf);
+   int retcode = 0;
+
+   if (data->iin_ep_present && data->iin_urb)
+   retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL);
+   if (retcode)
+   dev_err(>dev, "Failed to submit iin_urb\n");
+
+   return retcode;
 }
 
 static int usbtmc_pre_reset(struct usb_interface *intf)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 15/22] usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_OUT

2018-08-03 Thread Guido Kiener
Add parameter 'tag' to function usbtmc_ioctl_abort_bulk_out_tag()
for future versions.

Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.

Insert a sleep of 50 ms between subsequent
CHECK_ABORT_BULK_OUT_STATUS control requests to avoid stressing
the instrument with repeated requests.

Use common macro USB_CTRL_GET_TIMEOUT instead of USBTMC_TIMEOUT.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 16 
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index c197d8c629f2..4609dc0db8a8 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -406,7 +406,8 @@ static int usbtmc_ioctl_abort_bulk_in(struct 
usbtmc_device_data *data)
return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read);
 }
 
-static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
+static int usbtmc_ioctl_abort_bulk_out_tag(struct usbtmc_device_data *data,
+  u8 tag)
 {
struct device *dev;
u8 *buffer;
@@ -423,8 +424,8 @@ static int usbtmc_ioctl_abort_bulk_out(struct 
usbtmc_device_data *data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
-data->bTag_last_write, data->bulk_out,
-buffer, 2, USBTMC_TIMEOUT);
+tag, data->bulk_out,
+buffer, 2, USB_CTRL_GET_TIMEOUT);
 
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
@@ -443,12 +444,14 @@ static int usbtmc_ioctl_abort_bulk_out(struct 
usbtmc_device_data *data)
n = 0;
 
 usbtmc_abort_bulk_out_check_status:
+   /* do not stress device with subsequent requests */
+   msleep(50);
rv = usb_control_msg(data->usb_dev,
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
 0, data->bulk_out, buffer, 0x08,
-USBTMC_TIMEOUT);
+USB_CTRL_GET_TIMEOUT);
n++;
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
@@ -482,6 +485,11 @@ static int usbtmc_ioctl_abort_bulk_out(struct 
usbtmc_device_data *data)
return rv;
 }
 
+static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
+{
+   return usbtmc_ioctl_abort_bulk_out_tag(data, data->bTag_last_write);
+}
+
 static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,
void __user *arg)
 {
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 05/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_CANCEL_IO

2018-08-03 Thread Guido Kiener
ioctl USBTMC_IOCTL_CANCEL_IO stops and kills all flying urbs of
last USBTMC_IOCTL_READ and USBTMC_IOCTL_WRITE function calls.
A subsequent call to USBTMC_IOCTL_READ or
USBTMC_IOCTL_WRITE_RESULT returns -ECANCELED with
information about current transferred data.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 4 
 include/uapi/linux/usb/tmc.h | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 5edb548d9122..e78176ef0e42 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -2134,6 +2134,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
case USBTMC488_IOCTL_TRIGGER:
retval = usbtmc488_ioctl_trigger(file_data);
break;
+
+   case USBTMC_IOCTL_CANCEL_IO:
+   retval = usbtmc_ioctl_cancel_io(file_data);
+   break;
}
 
 skip_io_on_zombie:
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index c75354dfd592..934991624a28 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -97,6 +97,9 @@ struct usbtmc_message {
 #define USBTMC488_IOCTL_LOCAL_LOCKOUT  _IO(USBTMC_IOC_NR, 21)
 #define USBTMC488_IOCTL_TRIGGER_IO(USBTMC_IOC_NR, 22)
 
+/* Cancel and cleanup asynchronous calls */
+#define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
+
 /* Driver encoded usb488 capabilities */
 #define USBTMC488_CAPABILITY_TRIGGER 1
 #define USBTMC488_CAPABILITY_SIMPLE  2
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 22/22] usb: usbtmc: Remove sysfs group TermChar and auto_abort

2018-07-30 Thread Guido Kiener
As all the properties of the usbtmc driver can now be
controlled on a per file descriptor basis by ioctl functions
the sysfs interface is of limited use.
We are not aware about applications that are using the sysfs
parameter TermChar, TermCharEnabled or auto_abort.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 .../ABI/stable/sysfs-driver-usb-usbtmc| 35 
 drivers/usb/class/usbtmc.c| 84 +--
 2 files changed, 3 insertions(+), 116 deletions(-)

diff --git a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc 
b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
index e960cd027e1e..a9e123ba32cd 100644
--- a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
+++ b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
@@ -25,38 +25,3 @@ Description:
4.2.2.
 
The files are read only.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/TermChar
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file is the TermChar value to be sent to the USB TMC
-   device as described by the document, "Universal Serial Bus Test
-   and Measurement Class Specification
-   (USBTMC) Revision 1.0" as published by the USB-IF.
-
-   Note that the TermCharEnabled file determines if this value is
-   sent to the device or not.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/TermCharEnabled
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file determines if the TermChar is to be sent to the
-   device on every transaction or not.  For more details about
-   this, please see the document, "Universal Serial Bus Test and
-   Measurement Class Specification (USBTMC) Revision 1.0" as
-   published by the USB-IF.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/auto_abort
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file determines if the transaction of the USB TMC
-   device is to be automatically aborted if there is any error.
-   For more details about this, please see the document,
-   "Universal Serial Bus Test and Measurement Class Specification
-   (USBTMC) Revision 1.0" as published by the USB-IF.
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 6aef3447adcc..f8391d41b13d 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -102,11 +102,6 @@ struct usbtmc_device_data {
/* coalesced usb488_caps from usbtmc_dev_capabilities */
__u8 usb488_caps;
 
-   /* attributes from the USB TMC spec for this device */
-   u8 TermChar;
-   bool TermCharEnabled;
-   bool auto_abort;
-
bool zombie; /* fd of disconnected device */
 
struct usbtmc_dev_capabilities  capabilities;
@@ -204,11 +199,10 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
 
atomic_set(_data->closing, 0);
 
-   /* copy default values from device settings */
file_data->timeout = USBTMC_TIMEOUT;
-   file_data->term_char = data->TermChar;
-   file_data->term_char_enabled = data->TermCharEnabled;
-   file_data->auto_abort = data->auto_abort;
+   file_data->term_char = '\n';
+   file_data->term_char_enabled = 0;
+   file_data->auto_abort = 0;
file_data->eom_val = 1;
 
INIT_LIST_HEAD(_data->file_elem);
@@ -1859,72 +1853,6 @@ static const struct attribute_group capability_attr_grp 
= {
.attrs = capability_attrs,
 };
 
-static ssize_t TermChar_show(struct device *dev,
-struct device_attribute *attr, char *buf)
-{
-   struct usb_interface *intf = to_usb_interface(dev);
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);
-
-   return sprintf(buf, "%c\n", data->TermChar);
-}
-
-static ssize_t TermChar_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
-   struct usb_interface *intf = to_usb_interface(dev);
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);
-
-   if (count < 1)
-   return -EINVAL;
-   data->TermChar = buf[0];
-   return count;
-}
-static DEVICE_ATTR_RW(TermChar);
-
-#define data_attribute(name)   \
-static ssize_t name##_show(struct device *dev, \
-  struct device_attribute *attr, char *buf)\
-{  \
-   struct usb_interface *intf = to_usb_interface(dev); \
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);   \
-   

[PATCH v4 18/22] usb: usbtmc: Update ioctl-number.txt

2018-07-30 Thread Guido Kiener
Reserve a suitable range of ioctl numbers for USBTMC driver.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 Documentation/ioctl/ioctl-number.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/ioctl/ioctl-number.txt 
b/Documentation/ioctl/ioctl-number.txt
index 480c8609dc58..810dd6c30296 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -200,7 +200,7 @@ Code  Seq#(hex) Include FileComments
 'X'01  linux/pktcdvd.h conflict!
 'Y'all linux/cyclades.h
 'Z'14-15   drivers/message/fusion/mptctl.h
-'['00-07   linux/usb/tmc.h USB Test and Measurement Devices
+'['00-3F   linux/usb/tmc.h USB Test and Measurement Devices
<mailto:gre...@linuxfoundation.org>
 'a'all linux/atm*.h, linux/sonet.h ATM on linux
<http://lrcwww.epfl.ch/>
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 21/22] usb: usbtmc: Fix split quoted string in debug message

2018-07-30 Thread Guido Kiener
Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 785eee3a6b89..6aef3447adcc 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -2507,8 +2507,8 @@ static int usbtmc_probe(struct usb_interface *intf,
 
retcode = usb_register_dev(intf, _class);
if (retcode) {
-   dev_err(>dev, "Not able to get a minor"
-   " (base %u, slice default): %d\n", USBTMC_MINOR_BASE,
+   dev_err(>dev, "Not able to get a minor (base %u, slice 
default): %d\n",
+   USBTMC_MINOR_BASE,
retcode);
goto error_register;
}
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 13/22] usb: usbtmc: Fix ioctl USBTMC_IOCTL_CLEAR

2018-07-30 Thread Guido Kiener
Remove calculation of max_size (=wMaxPacketSize) and wrong
condition (actual == max_size) in while loop. A device clear
should always flush the complete Bulk-IN FIFO.

Insert a sleep of 50 ms between subsequent CHECK_CLEAR_STATUS
control requests to avoid stressing the instrument with
repeated requests.

Some instruments need time to cleanup internal I/O buffers.
Polling and nonbraked requests slow down the response time of
devices.

Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.

Check only bit 0 (field bmClear) of the CHECK_CLEAR_STATUS
response, since other bits are reserved and can change in
future versions.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 46 +++---
 1 file changed, 18 insertions(+), 28 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 11225c6d6c69..1903d98f5a18 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1640,20 +1640,17 @@ static ssize_t usbtmc_write(struct file *filp, const 
char __user *buf,
 
 static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
 {
-   struct usb_host_interface *current_setting;
-   struct usb_endpoint_descriptor *desc;
struct device *dev;
u8 *buffer;
int rv;
int n;
int actual = 0;
-   int max_size;
 
dev = >intf->dev;
 
dev_dbg(dev, "Sending INITIATE_CLEAR request\n");
 
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+   buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
 
@@ -1661,7 +1658,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INITIATE_CLEAR,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 1, USBTMC_TIMEOUT);
+0, 0, buffer, 1, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
@@ -1675,22 +1672,6 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
goto exit;
}
 
-   max_size = 0;
-   current_setting = data->intf->cur_altsetting;
-   for (n = 0; n < current_setting->desc.bNumEndpoints; n++) {
-   desc = _setting->endpoint[n].desc;
-   if (desc->bEndpointAddress == data->bulk_in)
-   max_size = usb_endpoint_maxp(desc);
-   }
-
-   if (max_size == 0) {
-   dev_err(dev, "Couldn't get wMaxPacketSize\n");
-   rv = -EPERM;
-   goto exit;
-   }
-
-   dev_dbg(dev, "wMaxPacketSize is %d\n", max_size);
-
n = 0;
 
 usbtmc_clear_check_status:
@@ -1701,7 +1682,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_CHECK_CLEAR_STATUS,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 2, USBTMC_TIMEOUT);
+0, 0, buffer, 2, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
@@ -1718,15 +1699,19 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
goto exit;
}
 
-   if (buffer[1] == 1)
+   if ((buffer[1] & 1) != 0) {
do {
dev_dbg(dev, "Reading from bulk in EP\n");
 
rv = usb_bulk_msg(data->usb_dev,
  usb_rcvbulkpipe(data->usb_dev,
  data->bulk_in),
- buffer, USBTMC_SIZE_IOBUFFER,
- , USBTMC_TIMEOUT);
+ buffer, USBTMC_BUFSIZE,
+ , USB_CTRL_GET_TIMEOUT);
+
+   print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
+16, 1, buffer, actual, true);
+
n++;
 
if (rv < 0) {
@@ -1734,10 +1719,15 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
rv);
goto exit;
}
-   } while ((actual == max_size) &&
+   } while ((actual == USBTMC_BUFSIZE) &&
  (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
+   } else {
+  

[PATCH v4 16/22] usb: usbtmc: Replace USBTMC_TIMEOUT macros for control messages

2018-07-30 Thread Guido Kiener
Use common timeout macro USB_CTRL_GET_TIMEOUT (=5s) for all
usb_control_msg() function calls.

The macro USBTMC_TIMEOUT should only be used as default value for
Bulk IN/OUT transfers.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 4609dc0db8a8..91fb2fbf1aeb 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -529,7 +529,7 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data 
*file_data,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
data->iin_bTag,
data->ifnum,
-   buffer, 0x03, USBTMC_TIMEOUT);
+   buffer, 0x03, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "stb usb_control_msg returned %d\n", rv);
goto exit;
@@ -663,7 +663,7 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data 
*data,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
wValue,
data->ifnum,
-   buffer, 0x01, USBTMC_TIMEOUT);
+   buffer, 0x01, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "simple usb_control_msg failed %d\n", rv);
goto exit;
@@ -1810,7 +1810,7 @@ static int get_capabilities(struct usbtmc_device_data 
*data)
rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_GET_CAPABILITIES,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 0x18, USBTMC_TIMEOUT);
+0, 0, buffer, 0x18, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto err_out;
@@ -1949,7 +1949,7 @@ static int usbtmc_ioctl_indicator_pulse(struct 
usbtmc_device_data *data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INDICATOR_PULSE,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 0x01, USBTMC_TIMEOUT);
+0, 0, buffer, 0x01, USB_CTRL_GET_TIMEOUT);
 
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 11/22] usb: usbtmc: Optimize usbtmc_write

2018-07-30 Thread Guido Kiener
Use new usbtmc_generic_write function to maximize bandwidth
during long data transfer.
The maximum output transfer size is limited to INT_MAX (=2GB).

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 176 +++--
 1 file changed, 109 insertions(+), 67 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 42989c7902a8..6d5f514b3081 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1517,94 +1517,136 @@ static ssize_t usbtmc_write(struct file *filp, const 
char __user *buf,
 {
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data;
+   struct urb *urb = NULL;
+   ssize_t retval = 0;
u8 *buffer;
-   int retval;
-   int actual;
-   unsigned long int n_bytes;
-   int remaining;
-   int done;
-   int this_part;
+   u32 remaining, done;
+   u32 transfersize, aligned, buflen;
 
file_data = filp->private_data;
data = file_data->data;
 
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
-   if (!buffer)
-   return -ENOMEM;
-
mutex_lock(>io_mutex);
+
if (data->zombie) {
retval = -ENODEV;
goto exit;
}
 
-   remaining = count;
done = 0;
 
-   while (remaining > 0) {
-   if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE) {
-   this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE;
-   buffer[8] = 0;
-   } else {
-   this_part = remaining;
-   buffer[8] = file_data->eom_val;
-   }
-
-   /* Setup IO buffer for DEV_DEP_MSG_OUT message */
-   buffer[0] = 1;
-   buffer[1] = data->bTag;
-   buffer[2] = ~data->bTag;
-   buffer[3] = 0; /* Reserved */
-   buffer[4] = this_part >> 0;
-   buffer[5] = this_part >> 8;
-   buffer[6] = this_part >> 16;
-   buffer[7] = this_part >> 24;
-   /* buffer[8] is set above... */
-   buffer[9] = 0; /* Reserved */
-   buffer[10] = 0; /* Reserved */
-   buffer[11] = 0; /* Reserved */
-
-   if (copy_from_user([USBTMC_HEADER_SIZE], buf + done, 
this_part)) {
-   retval = -EFAULT;
-   goto exit;
-   }
-
-   n_bytes = roundup(USBTMC_HEADER_SIZE + this_part, 4);
-   memset(buffer + USBTMC_HEADER_SIZE + this_part, 0, n_bytes - 
(USBTMC_HEADER_SIZE + this_part));
-
-   do {
-   retval = usb_bulk_msg(data->usb_dev,
- usb_sndbulkpipe(data->usb_dev,
- data->bulk_out),
- buffer, n_bytes,
- , file_data->timeout);
-   if (retval != 0)
-   break;
-   n_bytes -= actual;
-   } while (n_bytes);
-
-   data->bTag_last_write = data->bTag;
+   spin_lock_irq(_data->err_lock);
+   file_data->out_transfer_size = 0;
+   file_data->out_status = 0;
+   spin_unlock_irq(_data->err_lock);
+
+   if (!count)
+   goto exit;
+
+   if (down_trylock(_data->limit_write_sem)) {
+   /* previous calls were async */
+   retval = -EBUSY;
+   goto exit;
+   }
+
+   urb = usbtmc_create_urb();
+   if (!urb) {
+   retval = -ENOMEM;
+   up(_data->limit_write_sem);
+   goto exit;
+   }
+
+   buffer = urb->transfer_buffer;
+   buflen = urb->transfer_buffer_length;
+
+   if (count > INT_MAX) {
+   transfersize = INT_MAX;
+   buffer[8] = 0;
+   } else {
+   transfersize = count;
+   buffer[8] = file_data->eom_val;
+   }
+
+   /* Setup IO buffer for DEV_DEP_MSG_OUT message */
+   buffer[0] = 1;
+   buffer[1] = data->bTag;
+   buffer[2] = ~data->bTag;
+   buffer[3] = 0; /* Reserved */
+   buffer[4] = transfersize >> 0;
+   buffer[5] = transfersize >> 8;
+   buffer[6] = transfersize >> 16;
+   buffer[7] = transfersize >> 24;
+   /* buffer[8] is set above... */
+   buffer[9] = 0; /* Reserved */
+   buffer[10] = 0; /* Reserved */
+   buffer[11] = 0; /* Reserved */
+
+   remaining = transfersize;
+
+   if (transfersize + USBTMC_HEADER_SIZE > buflen) {
+   transfersize = buflen - USBTMC_HEADER_SIZE;
+   aligned = buflen;
+   } else {
+   alig

[PATCH v4 19/22] usb: usbtmc: Remove redundant code

2018-07-30 Thread Guido Kiener
Remove redundant code and fix debug messages.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 25 -
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index fb49a737ea61..81144c0c4772 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1753,12 +1753,9 @@ static int usbtmc_ioctl_clear_out_halt(struct 
usbtmc_device_data *data)
rv = usb_clear_halt(data->usb_dev,
usb_sndbulkpipe(data->usb_dev, data->bulk_out));
 
-   if (rv < 0) {
-   dev_err(>usb_dev->dev, "usb_control_msg returned %d\n",
-   rv);
-   return rv;
-   }
-   return 0;
+   if (rv < 0)
+   dev_err(>usb_dev->dev, "%s returned %d\n", __func__, rv);
+   return rv;
 }
 
 static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
@@ -1768,12 +1765,9 @@ static int usbtmc_ioctl_clear_in_halt(struct 
usbtmc_device_data *data)
rv = usb_clear_halt(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
 
-   if (rv < 0) {
-   dev_err(>usb_dev->dev, "usb_control_msg returned %d\n",
-   rv);
-   return rv;
-   }
-   return 0;
+   if (rv < 0)
+   dev_err(>usb_dev->dev, "%s returned %d\n", __func__, rv);
+   return rv;
 }
 
 static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data)
@@ -2197,11 +2191,8 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
break;
 
case USBTMC488_IOCTL_GET_CAPS:
-   retval = copy_to_user((void __user *)arg,
-   >usb488_caps,
-   sizeof(data->usb488_caps));
-   if (retval)
-   retval = -EFAULT;
+   retval = put_user(data->usb488_caps,
+ (unsigned char __user *)arg);
break;
 
case USBTMC488_IOCTL_READ_STB:
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 15/22] usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_OUT

2018-07-30 Thread Guido Kiener
Add parameter 'tag' to function usbtmc_ioctl_abort_bulk_out_tag()
for future versions.

Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.

Insert a sleep of 50 ms between subsequent
CHECK_ABORT_BULK_OUT_STATUS control requests to avoid stressing
the instrument with repeated requests.

Use common macro USB_CTRL_GET_TIMEOUT instead of USBTMC_TIMEOUT.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 16 
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index c197d8c629f2..4609dc0db8a8 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -406,7 +406,8 @@ static int usbtmc_ioctl_abort_bulk_in(struct 
usbtmc_device_data *data)
return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read);
 }
 
-static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
+static int usbtmc_ioctl_abort_bulk_out_tag(struct usbtmc_device_data *data,
+  u8 tag)
 {
struct device *dev;
u8 *buffer;
@@ -423,8 +424,8 @@ static int usbtmc_ioctl_abort_bulk_out(struct 
usbtmc_device_data *data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
-data->bTag_last_write, data->bulk_out,
-buffer, 2, USBTMC_TIMEOUT);
+tag, data->bulk_out,
+buffer, 2, USB_CTRL_GET_TIMEOUT);
 
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
@@ -443,12 +444,14 @@ static int usbtmc_ioctl_abort_bulk_out(struct 
usbtmc_device_data *data)
n = 0;
 
 usbtmc_abort_bulk_out_check_status:
+   /* do not stress device with subsequent requests */
+   msleep(50);
rv = usb_control_msg(data->usb_dev,
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
 0, data->bulk_out, buffer, 0x08,
-USBTMC_TIMEOUT);
+USB_CTRL_GET_TIMEOUT);
n++;
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
@@ -482,6 +485,11 @@ static int usbtmc_ioctl_abort_bulk_out(struct 
usbtmc_device_data *data)
return rv;
 }
 
+static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
+{
+   return usbtmc_ioctl_abort_bulk_out_tag(data, data->bTag_last_write);
+}
+
 static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,
void __user *arg)
 {
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 12/22] usb: usbtmc: Optimize usbtmc_read

2018-07-30 Thread Guido Kiener
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: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 222 ++---
 1 file changed, 105 insertions(+), 117 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 6d5f514b3081..11225c6d6c69 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1301,7 +1301,7 @@ static ssize_t usbtmc_ioctl_write_result(struct 
usbtmc_file_data *file_data,
  * Also updates bTag_last_write.
  */
 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;
int retval;
@@ -1344,12 +1344,11 @@ static int send_request_dev_dep_msg_in(struct 
usbtmc_file_data *file_data,
data->bTag++;
 
kfree(buffer);
-   if (retval < 0) {
-   dev_err(>intf->dev, "usb_bulk_msg in 
send_request_dev_dep_msg_in() returned %d\n", retval);
-   return retval;
-   }
+   if (retval < 0)
+   dev_err(>intf->dev, "%s returned %d\n",
+   __func__, retval);
 
-   return 0;
+   return retval;
 }
 
 static ssize_t usbtmc_read(struct file *filp, char __user *buf,
@@ -1358,20 +1357,20 @@ 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 n_characters;
u8 *buffer;
int actual;
-   size_t done;
-   size_t remaining;
+   u32 done = 0;
+   u32 remaining;
int retval;
-   size_t this_part;
 
/* Get pointer to private data structure */
file_data = filp->private_data;
data = file_data->data;
dev = >intf->dev;
 
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+   buffer = kmalloc(bufsize, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
 
@@ -1381,7 +1380,10 @@ static ssize_t usbtmc_read(struct file *filp, char 
__user *buf,
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);
 
@@ -1393,114 +1395,100 @@ static ssize_t usbtmc_read(struct file *filp, char 
__user *buf,
 
/* Loop until we have fetched everything we requested */
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, ,
- 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) */
-   data->bTag_last_read = data->bTag;
-
-   if (retval < 0) {
-   dev_dbg(dev, "Unable to read data, error %d\n", retval);
-   if (file_data->auto_abort)
-   usbtmc_ioctl_abort_bulk_in(data);
+
+   /* Send bulk URB */
+   retval = usb_bulk_msg(data->usb_dev,
+ usb_rcvbulkpipe(data->usb_dev,
+ data->bulk_in),
+ buffer, bufsize, ,
+ file_data->timeout);
+
+   dev_dbg(dev, "%s: bulk_msg retval(%u), actual(%d)\n",
+   __func__, retval, actual);
+
+   /* Store bTag (in case we need to abort) */
+   data->bTag_last_read = data->bTag;
+
+   if (retval < 0) {
+   if (file_data->auto_abort)
+   usbtmc_ioctl_abort_bulk_in(data);
+   goto exit;
+   }
+
+   /* 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)
+ 

[PATCH v4 17/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_API_VERSION

2018-07-30 Thread Guido Kiener
Add ioctl USBTMC_IOCTL_API_VERSION to get current API version
of usbtmc driver.

This is to allow an instrument library to determine whether
the driver API is compatible with the implementation.

The API may change in future versions. Therefore the macro
USBTMC_API_VERSION should be incremented when changing tmc.h
with new flags, ioctls or when changing a significant behavior
of the driver.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 9 +
 include/uapi/linux/usb/tmc.h | 1 +
 2 files changed, 10 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 91fb2fbf1aeb..fb49a737ea61 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -22,6 +22,10 @@
 #include 
 #include 
 
+/* Increment API VERSION when changing tmc.h with new flags or ioctls
+ * or when changing a significant behavior of the driver.
+ */
+#define USBTMC_API_VERSION (2)
 
 #define USBTMC_HEADER_SIZE 12
 #define USBTMC_MINOR_BASE  176
@@ -2187,6 +2191,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
   (void __user *)arg);
break;
 
+   case USBTMC_IOCTL_API_VERSION:
+   retval = put_user(USBTMC_API_VERSION,
+ (__u32 __user *)arg);
+   break;
+
case USBTMC488_IOCTL_GET_CAPS:
retval = copy_to_user((void __user *)arg,
>usb488_caps,
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 2435694d3ba5..1d3373922e5e 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -89,6 +89,7 @@ struct usbtmc_message {
 #define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct 
usbtmc_message)
 #define USBTMC_IOCTL_READ  _IOWR(USBTMC_IOC_NR, 14, struct 
usbtmc_message)
 #define USBTMC_IOCTL_WRITE_RESULT  _IOWR(USBTMC_IOC_NR, 15, __u32)
+#define USBTMC_IOCTL_API_VERSION   _IOR(USBTMC_IOC_NR, 16, __u32)
 
 #define USBTMC488_IOCTL_GET_CAPS   _IOR(USBTMC_IOC_NR, 17, unsigned char)
 #define USBTMC488_IOCTL_READ_STB   _IOR(USBTMC_IOC_NR, 18, unsigned char)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 20/22] usb: usbtmc: Remove redundant macro USBTMC_SIZE_IOBUFFER

2018-07-30 Thread Guido Kiener
Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 6 --
 1 file changed, 6 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 81144c0c4772..785eee3a6b89 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -30,12 +30,6 @@
 #define USBTMC_HEADER_SIZE 12
 #define USBTMC_MINOR_BASE  176
 
-/*
- * Size of driver internal IO buffer. Must be multiple of 4 and at least as
- * large as wMaxPacketSize (which is usually 512 bytes).
- */
-#define USBTMC_SIZE_IOBUFFER   2048
-
 /* Minimum USB timeout (in milliseconds) */
 #define USBTMC_MIN_TIMEOUT 100
 /* Default USB timeout (in milliseconds) */
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 14/22] usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_IN

2018-07-30 Thread Guido Kiener
Add parameter 'tag' to function usbtmc_ioctl_abort_bulk_in_tag()
for future versions.

Remove calculation of max_size (=wMaxPacketSize) and wrong
condition (actual == max_size) in while loop. An abort operation
should always flush the complete Bulk-IN until a short packet is
received.

Return error code ENOMSG when transfer (specified by given tag)
is not in progress and device returns code
USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS.

Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.

Use common macro USB_CTRL_GET_TIMEOUT instead of USBTMC_TIMEOUT.

Check only bit 0 (field bmAbortBulkIn) of the
CHECK_ABORT_BULK_IN_STATUS response, since other bits are reserved
and can change in future versions.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 139 -
 1 file changed, 61 insertions(+), 78 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 1903d98f5a18..c197d8c629f2 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -278,18 +278,17 @@ static int usbtmc_release(struct inode *inode, struct 
file *file)
return 0;
 }
 
-static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
+static int usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data *data,
+ u8 tag)
 {
u8 *buffer;
struct device *dev;
int rv;
int n;
int actual;
-   struct usb_host_interface *current_setting;
-   int max_size;
 
dev = >intf->dev;
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+   buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
 
@@ -297,21 +296,34 @@ static int usbtmc_ioctl_abort_bulk_in(struct 
usbtmc_device_data *data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INITIATE_ABORT_BULK_IN,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
-data->bTag_last_read, data->bulk_in,
-buffer, 2, USBTMC_TIMEOUT);
+tag, data->bulk_in,
+buffer, 2, USB_CTRL_GET_TIMEOUT);
 
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
}
 
-   dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]);
+   dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x with tag %02x\n",
+   buffer[0], buffer[1]);
 
if (buffer[0] == USBTMC_STATUS_FAILED) {
+   /* No transfer in progress and the Bulk-OUT FIFO is empty. */
rv = 0;
goto exit;
}
 
+   if (buffer[0] == USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS) {
+   /* The device returns this status if either:
+* - There is a transfer in progress, but the specified bTag
+*   does not match.
+* - There is no transfer in progress, but the Bulk-OUT FIFO
+*   is not empty.
+*/
+   rv = -ENOMSG;
+   goto exit;
+   }
+
if (buffer[0] != USBTMC_STATUS_SUCCESS) {
dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n",
buffer[0]);
@@ -319,64 +331,52 @@ static int usbtmc_ioctl_abort_bulk_in(struct 
usbtmc_device_data *data)
goto exit;
}
 
-   max_size = 0;
-   current_setting = data->intf->cur_altsetting;
-   for (n = 0; n < current_setting->desc.bNumEndpoints; n++)
-   if (current_setting->endpoint[n].desc.bEndpointAddress ==
-   data->bulk_in)
-   max_size = 
usb_endpoint_maxp(_setting->endpoint[n].desc);
-
-   if (max_size == 0) {
-   dev_err(dev, "Couldn't get wMaxPacketSize\n");
-   rv = -EPERM;
-   goto exit;
-   }
-
-   dev_dbg(>intf->dev, "wMaxPacketSize is %d\n", max_size);
-
-   n = 0;
-
-   do {
-   dev_dbg(dev, "Reading from bulk in EP\n");
-
-   rv = usb_bulk_msg(data->usb_dev,
- usb_rcvbulkpipe(data->usb_dev,
- data->bulk_in),
- buffer, USBTMC_SIZE_IOBUFFER,
- , USBTMC_TIMEOUT);
-
-   n++;
-
-   if (rv < 0) {
-   dev_err(dev, "usb_bulk_msg returned %d\n", rv);
-   goto exit;
-   }
-   } while ((actual == max_size) &&
-(n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
-
-   if (actual =

[PATCH v4 01/22] usb: usbtmc: Add ioctl for generic requests on control

2018-07-30 Thread Guido Kiener
Add USBTMC_IOCTL_CTRL_REQUEST to send arbitrary requests on the
control pipe.  Used by specific applications of IVI Foundation,
Inc. to implement VISA API functions: viUsbControlIn/Out.

The maximum length of control request is set to 4k.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 77 
 include/uapi/linux/usb/tmc.h | 15 +++
 2 files changed, 92 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 83ffa5a14c3d..f5603c835336 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 Greg Kroah-Hartman 
+ * Copyright (C) 2018 IVI Foundation, Inc.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -36,6 +37,9 @@
 /* Default USB timeout (in milliseconds) */
 #define USBTMC_TIMEOUT 5000
 
+/* I/O buffer size used in generic read/write functions */
+#define USBTMC_BUFSIZE (4096)
+
 /*
  * Maximum number of read cycles to empty bulk in endpoint during CLEAR and
  * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short
@@ -129,6 +133,14 @@ struct usbtmc_file_data {
 /* Forward declarations */
 static struct usb_driver usbtmc_driver;
 
+static void __user *u64_to_uptr(u64 value)
+{
+   if (in_compat_syscall())
+   return compat_ptr(value);
+   else
+   return (void __user *)(unsigned long)value;
+}
+
 static void usbtmc_delete(struct kref *kref)
 {
struct usbtmc_device_data *data = to_usbtmc_data(kref);
@@ -1250,6 +1262,67 @@ static int usbtmc_ioctl_indicator_pulse(struct 
usbtmc_device_data *data)
return rv;
 }
 
+static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
+   void __user *arg)
+{
+   struct device *dev = >intf->dev;
+   struct usbtmc_ctrlrequest request;
+   u8 *buffer = NULL;
+   int rv;
+   unsigned long res;
+
+   res = copy_from_user(, arg, sizeof(struct usbtmc_ctrlrequest));
+   if (res)
+   return -EFAULT;
+
+   buffer = kmalloc(request.req.wLength, GFP_KERNEL);
+   if (!buffer)
+   return -ENOMEM;
+
+   if (request.req.wLength > USBTMC_BUFSIZE)
+   return -EMSGSIZE;
+
+   if (request.req.wLength) {
+   buffer = kmalloc(request.req.wLength, GFP_KERNEL);
+   if (!buffer)
+   return -ENOMEM;
+
+   if ((request.req.bRequestType & USB_DIR_IN) == 0) {
+   /* Send control data to device */
+   res = copy_from_user(buffer, u64_to_uptr(request.data),
+request.req.wLength);
+   if (res) {
+   rv = -EFAULT;
+   goto exit;
+   }
+   }
+   }
+
+   rv = usb_control_msg(data->usb_dev,
+   usb_rcvctrlpipe(data->usb_dev, 0),
+   request.req.bRequest,
+   request.req.bRequestType,
+   request.req.wValue,
+   request.req.wIndex,
+   buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT);
+
+   if (rv < 0) {
+   dev_err(dev, "%s failed %d\n", __func__, rv);
+   goto exit;
+   }
+
+   if (rv && (request.req.bRequestType & USB_DIR_IN)) {
+   /* Read control data from device */
+   res = copy_to_user(u64_to_uptr(request.data), buffer, rv);
+   if (res)
+   rv = -EFAULT;
+   }
+
+ exit:
+   kfree(buffer);
+   return rv;
+}
+
 /*
  * Get the usb timeout value
  */
@@ -1366,6 +1439,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
retval = usbtmc_ioctl_abort_bulk_in(data);
break;
 
+   case USBTMC_IOCTL_CTRL_REQUEST:
+   retval = usbtmc_ioctl_request(data, (void __user *)arg);
+   break;
+
case USBTMC_IOCTL_GET_TIMEOUT:
retval = usbtmc_ioctl_get_timeout(file_data,
  (void __user *)arg);
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 729af2f861a4..95533118ac34 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -4,6 +4,7 @@
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 Greg Kroah-Hartman 
  * Copyright (C) 2015 Dave Penkler 
+ * Copyright (C) 2018 IVI Foundation, Inc.
  *
  * This file holds USB constants defined by the USB Device Class
  * and USB488 Subclass Definitions for Test and Measurement devices
@@ -40,6 +41,19 @@
 #define USBTMC488_REQUEST_GOTO_LOCAL   161
 #define USBT

[PATCH v4 10/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_AUTO_ABORT

2018-07-30 Thread Guido Kiener
Add ioctl USBTMC_IOCTL_AUTO_ABORT to configure auto_abort for
each specific file handle.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 23 ---
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 1e7a1dcfcec7..42989c7902a8 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -136,6 +136,7 @@ struct usbtmc_file_data {
u8 eom_val;
u8 term_char;
bool   term_char_enabled;
+   bool   auto_abort;
 
spinlock_t err_lock; /* lock for errors */
 
@@ -209,6 +210,7 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
file_data->timeout = USBTMC_TIMEOUT;
file_data->term_char = data->TermChar;
file_data->term_char_enabled = data->TermCharEnabled;
+   file_data->auto_abort = data->auto_abort;
file_data->eom_val = 1;
 
INIT_LIST_HEAD(_data->file_elem);
@@ -1384,7 +1386,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
retval = send_request_dev_dep_msg_in(file_data, count);
 
if (retval < 0) {
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_out(data);
goto exit;
}
@@ -1409,7 +1411,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
 
if (retval < 0) {
dev_dbg(dev, "Unable to read data, error %d\n", retval);
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
@@ -1419,21 +1421,21 @@ static ssize_t usbtmc_read(struct file *filp, char 
__user *buf,
/* 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)
+   if (file_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)
+   if (file_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 (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
@@ -1448,7 +1450,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
 
if (n_characters > this_part) {
dev_err(dev, "Device wants to return more data 
than requested: %u > %zu\n", n_characters, count);
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
@@ -1590,7 +1592,7 @@ static ssize_t usbtmc_write(struct file *filp, const char 
__user *buf,
if (retval < 0) {
dev_err(>intf->dev,
"Unable to send data, error %d\n", retval);
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_out(data);
goto exit;
}
@@ -2099,6 +2101,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data;
int retval = -EBADRQC;
+   __u8 tmp_byte;
 
file_data = file->private_data;
data = file_data->data;
@@ -2215,6 +2218,12 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
  (__u8 __user *)arg);
break;
 
+   ca

[PATCH v4 02/22] usb: usbtmc: Add ioctl for vendor specific write

2018-07-30 Thread Guido Kiener
The new ioctl USBTMC_IOCTL_WRITE sends a generic message to bulk OUT.
This ioctl is used for vendor specific or asynchronous I/O as well.

The message is split into chunks of 4k (page size).
Message size is aligned to 32 bit boundaries.

With flag USBTMC_FLAG_ASYNC the ioctl is non blocking.
With flag USBTMC_FLAG_APPEND additional urbs are queued and
out_status/out_transfer_size is not reset. EPOLLOUT | EPOLLWRNORM
is signaled when all submitted urbs are completed.

Flush flying urbs when file handle is closed or device is
suspended or reset.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 376 ++-
 include/uapi/linux/usb/tmc.h |  14 ++
 2 files changed, 388 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index f5603c835336..b30935d8af6b 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -37,6 +37,8 @@
 /* Default USB timeout (in milliseconds) */
 #define USBTMC_TIMEOUT 5000
 
+/* Max number of urbs used in write transfers */
+#define MAX_URBS_IN_FLIGHT 16
 /* I/O buffer size used in generic read/write functions */
 #define USBTMC_BUFSIZE (4096)
 
@@ -125,13 +127,24 @@ struct usbtmc_file_data {
u32timeout;
u8 srq_byte;
atomic_t   srq_asserted;
+
u8 eom_val;
u8 term_char;
bool   term_char_enabled;
+
+   spinlock_t err_lock; /* lock for errors */
+
+   struct usb_anchor submitted;
+
+   /* data for generic_write */
+   struct semaphore limit_write_sem;
+   u32 out_transfer_size;
+   int out_status;
 };
 
 /* Forward declarations */
 static struct usb_driver usbtmc_driver;
+static void usbtmc_draw_down(struct usbtmc_file_data *file_data);
 
 static void __user *u64_to_uptr(u64 value)
 {
@@ -165,6 +178,10 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
if (!file_data)
return -ENOMEM;
 
+   spin_lock_init(_data->err_lock);
+   sema_init(_data->limit_write_sem, MAX_URBS_IN_FLIGHT);
+   init_usb_anchor(_data->submitted);
+
data = usb_get_intfdata(intf);
/* Protect reference to data from file structure until release */
kref_get(>kref);
@@ -190,6 +207,36 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
return 0;
 }
 
+/*
+ * usbtmc_flush - called before file handle is closed
+ */
+static int usbtmc_flush(struct file *file, fl_owner_t id)
+{
+   struct usbtmc_file_data *file_data;
+   struct usbtmc_device_data *data;
+
+   file_data = file->private_data;
+   if (file_data == NULL)
+   return -ENODEV;
+
+   data = file_data->data;
+
+   /* wait for io to stop */
+   mutex_lock(>io_mutex);
+
+   usbtmc_draw_down(file_data);
+
+   spin_lock_irq(_data->err_lock);
+   file_data->out_status = 0;
+   file_data->out_transfer_size = 0;
+   spin_unlock_irq(_data->err_lock);
+
+   wake_up_interruptible_all(>waitq);
+   mutex_unlock(>io_mutex);
+
+   return 0;
+}
+
 static int usbtmc_release(struct inode *inode, struct file *file)
 {
struct usbtmc_file_data *file_data = file->private_data;
@@ -622,6 +669,238 @@ static int usbtmc488_ioctl_trigger(struct 
usbtmc_file_data *file_data)
return 0;
 }
 
+static struct urb *usbtmc_create_urb(void)
+{
+   const size_t bufsize = USBTMC_BUFSIZE;
+   u8 *dmabuf = NULL;
+   struct urb *urb = usb_alloc_urb(0, GFP_KERNEL);
+
+   if (!urb)
+   return NULL;
+
+   dmabuf = kmalloc(bufsize, GFP_KERNEL);
+   if (!dmabuf) {
+   usb_free_urb(urb);
+   return NULL;
+   }
+
+   urb->transfer_buffer = dmabuf;
+   urb->transfer_buffer_length = bufsize;
+   urb->transfer_flags |= URB_FREE_BUFFER;
+   return urb;
+}
+
+static void usbtmc_write_bulk_cb(struct urb *urb)
+{
+   struct usbtmc_file_data *file_data = urb->context;
+   int wakeup = 0;
+   unsigned long flags;
+
+   spin_lock_irqsave(_data->err_lock, flags);
+   file_data->out_transfer_size += urb->actual_length;
+
+   /* sync/async unlink faults aren't errors */
+   if (urb->status) {
+   if (!(urb->status == -ENOENT ||
+   urb->status == -ECONNRESET ||
+   urb->status == -ESHUTDOWN))
+   dev_err(_data->data->intf->dev,
+   "%s - nonzero write bulk status received: %d\n",
+   __func__, urb->status);
+
+   if (!file_data->out_status) {
+   file_data->out_status = urb->status;
+   wakeup = 1;
+   }
+   }
+   spin_unlock_irqrestore(_data->

[PATCH v4 08/22] usb: usbtmc: Add ioctl USBTMC488_IOCTL_WAIT_SRQ

2018-07-30 Thread Guido Kiener
Wait until an SRQ (service request) is received on the interrupt pipe
or until the given period of time is expired. In contrast to the
poll() function this ioctl does not return when other (a)synchronous
I/O operations fail with EPOLLERR.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 57 
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 58 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 9953b62b7db4..15421aa71eef 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -130,6 +130,7 @@ struct usbtmc_file_data {
u32timeout;
u8 srq_byte;
atomic_t   srq_asserted;
+   atomic_t   closing;
 
u8 eom_val;
u8 term_char;
@@ -201,6 +202,8 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
mutex_lock(>io_mutex);
file_data->data = data;
 
+   atomic_set(_data->closing, 0);
+
/* copy default values from device settings */
file_data->timeout = USBTMC_TIMEOUT;
file_data->term_char = data->TermChar;
@@ -231,6 +234,7 @@ static int usbtmc_flush(struct file *file, fl_owner_t id)
if (file_data == NULL)
return -ENODEV;
 
+   atomic_set(_data->closing, 1);
data = file_data->data;
 
/* wait for io to stop */
@@ -584,6 +588,54 @@ static int usbtmc488_ioctl_read_stb(struct 
usbtmc_file_data *file_data,
return rv;
 }
 
+static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data,
+   __u32 __user *arg)
+{
+   struct usbtmc_device_data *data = file_data->data;
+   struct device *dev = >intf->dev;
+   int rv;
+   u32 timeout;
+   unsigned long expire;
+
+   if (!data->iin_ep_present) {
+   dev_dbg(dev, "no interrupt endpoint present\n");
+   return -EFAULT;
+   }
+
+   if (get_user(timeout, arg))
+   return -EFAULT;
+
+   expire = msecs_to_jiffies(timeout);
+
+   mutex_unlock(>io_mutex);
+
+   rv = wait_event_interruptible_timeout(
+   data->waitq,
+   atomic_read(_data->srq_asserted) != 0 ||
+   atomic_read(_data->closing),
+   expire);
+
+   mutex_lock(>io_mutex);
+
+   /* Note! disconnect or close could be called in the meantime */
+   if (atomic_read(_data->closing) || data->zombie)
+   rv = -ENODEV;
+
+   if (rv < 0) {
+   /* dev can be invalid now! */
+   pr_debug("%s - wait interrupted %d\n", __func__, rv);
+   return rv;
+   }
+
+   if (rv == 0) {
+   dev_dbg(dev, "%s - wait timed out\n", __func__);
+   return -ETIMEDOUT;
+   }
+
+   dev_dbg(dev, "%s - srq asserted\n", __func__);
+   return 0;
+}
+
 static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
void __user *arg, unsigned int cmd)
 {
@@ -2150,6 +2202,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
retval = usbtmc488_ioctl_trigger(file_data);
break;
 
+   case USBTMC488_IOCTL_WAIT_SRQ:
+   retval = usbtmc488_ioctl_wait_srq(file_data,
+ (__u32 __user *)arg);
+   break;
+
case USBTMC_IOCTL_CANCEL_IO:
retval = usbtmc_ioctl_cancel_io(file_data);
break;
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index d638c198c7a8..56c76a9680e5 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -96,6 +96,7 @@ struct usbtmc_message {
 #define USBTMC488_IOCTL_GOTO_LOCAL _IO(USBTMC_IOC_NR, 20)
 #define USBTMC488_IOCTL_LOCAL_LOCKOUT  _IO(USBTMC_IOC_NR, 21)
 #define USBTMC488_IOCTL_TRIGGER_IO(USBTMC_IOC_NR, 22)
+#define USBTMC488_IOCTL_WAIT_SRQ   _IOW(USBTMC_IOC_NR, 23, __u32)
 
 /* Cancel and cleanup asynchronous calls */
 #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 09/22] usb: usbtmc: add ioctl USBTMC_IOCTL_MSG_IN_ATTR

2018-07-30 Thread Guido Kiener
add ioctl USBTMC_IOCTL_MSG_IN_ATTR that returns the specific
bmTransferAttributes field of the last DEV_DEP_MSG_IN Bulk-IN
header. This header is received by the read() function. The
meaning of the (u8) bitmap bmTransferAttributes is:

Bit 0 = EOM flag is set when the last transfer of a USBTMC
message is received.

Bit 1 = is set when the last byte is a termchar (e.g. '\n').
Note that this bit is always zero when the device does not support
the termchar feature or when termchar detection is not enabled
(see ioctl USBTMC_IOCTL_CONFIG_TERMCHAR).

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 8 
 include/uapi/linux/usb/tmc.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 15421aa71eef..1e7a1dcfcec7 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -131,6 +131,7 @@ struct usbtmc_file_data {
u8 srq_byte;
atomic_t   srq_asserted;
atomic_t   closing;
+   u8 bmTransferAttributes; /* member of DEV_DEP_MSG_IN */
 
u8 eom_val;
u8 term_char;
@@ -1443,6 +1444,8 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
   (buffer[6] << 16) +
   (buffer[7] << 24);
 
+   file_data->bmTransferAttributes = buffer[8];
+
if (n_characters > this_part) {
dev_err(dev, "Device wants to return more data 
than requested: %u > %zu\n", n_characters, count);
if (data->auto_abort)
@@ -2207,6 +2210,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
  (__u32 __user *)arg);
break;
 
+   case USBTMC_IOCTL_MSG_IN_ATTR:
+   retval = put_user(file_data->bmTransferAttributes,
+ (__u8 __user *)arg);
+   break;
+
case USBTMC_IOCTL_CANCEL_IO:
retval = usbtmc_ioctl_cancel_io(file_data);
break;
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 56c76a9680e5..d2ed6a20de6b 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -98,6 +98,8 @@ struct usbtmc_message {
 #define USBTMC488_IOCTL_TRIGGER_IO(USBTMC_IOC_NR, 22)
 #define USBTMC488_IOCTL_WAIT_SRQ   _IOW(USBTMC_IOC_NR, 23, __u32)
 
+#define USBTMC_IOCTL_MSG_IN_ATTR   _IOR(USBTMC_IOC_NR, 24, __u8)
+
 /* Cancel and cleanup asynchronous calls */
 #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
 #define USBTMC_IOCTL_CLEANUP_IO_IO(USBTMC_IOC_NR, 36)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 03/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_WRITE_RESULT

2018-07-30 Thread Guido Kiener
ioctl USBTMC_IOCTL_WRITE_RESULT copies current out_transfer_size
to given __u32 pointer and returns current out_status of the last
(asnynchronous) USBTMC_IOCTL_WRITE call.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 25 +
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 26 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index b30935d8af6b..32aef9e53bc5 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -901,6 +901,26 @@ static ssize_t usbtmc_ioctl_generic_write(struct 
usbtmc_file_data *file_data,
return retval;
 }
 
+/*
+ * Get the generic write result
+ */
+static ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data,
+   void __user *arg)
+{
+   u32 transferred;
+   int retval;
+
+   spin_lock_irq(_data->err_lock);
+   transferred = file_data->out_transfer_size;
+   retval = file_data->out_status;
+   spin_unlock_irq(_data->err_lock);
+
+   if (put_user(transferred, (__u32 __user *)arg))
+   return -EFAULT;
+
+   return retval;
+}
+
 /*
  * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint.
  * @transfer_size: number of bytes to request from the device.
@@ -1756,6 +1776,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
(void __user *)arg);
break;
 
+   case USBTMC_IOCTL_WRITE_RESULT:
+   retval = usbtmc_ioctl_write_result(file_data,
+  (void __user *)arg);
+   break;
+
case USBTMC488_IOCTL_GET_CAPS:
retval = copy_to_user((void __user *)arg,
>usb488_caps,
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 56faeb3b5f0f..4a47b11e4a7e 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -86,6 +86,7 @@ struct usbtmc_message {
 #define USBTMC_IOCTL_EOM_ENABLE_IOW(USBTMC_IOC_NR, 11, __u8)
 #define USBTMC_IOCTL_CONFIG_TERMCHAR   _IOW(USBTMC_IOC_NR, 12, struct 
usbtmc_termchar)
 #define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct 
usbtmc_message)
+#define USBTMC_IOCTL_WRITE_RESULT  _IOWR(USBTMC_IOC_NR, 15, __u32)
 
 #define USBTMC488_IOCTL_GET_CAPS   _IOR(USBTMC_IOC_NR, 17, unsigned char)
 #define USBTMC488_IOCTL_READ_STB   _IOR(USBTMC_IOC_NR, 18, unsigned char)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 07/22] usb: usbtmc: Fix suspend/resume

2018-07-30 Thread Guido Kiener
Submitted urbs are not allowed when system is suspended.
Thus the submitted urb waiting at interrupt pipe is killed
during suspend callback and submitted again when system resumes.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 16 +++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index b8a4140bd161..9953b62b7db4 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -2314,7 +2314,9 @@ static void usbtmc_free_int(struct usbtmc_device_data 
*data)
return;
usb_kill_urb(data->iin_urb);
kfree(data->iin_buffer);
+   data->iin_buffer = NULL;
usb_free_urb(data->iin_urb);
+   data->iin_urb = NULL;
kref_put(>kref, usbtmc_delete);
 }
 
@@ -2496,13 +2498,25 @@ static int usbtmc_suspend(struct usb_interface *intf, 
pm_message_t message)
   file_elem);
usbtmc_draw_down(file_data);
}
+
+   if (data->iin_ep_present && data->iin_urb)
+   usb_kill_urb(data->iin_urb);
+
mutex_unlock(>io_mutex);
return 0;
 }
 
 static int usbtmc_resume(struct usb_interface *intf)
 {
-   return 0;
+   struct usbtmc_device_data *data = usb_get_intfdata(intf);
+   int retcode = 0;
+
+   if (data->iin_ep_present && data->iin_urb)
+   retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL);
+   if (retcode)
+   dev_err(>dev, "Failed to submit iin_urb\n");
+
+   return retcode;
 }
 
 static int usbtmc_pre_reset(struct usb_interface *intf)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 06/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_CLEANUP_IO

2018-07-30 Thread Guido Kiener
The ioctl USBTMC_IOCTL_CLEANUP_IO kills all submitted urbs to OUT
and IN bulk, and clears all received data from IN bulk. Internal
transfer counters and error states are reset.

An application should use this ioctl after an asnychronous transfer
was canceled and/or error handling has finished.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 19 +++
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 20 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index e78176ef0e42..b8a4140bd161 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1714,6 +1714,21 @@ static int usbtmc_ioctl_cancel_io(struct 
usbtmc_file_data *file_data)
return 0;
 }
 
+static int usbtmc_ioctl_cleanup_io(struct usbtmc_file_data *file_data)
+{
+   usb_kill_anchored_urbs(_data->submitted);
+   usb_scuttle_anchored_urbs(_data->in_anchor);
+   spin_lock_irq(_data->err_lock);
+   file_data->in_status = 0;
+   file_data->in_transfer_size = 0;
+   file_data->out_status = 0;
+   file_data->out_transfer_size = 0;
+   spin_unlock_irq(_data->err_lock);
+
+   file_data->in_urbs_used = 0;
+   return 0;
+}
+
 static int get_capabilities(struct usbtmc_device_data *data)
 {
struct device *dev = >usb_dev->dev;
@@ -2138,6 +2153,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
case USBTMC_IOCTL_CANCEL_IO:
retval = usbtmc_ioctl_cancel_io(file_data);
break;
+
+   case USBTMC_IOCTL_CLEANUP_IO:
+   retval = usbtmc_ioctl_cleanup_io(file_data);
+   break;
}
 
 skip_io_on_zombie:
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 934991624a28..d638c198c7a8 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -99,6 +99,7 @@ struct usbtmc_message {
 
 /* Cancel and cleanup asynchronous calls */
 #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
+#define USBTMC_IOCTL_CLEANUP_IO_IO(USBTMC_IOC_NR, 36)
 
 /* Driver encoded usb488 capabilities */
 #define USBTMC488_CAPABILITY_TRIGGER 1
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 04/22] usb: usbtmc: Add ioctl for vendor specific read

2018-07-30 Thread Guido Kiener
The USBTMC_IOCTL_READ call provides for generic synchronous and
asynchronous reads on bulk IN to implement vendor specific library
routines.

Depending on transfer_size the function submits one or more urbs (up
to 16) each with a size of up to 4kB.

The flag USBTMC_FLAG_IGNORE_TRAILER can be used when the transmission
size is already known. Then the function does not truncate the
transfer_size to a multiple of 4 kB, but does reserve extra space
to receive the final short or zero length packet. Note that the
instrument is allowed to send up to wMaxPacketSize - 1 bytes at the
end of a message to avoid sending a zero length packet.

With flag USBTMC_FLAG_ASYNC the ioctl is non blocking. When no
received data is available, the read function submits as many urbs as
needed to receive transfer_size bytes. However the number of flying
urbs (=4kB) is limited to 16 even with subsequent calls of this ioctl.

Returns -EAGAIN when non blocking and no data is received.
Signals EPOLLIN | EPOLLRDNORM when asynchronous urbs are ready to
be read.

In non blocking mode the usbtmc_message.message pointer may be NULL
and the ioctl just submits urbs to initiate receiving data. However if
data is already available due to a previous non blocking call the ioctl
will return -EINVAL when the message pointer is NULL.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 336 ++-
 include/uapi/linux/usb/tmc.h |   2 +
 2 files changed, 337 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 32aef9e53bc5..5edb548d9122 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -85,6 +85,9 @@ struct usbtmc_device_data {
u8 bTag_last_write; /* needed for abort */
u8 bTag_last_read;  /* needed for abort */
 
+   /* packet size of IN bulk */
+   u16wMaxPacketSize;
+
/* data for interrupt in endpoint handling */
u8 bNotify1;
u8 bNotify2;
@@ -140,6 +143,13 @@ struct usbtmc_file_data {
struct semaphore limit_write_sem;
u32 out_transfer_size;
int out_status;
+
+   /* data for generic_read */
+   u32 in_transfer_size;
+   int in_status;
+   int in_urbs_used;
+   struct usb_anchor in_anchor;
+   wait_queue_head_t wait_bulk_in;
 };
 
 /* Forward declarations */
@@ -181,6 +191,8 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
spin_lock_init(_data->err_lock);
sema_init(_data->limit_write_sem, MAX_URBS_IN_FLIGHT);
init_usb_anchor(_data->submitted);
+   init_usb_anchor(_data->in_anchor);
+   init_waitqueue_head(_data->wait_bulk_in);
 
data = usb_get_intfdata(intf);
/* Protect reference to data from file structure until release */
@@ -227,6 +239,9 @@ static int usbtmc_flush(struct file *file, fl_owner_t id)
usbtmc_draw_down(file_data);
 
spin_lock_irq(_data->err_lock);
+   file_data->in_status = 0;
+   file_data->in_transfer_size = 0;
+   file_data->in_urbs_used = 0;
file_data->out_status = 0;
file_data->out_transfer_size = 0;
spin_unlock_irq(_data->err_lock);
@@ -690,6 +705,307 @@ static struct urb *usbtmc_create_urb(void)
return urb;
 }
 
+static void usbtmc_read_bulk_cb(struct urb *urb)
+{
+   struct usbtmc_file_data *file_data = urb->context;
+   int status = urb->status;
+   unsigned long flags;
+
+   /* sync/async unlink faults aren't errors */
+   if (status) {
+   if (!(/* status == -ENOENT || */
+   status == -ECONNRESET ||
+   status == -EREMOTEIO || /* Short packet */
+   status == -ESHUTDOWN))
+   dev_err(_data->data->intf->dev,
+   "%s - nonzero read bulk status received: %d\n",
+   __func__, status);
+
+   spin_lock_irqsave(_data->err_lock, flags);
+   if (!file_data->in_status)
+   file_data->in_status = status;
+   spin_unlock_irqrestore(_data->err_lock, flags);
+   }
+
+   spin_lock_irqsave(_data->err_lock, flags);
+   file_data->in_transfer_size += urb->actual_length;
+   dev_dbg(_data->data->intf->dev,
+   "%s - total size: %u current: %d status: %d\n",
+   __func__, file_data->in_transfer_size,
+   urb->actual_length, status);
+   spin_unlock_irqrestore(_data->err_lock, flags);
+   usb_anchor_urb(urb, _data->in_anchor);
+
+   wake_up_interruptible(_data->wait_bulk_in);
+   wake_up_interruptible(_data->data->waitq);
+}
+
+static inline bool usbtmc_do_transfer(struct usbtmc_file_data *file_data)
+{
+   bool data_or_error;
+
+   spin_l

[PATCH v4 00/22] usb: usbtmc: Changes needed for compatible IVI/VISA library

2018-07-30 Thread Guido Kiener
The working group "VISA for Linux" of the IVI Foundation
www.ivifoundation.org specifies common rules, shared libraries and
drivers to implement the specification of "VPP-4.3: The VISA Library"
on Linux to be compatible with implementations on other operating systems.

The USBTMC protocol is part of the "VISA Library" that is used by many
popular T applications.

Initial implementations for Linux based on libusb has been created.
However using one common USBTMC driver results in more benefits:

- Multiple applications can share access to the same instruments.
- The driver handles SRQ conflicts.
- Simplifies definition of udev rules for USBTMC devices.
- Simplifies development of applications using T instruments.

The following collaborative patches meet the requirements of the IVI
Foundation to implement the library based on the usbtmc driver.

Improvements in the data transfer rate of over 130 MByte/s for
usb 3.x connections have been measured.

Guido Kiener, Dave Penkler, Steve Bayless (22):
  usb: usbtmc: Add ioctl for generic requests on control
  usb: usbtmc: Add ioctl for vendor specific write
  usb: usbtmc: Add ioctl USBTMC_IOCTL_WRITE_RESULT
  usb: usbtmc: Add ioctl for vendor specific read
  usb: usbtmc: Add ioctl USBTMC_IOCTL_CANCEL_IO
  usb: usbtmc: Add ioctl USBTMC_IOCTL_CLEANUP_IO
  usb: usbtmc: Fix suspend/resume
  usb: usbtmc: Add ioctl USBTMC488_IOCTL_WAIT_SRQ
  usb: usbtmc: add ioctl USBTMC_IOCTL_MSG_IN_ATTR
  usb: usbtmc: Add ioctl USBTMC_IOCTL_AUTO_ABORT
  usb: usbtmc: Optimize usbtmc_write
  usb: usbtmc: Optimize usbtmc_read
  usb: usbtmc: Fix ioctl USBTMC_IOCTL_CLEAR
  usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_IN
  usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_OUT
  usb: usbtmc: Replace USBTMC_TIMEOUT macros for control messages
  usb: usbtmc: Add ioctl USBTMC_IOCTL_API_VERSION
  usb: usbtmc: Update ioctl-number.txt
  usb: usbtmc: Remove redundant code
  usb: usbtmc: Remove redundant macro USBTMC_SIZE_IOBUFFER
  usb: usbtmc: Fix split quoted string in debug message
  usb: usbtmc: Remove sysfs group TermChar and auto_abort

 .../ABI/stable/sysfs-driver-usb-usbtmc|   35 -
 Documentation/ioctl/ioctl-number.txt  |2 +-
 drivers/usb/class/usbtmc.c| 1652 +
 include/uapi/linux/usb/tmc.h  |   41 +
 4 files changed, 1291 insertions(+), 439 deletions(-)

-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 05/22] usb: usbtmc: Add ioctl USBTMC_IOCTL_CANCEL_IO

2018-07-30 Thread Guido Kiener
ioctl USBTMC_IOCTL_CANCEL_IO stops and kills all flying urbs of
last USBTMC_IOCTL_READ and USBTMC_IOCTL_WRITE function calls.
A subsequent call to USBTMC_IOCTL_READ or
USBTMC_IOCTL_WRITE_RESULT returns -ECANCELED with
information about current transferred data.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 4 
 include/uapi/linux/usb/tmc.h | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 5edb548d9122..e78176ef0e42 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -2134,6 +2134,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
case USBTMC488_IOCTL_TRIGGER:
retval = usbtmc488_ioctl_trigger(file_data);
break;
+
+   case USBTMC_IOCTL_CANCEL_IO:
+   retval = usbtmc_ioctl_cancel_io(file_data);
+   break;
}
 
 skip_io_on_zombie:
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index c75354dfd592..934991624a28 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -97,6 +97,9 @@ struct usbtmc_message {
 #define USBTMC488_IOCTL_LOCAL_LOCKOUT  _IO(USBTMC_IOC_NR, 21)
 #define USBTMC488_IOCTL_TRIGGER_IO(USBTMC_IOC_NR, 22)
 
+/* Cancel and cleanup asynchronous calls */
+#define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
+
 /* Driver encoded usb488 capabilities */
 #define USBTMC488_CAPABILITY_TRIGGER 1
 #define USBTMC488_CAPABILITY_SIMPLE  2
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 22/23] usb: usbtmc: Fix split quoted string in debug message

2018-07-24 Thread Guido Kiener
Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index ddc2e4b78a3b..9a6312a49b55 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -2514,8 +2514,8 @@ static int usbtmc_probe(struct usb_interface *intf,
 
retcode = usb_register_dev(intf, _class);
if (retcode) {
-   dev_err(>dev, "Not able to get a minor"
-   " (base %u, slice default): %d\n", USBTMC_MINOR_BASE,
+   dev_err(>dev, "Not able to get a minor (base %u, slice 
default): %d\n",
+   USBTMC_MINOR_BASE,
retcode);
goto error_register;
}
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 14/23] usb: usbtmc: Fix ioctl USBTMC_IOCTL_CLEAR

2018-07-24 Thread Guido Kiener
Remove calculation of max_size (=wMaxPacketSize) and wrong
condition (actual == max_size) in while loop. A device clear
should always flush the complete Bulk-IN FIFO.

Insert a sleep of 50 ms between subsequent CHECK_CLEAR_STATUS
control requests to avoid stressing the instrument with
repeated requests.

Some instruments need time to cleanup internal I/O buffers.
Polling and nonbraked requests slow down the response time of
devices.

Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.

Check only bit 0 (field bmClear) of the CHECK_CLEAR_STATUS
response, since other bits are reserved and can change in
future versions.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 46 +++---
 1 file changed, 18 insertions(+), 28 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index e5ea2d822ae3..a7fa9e287477 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1647,20 +1647,17 @@ static ssize_t usbtmc_write(struct file *filp, const 
char __user *buf,
 
 static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
 {
-   struct usb_host_interface *current_setting;
-   struct usb_endpoint_descriptor *desc;
struct device *dev;
u8 *buffer;
int rv;
int n;
int actual = 0;
-   int max_size;
 
dev = >intf->dev;
 
dev_dbg(dev, "Sending INITIATE_CLEAR request\n");
 
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+   buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
 
@@ -1668,7 +1665,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INITIATE_CLEAR,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 1, USBTMC_TIMEOUT);
+0, 0, buffer, 1, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
@@ -1682,22 +1679,6 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
goto exit;
}
 
-   max_size = 0;
-   current_setting = data->intf->cur_altsetting;
-   for (n = 0; n < current_setting->desc.bNumEndpoints; n++) {
-   desc = _setting->endpoint[n].desc;
-   if (desc->bEndpointAddress == data->bulk_in)
-   max_size = usb_endpoint_maxp(desc);
-   }
-
-   if (max_size == 0) {
-   dev_err(dev, "Couldn't get wMaxPacketSize\n");
-   rv = -EPERM;
-   goto exit;
-   }
-
-   dev_dbg(dev, "wMaxPacketSize is %d\n", max_size);
-
n = 0;
 
 usbtmc_clear_check_status:
@@ -1708,7 +1689,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_CHECK_CLEAR_STATUS,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 2, USBTMC_TIMEOUT);
+0, 0, buffer, 2, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
@@ -1725,15 +1706,19 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
goto exit;
}
 
-   if (buffer[1] == 1)
+   if ((buffer[1] & 1) != 0) {
do {
dev_dbg(dev, "Reading from bulk in EP\n");
 
rv = usb_bulk_msg(data->usb_dev,
  usb_rcvbulkpipe(data->usb_dev,
  data->bulk_in),
- buffer, USBTMC_SIZE_IOBUFFER,
- , USBTMC_TIMEOUT);
+ buffer, USBTMC_BUFSIZE,
+ , USB_CTRL_GET_TIMEOUT);
+
+   print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
+16, 1, buffer, actual, true);
+
n++;
 
if (rv < 0) {
@@ -1741,10 +1726,15 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data 
*data)
rv);
goto exit;
}
-   } while ((actual == max_size) &&
+   } while ((actual == USBTMC_BUFSIZE) &&
  (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
+   } else {
+  

[PATCH v3 15/23] usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_IN

2018-07-24 Thread Guido Kiener
Add parameter 'tag' to function usbtmc_ioctl_abort_bulk_in_tag()
for future versions.

Remove calculation of max_size (=wMaxPacketSize) and wrong
condition (actual == max_size) in while loop. An abort operation
should always flush the complete Bulk-IN until a short packet is
received.

Return error code ENOMSG when transfer (specified by given tag)
is not in progress and device returns code
USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS.

Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.

Use common macro USB_CTRL_GET_TIMEOUT instead of USBTMC_TIMEOUT.

Check only bit 0 (field bmAbortBulkIn) of the
CHECK_ABORT_BULK_IN_STATUS response, since other bits are reserved
and can change in future versions.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 139 -
 1 file changed, 61 insertions(+), 78 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index a7fa9e287477..e05c11ba26f6 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -285,18 +285,17 @@ static int usbtmc_release(struct inode *inode, struct 
file *file)
return 0;
 }
 
-static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
+static int usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data *data,
+ u8 tag)
 {
u8 *buffer;
struct device *dev;
int rv;
int n;
int actual;
-   struct usb_host_interface *current_setting;
-   int max_size;
 
dev = >intf->dev;
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+   buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
 
@@ -304,21 +303,34 @@ static int usbtmc_ioctl_abort_bulk_in(struct 
usbtmc_device_data *data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INITIATE_ABORT_BULK_IN,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
-data->bTag_last_read, data->bulk_in,
-buffer, 2, USBTMC_TIMEOUT);
+tag, data->bulk_in,
+buffer, 2, USB_CTRL_GET_TIMEOUT);
 
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
}
 
-   dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]);
+   dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x with tag %02x\n",
+   buffer[0], buffer[1]);
 
if (buffer[0] == USBTMC_STATUS_FAILED) {
+   /* No transfer in progress and the Bulk-OUT FIFO is empty. */
rv = 0;
goto exit;
}
 
+   if (buffer[0] == USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS) {
+   /* The device returns this status if either:
+* - There is a transfer in progress, but the specified bTag
+*   does not match.
+* - There is no transfer in progress, but the Bulk-OUT FIFO
+*   is not empty.
+*/
+   rv = -ENOMSG;
+   goto exit;
+   }
+
if (buffer[0] != USBTMC_STATUS_SUCCESS) {
dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n",
buffer[0]);
@@ -326,64 +338,52 @@ static int usbtmc_ioctl_abort_bulk_in(struct 
usbtmc_device_data *data)
goto exit;
}
 
-   max_size = 0;
-   current_setting = data->intf->cur_altsetting;
-   for (n = 0; n < current_setting->desc.bNumEndpoints; n++)
-   if (current_setting->endpoint[n].desc.bEndpointAddress ==
-   data->bulk_in)
-   max_size = 
usb_endpoint_maxp(_setting->endpoint[n].desc);
-
-   if (max_size == 0) {
-   dev_err(dev, "Couldn't get wMaxPacketSize\n");
-   rv = -EPERM;
-   goto exit;
-   }
-
-   dev_dbg(>intf->dev, "wMaxPacketSize is %d\n", max_size);
-
-   n = 0;
-
-   do {
-   dev_dbg(dev, "Reading from bulk in EP\n");
-
-   rv = usb_bulk_msg(data->usb_dev,
- usb_rcvbulkpipe(data->usb_dev,
- data->bulk_in),
- buffer, USBTMC_SIZE_IOBUFFER,
- , USBTMC_TIMEOUT);
-
-   n++;
-
-   if (rv < 0) {
-   dev_err(dev, "usb_bulk_msg returned %d\n", rv);
-   goto exit;
-   }
-   } while ((actual == max_size) &&
-(n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
-
-   if (actual =

[PATCH v3 20/23] usb: usbtmc: Remove redundant code

2018-07-24 Thread Guido Kiener
Remove redundant code and fix debug messages.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 25 -
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 10dc896bf043..a6482e850532 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1760,12 +1760,9 @@ static int usbtmc_ioctl_clear_out_halt(struct 
usbtmc_device_data *data)
rv = usb_clear_halt(data->usb_dev,
usb_sndbulkpipe(data->usb_dev, data->bulk_out));
 
-   if (rv < 0) {
-   dev_err(>usb_dev->dev, "usb_control_msg returned %d\n",
-   rv);
-   return rv;
-   }
-   return 0;
+   if (rv < 0)
+   dev_err(>usb_dev->dev, "%s returned %d\n", __func__, rv);
+   return rv;
 }
 
 static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
@@ -1775,12 +1772,9 @@ static int usbtmc_ioctl_clear_in_halt(struct 
usbtmc_device_data *data)
rv = usb_clear_halt(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
 
-   if (rv < 0) {
-   dev_err(>usb_dev->dev, "usb_control_msg returned %d\n",
-   rv);
-   return rv;
-   }
-   return 0;
+   if (rv < 0)
+   dev_err(>usb_dev->dev, "%s returned %d\n", __func__, rv);
+   return rv;
 }
 
 static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data)
@@ -2204,11 +2198,8 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
break;
 
case USBTMC488_IOCTL_GET_CAPS:
-   retval = copy_to_user((void __user *)arg,
-   >usb488_caps,
-   sizeof(data->usb488_caps));
-   if (retval)
-   retval = -EFAULT;
+   retval = put_user(data->usb488_caps,
+ (unsigned char __user *)arg);
break;
 
case USBTMC488_IOCTL_READ_STB:
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 10/23] usb: usbtmc: add ioctl USBTMC_IOCTL_MSG_IN_ATTR

2018-07-24 Thread Guido Kiener
add ioctl USBTMC_IOCTL_MSG_IN_ATTR that returns the specific
bmTransferAttributes field of the last DEV_DEP_MSG_IN Bulk-IN
header. This header is received by the read() function. The
meaning of the (u8) bitmap bmTransferAttributes is:

Bit 0 = EOM flag is set when the last transfer of a USBTMC
message is received.

Bit 1 = is set when the last byte is a termchar (e.g. '\n').
Note that this bit is always zero when the device does not support
the termchar feature or when termchar detection is not enabled
(see ioctl USBTMC_IOCTL_CONFIG_TERMCHAR).

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 8 
 include/uapi/linux/usb/tmc.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index edce0a753623..d659c083a19b 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -131,6 +131,7 @@ struct usbtmc_file_data {
u8 srq_byte;
atomic_t   srq_asserted;
atomic_t   closing;
+   u8 bmTransferAttributes; /* member of DEV_DEP_MSG_IN */
 
u8 eom_val;
u8 term_char;
@@ -1450,6 +1451,8 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
   (buffer[6] << 16) +
   (buffer[7] << 24);
 
+   file_data->bmTransferAttributes = buffer[8];
+
if (n_characters > this_part) {
dev_err(dev, "Device wants to return more data 
than requested: %u > %zu\n", n_characters, count);
if (data->auto_abort)
@@ -2214,6 +2217,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
  (__u32 __user *)arg);
break;
 
+   case USBTMC_IOCTL_MSG_IN_ATTR:
+   retval = put_user(file_data->bmTransferAttributes,
+ (__u8 __user *)arg);
+   break;
+
case USBTMC_IOCTL_CANCEL_IO:
retval = usbtmc_ioctl_cancel_io(file_data);
break;
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 56c76a9680e5..d2ed6a20de6b 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -98,6 +98,8 @@ struct usbtmc_message {
 #define USBTMC488_IOCTL_TRIGGER_IO(USBTMC_IOC_NR, 22)
 #define USBTMC488_IOCTL_WAIT_SRQ   _IOW(USBTMC_IOC_NR, 23, __u32)
 
+#define USBTMC_IOCTL_MSG_IN_ATTR   _IOR(USBTMC_IOC_NR, 24, __u8)
+
 /* Cancel and cleanup asynchronous calls */
 #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
 #define USBTMC_IOCTL_CLEANUP_IO_IO(USBTMC_IOC_NR, 36)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 00/23] usb: usbtmc: Changes needed for compatible IVI/VISA library

2018-07-24 Thread Guido Kiener
The working group "VISA for Linux" of the IVI Foundation
www.ivifoundation.org specifies common rules, shared libraries and
drivers to implement the specification of "VPP-4.3: The VISA Library"
on Linux to be compatible with implementations on other operating systems.

The USBTMC protocol is part of the "VISA Library" that is used by many
popular T applications.

Initial implementations for Linux based on libusb has been created.
However using one common USBTMC driver results in more benefits:

- Multiple applications can share access to the same instruments.
- The driver handles SRQ conflicts.
- Simplifies definition of udev rules for USBTMC devices.
- Simplifies development of applications using T instruments.

The following collaborative patches meet the requirements of the IVI
Foundation to implement the library based on the usbtmc driver.

Improvements in the data transfer rate of over 130 MByte/s for
usb 3.x connections have been measured.

Guido Kiener, Dave Penkler, Steve Bayless (23):
  usb: usbtmc: Add support for 32 bit compat applications
  usb: usbtmc: Add ioctl for generic requests on control
  usb: usbtmc: Add ioctl for vendor specific write
  usb: usbtmc: Add ioctl USBTMC_IOCTL_WRITE_RESULT
  usb: usbtmc: Add ioctl for vendor specific read
  usb: usbtmc: Add ioctl USBTMC_IOCTL_CANCEL_IO
  usb: usbtmc: Add ioctl USBTMC_IOCTL_CLEANUP_IO
  usb: usbtmc: Fix suspend/resume
  usb: usbtmc: Add ioctl USBTMC488_IOCTL_WAIT_SRQ
  usb: usbtmc: add ioctl USBTMC_IOCTL_MSG_IN_ATTR
  usb: usbtmc: Add ioctl USBTMC_IOCTL_AUTO_ABORT
  usb: usbtmc: Optimize usbtmc_write
  usb: usbtmc: Optimize usbtmc_read
  usb: usbtmc: Fix ioctl USBTMC_IOCTL_CLEAR
  usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_IN
  usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_OUT
  usb: usbtmc: Replace USBTMC_TIMEOUT macros for control messages
  usb: usbtmc: Add ioctl USBTMC_IOCTL_API_VERSION
  usb: usbtmc: Update ioctl-number.txt
  usb: usbtmc: Remove redundant code
  usb: usbtmc: Remove redundant macro USBTMC_SIZE_IOBUFFER
  usb: usbtmc: Fix split quoted string in debug message
  usb: usbtmc: Remove sysfs group TermChar and auto_abort

 .../ABI/stable/sysfs-driver-usb-usbtmc|   35 -
 Documentation/ioctl/ioctl-number.txt  |2 +-
 drivers/usb/class/usbtmc.c| 1663 +
 include/uapi/linux/usb/tmc.h  |   41 +
 4 files changed, 1302 insertions(+), 439 deletions(-)

-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 17/23] usb: usbtmc: Replace USBTMC_TIMEOUT macros for control messages

2018-07-24 Thread Guido Kiener
Use common timeout macro USB_CTRL_GET_TIMEOUT (=5s) for all
usb_control_msg() function calls.

The macro USBTMC_TIMEOUT should only be used as default value for
Bulk IN/OUT transfers.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 5dad62c7a996..1d0ac45346c5 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -536,7 +536,7 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data 
*file_data,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
data->iin_bTag,
data->ifnum,
-   buffer, 0x03, USBTMC_TIMEOUT);
+   buffer, 0x03, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "stb usb_control_msg returned %d\n", rv);
goto exit;
@@ -670,7 +670,7 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data 
*data,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
wValue,
data->ifnum,
-   buffer, 0x01, USBTMC_TIMEOUT);
+   buffer, 0x01, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "simple usb_control_msg failed %d\n", rv);
goto exit;
@@ -1817,7 +1817,7 @@ static int get_capabilities(struct usbtmc_device_data 
*data)
rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_GET_CAPABILITIES,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 0x18, USBTMC_TIMEOUT);
+0, 0, buffer, 0x18, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto err_out;
@@ -1956,7 +1956,7 @@ static int usbtmc_ioctl_indicator_pulse(struct 
usbtmc_device_data *data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INDICATOR_PULSE,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-0, 0, buffer, 0x01, USBTMC_TIMEOUT);
+0, 0, buffer, 0x01, USB_CTRL_GET_TIMEOUT);
 
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 16/23] usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_OUT

2018-07-24 Thread Guido Kiener
Add parameter 'tag' to function usbtmc_ioctl_abort_bulk_out_tag()
for future versions.

Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.

Insert a sleep of 50 ms between subsequent
CHECK_ABORT_BULK_OUT_STATUS control requests to avoid stressing
the instrument with repeated requests.

Use common macro USB_CTRL_GET_TIMEOUT instead of USBTMC_TIMEOUT.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 16 
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index e05c11ba26f6..5dad62c7a996 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -413,7 +413,8 @@ static int usbtmc_ioctl_abort_bulk_in(struct 
usbtmc_device_data *data)
return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read);
 }
 
-static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
+static int usbtmc_ioctl_abort_bulk_out_tag(struct usbtmc_device_data *data,
+  u8 tag)
 {
struct device *dev;
u8 *buffer;
@@ -430,8 +431,8 @@ static int usbtmc_ioctl_abort_bulk_out(struct 
usbtmc_device_data *data)
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
-data->bTag_last_write, data->bulk_out,
-buffer, 2, USBTMC_TIMEOUT);
+tag, data->bulk_out,
+buffer, 2, USB_CTRL_GET_TIMEOUT);
 
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
@@ -450,12 +451,14 @@ static int usbtmc_ioctl_abort_bulk_out(struct 
usbtmc_device_data *data)
n = 0;
 
 usbtmc_abort_bulk_out_check_status:
+   /* do not stress device with subsequent requests */
+   msleep(50);
rv = usb_control_msg(data->usb_dev,
 usb_rcvctrlpipe(data->usb_dev, 0),
 USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS,
 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
 0, data->bulk_out, buffer, 0x08,
-USBTMC_TIMEOUT);
+USB_CTRL_GET_TIMEOUT);
n++;
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
@@ -489,6 +492,11 @@ static int usbtmc_ioctl_abort_bulk_out(struct 
usbtmc_device_data *data)
return rv;
 }
 
+static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
+{
+   return usbtmc_ioctl_abort_bulk_out_tag(data, data->bTag_last_write);
+}
+
 static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,
void __user *arg)
 {
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 03/23] usb: usbtmc: Add ioctl for vendor specific write

2018-07-24 Thread Guido Kiener
The new ioctl USBTMC_IOCTL_WRITE sends a generic message to bulk OUT.
This ioctl is used for vendor specific or asynchronous I/O as well.

The message is split into chunks of 4k (page size).
Message size is aligned to 32 bit boundaries.

With flag USBTMC_FLAG_ASYNC the ioctl is non blocking.
With flag USBTMC_FLAG_APPEND additional urbs are queued and
out_status/out_transfer_size is not reset. EPOLLOUT | EPOLLWRNORM
is signaled when all submitted urbs are completed.

Flush flying urbs when file handle is closed or device is
suspended or reset.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 376 ++-
 include/uapi/linux/usb/tmc.h |  14 ++
 2 files changed, 388 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 3b3b4284d04e..0328f1beb32d 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -37,6 +37,8 @@
 /* Default USB timeout (in milliseconds) */
 #define USBTMC_TIMEOUT 5000
 
+/* Max number of urbs used in write transfers */
+#define MAX_URBS_IN_FLIGHT 16
 /* I/O buffer size used in generic read/write functions */
 #define USBTMC_BUFSIZE (4096)
 
@@ -125,13 +127,24 @@ struct usbtmc_file_data {
u32timeout;
u8 srq_byte;
atomic_t   srq_asserted;
+
u8 eom_val;
u8 term_char;
bool   term_char_enabled;
+
+   spinlock_t err_lock; /* lock for errors */
+
+   struct usb_anchor submitted;
+
+   /* data for generic_write */
+   struct semaphore limit_write_sem;
+   u32 out_transfer_size;
+   int out_status;
 };
 
 /* Forward declarations */
 static struct usb_driver usbtmc_driver;
+static void usbtmc_draw_down(struct usbtmc_file_data *file_data);
 
 #ifdef CONFIG_COMPAT
 static void __user *u64_to_uptr(u64 value)
@@ -172,6 +185,10 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
if (!file_data)
return -ENOMEM;
 
+   spin_lock_init(_data->err_lock);
+   sema_init(_data->limit_write_sem, MAX_URBS_IN_FLIGHT);
+   init_usb_anchor(_data->submitted);
+
data = usb_get_intfdata(intf);
/* Protect reference to data from file structure until release */
kref_get(>kref);
@@ -197,6 +214,36 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
return 0;
 }
 
+/*
+ * usbtmc_flush - called before file handle is closed
+ */
+static int usbtmc_flush(struct file *file, fl_owner_t id)
+{
+   struct usbtmc_file_data *file_data;
+   struct usbtmc_device_data *data;
+
+   file_data = file->private_data;
+   if (file_data == NULL)
+   return -ENODEV;
+
+   data = file_data->data;
+
+   /* wait for io to stop */
+   mutex_lock(>io_mutex);
+
+   usbtmc_draw_down(file_data);
+
+   spin_lock_irq(_data->err_lock);
+   file_data->out_status = 0;
+   file_data->out_transfer_size = 0;
+   spin_unlock_irq(_data->err_lock);
+
+   wake_up_interruptible_all(>waitq);
+   mutex_unlock(>io_mutex);
+
+   return 0;
+}
+
 static int usbtmc_release(struct inode *inode, struct file *file)
 {
struct usbtmc_file_data *file_data = file->private_data;
@@ -629,6 +676,238 @@ static int usbtmc488_ioctl_trigger(struct 
usbtmc_file_data *file_data)
return 0;
 }
 
+static struct urb *usbtmc_create_urb(void)
+{
+   const size_t bufsize = USBTMC_BUFSIZE;
+   u8 *dmabuf = NULL;
+   struct urb *urb = usb_alloc_urb(0, GFP_KERNEL);
+
+   if (!urb)
+   return NULL;
+
+   dmabuf = kmalloc(bufsize, GFP_KERNEL);
+   if (!dmabuf) {
+   usb_free_urb(urb);
+   return NULL;
+   }
+
+   urb->transfer_buffer = dmabuf;
+   urb->transfer_buffer_length = bufsize;
+   urb->transfer_flags |= URB_FREE_BUFFER;
+   return urb;
+}
+
+static void usbtmc_write_bulk_cb(struct urb *urb)
+{
+   struct usbtmc_file_data *file_data = urb->context;
+   int wakeup = 0;
+   unsigned long flags;
+
+   spin_lock_irqsave(_data->err_lock, flags);
+   file_data->out_transfer_size += urb->actual_length;
+
+   /* sync/async unlink faults aren't errors */
+   if (urb->status) {
+   if (!(urb->status == -ENOENT ||
+   urb->status == -ECONNRESET ||
+   urb->status == -ESHUTDOWN))
+   dev_err(_data->data->intf->dev,
+   "%s - nonzero write bulk status received: %d\n",
+   __func__, urb->status);
+
+   if (!file_data->out_status) {
+   file_data->out_status = urb->status;
+   wakeup = 1;
+   }
+   }
+   spin_unlock_irqr

[PATCH v3 18/23] usb: usbtmc: Add ioctl USBTMC_IOCTL_API_VERSION

2018-07-24 Thread Guido Kiener
Add ioctl USBTMC_IOCTL_API_VERSION to get current API version
of usbtmc driver.

This is to allow an instrument library to determine whether
the driver API is compatible with the implementation.

The API may change in future versions. Therefore the macro
USBTMC_API_VERSION should be incremented when changing tmc.h
with new flags, ioctls or when changing a significant behavior
of the driver.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 9 +
 include/uapi/linux/usb/tmc.h | 1 +
 2 files changed, 10 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 1d0ac45346c5..10dc896bf043 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -22,6 +22,10 @@
 #include 
 #include 
 
+/* Increment API VERSION when changing tmc.h with new flags or ioctls
+ * or when changing a significant behavior of the driver.
+ */
+#define USBTMC_API_VERSION (2)
 
 #define USBTMC_HEADER_SIZE 12
 #define USBTMC_MINOR_BASE  176
@@ -2194,6 +2198,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
   (void __user *)arg);
break;
 
+   case USBTMC_IOCTL_API_VERSION:
+   retval = put_user(USBTMC_API_VERSION,
+ (__u32 __user *)arg);
+   break;
+
case USBTMC488_IOCTL_GET_CAPS:
retval = copy_to_user((void __user *)arg,
>usb488_caps,
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 2435694d3ba5..1d3373922e5e 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -89,6 +89,7 @@ struct usbtmc_message {
 #define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct 
usbtmc_message)
 #define USBTMC_IOCTL_READ  _IOWR(USBTMC_IOC_NR, 14, struct 
usbtmc_message)
 #define USBTMC_IOCTL_WRITE_RESULT  _IOWR(USBTMC_IOC_NR, 15, __u32)
+#define USBTMC_IOCTL_API_VERSION   _IOR(USBTMC_IOC_NR, 16, __u32)
 
 #define USBTMC488_IOCTL_GET_CAPS   _IOR(USBTMC_IOC_NR, 17, unsigned char)
 #define USBTMC488_IOCTL_READ_STB   _IOR(USBTMC_IOC_NR, 18, unsigned char)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 07/23] usb: usbtmc: Add ioctl USBTMC_IOCTL_CLEANUP_IO

2018-07-24 Thread Guido Kiener
The ioctl USBTMC_IOCTL_CLEANUP_IO kills all submitted urbs to OUT
and IN bulk, and clears all received data from IN bulk. Internal
transfer counters and error states are reset.

An application should use this ioctl after an asnychronous transfer
was canceled and/or error handling has finished.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 19 +++
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 20 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 67cdf5df90d7..fe140d400e1d 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1721,6 +1721,21 @@ static int usbtmc_ioctl_cancel_io(struct 
usbtmc_file_data *file_data)
return 0;
 }
 
+static int usbtmc_ioctl_cleanup_io(struct usbtmc_file_data *file_data)
+{
+   usb_kill_anchored_urbs(_data->submitted);
+   usb_scuttle_anchored_urbs(_data->in_anchor);
+   spin_lock_irq(_data->err_lock);
+   file_data->in_status = 0;
+   file_data->in_transfer_size = 0;
+   file_data->out_status = 0;
+   file_data->out_transfer_size = 0;
+   spin_unlock_irq(_data->err_lock);
+
+   file_data->in_urbs_used = 0;
+   return 0;
+}
+
 static int get_capabilities(struct usbtmc_device_data *data)
 {
struct device *dev = >usb_dev->dev;
@@ -2145,6 +2160,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
case USBTMC_IOCTL_CANCEL_IO:
retval = usbtmc_ioctl_cancel_io(file_data);
break;
+
+   case USBTMC_IOCTL_CLEANUP_IO:
+   retval = usbtmc_ioctl_cleanup_io(file_data);
+   break;
}
 
 skip_io_on_zombie:
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 934991624a28..d638c198c7a8 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -99,6 +99,7 @@ struct usbtmc_message {
 
 /* Cancel and cleanup asynchronous calls */
 #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
+#define USBTMC_IOCTL_CLEANUP_IO_IO(USBTMC_IOC_NR, 36)
 
 /* Driver encoded usb488 capabilities */
 #define USBTMC488_CAPABILITY_TRIGGER 1
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 11/23] usb: usbtmc: Add ioctl USBTMC_IOCTL_AUTO_ABORT

2018-07-24 Thread Guido Kiener
Add ioctl USBTMC_IOCTL_AUTO_ABORT to configure auto_abort for
each specific file handle.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 23 ---
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index d659c083a19b..caadd2df13a9 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -136,6 +136,7 @@ struct usbtmc_file_data {
u8 eom_val;
u8 term_char;
bool   term_char_enabled;
+   bool   auto_abort;
 
spinlock_t err_lock; /* lock for errors */
 
@@ -216,6 +217,7 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
file_data->timeout = USBTMC_TIMEOUT;
file_data->term_char = data->TermChar;
file_data->term_char_enabled = data->TermCharEnabled;
+   file_data->auto_abort = data->auto_abort;
file_data->eom_val = 1;
 
INIT_LIST_HEAD(_data->file_elem);
@@ -1391,7 +1393,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
retval = send_request_dev_dep_msg_in(file_data, count);
 
if (retval < 0) {
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_out(data);
goto exit;
}
@@ -1416,7 +1418,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
 
if (retval < 0) {
dev_dbg(dev, "Unable to read data, error %d\n", retval);
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
@@ -1426,21 +1428,21 @@ static ssize_t usbtmc_read(struct file *filp, char 
__user *buf,
/* 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)
+   if (file_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)
+   if (file_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 (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
@@ -1455,7 +1457,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user 
*buf,
 
if (n_characters > this_part) {
dev_err(dev, "Device wants to return more data 
than requested: %u > %zu\n", n_characters, count);
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
@@ -1597,7 +1599,7 @@ static ssize_t usbtmc_write(struct file *filp, const char 
__user *buf,
if (retval < 0) {
dev_err(>intf->dev,
"Unable to send data, error %d\n", retval);
-   if (data->auto_abort)
+   if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_out(data);
goto exit;
}
@@ -2106,6 +2108,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data;
int retval = -EBADRQC;
+   __u8 tmp_byte;
 
file_data = file->private_data;
data = file_data->data;
@@ -,6 +2225,12 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
  (__u8 __user *)arg);
break;
 
+   ca

[PATCH v3 08/23] usb: usbtmc: Fix suspend/resume

2018-07-24 Thread Guido Kiener
Submitted urbs are not allowed when system is suspended.
Thus the submitted urb waiting at interrupt pipe is killed
during suspend callback and submitted again when system resumes.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 16 +++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index fe140d400e1d..3babca045c02 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -2321,7 +2321,9 @@ static void usbtmc_free_int(struct usbtmc_device_data 
*data)
return;
usb_kill_urb(data->iin_urb);
kfree(data->iin_buffer);
+   data->iin_buffer = NULL;
usb_free_urb(data->iin_urb);
+   data->iin_urb = NULL;
kref_put(>kref, usbtmc_delete);
 }
 
@@ -2503,13 +2505,25 @@ static int usbtmc_suspend(struct usb_interface *intf, 
pm_message_t message)
   file_elem);
usbtmc_draw_down(file_data);
}
+
+   if (data->iin_ep_present && data->iin_urb)
+   usb_kill_urb(data->iin_urb);
+
mutex_unlock(>io_mutex);
return 0;
 }
 
 static int usbtmc_resume(struct usb_interface *intf)
 {
-   return 0;
+   struct usbtmc_device_data *data = usb_get_intfdata(intf);
+   int retcode = 0;
+
+   if (data->iin_ep_present && data->iin_urb)
+   retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL);
+   if (retcode)
+   dev_err(>dev, "Failed to submit iin_urb\n");
+
+   return retcode;
 }
 
 static int usbtmc_pre_reset(struct usb_interface *intf)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 23/23] usb: usbtmc: Remove sysfs group TermChar and auto_abort

2018-07-24 Thread Guido Kiener
As all the properties of the usbtmc driver can now be
controlled on a per file descriptor basis by ioctl functions
the sysfs interface is of limited use.
We are not aware about applications that are using the sysfs
parameter TermChar, TermCharEnabled or auto_abort.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 .../ABI/stable/sysfs-driver-usb-usbtmc| 35 
 drivers/usb/class/usbtmc.c| 84 +--
 2 files changed, 3 insertions(+), 116 deletions(-)

diff --git a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc 
b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
index e960cd027e1e..a9e123ba32cd 100644
--- a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
+++ b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
@@ -25,38 +25,3 @@ Description:
4.2.2.
 
The files are read only.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/TermChar
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file is the TermChar value to be sent to the USB TMC
-   device as described by the document, "Universal Serial Bus Test
-   and Measurement Class Specification
-   (USBTMC) Revision 1.0" as published by the USB-IF.
-
-   Note that the TermCharEnabled file determines if this value is
-   sent to the device or not.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/TermCharEnabled
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file determines if the TermChar is to be sent to the
-   device on every transaction or not.  For more details about
-   this, please see the document, "Universal Serial Bus Test and
-   Measurement Class Specification (USBTMC) Revision 1.0" as
-   published by the USB-IF.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/auto_abort
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file determines if the transaction of the USB TMC
-   device is to be automatically aborted if there is any error.
-   For more details about this, please see the document,
-   "Universal Serial Bus Test and Measurement Class Specification
-   (USBTMC) Revision 1.0" as published by the USB-IF.
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 9a6312a49b55..f8c7dab6d786 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -102,11 +102,6 @@ struct usbtmc_device_data {
/* coalesced usb488_caps from usbtmc_dev_capabilities */
__u8 usb488_caps;
 
-   /* attributes from the USB TMC spec for this device */
-   u8 TermChar;
-   bool TermCharEnabled;
-   bool auto_abort;
-
bool zombie; /* fd of disconnected device */
 
struct usbtmc_dev_capabilities  capabilities;
@@ -211,11 +206,10 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
 
atomic_set(_data->closing, 0);
 
-   /* copy default values from device settings */
file_data->timeout = USBTMC_TIMEOUT;
-   file_data->term_char = data->TermChar;
-   file_data->term_char_enabled = data->TermCharEnabled;
-   file_data->auto_abort = data->auto_abort;
+   file_data->term_char = '\n';
+   file_data->term_char_enabled = 0;
+   file_data->auto_abort = 0;
file_data->eom_val = 1;
 
INIT_LIST_HEAD(_data->file_elem);
@@ -1866,72 +1860,6 @@ static const struct attribute_group capability_attr_grp 
= {
.attrs = capability_attrs,
 };
 
-static ssize_t TermChar_show(struct device *dev,
-struct device_attribute *attr, char *buf)
-{
-   struct usb_interface *intf = to_usb_interface(dev);
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);
-
-   return sprintf(buf, "%c\n", data->TermChar);
-}
-
-static ssize_t TermChar_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
-   struct usb_interface *intf = to_usb_interface(dev);
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);
-
-   if (count < 1)
-   return -EINVAL;
-   data->TermChar = buf[0];
-   return count;
-}
-static DEVICE_ATTR_RW(TermChar);
-
-#define data_attribute(name)   \
-static ssize_t name##_show(struct device *dev, \
-  struct device_attribute *attr, char *buf)\
-{  \
-   struct usb_interface *intf = to_usb_interface(dev); \
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);   \
-   

[PATCH v3 21/23] usb: usbtmc: Remove redundant macro USBTMC_SIZE_IOBUFFER

2018-07-24 Thread Guido Kiener
Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 6 --
 1 file changed, 6 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index a6482e850532..ddc2e4b78a3b 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -30,12 +30,6 @@
 #define USBTMC_HEADER_SIZE 12
 #define USBTMC_MINOR_BASE  176
 
-/*
- * Size of driver internal IO buffer. Must be multiple of 4 and at least as
- * large as wMaxPacketSize (which is usually 512 bytes).
- */
-#define USBTMC_SIZE_IOBUFFER   2048
-
 /* Minimum USB timeout (in milliseconds) */
 #define USBTMC_MIN_TIMEOUT 100
 /* Default USB timeout (in milliseconds) */
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 19/23] usb: usbtmc: Update ioctl-number.txt

2018-07-24 Thread Guido Kiener
Reserve a suitable range of ioctl numbers for USBTMC driver.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 Documentation/ioctl/ioctl-number.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/ioctl/ioctl-number.txt 
b/Documentation/ioctl/ioctl-number.txt
index 480c8609dc58..810dd6c30296 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -200,7 +200,7 @@ Code  Seq#(hex) Include FileComments
 'X'01  linux/pktcdvd.h conflict!
 'Y'all linux/cyclades.h
 'Z'14-15   drivers/message/fusion/mptctl.h
-'['00-07   linux/usb/tmc.h USB Test and Measurement Devices
+'['00-3F   linux/usb/tmc.h USB Test and Measurement Devices
<mailto:gre...@linuxfoundation.org>
 'a'all linux/atm*.h, linux/sonet.h ATM on linux
<http://lrcwww.epfl.ch/>
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 01/23] usb: usbtmc: Add support for 32 bit compat applications

2018-07-24 Thread Guido Kiener
32 bit applications can only call ioctl functions on 64 bit systems
when the field .compat_ioctl is defined for file operations.

Tested-by: Dave Penkler 
Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 1b7b2e402adb..83ffa5a14c3d 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 
@@ -1459,6 +1460,9 @@ static const struct file_operations fops = {
.open   = usbtmc_open,
.release= usbtmc_release,
.unlocked_ioctl = usbtmc_ioctl,
+#ifdef CONFIG_COMPAT
+   .compat_ioctl   = usbtmc_ioctl,
+#endif
.fasync = usbtmc_fasync,
.poll   = usbtmc_poll,
.llseek = default_llseek,
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 06/23] usb: usbtmc: Add ioctl USBTMC_IOCTL_CANCEL_IO

2018-07-24 Thread Guido Kiener
ioctl USBTMC_IOCTL_CANCEL_IO stops and kills all flying urbs of
last USBTMC_IOCTL_READ and USBTMC_IOCTL_WRITE function calls.
A subsequent call to USBTMC_IOCTL_READ or
USBTMC_IOCTL_WRITE_RESULT returns -ECANCELED with
information about current transferred data.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 4 
 include/uapi/linux/usb/tmc.h | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 32b588eb0304..67cdf5df90d7 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -2141,6 +2141,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
case USBTMC488_IOCTL_TRIGGER:
retval = usbtmc488_ioctl_trigger(file_data);
break;
+
+   case USBTMC_IOCTL_CANCEL_IO:
+   retval = usbtmc_ioctl_cancel_io(file_data);
+   break;
}
 
 skip_io_on_zombie:
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index c75354dfd592..934991624a28 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -97,6 +97,9 @@ struct usbtmc_message {
 #define USBTMC488_IOCTL_LOCAL_LOCKOUT  _IO(USBTMC_IOC_NR, 21)
 #define USBTMC488_IOCTL_TRIGGER_IO(USBTMC_IOC_NR, 22)
 
+/* Cancel and cleanup asynchronous calls */
+#define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
+
 /* Driver encoded usb488 capabilities */
 #define USBTMC488_CAPABILITY_TRIGGER 1
 #define USBTMC488_CAPABILITY_SIMPLE  2
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 13/23] usb: usbtmc: Optimize usbtmc_read

2018-07-24 Thread Guido Kiener
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: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 222 ++---
 1 file changed, 105 insertions(+), 117 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 26d5af413009..e5ea2d822ae3 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1308,7 +1308,7 @@ static ssize_t usbtmc_ioctl_write_result(struct 
usbtmc_file_data *file_data,
  * Also updates bTag_last_write.
  */
 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;
int retval;
@@ -1351,12 +1351,11 @@ static int send_request_dev_dep_msg_in(struct 
usbtmc_file_data *file_data,
data->bTag++;
 
kfree(buffer);
-   if (retval < 0) {
-   dev_err(>intf->dev, "usb_bulk_msg in 
send_request_dev_dep_msg_in() returned %d\n", retval);
-   return retval;
-   }
+   if (retval < 0)
+   dev_err(>intf->dev, "%s returned %d\n",
+   __func__, retval);
 
-   return 0;
+   return retval;
 }
 
 static ssize_t usbtmc_read(struct file *filp, char __user *buf,
@@ -1365,20 +1364,20 @@ 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 n_characters;
u8 *buffer;
int actual;
-   size_t done;
-   size_t remaining;
+   u32 done = 0;
+   u32 remaining;
int retval;
-   size_t this_part;
 
/* Get pointer to private data structure */
file_data = filp->private_data;
data = file_data->data;
dev = >intf->dev;
 
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+   buffer = kmalloc(bufsize, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
 
@@ -1388,7 +1387,10 @@ static ssize_t usbtmc_read(struct file *filp, char 
__user *buf,
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);
 
@@ -1400,114 +1402,100 @@ static ssize_t usbtmc_read(struct file *filp, char 
__user *buf,
 
/* Loop until we have fetched everything we requested */
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, ,
- 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) */
-   data->bTag_last_read = data->bTag;
-
-   if (retval < 0) {
-   dev_dbg(dev, "Unable to read data, error %d\n", retval);
-   if (file_data->auto_abort)
-   usbtmc_ioctl_abort_bulk_in(data);
+
+   /* Send bulk URB */
+   retval = usb_bulk_msg(data->usb_dev,
+ usb_rcvbulkpipe(data->usb_dev,
+ data->bulk_in),
+ buffer, bufsize, ,
+ file_data->timeout);
+
+   dev_dbg(dev, "%s: bulk_msg retval(%u), actual(%d)\n",
+   __func__, retval, actual);
+
+   /* Store bTag (in case we need to abort) */
+   data->bTag_last_read = data->bTag;
+
+   if (retval < 0) {
+   if (file_data->auto_abort)
+   usbtmc_ioctl_abort_bulk_in(data);
+   goto exit;
+   }
+
+   /* 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)
+ 

[PATCH v3 12/23] usb: usbtmc: Optimize usbtmc_write

2018-07-24 Thread Guido Kiener
Use new usbtmc_generic_write function to maximize bandwidth
during long data transfer.
The maximum output transfer size is limited to INT_MAX (=2GB).

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 176 +++--
 1 file changed, 109 insertions(+), 67 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index caadd2df13a9..26d5af413009 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1524,94 +1524,136 @@ static ssize_t usbtmc_write(struct file *filp, const 
char __user *buf,
 {
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data;
+   struct urb *urb = NULL;
+   ssize_t retval = 0;
u8 *buffer;
-   int retval;
-   int actual;
-   unsigned long int n_bytes;
-   int remaining;
-   int done;
-   int this_part;
+   u32 remaining, done;
+   u32 transfersize, aligned, buflen;
 
file_data = filp->private_data;
data = file_data->data;
 
-   buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
-   if (!buffer)
-   return -ENOMEM;
-
mutex_lock(>io_mutex);
+
if (data->zombie) {
retval = -ENODEV;
goto exit;
}
 
-   remaining = count;
done = 0;
 
-   while (remaining > 0) {
-   if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE) {
-   this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE;
-   buffer[8] = 0;
-   } else {
-   this_part = remaining;
-   buffer[8] = file_data->eom_val;
-   }
-
-   /* Setup IO buffer for DEV_DEP_MSG_OUT message */
-   buffer[0] = 1;
-   buffer[1] = data->bTag;
-   buffer[2] = ~data->bTag;
-   buffer[3] = 0; /* Reserved */
-   buffer[4] = this_part >> 0;
-   buffer[5] = this_part >> 8;
-   buffer[6] = this_part >> 16;
-   buffer[7] = this_part >> 24;
-   /* buffer[8] is set above... */
-   buffer[9] = 0; /* Reserved */
-   buffer[10] = 0; /* Reserved */
-   buffer[11] = 0; /* Reserved */
-
-   if (copy_from_user([USBTMC_HEADER_SIZE], buf + done, 
this_part)) {
-   retval = -EFAULT;
-   goto exit;
-   }
-
-   n_bytes = roundup(USBTMC_HEADER_SIZE + this_part, 4);
-   memset(buffer + USBTMC_HEADER_SIZE + this_part, 0, n_bytes - 
(USBTMC_HEADER_SIZE + this_part));
-
-   do {
-   retval = usb_bulk_msg(data->usb_dev,
- usb_sndbulkpipe(data->usb_dev,
- data->bulk_out),
- buffer, n_bytes,
- , file_data->timeout);
-   if (retval != 0)
-   break;
-   n_bytes -= actual;
-   } while (n_bytes);
-
-   data->bTag_last_write = data->bTag;
+   spin_lock_irq(_data->err_lock);
+   file_data->out_transfer_size = 0;
+   file_data->out_status = 0;
+   spin_unlock_irq(_data->err_lock);
+
+   if (!count)
+   goto exit;
+
+   if (down_trylock(_data->limit_write_sem)) {
+   /* previous calls were async */
+   retval = -EBUSY;
+   goto exit;
+   }
+
+   urb = usbtmc_create_urb();
+   if (!urb) {
+   retval = -ENOMEM;
+   up(_data->limit_write_sem);
+   goto exit;
+   }
+
+   buffer = urb->transfer_buffer;
+   buflen = urb->transfer_buffer_length;
+
+   if (count > INT_MAX) {
+   transfersize = INT_MAX;
+   buffer[8] = 0;
+   } else {
+   transfersize = count;
+   buffer[8] = file_data->eom_val;
+   }
+
+   /* Setup IO buffer for DEV_DEP_MSG_OUT message */
+   buffer[0] = 1;
+   buffer[1] = data->bTag;
+   buffer[2] = ~data->bTag;
+   buffer[3] = 0; /* Reserved */
+   buffer[4] = transfersize >> 0;
+   buffer[5] = transfersize >> 8;
+   buffer[6] = transfersize >> 16;
+   buffer[7] = transfersize >> 24;
+   /* buffer[8] is set above... */
+   buffer[9] = 0; /* Reserved */
+   buffer[10] = 0; /* Reserved */
+   buffer[11] = 0; /* Reserved */
+
+   remaining = transfersize;
+
+   if (transfersize + USBTMC_HEADER_SIZE > buflen) {
+   transfersize = buflen - USBTMC_HEADER_SIZE;
+   aligned = buflen;
+   } else {
+   alig

[PATCH v3 09/23] usb: usbtmc: Add ioctl USBTMC488_IOCTL_WAIT_SRQ

2018-07-24 Thread Guido Kiener
Wait until an SRQ (service request) is received on the interrupt pipe
or until the given period of time is expired. In contrast to the
poll() function this ioctl does not return when other (a)synchronous
I/O operations fail with EPOLLERR.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 57 
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 58 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 3babca045c02..edce0a753623 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -130,6 +130,7 @@ struct usbtmc_file_data {
u32timeout;
u8 srq_byte;
atomic_t   srq_asserted;
+   atomic_t   closing;
 
u8 eom_val;
u8 term_char;
@@ -208,6 +209,8 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
mutex_lock(>io_mutex);
file_data->data = data;
 
+   atomic_set(_data->closing, 0);
+
/* copy default values from device settings */
file_data->timeout = USBTMC_TIMEOUT;
file_data->term_char = data->TermChar;
@@ -238,6 +241,7 @@ static int usbtmc_flush(struct file *file, fl_owner_t id)
if (file_data == NULL)
return -ENODEV;
 
+   atomic_set(_data->closing, 1);
data = file_data->data;
 
/* wait for io to stop */
@@ -591,6 +595,54 @@ static int usbtmc488_ioctl_read_stb(struct 
usbtmc_file_data *file_data,
return rv;
 }
 
+static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data,
+   __u32 __user *arg)
+{
+   struct usbtmc_device_data *data = file_data->data;
+   struct device *dev = >intf->dev;
+   int rv;
+   u32 timeout;
+   unsigned long expire;
+
+   if (!data->iin_ep_present) {
+   dev_dbg(dev, "no interrupt endpoint present\n");
+   return -EFAULT;
+   }
+
+   if (get_user(timeout, arg))
+   return -EFAULT;
+
+   expire = msecs_to_jiffies(timeout);
+
+   mutex_unlock(>io_mutex);
+
+   rv = wait_event_interruptible_timeout(
+   data->waitq,
+   atomic_read(_data->srq_asserted) != 0 ||
+   atomic_read(_data->closing),
+   expire);
+
+   mutex_lock(>io_mutex);
+
+   /* Note! disconnect or close could be called in the meantime */
+   if (atomic_read(_data->closing) || data->zombie)
+   rv = -ENODEV;
+
+   if (rv < 0) {
+   /* dev can be invalid now! */
+   pr_debug("%s - wait interrupted %d\n", __func__, rv);
+   return rv;
+   }
+
+   if (rv == 0) {
+   dev_dbg(dev, "%s - wait timed out\n", __func__);
+   return -ETIMEDOUT;
+   }
+
+   dev_dbg(dev, "%s - srq asserted\n", __func__);
+   return 0;
+}
+
 static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
void __user *arg, unsigned int cmd)
 {
@@ -2157,6 +2209,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
retval = usbtmc488_ioctl_trigger(file_data);
break;
 
+   case USBTMC488_IOCTL_WAIT_SRQ:
+   retval = usbtmc488_ioctl_wait_srq(file_data,
+ (__u32 __user *)arg);
+   break;
+
case USBTMC_IOCTL_CANCEL_IO:
retval = usbtmc_ioctl_cancel_io(file_data);
break;
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index d638c198c7a8..56c76a9680e5 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -96,6 +96,7 @@ struct usbtmc_message {
 #define USBTMC488_IOCTL_GOTO_LOCAL _IO(USBTMC_IOC_NR, 20)
 #define USBTMC488_IOCTL_LOCAL_LOCKOUT  _IO(USBTMC_IOC_NR, 21)
 #define USBTMC488_IOCTL_TRIGGER_IO(USBTMC_IOC_NR, 22)
+#define USBTMC488_IOCTL_WAIT_SRQ   _IOW(USBTMC_IOC_NR, 23, __u32)
 
 /* Cancel and cleanup asynchronous calls */
 #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 04/23] usb: usbtmc: Add ioctl USBTMC_IOCTL_WRITE_RESULT

2018-07-24 Thread Guido Kiener
ioctl USBTMC_IOCTL_WRITE_RESULT copies current out_transfer_size
to given __u32 pointer and returns current out_status of the last
(asnynchronous) USBTMC_IOCTL_WRITE call.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 25 +
 include/uapi/linux/usb/tmc.h |  1 +
 2 files changed, 26 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 0328f1beb32d..ea4e6f033c26 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -908,6 +908,26 @@ static ssize_t usbtmc_ioctl_generic_write(struct 
usbtmc_file_data *file_data,
return retval;
 }
 
+/*
+ * Get the generic write result
+ */
+static ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data,
+   void __user *arg)
+{
+   u32 transferred;
+   int retval;
+
+   spin_lock_irq(_data->err_lock);
+   transferred = file_data->out_transfer_size;
+   retval = file_data->out_status;
+   spin_unlock_irq(_data->err_lock);
+
+   if (put_user(transferred, (__u32 __user *)arg))
+   return -EFAULT;
+
+   return retval;
+}
+
 /*
  * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint.
  * @transfer_size: number of bytes to request from the device.
@@ -1763,6 +1783,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
(void __user *)arg);
break;
 
+   case USBTMC_IOCTL_WRITE_RESULT:
+   retval = usbtmc_ioctl_write_result(file_data,
+  (void __user *)arg);
+   break;
+
case USBTMC488_IOCTL_GET_CAPS:
retval = copy_to_user((void __user *)arg,
>usb488_caps,
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 56faeb3b5f0f..4a47b11e4a7e 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -86,6 +86,7 @@ struct usbtmc_message {
 #define USBTMC_IOCTL_EOM_ENABLE_IOW(USBTMC_IOC_NR, 11, __u8)
 #define USBTMC_IOCTL_CONFIG_TERMCHAR   _IOW(USBTMC_IOC_NR, 12, struct 
usbtmc_termchar)
 #define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct 
usbtmc_message)
+#define USBTMC_IOCTL_WRITE_RESULT  _IOWR(USBTMC_IOC_NR, 15, __u32)
 
 #define USBTMC488_IOCTL_GET_CAPS   _IOR(USBTMC_IOC_NR, 17, unsigned char)
 #define USBTMC488_IOCTL_READ_STB   _IOR(USBTMC_IOC_NR, 18, unsigned char)
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 05/23] usb: usbtmc: Add ioctl for vendor specific read

2018-07-24 Thread Guido Kiener
The USBTMC_IOCTL_READ call provides for generic synchronous and
asynchronous reads on bulk IN to implement vendor specific library
routines.

Depending on transfer_size the function submits one or more urbs (up
to 16) each with a size of up to 4kB.

The flag USBTMC_FLAG_IGNORE_TRAILER can be used when the transmission
size is already known. Then the function does not truncate the
transfer_size to a multiple of 4 kB, but does reserve extra space
to receive the final short or zero length packet. Note that the
instrument is allowed to send up to wMaxPacketSize - 1 bytes at the
end of a message to avoid sending a zero length packet.

With flag USBTMC_FLAG_ASYNC the ioctl is non blocking. When no
received data is available, the read function submits as many urbs as
needed to receive transfer_size bytes. However the number of flying
urbs (=4kB) is limited to 16 even with subsequent calls of this ioctl.

Returns -EAGAIN when non blocking and no data is received.
Signals EPOLLIN | EPOLLRDNORM when asynchronous urbs are ready to
be read.

In non blocking mode the usbtmc_message.message pointer may be NULL
and the ioctl just submits urbs to initiate receiving data. However if
data is already available due to a previous non blocking call the ioctl
will return -EINVAL when the message pointer is NULL.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 336 ++-
 include/uapi/linux/usb/tmc.h |   2 +
 2 files changed, 337 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index ea4e6f033c26..32b588eb0304 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -85,6 +85,9 @@ struct usbtmc_device_data {
u8 bTag_last_write; /* needed for abort */
u8 bTag_last_read;  /* needed for abort */
 
+   /* packet size of IN bulk */
+   u16wMaxPacketSize;
+
/* data for interrupt in endpoint handling */
u8 bNotify1;
u8 bNotify2;
@@ -140,6 +143,13 @@ struct usbtmc_file_data {
struct semaphore limit_write_sem;
u32 out_transfer_size;
int out_status;
+
+   /* data for generic_read */
+   u32 in_transfer_size;
+   int in_status;
+   int in_urbs_used;
+   struct usb_anchor in_anchor;
+   wait_queue_head_t wait_bulk_in;
 };
 
 /* Forward declarations */
@@ -188,6 +198,8 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
spin_lock_init(_data->err_lock);
sema_init(_data->limit_write_sem, MAX_URBS_IN_FLIGHT);
init_usb_anchor(_data->submitted);
+   init_usb_anchor(_data->in_anchor);
+   init_waitqueue_head(_data->wait_bulk_in);
 
data = usb_get_intfdata(intf);
/* Protect reference to data from file structure until release */
@@ -234,6 +246,9 @@ static int usbtmc_flush(struct file *file, fl_owner_t id)
usbtmc_draw_down(file_data);
 
spin_lock_irq(_data->err_lock);
+   file_data->in_status = 0;
+   file_data->in_transfer_size = 0;
+   file_data->in_urbs_used = 0;
file_data->out_status = 0;
file_data->out_transfer_size = 0;
spin_unlock_irq(_data->err_lock);
@@ -697,6 +712,307 @@ static struct urb *usbtmc_create_urb(void)
return urb;
 }
 
+static void usbtmc_read_bulk_cb(struct urb *urb)
+{
+   struct usbtmc_file_data *file_data = urb->context;
+   int status = urb->status;
+   unsigned long flags;
+
+   /* sync/async unlink faults aren't errors */
+   if (status) {
+   if (!(/* status == -ENOENT || */
+   status == -ECONNRESET ||
+   status == -EREMOTEIO || /* Short packet */
+   status == -ESHUTDOWN))
+   dev_err(_data->data->intf->dev,
+   "%s - nonzero read bulk status received: %d\n",
+   __func__, status);
+
+   spin_lock_irqsave(_data->err_lock, flags);
+   if (!file_data->in_status)
+   file_data->in_status = status;
+   spin_unlock_irqrestore(_data->err_lock, flags);
+   }
+
+   spin_lock_irqsave(_data->err_lock, flags);
+   file_data->in_transfer_size += urb->actual_length;
+   dev_dbg(_data->data->intf->dev,
+   "%s - total size: %u current: %d status: %d\n",
+   __func__, file_data->in_transfer_size,
+   urb->actual_length, status);
+   spin_unlock_irqrestore(_data->err_lock, flags);
+   usb_anchor_urb(urb, _data->in_anchor);
+
+   wake_up_interruptible(_data->wait_bulk_in);
+   wake_up_interruptible(_data->data->waitq);
+}
+
+static inline bool usbtmc_do_transfer(struct usbtmc_file_data *file_data)
+{
+   bool data_or_error;
+
+   spin_l

[PATCH v3 02/23] usb: usbtmc: Add ioctl for generic requests on control

2018-07-24 Thread Guido Kiener
Add USBTMC_IOCTL_CTRL_REQUEST to send arbitrary requests on the
control pipe.  Used by specific applications of IVI Foundation,
Inc. to implement VISA API functions: viUsbControlIn/Out.

The maximum length of control request is set to 4k.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c   | 84 
 include/uapi/linux/usb/tmc.h | 15 +++
 2 files changed, 99 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 83ffa5a14c3d..3b3b4284d04e 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 Greg Kroah-Hartman 
+ * Copyright (C) 2018 IVI Foundation, Inc.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -36,6 +37,9 @@
 /* Default USB timeout (in milliseconds) */
 #define USBTMC_TIMEOUT 5000
 
+/* I/O buffer size used in generic read/write functions */
+#define USBTMC_BUFSIZE (4096)
+
 /*
  * Maximum number of read cycles to empty bulk in endpoint during CLEAR and
  * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short
@@ -129,6 +133,21 @@ struct usbtmc_file_data {
 /* Forward declarations */
 static struct usb_driver usbtmc_driver;
 
+#ifdef CONFIG_COMPAT
+static void __user *u64_to_uptr(u64 value)
+{
+   if (in_compat_syscall())
+   return compat_ptr(value);
+   else
+   return (void __user *)(unsigned long)value;
+}
+#else
+static inline void __user *u64_to_uptr(u64 value)
+{
+   return (void __user *)(unsigned long)value;
+}
+#endif /* CONFIG_COMPAT */
+
 static void usbtmc_delete(struct kref *kref)
 {
struct usbtmc_device_data *data = to_usbtmc_data(kref);
@@ -1250,6 +1269,67 @@ static int usbtmc_ioctl_indicator_pulse(struct 
usbtmc_device_data *data)
return rv;
 }
 
+static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
+   void __user *arg)
+{
+   struct device *dev = >intf->dev;
+   struct usbtmc_ctrlrequest request;
+   u8 *buffer = NULL;
+   int rv;
+   unsigned long res;
+
+   res = copy_from_user(, arg, sizeof(struct usbtmc_ctrlrequest));
+   if (res)
+   return -EFAULT;
+
+   buffer = kmalloc(request.req.wLength, GFP_KERNEL);
+   if (!buffer)
+   return -ENOMEM;
+
+   if (request.req.wLength > USBTMC_BUFSIZE)
+   return -EMSGSIZE;
+
+   if (request.req.wLength) {
+   buffer = kmalloc(request.req.wLength, GFP_KERNEL);
+   if (!buffer)
+   return -ENOMEM;
+
+   if ((request.req.bRequestType & USB_DIR_IN) == 0) {
+   /* Send control data to device */
+   res = copy_from_user(buffer, u64_to_uptr(request.data),
+request.req.wLength);
+   if (res) {
+   rv = -EFAULT;
+   goto exit;
+   }
+   }
+   }
+
+   rv = usb_control_msg(data->usb_dev,
+   usb_rcvctrlpipe(data->usb_dev, 0),
+   request.req.bRequest,
+   request.req.bRequestType,
+   request.req.wValue,
+   request.req.wIndex,
+   buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT);
+
+   if (rv < 0) {
+   dev_err(dev, "%s failed %d\n", __func__, rv);
+   goto exit;
+   }
+
+   if (rv && (request.req.bRequestType & USB_DIR_IN)) {
+   /* Read control data from device */
+   res = copy_to_user(u64_to_uptr(request.data), buffer, rv);
+   if (res)
+   rv = -EFAULT;
+   }
+
+ exit:
+   kfree(buffer);
+   return rv;
+}
+
 /*
  * Get the usb timeout value
  */
@@ -1366,6 +1446,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
retval = usbtmc_ioctl_abort_bulk_in(data);
break;
 
+   case USBTMC_IOCTL_CTRL_REQUEST:
+   retval = usbtmc_ioctl_request(data, (void __user *)arg);
+   break;
+
case USBTMC_IOCTL_GET_TIMEOUT:
retval = usbtmc_ioctl_get_timeout(file_data,
  (void __user *)arg);
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 729af2f861a4..95533118ac34 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -4,6 +4,7 @@
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 Greg Kroah-Hartman 
  * Copyright (C) 2015 Dave Penkler 
+ * Copyright (C) 2018 IVI Foundation, Inc.
  *
  * This file holds USB constants defined by the USB Dev

[PATCH v2 29/29] usb: usbtmc: Remove sysfs group TermChar and auto_abort

2018-07-18 Thread Guido Kiener
As all the properties of the usbtmc driver can now be
controlled on a per file descriptor basis by ioctl functions
the sysfs interface is of limited use.
We are not aware about applications that are using the sysfs
parameter TermChar, TermCharEnabled or auto_abort.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 .../ABI/stable/sysfs-driver-usb-usbtmc| 35 
 drivers/usb/class/usbtmc.c| 84 +--
 2 files changed, 3 insertions(+), 116 deletions(-)

diff --git a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc 
b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
index e960cd027e1e..a9e123ba32cd 100644
--- a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
+++ b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
@@ -25,38 +25,3 @@ Description:
4.2.2.
 
The files are read only.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/TermChar
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file is the TermChar value to be sent to the USB TMC
-   device as described by the document, "Universal Serial Bus Test
-   and Measurement Class Specification
-   (USBTMC) Revision 1.0" as published by the USB-IF.
-
-   Note that the TermCharEnabled file determines if this value is
-   sent to the device or not.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/TermCharEnabled
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file determines if the TermChar is to be sent to the
-   device on every transaction or not.  For more details about
-   this, please see the document, "Universal Serial Bus Test and
-   Measurement Class Specification (USBTMC) Revision 1.0" as
-   published by the USB-IF.
-
-
-What:  /sys/bus/usb/drivers/usbtmc/*/auto_abort
-Date:  August 2008
-Contact:   Greg Kroah-Hartman 
-Description:
-   This file determines if the transaction of the USB TMC
-   device is to be automatically aborted if there is any error.
-   For more details about this, please see the document,
-   "Universal Serial Bus Test and Measurement Class Specification
-   (USBTMC) Revision 1.0" as published by the USB-IF.
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 821f3e47b6b3..0ff4dd0a4f88 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -102,11 +102,6 @@ struct usbtmc_device_data {
/* coalesced usb488_caps from usbtmc_dev_capabilities */
__u8 usb488_caps;
 
-   /* attributes from the USB TMC spec for this device */
-   u8 TermChar;
-   bool TermCharEnabled;
-   bool auto_abort;
-
bool zombie; /* fd of disconnected device */
 
struct usbtmc_dev_capabilities  capabilities;
@@ -216,11 +211,10 @@ static int usbtmc_open(struct inode *inode, struct file 
*filp)
 
atomic_set(_data->closing, 0);
 
-   /* copy default values from device settings */
file_data->timeout = USBTMC_TIMEOUT;
-   file_data->term_char = data->TermChar;
-   file_data->term_char_enabled = data->TermCharEnabled;
-   file_data->auto_abort = data->auto_abort;
+   file_data->term_char = '\n';
+   file_data->term_char_enabled = 0;
+   file_data->auto_abort = 0;
file_data->eom_val = 1;
 
INIT_LIST_HEAD(_data->file_elem);
@@ -1919,72 +1913,6 @@ static const struct attribute_group capability_attr_grp 
= {
.attrs = capability_attrs,
 };
 
-static ssize_t TermChar_show(struct device *dev,
-struct device_attribute *attr, char *buf)
-{
-   struct usb_interface *intf = to_usb_interface(dev);
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);
-
-   return sprintf(buf, "%c\n", data->TermChar);
-}
-
-static ssize_t TermChar_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
-   struct usb_interface *intf = to_usb_interface(dev);
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);
-
-   if (count < 1)
-   return -EINVAL;
-   data->TermChar = buf[0];
-   return count;
-}
-static DEVICE_ATTR_RW(TermChar);
-
-#define data_attribute(name)   \
-static ssize_t name##_show(struct device *dev, \
-  struct device_attribute *attr, char *buf)\
-{  \
-   struct usb_interface *intf = to_usb_interface(dev); \
-   struct usbtmc_device_data *data = usb_get_intfdata(intf);   \
-   

[PATCH v2 26/29] usb: usbtmc: Remove redundant code

2018-07-18 Thread Guido Kiener
Remove redundant code and fix debug messages.

Signed-off-by: Guido Kiener 
Reviewed-by: Steve Bayless 
---
 drivers/usb/class/usbtmc.c | 25 -
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index ffc89a7d7dfa..dc4f7706b4c2 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1813,12 +1813,9 @@ static int usbtmc_ioctl_clear_out_halt(struct 
usbtmc_device_data *data)
rv = usb_clear_halt(data->usb_dev,
usb_sndbulkpipe(data->usb_dev, data->bulk_out));
 
-   if (rv < 0) {
-   dev_err(>usb_dev->dev, "usb_control_msg returned %d\n",
-   rv);
-   return rv;
-   }
-   return 0;
+   if (rv < 0)
+   dev_err(>usb_dev->dev, "%s returned %d\n", __func__, rv);
+   return rv;
 }
 
 static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
@@ -1828,12 +1825,9 @@ static int usbtmc_ioctl_clear_in_halt(struct 
usbtmc_device_data *data)
rv = usb_clear_halt(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
 
-   if (rv < 0) {
-   dev_err(>usb_dev->dev, "usb_control_msg returned %d\n",
-   rv);
-   return rv;
-   }
-   return 0;
+   if (rv < 0)
+   dev_err(>usb_dev->dev, "%s returned %d\n", __func__, rv);
+   return rv;
 }
 
 static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data)
@@ -2337,11 +2331,8 @@ static long usbtmc_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
break;
 
case USBTMC488_IOCTL_GET_CAPS:
-   retval = copy_to_user((void __user *)arg,
-   >usb488_caps,
-   sizeof(data->usb488_caps));
-   if (retval)
-   retval = -EFAULT;
+   retval = put_user(data->usb488_caps,
+ (unsigned char __user *)arg);
break;
 
case USBTMC488_IOCTL_READ_STB:
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


  1   2   >