summaryrefslogtreecommitdiffstats
path: root/drivers/usb/misc
diff options
context:
space:
mode:
authorMathias Nyman <mathias.nyman@linux.intel.com>2017-12-15 15:11:38 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-12-15 20:45:44 +0100
commitcc2e60dfa6ba4ff2c054bca932b9afc8702a2f9a (patch)
treeebf01da5b4c5a41e932088452c313d713190f186 /drivers/usb/misc
parent886ee36e7205a7b850e2e5c2298a479f581f9b3b (diff)
downloadlinux-stable-cc2e60dfa6ba4ff2c054bca932b9afc8702a2f9a.tar.gz
linux-stable-cc2e60dfa6ba4ff2c054bca932b9afc8702a2f9a.tar.bz2
linux-stable-cc2e60dfa6ba4ff2c054bca932b9afc8702a2f9a.zip
usb: usbtest: Add TEST 29, toggle sync, Clear toggle between bulk writes
Clear Feature Endpoint Halt should reset the data toggle even if the endpoint isn't halted. Host should manage to clear the host side data toggle to keep in sync with the device. Test by sending a "3 data packet URB" before and after clearing the halt. this should create a toggle sequence with two consecutive DATA0 packets. A successful test sequence looks like this ClearFeature(ENDPOINT_HALT) - initial toggle clear DATA0 (max packet sized) DATA1 (max packet sized) DATA0 (zero length packet) ClearFeature(ENDPOINT_HALT) - resets toggle DATA0 (max packet sized), if clear halt fails then toggle is DATA1 DATA1 (max packet sized) DATA0 (zero length packet) Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/misc')
-rw-r--r--drivers/usb/misc/usbtest.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index aedc9a7f149e..90028ef541e3 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -1710,6 +1710,35 @@ static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)
return 0;
}
+static int test_toggle_sync(struct usbtest_dev *tdev, int ep, struct urb *urb)
+{
+ int retval;
+
+ /* clear initial data toggle to DATA0 */
+ retval = usb_clear_halt(urb->dev, urb->pipe);
+ if (retval < 0) {
+ ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval);
+ return retval;
+ }
+
+ /* transfer 3 data packets, should be DATA0, DATA1, DATA0 */
+ retval = simple_io(tdev, urb, 1, 0, 0, __func__);
+ if (retval != 0)
+ return -EINVAL;
+
+ /* clear halt resets device side data toggle, host should react to it */
+ retval = usb_clear_halt(urb->dev, urb->pipe);
+ if (retval < 0) {
+ ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval);
+ return retval;
+ }
+
+ /* host should use DATA0 again after clear halt */
+ retval = simple_io(tdev, urb, 1, 0, 0, __func__);
+
+ return retval;
+}
+
static int halt_simple(struct usbtest_dev *dev)
{
int ep;
@@ -1742,6 +1771,33 @@ done:
return retval;
}
+static int toggle_sync_simple(struct usbtest_dev *dev)
+{
+ int ep;
+ int retval = 0;
+ struct urb *urb;
+ struct usb_device *udev = testdev_to_usbdev(dev);
+ unsigned maxp = get_maxpacket(udev, dev->out_pipe);
+
+ /*
+ * Create a URB that causes a transfer of uneven amount of data packets
+ * This way the clear toggle has an impact on the data toggle sequence.
+ * Use 2 maxpacket length packets and one zero packet.
+ */
+ urb = simple_alloc_urb(udev, 0, 2 * maxp, 0);
+ if (urb == NULL)
+ return -ENOMEM;
+
+ urb->transfer_flags |= URB_ZERO_PACKET;
+
+ ep = usb_pipeendpoint(dev->out_pipe);
+ urb->pipe = dev->out_pipe;
+ retval = test_toggle_sync(dev, ep, urb);
+
+ simple_free_urb(urb);
+ return retval;
+}
+
/*-------------------------------------------------------------------------*/
/* Control OUT tests use the vendor control requests from Intel's
@@ -2524,6 +2580,20 @@ usbtest_do_ioctl(struct usb_interface *intf, struct usbtest_param_32 *param)
retval = test_queue(dev, param,
dev->in_pipe, NULL, 0);
break;
+ /* Test data Toggle/seq_nr clear between bulk out transfers */
+ case 29:
+ if (dev->out_pipe == 0)
+ break;
+ retval = 0;
+ dev_info(&intf->dev, "TEST 29: Clear toggle between bulk writes %d times\n",
+ param->iterations);
+ for (i = param->iterations; retval == 0 && i > 0; --i)
+ retval = toggle_sync_simple(dev);
+
+ if (retval)
+ ERROR(dev, "toggle sync failed, iterations left %d\n",
+ i);
+ break;
}
return retval;
}