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.

Signed-off-by: Guido Kiener <guido.kie...@rohde-schwarz.com>
Reviewed-by: Steve Bayless <steve_bayl...@keysight.com>
---
 drivers/usb/class/usbtmc.c   | 61 ++++++++++++++++++++++++++++++++++++
 include/uapi/linux/usb/tmc.h | 15 +++++++++
 2 files changed, 76 insertions(+)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 152e2daa9644..00c2e51a23a7 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 <gre...@suse.de>
+ * Copyright (C) 2018, IVI Foundation, Inc.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -1263,6 +1264,62 @@ 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 = &data->intf->dev;
+       struct usbtmc_ctrlrequest request;
+       u8 *buffer = NULL;
+       int rv;
+       unsigned long res;
+
+       res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest));
+       if (res)
+               return -EFAULT;
+
+       buffer = kmalloc(min_t(u16, 256, request.req.wLength), GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       if ((request.req.bRequestType & USB_DIR_IN) == 0
+           && request.req.wLength) {
+               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 ((request.req.bRequestType & USB_DIR_IN)) {
+               if (rv > request.req.wLength) {
+                       dev_warn(dev, "%s returned too much data: %d\n",
+                                __func__, rv);
+                       rv = request.req.wLength;
+               }
+
+               res = copy_to_user(request.data, buffer, rv);
+               if (res)
+                       rv = -EFAULT;
+       }
+
+ exit:
+       kfree(buffer);
+       return rv;
+}
+
 /*
  * Get the usb timeout value
  */
@@ -1379,6 +1436,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 60369825691c..c1acec9ad834 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 <gre...@suse.de>
  * Copyright (C) 2015 Dave Penkler <dpenk...@gmail.com>
+ * 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_LOCKOUT                        162
 
+struct usbtmc_request {
+       __u8 bRequestType;
+       __u8 bRequest;
+       __u16 wValue;
+       __u16 wIndex;
+       __u16 wLength;
+} __attribute__ ((packed));
+
+struct usbtmc_ctrlrequest {
+       struct usbtmc_request req;
+       void __user *data;
+} __attribute__ ((packed));
+
 struct usbtmc_termchar {
        __u8 term_char;
        __u8 term_char_enabled; // bool
@@ -53,6 +67,7 @@ struct usbtmc_termchar {
 #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_CTRL_REQUEST      _IOWR(USBTMC_IOC_NR, 8, struct 
usbtmc_ctrlrequest)
 #define USBTMC_IOCTL_GET_TIMEOUT       _IOR(USBTMC_IOC_NR, 9, unsigned int)
 #define USBTMC_IOCTL_SET_TIMEOUT       _IOW(USBTMC_IOC_NR, 10, unsigned int)
 #define USBTMC_IOCTL_EOM_ENABLE                _IOW(USBTMC_IOC_NR, 11, __u8)
-- 
2.17.0

--
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

Reply via email to