summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido Kiener <guido@kiener-muenchen.de>2018-07-18 10:45:36 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-07-21 08:22:15 +0200
commit048c6d88a0214757926f264823829e79154fcd4f (patch)
treef2ed756ff671eb19c82bcbe731e3d6ca6885de50
parentusb: usbtmc: use consistent timeout error (diff)
downloadlinux-048c6d88a0214757926f264823829e79154fcd4f.tar.xz
linux-048c6d88a0214757926f264823829e79154fcd4f.zip
usb: usbtmc: Add ioctls to set/get usb timeout
Add ioctls USBTMC_IOCTL_GET_TIMEOUT / USBTMC_IOCTL_SET_TIMEOUT to get/set I/O timeout for specific file handle. Different operations on an instrument can take different lengths of time thus it is important to be able to set the timeout slightly longer than the expected duration of each operation to optimise the responsiveness of the application. As the instrument may be shared by multiple applications the timeout should be settable on a per file descriptor basis. Tested-by: Dave Penkler <dpenkler@gmail.com> Reviewed-by: Steve Bayless <steve_bayless@keysight.com> Signed-off-by: Dave Penkler <dpenkler@gmail.com> Signed-off-by: Guido Kiener <guido.kiener@rohde-schwarz.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/class/usbtmc.c65
-rw-r--r--include/uapi/linux/usb/tmc.h4
2 files changed, 63 insertions, 6 deletions
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 243e8446b8dd..36d740c4c6fb 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -30,6 +30,8 @@
*/
#define USBTMC_SIZE_IOBUFFER 2048
+/* Minimum USB timeout (in milliseconds) */
+#define USBTMC_MIN_TIMEOUT 100
/* Default USB timeout (in milliseconds) */
#define USBTMC_TIMEOUT 5000
@@ -115,6 +117,7 @@ struct usbtmc_file_data {
struct usbtmc_device_data *data;
struct list_head file_elem;
+ u32 timeout;
u8 srq_byte;
atomic_t srq_asserted;
};
@@ -153,6 +156,8 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
mutex_lock(&data->io_mutex);
file_data->data = data;
+ file_data->timeout = USBTMC_TIMEOUT;
+
INIT_LIST_HEAD(&file_data->file_elem);
spin_lock_irq(&data->dev_lock);
list_add_tail(&file_data->file_elem, &data->file_list);
@@ -460,7 +465,7 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,
rv = wait_event_interruptible_timeout(
data->waitq,
atomic_read(&data->iin_data_valid) != 0,
- USBTMC_TIMEOUT);
+ file_data->timeout);
if (rv < 0) {
dev_dbg(dev, "wait interrupted %d\n", rv);
goto exit;
@@ -560,8 +565,10 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
*
* Also updates bTag_last_write.
*/
-static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t transfer_size)
+static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data,
+ size_t transfer_size)
{
+ struct usbtmc_device_data *data = file_data->data;
int retval;
u8 *buffer;
int actual;
@@ -590,7 +597,8 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t
retval = usb_bulk_msg(data->usb_dev,
usb_sndbulkpipe(data->usb_dev,
data->bulk_out),
- buffer, USBTMC_HEADER_SIZE, &actual, USBTMC_TIMEOUT);
+ buffer, USBTMC_HEADER_SIZE,
+ &actual, file_data->timeout);
/* Store bTag (in case we need to abort) */
data->bTag_last_write = data->bTag;
@@ -640,7 +648,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
dev_dbg(dev, "usb_bulk_msg_in: count(%zu)\n", count);
- retval = send_request_dev_dep_msg_in(data, count);
+ retval = send_request_dev_dep_msg_in(file_data, count);
if (retval < 0) {
if (data->auto_abort)
@@ -659,7 +667,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
usb_rcvbulkpipe(data->usb_dev,
data->bulk_in),
buffer, USBTMC_SIZE_IOBUFFER, &actual,
- USBTMC_TIMEOUT);
+ file_data->timeout);
dev_dbg(dev, "usb_bulk_msg: retval(%u), done(%zu), remaining(%zu), actual(%d)\n", retval, done, remaining, actual);
@@ -832,7 +840,7 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
usb_sndbulkpipe(data->usb_dev,
data->bulk_out),
buffer, n_bytes,
- &actual, USBTMC_TIMEOUT);
+ &actual, file_data->timeout);
if (retval != 0)
break;
n_bytes -= actual;
@@ -1189,6 +1197,41 @@ exit:
return rv;
}
+/*
+ * Get the usb timeout value
+ */
+static int usbtmc_ioctl_get_timeout(struct usbtmc_file_data *file_data,
+ void __user *arg)
+{
+ u32 timeout;
+
+ timeout = file_data->timeout;
+
+ return put_user(timeout, (__u32 __user *)arg);
+}
+
+/*
+ * Set the usb timeout value
+ */
+static int usbtmc_ioctl_set_timeout(struct usbtmc_file_data *file_data,
+ void __user *arg)
+{
+ u32 timeout;
+
+ if (get_user(timeout, (__u32 __user *)arg))
+ return -EFAULT;
+
+ /* Note that timeout = 0 means
+ * MAX_SCHEDULE_TIMEOUT in usb_control_msg
+ */
+ if (timeout < USBTMC_MIN_TIMEOUT)
+ return -EINVAL;
+
+ file_data->timeout = timeout;
+
+ return 0;
+}
+
static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct usbtmc_file_data *file_data;
@@ -1229,6 +1272,16 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
retval = usbtmc_ioctl_abort_bulk_in(data);
break;
+ case USBTMC_IOCTL_GET_TIMEOUT:
+ retval = usbtmc_ioctl_get_timeout(file_data,
+ (void __user *)arg);
+ break;
+
+ case USBTMC_IOCTL_SET_TIMEOUT:
+ retval = usbtmc_ioctl_set_timeout(file_data,
+ (void __user *)arg);
+ break;
+
case USBTMC488_IOCTL_GET_CAPS:
retval = copy_to_user((void __user *)arg,
&data->usb488_caps,
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 03f6adc8f35b..a89ffc33532e 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -16,6 +16,8 @@
#ifndef __LINUX_USB_TMC_H
#define __LINUX_USB_TMC_H
+#include <linux/types.h> /* __u8 etc */
+
/* USB TMC status values */
#define USBTMC_STATUS_SUCCESS 0x01
#define USBTMC_STATUS_PENDING 0x02
@@ -46,6 +48,8 @@
#define USBTMC_IOCTL_ABORT_BULK_IN _IO(USBTMC_IOC_NR, 4)
#define USBTMC_IOCTL_CLEAR_OUT_HALT _IO(USBTMC_IOC_NR, 6)
#define USBTMC_IOCTL_CLEAR_IN_HALT _IO(USBTMC_IOC_NR, 7)
+#define USBTMC_IOCTL_GET_TIMEOUT _IOR(USBTMC_IOC_NR, 9, __u32)
+#define USBTMC_IOCTL_SET_TIMEOUT _IOW(USBTMC_IOC_NR, 10, __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)
#define USBTMC488_IOCTL_REN_CONTROL _IOW(USBTMC_IOC_NR, 19, unsigned char)