]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/usb/misc/usbtest.c
usb: misc: usbtest: Remove timeval usage
[karo-tx-linux.git] / drivers / usb / misc / usbtest.c
index c1bd1eb548bb9fcff1e32735cc8b8546b4bb755c..92fdb6e9faff4003a157ea742a2193e869d06519 100644 (file)
@@ -22,18 +22,42 @@ static void complicated_callback(struct urb *urb);
 /*-------------------------------------------------------------------------*/
 
 /* FIXME make these public somewhere; usbdevfs.h? */
-struct usbtest_param {
+
+/* Parameter for usbtest driver. */
+struct usbtest_param_32 {
        /* inputs */
-       unsigned                test_num;       /* 0..(TEST_CASES-1) */
-       unsigned                iterations;
-       unsigned                length;
-       unsigned                vary;
-       unsigned                sglen;
+       __u32           test_num;       /* 0..(TEST_CASES-1) */
+       __u32           iterations;
+       __u32           length;
+       __u32           vary;
+       __u32           sglen;
 
        /* outputs */
-       struct timeval          duration;
+       __s32           duration_sec;
+       __s32           duration_usec;
 };
-#define USBTEST_REQUEST        _IOWR('U', 100, struct usbtest_param)
+
+/*
+ * Compat parameter to the usbtest driver.
+ * This supports older user space binaries compiled with 64 bit compiler.
+ */
+struct usbtest_param_64 {
+       /* inputs */
+       __u32           test_num;       /* 0..(TEST_CASES-1) */
+       __u32           iterations;
+       __u32           length;
+       __u32           vary;
+       __u32           sglen;
+
+       /* outputs */
+       __s64           duration_sec;
+       __s64           duration_usec;
+};
+
+/* IOCTL interface to the driver. */
+#define USBTEST_REQUEST_32    _IOWR('U', 100, struct usbtest_param_32)
+/* COMPAT IOCTL interface to the driver. */
+#define USBTEST_REQUEST_64    _IOWR('U', 100, struct usbtest_param_64)
 
 /*-------------------------------------------------------------------------*/
 
@@ -1030,7 +1054,7 @@ struct ctrl_ctx {
        unsigned                pending;
        int                     status;
        struct urb              **urb;
-       struct usbtest_param    *param;
+       struct usbtest_param_32 *param;
        int                     last;
 };
 
@@ -1155,7 +1179,7 @@ error:
 }
 
 static int
-test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)
+test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param_32 *param)
 {
        struct usb_device       *udev = testdev_to_usbdev(dev);
        struct urb              **urb;
@@ -1930,7 +1954,7 @@ static struct urb *iso_alloc_urb(
 }
 
 static int
-test_queue(struct usbtest_dev *dev, struct usbtest_param *param,
+test_queue(struct usbtest_dev *dev, struct usbtest_param_32 *param,
                int pipe, struct usb_endpoint_descriptor *desc, unsigned offset)
 {
        struct transfer_context context;
@@ -2049,81 +2073,20 @@ static int test_unaligned_bulk(
        return retval;
 }
 
-/*-------------------------------------------------------------------------*/
-
-/* We only have this one interface to user space, through usbfs.
- * User mode code can scan usbfs to find N different devices (maybe on
- * different busses) to use when testing, and allocate one thread per
- * test.  So discovery is simplified, and we have no device naming issues.
- *
- * Don't use these only as stress/load tests.  Use them along with with
- * other USB bus activity:  plugging, unplugging, mousing, mp3 playback,
- * video capture, and so on.  Run different tests at different times, in
- * different sequences.  Nothing here should interact with other devices,
- * except indirectly by consuming USB bandwidth and CPU resources for test
- * threads and request completion.  But the only way to know that for sure
- * is to test when HC queues are in use by many devices.
- *
- * WARNING:  Because usbfs grabs udev->dev.sem before calling this ioctl(),
- * it locks out usbcore in certain code paths.  Notably, if you disconnect
- * the device-under-test, hub_wq will wait block forever waiting for the
- * ioctl to complete ... so that usb_disconnect() can abort the pending
- * urbs and then call usbtest_disconnect().  To abort a test, you're best
- * off just killing the userspace task and waiting for it to exit.
- */
-
+/* Run tests. */
 static int
-usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
+usbtest_do_ioctl(struct usb_interface *intf, struct usbtest_param_32 *param)
 {
        struct usbtest_dev      *dev = usb_get_intfdata(intf);
        struct usb_device       *udev = testdev_to_usbdev(dev);
-       struct usbtest_param    *param = buf;
-       int                     retval = -EOPNOTSUPP;
        struct urb              *urb;
        struct scatterlist      *sg;
        struct usb_sg_request   req;
-       struct timeval          start;
        unsigned                i;
-
-       /* FIXME USBDEVFS_CONNECTINFO doesn't say how fast the device is. */
-
-       pattern = mod_pattern;
-
-       if (code != USBTEST_REQUEST)
-               return -EOPNOTSUPP;
+       int     retval = -EOPNOTSUPP;
 
        if (param->iterations <= 0)
                return -EINVAL;
-
-       if (param->sglen > MAX_SGLEN)
-               return -EINVAL;
-
-       if (mutex_lock_interruptible(&dev->lock))
-               return -ERESTARTSYS;
-
-       /* FIXME: What if a system sleep starts while a test is running? */
-
-       /* some devices, like ez-usb default devices, need a non-default
-        * altsetting to have any active endpoints.  some tests change
-        * altsettings; force a default so most tests don't need to check.
-        */
-       if (dev->info->alt >= 0) {
-               int     res;
-
-               if (intf->altsetting->desc.bInterfaceNumber) {
-                       mutex_unlock(&dev->lock);
-                       return -ENODEV;
-               }
-               res = set_altsetting(dev, dev->info->alt);
-               if (res) {
-                       dev_err(&intf->dev,
-                                       "set altsetting to %d failed, %d\n",
-                                       dev->info->alt, res);
-                       mutex_unlock(&dev->lock);
-                       return res;
-               }
-       }
-
        /*
         * Just a bunch of test cases that every HCD is expected to handle.
         *
@@ -2133,7 +2096,6 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
         * FIXME add more tests!  cancel requests, verify the data, control
         * queueing, concurrent read+write threads, and so on.
         */
-       do_gettimeofday(&start);
        switch (param->test_num) {
 
        case 0:
@@ -2548,13 +2510,116 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
                                dev->in_pipe, NULL, 0);
                break;
        }
-       do_gettimeofday(&param->duration);
-       param->duration.tv_sec -= start.tv_sec;
-       param->duration.tv_usec -= start.tv_usec;
-       if (param->duration.tv_usec < 0) {
-               param->duration.tv_usec += 1000 * 1000;
-               param->duration.tv_sec -= 1;
+       return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* We only have this one interface to user space, through usbfs.
+ * User mode code can scan usbfs to find N different devices (maybe on
+ * different busses) to use when testing, and allocate one thread per
+ * test.  So discovery is simplified, and we have no device naming issues.
+ *
+ * Don't use these only as stress/load tests.  Use them along with with
+ * other USB bus activity:  plugging, unplugging, mousing, mp3 playback,
+ * video capture, and so on.  Run different tests at different times, in
+ * different sequences.  Nothing here should interact with other devices,
+ * except indirectly by consuming USB bandwidth and CPU resources for test
+ * threads and request completion.  But the only way to know that for sure
+ * is to test when HC queues are in use by many devices.
+ *
+ * WARNING:  Because usbfs grabs udev->dev.sem before calling this ioctl(),
+ * it locks out usbcore in certain code paths.  Notably, if you disconnect
+ * the device-under-test, hub_wq will wait block forever waiting for the
+ * ioctl to complete ... so that usb_disconnect() can abort the pending
+ * urbs and then call usbtest_disconnect().  To abort a test, you're best
+ * off just killing the userspace task and waiting for it to exit.
+ */
+
+static int
+usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
+{
+
+       struct usbtest_dev      *dev = usb_get_intfdata(intf);
+       struct usbtest_param_64 *param_64 = buf;
+       struct usbtest_param_32 temp;
+       struct usbtest_param_32 *param_32 = buf;
+       struct timespec64 start;
+       struct timespec64 end;
+       struct timespec64 duration;
+       int retval = -EOPNOTSUPP;
+
+       /* FIXME USBDEVFS_CONNECTINFO doesn't say how fast the device is. */
+
+       pattern = mod_pattern;
+
+       if (mutex_lock_interruptible(&dev->lock))
+               return -ERESTARTSYS;
+
+       /* FIXME: What if a system sleep starts while a test is running? */
+
+       /* some devices, like ez-usb default devices, need a non-default
+        * altsetting to have any active endpoints.  some tests change
+        * altsettings; force a default so most tests don't need to check.
+        */
+       if (dev->info->alt >= 0) {
+               if (intf->altsetting->desc.bInterfaceNumber) {
+                       retval = -ENODEV;
+                       goto free_mutex;
+               }
+               retval = set_altsetting(dev, dev->info->alt);
+               if (retval) {
+                       dev_err(&intf->dev,
+                                       "set altsetting to %d failed, %d\n",
+                                       dev->info->alt, retval);
+                       goto free_mutex;
+               }
+       }
+
+       switch (code) {
+       case USBTEST_REQUEST_64:
+               temp.test_num = param_64->test_num;
+               temp.iterations = param_64->iterations;
+               temp.length = param_64->length;
+               temp.sglen = param_64->sglen;
+               temp.vary = param_64->vary;
+               param_32 = &temp;
+               break;
+
+       case USBTEST_REQUEST_32:
+               break;
+
+       default:
+               retval = -EOPNOTSUPP;
+               goto free_mutex;
+       }
+
+       ktime_get_ts64(&start);
+
+       retval = usbtest_do_ioctl(intf, param_32);
+       if (retval)
+               goto free_mutex;
+
+       ktime_get_ts64(&end);
+
+       duration = timespec64_sub(end, start);
+
+       temp.duration_sec = duration.tv_sec;
+       temp.duration_usec = duration.tv_nsec/NSEC_PER_USEC;
+
+       switch (code) {
+       case USBTEST_REQUEST_32:
+               param_32->duration_sec = temp.duration_sec;
+               param_32->duration_usec = temp.duration_usec;
+               break;
+
+       case USBTEST_REQUEST_64:
+               param_64->duration_sec = temp.duration_sec;
+               param_64->duration_usec = temp.duration_usec;
+               break;
        }
+
+free_mutex:
        mutex_unlock(&dev->lock);
        return retval;
 }