diff mbox

[10/12] usb: usbtmc: Add test functions to set HALT Feature (Stall)

Message ID 20180517170336.8426-11-guido@kiener-muenchen.de (mailing list archive)
State New, archived
Headers show

Commit Message

Guido Kiener May 17, 2018, 5:03 p.m. UTC
The ioctls USBTMC_IOCTL_SET_OUT_HALT or USBTMC_IOCTL_SET_IN_HALT
send a SET_FEATURE(HALT) request to the corresponding OUT or IN pipe.

Useful for testing devices and client applications: The ioctls force
the device to simulate the error state at the specified pipe.

Signed-off-by: Guido Kiener <guido.kiener@rohde-schwarz.com>
Reviewed-by: Steve Bayless <steve_bayless@keysight.com>
---
 drivers/usb/class/usbtmc.c   | 78 ++++++++++++++++++++++++++++++------
 include/uapi/linux/usb/tmc.h |  4 ++
 2 files changed, 70 insertions(+), 12 deletions(-)

Comments

Greg KH May 18, 2018, 1:40 p.m. UTC | #1
On Thu, May 17, 2018 at 07:03:34PM +0200, Guido Kiener wrote:
> The ioctls USBTMC_IOCTL_SET_OUT_HALT or USBTMC_IOCTL_SET_IN_HALT
> send a SET_FEATURE(HALT) request to the corresponding OUT or IN pipe.
> 
> Useful for testing devices and client applications: The ioctls force
> the device to simulate the error state at the specified pipe.

Nice for testing, yes, but is this really needed in the generic kernel
driver?  Shouldn't you be testing your device with the correct usbtest
driver instead?

thanks,

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

Patch

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 165b707991f3..8b464598bee5 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1754,34 +1754,80 @@  static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
 	return rv;
 }
 
+/*
+ * set pipe in halt state (stalled)
+ * Needed for test purpose or workarounds.
+ */
+static int usbtmc_set_halt(struct usb_device *dev, int pipe)
+{
+	int rv;
+	int endp = usb_pipeendpoint(pipe);
+
+	if (usb_pipein(pipe))
+		endp |= USB_DIR_IN;
+
+	rv = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			     USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT,
+			     USB_ENDPOINT_HALT, endp, NULL, 0,
+			     USB_CTRL_SET_TIMEOUT);
+
+	return rv;
+}
+
+static int usbtmc_ioctl_set_out_halt(struct usbtmc_device_data *data)
+{
+	int rv;
+
+	dev_dbg(&data->intf->dev, "%s - called\n", __func__);
+
+	rv = usbtmc_set_halt(data->usb_dev,
+			     usb_sndbulkpipe(data->usb_dev, data->bulk_out));
+
+	if (rv < 0)
+		dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv);
+	return rv;
+}
+
+static int usbtmc_ioctl_set_in_halt(struct usbtmc_device_data *data)
+{
+	int rv;
+
+	dev_dbg(&data->intf->dev, "%s - called\n", __func__);
+
+	rv = usbtmc_set_halt(data->usb_dev,
+			     usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
+
+	if (rv < 0)
+		dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv);
+	return rv;
+}
+
 static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data)
 {
 	int rv;
 
+	dev_dbg(&data->intf->dev, "%s - called\n", __func__);
+
 	rv = usb_clear_halt(data->usb_dev,
 			    usb_sndbulkpipe(data->usb_dev, data->bulk_out));
 
-	if (rv < 0) {
-		dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
-			rv);
-		return rv;
-	}
-	return 0;
+	if (rv < 0)
+		dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv);
+	return rv;
 }
 
 static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
 {
 	int rv;
 
+	dev_dbg(&data->intf->dev, "%s - called\n", __func__);
+
 	rv = usb_clear_halt(data->usb_dev,
 			    usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
 
-	if (rv < 0) {
-		dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
-			rv);
-		return rv;
-	}
-	return 0;
+	if (rv < 0)
+		dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv);
+	return rv;
 }
 
 static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data)
@@ -2241,6 +2287,14 @@  static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 			file_data->auto_abort = !!tmp_byte;
 		break;
 
+	case USBTMC_IOCTL_SET_OUT_HALT:
+		retval = usbtmc_ioctl_set_out_halt(data);
+		break;
+
+	case USBTMC_IOCTL_SET_IN_HALT:
+		retval = usbtmc_ioctl_set_in_halt(data);
+		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 e3bdfc1935ed..886fabf5dfea 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -101,6 +101,10 @@  struct usbtmc_message {
 #define USBTMC_IOCTL_MSG_IN_ATTR	_IOR(USBTMC_IOC_NR, 24, __u8)
 #define USBTMC_IOCTL_AUTO_ABORT		_IOW(USBTMC_IOC_NR, 25, __u8)
 
+/* For test purpose only */
+#define USBTMC_IOCTL_SET_OUT_HALT	_IO(USBTMC_IOC_NR, 30)
+#define USBTMC_IOCTL_SET_IN_HALT	_IO(USBTMC_IOC_NR, 31)
+
 /* 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)