Merge remote-tracking branch 'lsk/v3.10/topic/gator' into linux-linaro-lsk
[firefly-linux-kernel-4.4.55.git] / drivers / usb / misc / usbtest.c
index 8b4ca1cb450aacce4dffaf67b0ca650b0cfa2544..98438b90838ff1ef22dffb4fb70d6123f9e6ca64 100644 (file)
@@ -7,9 +7,10 @@
 #include <linux/moduleparam.h>
 #include <linux/scatterlist.h>
 #include <linux/mutex.h>
-
+#include <linux/timer.h>
 #include <linux/usb.h>
 
+#define SIMPLE_IO_TIMEOUT      10000   /* in milliseconds */
 
 /*-------------------------------------------------------------------------*/
 
@@ -366,6 +367,7 @@ static int simple_io(
        int                     max = urb->transfer_buffer_length;
        struct completion       completion;
        int                     retval = 0;
+       unsigned long           expire;
 
        urb->context = &completion;
        while (retval == 0 && iterations-- > 0) {
@@ -378,9 +380,15 @@ static int simple_io(
                if (retval != 0)
                        break;
 
-               /* NOTE:  no timeouts; can't be broken out of by interrupt */
-               wait_for_completion(&completion);
-               retval = urb->status;
+               expire = msecs_to_jiffies(SIMPLE_IO_TIMEOUT);
+               if (!wait_for_completion_timeout(&completion, expire)) {
+                       usb_kill_urb(urb);
+                       retval = (urb->status == -ENOENT ?
+                                 -ETIMEDOUT : urb->status);
+               } else {
+                       retval = urb->status;
+               }
+
                urb->dev = udev;
                if (retval == 0 && usb_pipein(urb->pipe))
                        retval = simple_check_buf(tdev, urb);
@@ -476,6 +484,14 @@ alloc_sglist(int nents, int max, int vary)
        return sg;
 }
 
+static void sg_timeout(unsigned long _req)
+{
+       struct usb_sg_request   *req = (struct usb_sg_request *) _req;
+
+       req->status = -ETIMEDOUT;
+       usb_sg_cancel(req);
+}
+
 static int perform_sglist(
        struct usbtest_dev      *tdev,
        unsigned                iterations,
@@ -487,6 +503,9 @@ static int perform_sglist(
 {
        struct usb_device       *udev = testdev_to_usbdev(tdev);
        int                     retval = 0;
+       struct timer_list       sg_timer;
+
+       setup_timer_on_stack(&sg_timer, sg_timeout, (unsigned long) req);
 
        while (retval == 0 && iterations-- > 0) {
                retval = usb_sg_init(req, udev, pipe,
@@ -497,7 +516,10 @@ static int perform_sglist(
 
                if (retval)
                        break;
+               mod_timer(&sg_timer, jiffies +
+                               msecs_to_jiffies(SIMPLE_IO_TIMEOUT));
                usb_sg_wait(req);
+               del_timer_sync(&sg_timer);
                retval = req->status;
 
                /* FIXME check resulting data pattern */
@@ -1149,6 +1171,11 @@ static int unlink1(struct usbtest_dev *dev, int pipe, int size, int async)
        urb->context = &completion;
        urb->complete = unlink1_callback;
 
+       if (usb_pipeout(urb->pipe)) {
+               simple_fill_buf(urb);
+               urb->transfer_flags |= URB_ZERO_PACKET;
+       }
+
        /* keep the endpoint busy.  there are lots of hc/hcd-internal
         * states, and testing should get to all of them over time.
         *
@@ -1279,6 +1306,11 @@ static int unlink_queued(struct usbtest_dev *dev, int pipe, unsigned num,
                                unlink_queued_callback, &ctx);
                ctx.urbs[i]->transfer_dma = buf_dma;
                ctx.urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+
+               if (usb_pipeout(ctx.urbs[i]->pipe)) {
+                       simple_fill_buf(ctx.urbs[i]);
+                       ctx.urbs[i]->transfer_flags |= URB_ZERO_PACKET;
+               }
        }
 
        /* Submit all the URBs and then unlink URBs num - 4 and num - 2. */