usb: usbtmc: Add ioctl USBTMC488_IOCTL_WAIT_SRQ
authorGuido Kiener <guido@kiener-muenchen.de>
Wed, 12 Sep 2018 08:50:58 +0000 (10:50 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 20 Sep 2018 11:04:02 +0000 (13:04 +0200)
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 <guido.kiener@rohde-schwarz.com>
Reviewed-by: Steve Bayless <steve_bayless@keysight.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/class/usbtmc.c
include/uapi/linux/usb/tmc.h

index e4c80b44b55a8a011dd0b6029a497b041e34d2a0..e177bac777f486e9e331e7de56c8b090eee81b7f 100644 (file)
@@ -130,6 +130,7 @@ struct usbtmc_file_data {
        u32            timeout;
        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(&data->io_mutex);
        file_data->data = data;
 
+       atomic_set(&file_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(&file_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 = &data->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(&data->io_mutex);
+
+       rv = wait_event_interruptible_timeout(
+                       data->waitq,
+                       atomic_read(&file_data->srq_asserted) != 0 ||
+                       atomic_read(&file_data->closing),
+                       expire);
+
+       mutex_lock(&data->io_mutex);
+
+       /* Note! disconnect or close could be called in the meantime */
+       if (atomic_read(&file_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;
index 5a69d9dc967db131a7a045bb6c422b10dd566f04..e228ad7fc14156011ad07cedc18d9f857862b550 100644 (file)
@@ -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)