Two simple test cases for interrupt endpoints are added to the usbtest.c file.
These are simple non-queued interrupt IN and interrupt OUT transfers. Currently,
only gadget zero is capable of executing the interrupt EP test cases. However,
extending the same to other gadgets is extremely simple and can be done
on-demand.

The two new tests added are
  - Test 25: To verify Interrupt OUT transfer
  - Test 26: To verify Interrupt IN transfer

Since the default value of wMaxPacketSize is set as 1024, so interrupt
IN transfers must be specified with the size parameter = multiple of
1024. Otherwise the default value (512) in the usbtest application fails
the transfer. See [RUN 4] for sample logs

The application logs (usbtest) and corresponding kernel logs are as
following:
---
        [Run 1]
        ./testusb -a -c 10 -s 2048 -t 26 -v 511
        Jul 17 10:31:13 dlhl1014 kernel: [72056.950910] usbtest 7-1:3.0: TEST
        26: read 2048 bytes 10 times

        [Run 2]
        ./testusb -a -c 10 -s 1024 -t 25 -v 511
        Jul 17 10:31:29 dlhl1014 kernel: [72072.834853] usbtest 7-1:3.0: TEST
        25: write 1024 bytes 10 times

        [Run 3]
        ./testusb -a -c 10 -s 1098 -t 25 -v 511
        Jul 17 10:31:39 dlhl1014 kernel: [72082.322219] usbtest 7-1:3.0: TEST
        25: write 1098 bytes 10 times

        [Run 4 - Failure case scenario]
        ./testusb -a  -t 26
        unknown speed   /dev/bus/usb/007/004    0
        /dev/bus/usb/007/004 test 26 --> 75 (Value too large for defined data
        type)

        Jul 17 11:11:30 dlhl1014 kernel: [74473.347219] usbtest 7-1:3.0: TEST
        26: read 512 bytes 1000 times
        Jul 17 11:11:30 dlhl1014 kernel: [74473.348959] usb 7-1: test26 failed,
        iterations left 999, status -75 (not 0)
---

This code has been tested only with gadget zero and care has been taken so as to
not break the existing functionality. However, if anyone can test with other
gadgets then that would be great!

Signed-off-by: Amit Virdi <amit.vi...@st.com>
---
 drivers/usb/misc/usbtest.c | 113 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 98 insertions(+), 15 deletions(-)

diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 829f446064ea..90e6644dc886 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -54,6 +54,7 @@ struct usbtest_info {
        unsigned                autoconf:1;
        unsigned                ctrl_out:1;
        unsigned                iso:1;          /* try iso in/out */
+       unsigned                intr:1;         /* try interrupt in/out */
        int                     alt;
 };
 
@@ -70,7 +71,10 @@ struct usbtest_dev {
        int                     out_pipe;
        int                     in_iso_pipe;
        int                     out_iso_pipe;
+       int                     in_int_pipe;
+       int                     out_int_pipe;
        struct usb_endpoint_descriptor  *iso_in, *iso_out;
+       struct usb_endpoint_descriptor  *int_in, *int_out;
        struct mutex            lock;
 
 #define TBUF_SIZE      256
@@ -101,6 +105,7 @@ get_endpoints(struct usbtest_dev *dev, struct usb_interface 
*intf)
        struct usb_host_interface       *alt;
        struct usb_host_endpoint        *in, *out;
        struct usb_host_endpoint        *iso_in, *iso_out;
+       struct usb_host_endpoint        *int_in, *int_out;
        struct usb_device               *udev;
 
        for (tmp = 0; tmp < intf->num_altsetting; tmp++) {
@@ -108,6 +113,7 @@ get_endpoints(struct usbtest_dev *dev, struct usb_interface 
*intf)
 
                in = out = NULL;
                iso_in = iso_out = NULL;
+               int_in = int_out = NULL;
                alt = intf->altsetting + tmp;
 
                if (override_alt >= 0 &&
@@ -124,6 +130,9 @@ get_endpoints(struct usbtest_dev *dev, struct usb_interface 
*intf)
                        switch (usb_endpoint_type(&e->desc)) {
                        case USB_ENDPOINT_XFER_BULK:
                                break;
+                       case USB_ENDPOINT_XFER_INT:
+                               if (dev->info->intr)
+                                       goto try_intr;
                        case USB_ENDPOINT_XFER_ISOC:
                                if (dev->info->iso)
                                        goto try_iso;
@@ -139,6 +148,15 @@ get_endpoints(struct usbtest_dev *dev, struct 
usb_interface *intf)
                                        out = e;
                        }
                        continue;
+try_intr:
+                       if (usb_endpoint_dir_in(&e->desc)) {
+                               if (!int_in)
+                                       int_in = e;
+                       } else {
+                               if (!int_out)
+                                       int_out = e;
+                       }
+                       continue;
 try_iso:
                        if (usb_endpoint_dir_in(&e->desc)) {
                                if (!iso_in)
@@ -148,7 +166,7 @@ try_iso:
                                        iso_out = e;
                        }
                }
-               if ((in && out)  ||  iso_in || iso_out)
+               if ((in && out)  ||  iso_in || iso_out || int_in || int_out)
                        goto found;
        }
        return -EINVAL;
@@ -183,6 +201,20 @@ found:
                                iso_out->desc.bEndpointAddress
                                        & USB_ENDPOINT_NUMBER_MASK);
        }
+
+       if (int_in) {
+               dev->int_in = &int_in->desc;
+               dev->in_int_pipe = usb_rcvintpipe(udev,
+                               int_in->desc.bEndpointAddress
+                                       & USB_ENDPOINT_NUMBER_MASK);
+       }
+
+       if (int_out) {
+               dev->int_out = &int_out->desc;
+               dev->out_int_pipe = usb_sndintpipe(udev,
+                               int_out->desc.bEndpointAddress
+                                       & USB_ENDPOINT_NUMBER_MASK);
+       }
        return 0;
 }
 
@@ -205,14 +237,22 @@ static struct urb *usbtest_alloc_urb(
        int                     pipe,
        unsigned long           bytes,
        unsigned                transfer_flags,
-       unsigned                offset)
+       unsigned                offset,
+       u8                      bInterval)
 {
        struct urb              *urb;
 
        urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!urb)
                return urb;
-       usb_fill_bulk_urb(urb, udev, pipe, NULL, bytes, simple_callback, NULL);
+
+       if (bInterval)
+               usb_fill_int_urb(urb, udev, pipe, NULL, bytes, simple_callback,
+                               NULL, bInterval);
+       else
+               usb_fill_bulk_urb(urb, udev, pipe, NULL, bytes, simple_callback,
+                               NULL);
+
        urb->interval = (udev->speed == USB_SPEED_HIGH)
                        ? (INTERRUPT_RATE << 3)
                        : INTERRUPT_RATE;
@@ -251,9 +291,11 @@ static struct urb *usbtest_alloc_urb(
 static struct urb *simple_alloc_urb(
        struct usb_device       *udev,
        int                     pipe,
-       unsigned long           bytes)
+       unsigned long           bytes,
+       u8                      bInterval)
 {
-       return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0);
+       return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0,
+                       bInterval);
 }
 
 static unsigned pattern;
@@ -1255,7 +1297,7 @@ test_ctrl_queue(struct usbtest_dev *dev, struct 
usbtest_param *param)
                        goto cleanup;
                }
                req.wLength = cpu_to_le16(len);
-               urb[i] = u = simple_alloc_urb(udev, pipe, len);
+               urb[i] = u = simple_alloc_urb(udev, pipe, len, 0);
                if (!u)
                        goto cleanup;
 
@@ -1328,7 +1370,7 @@ static int unlink1(struct usbtest_dev *dev, int pipe, int 
size, int async)
        int                     retval = 0;
 
        init_completion(&completion);
-       urb = simple_alloc_urb(testdev_to_usbdev(dev), pipe, size);
+       urb = simple_alloc_urb(testdev_to_usbdev(dev), pipe, size, 0);
        if (!urb)
                return -ENOMEM;
        urb->context = &completion;
@@ -1616,9 +1658,9 @@ static int halt_simple(struct usbtest_dev *dev)
        struct usb_device       *udev = testdev_to_usbdev(dev);
 
        if (udev->speed == USB_SPEED_SUPER)
-               urb = simple_alloc_urb(udev, 0, 1024);
+               urb = simple_alloc_urb(udev, 0, 1024, 0);
        else
-               urb = simple_alloc_urb(udev, 0, 512);
+               urb = simple_alloc_urb(udev, 0, 512, 0);
        if (urb == NULL)
                return -ENOMEM;
 
@@ -1962,7 +2004,7 @@ static int test_unaligned_bulk(
 {
        int retval;
        struct urb *urb = usbtest_alloc_urb(
-               testdev_to_usbdev(tdev), pipe, length, transfer_flags, 1);
+               testdev_to_usbdev(tdev), pipe, length, transfer_flags, 1, 0);
 
        if (!urb)
                return -ENOMEM;
@@ -2068,7 +2110,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int 
code, void *buf)
                dev_info(&intf->dev,
                                "TEST 1:  write %d bytes %u times\n",
                                param->length, param->iterations);
-               urb = simple_alloc_urb(udev, dev->out_pipe, param->length);
+               urb = simple_alloc_urb(udev, dev->out_pipe, param->length, 0);
                if (!urb) {
                        retval = -ENOMEM;
                        break;
@@ -2083,7 +2125,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int 
code, void *buf)
                dev_info(&intf->dev,
                                "TEST 2:  read %d bytes %u times\n",
                                param->length, param->iterations);
-               urb = simple_alloc_urb(udev, dev->in_pipe, param->length);
+               urb = simple_alloc_urb(udev, dev->in_pipe, param->length, 0);
                if (!urb) {
                        retval = -ENOMEM;
                        break;
@@ -2098,7 +2140,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int 
code, void *buf)
                dev_info(&intf->dev,
                                "TEST 3:  write/%d 0..%d bytes %u times\n",
                                param->vary, param->length, param->iterations);
-               urb = simple_alloc_urb(udev, dev->out_pipe, param->length);
+               urb = simple_alloc_urb(udev, dev->out_pipe, param->length, 0);
                if (!urb) {
                        retval = -ENOMEM;
                        break;
@@ -2114,7 +2156,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int 
code, void *buf)
                dev_info(&intf->dev,
                                "TEST 4:  read/%d 0..%d bytes %u times\n",
                                param->vary, param->length, param->iterations);
-               urb = simple_alloc_urb(udev, dev->in_pipe, param->length);
+               urb = simple_alloc_urb(udev, dev->in_pipe, param->length, 0);
                if (!urb) {
                        retval = -ENOMEM;
                        break;
@@ -2411,6 +2453,39 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int 
code, void *buf)
                }
                break;
 
+       /* Simple non-queued interrupt I/O tests */
+       case 25:
+               if (dev->out_int_pipe == 0)
+                       break;
+               dev_info(&intf->dev,
+                               "TEST 25: write %d bytes %u times\n",
+                               param->length, param->iterations);
+               urb = simple_alloc_urb(udev, dev->out_int_pipe, param->length,
+                               dev->int_out->bInterval);
+               if (!urb) {
+                       retval = -ENOMEM;
+                       break;
+               }
+               /* FIRMWARE: interrupt sink (maybe accepts short writes) */
+               retval = simple_io(dev, urb, param->iterations, 0, 0, "test25");
+               simple_free_urb(urb);
+               break;
+       case 26:
+               if (dev->in_int_pipe == 0)
+                       break;
+               dev_info(&intf->dev,
+                               "TEST 26: read %d bytes %u times\n",
+                               param->length, param->iterations);
+               urb = simple_alloc_urb(udev, dev->in_int_pipe, param->length,
+                               dev->int_in->bInterval);
+               if (!urb) {
+                       retval = -ENOMEM;
+                       break;
+               }
+               /* FIRMWARE: interrupt source (maybe generates short writes) */
+               retval = simple_io(dev, urb, param->iterations, 0, 0, "test26");
+               simple_free_urb(urb);
+               break;
        }
        do_gettimeofday(&param->duration);
        param->duration.tv_sec -= start.tv_sec;
@@ -2447,6 +2522,7 @@ usbtest_probe(struct usb_interface *intf, const struct 
usb_device_id *id)
        struct usbtest_info     *info;
        char                    *rtest, *wtest;
        char                    *irtest, *iwtest;
+       char                    *intrtest, *intwtest;
 
        udev = interface_to_usbdev(intf);
 
@@ -2487,6 +2563,7 @@ usbtest_probe(struct usb_interface *intf, const struct 
usb_device_id *id)
         */
        rtest = wtest = "";
        irtest = iwtest = "";
+       intrtest = intwtest = "";
        if (force_interrupt || udev->speed == USB_SPEED_LOW) {
                if (info->ep_in) {
                        dev->in_pipe = usb_rcvintpipe(udev, info->ep_in);
@@ -2525,15 +2602,20 @@ usbtest_probe(struct usb_interface *intf, const struct 
usb_device_id *id)
                        irtest = " iso-in";
                if (dev->out_iso_pipe)
                        iwtest = " iso-out";
+               if (dev->in_int_pipe)
+                       intrtest = " int-in";
+               if (dev->out_int_pipe)
+                       intwtest = " int-out";
        }
 
        usb_set_intfdata(intf, dev);
        dev_info(&intf->dev, "%s\n", info->name);
-       dev_info(&intf->dev, "%s {control%s%s%s%s%s} tests%s\n",
+       dev_info(&intf->dev, "%s {control%s%s%s%s%s%s%s} tests%s\n",
                        usb_speed_string(udev->speed),
                        info->ctrl_out ? " in/out" : "",
                        rtest, wtest,
                        irtest, iwtest,
+                       intrtest, intwtest,
                        info->alt >= 0 ? " (+alt)" : "");
        return 0;
 }
@@ -2607,6 +2689,7 @@ static struct usbtest_info gz_info = {
        .autoconf       = 1,
        .ctrl_out       = 1,
        .iso            = 1,
+       .intr           = 1,
        .alt            = 0,
 };
 
-- 
1.8.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