Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* $(CROSS_COMPILE)cc -Wall -Wextra -g -lpthread -o testusb testusb.c */
0003 
0004 /*
0005  * Copyright (c) 2002 by David Brownell
0006  * Copyright (c) 2010 by Samsung Electronics
0007  * Author: Michal Nazarewicz <mina86@mina86.com>
0008  */
0009 
0010 /*
0011  * This program issues ioctls to perform the tests implemented by the
0012  * kernel driver.  It can generate a variety of transfer patterns; you
0013  * should make sure to test both regular streaming and mixes of
0014  * transfer sizes (including short transfers).
0015  *
0016  * For more information on how this can be used and on USB testing
0017  * refer to <URL:http://www.linux-usb.org/usbtest/>.
0018  */
0019 
0020 #include <stdio.h>
0021 #include <string.h>
0022 #include <ftw.h>
0023 #include <stdlib.h>
0024 #include <pthread.h>
0025 #include <unistd.h>
0026 #include <errno.h>
0027 #include <limits.h>
0028 
0029 #include <sys/types.h>
0030 #include <sys/stat.h>
0031 #include <fcntl.h>
0032 
0033 #include <sys/ioctl.h>
0034 #include <linux/usbdevice_fs.h>
0035 
0036 /*-------------------------------------------------------------------------*/
0037 
0038 #define TEST_CASES  30
0039 
0040 // FIXME make these public somewhere; usbdevfs.h?
0041 
0042 struct usbtest_param {
0043     // inputs
0044     unsigned        test_num;   /* 0..(TEST_CASES-1) */
0045     unsigned        iterations;
0046     unsigned        length;
0047     unsigned        vary;
0048     unsigned        sglen;
0049 
0050     // outputs
0051     struct timeval      duration;
0052 };
0053 #define USBTEST_REQUEST _IOWR('U', 100, struct usbtest_param)
0054 
0055 /*-------------------------------------------------------------------------*/
0056 
0057 /* #include <linux/usb_ch9.h> */
0058 
0059 #define USB_DT_DEVICE           0x01
0060 #define USB_DT_INTERFACE        0x04
0061 
0062 #define USB_CLASS_PER_INTERFACE     0   /* for DeviceClass */
0063 #define USB_CLASS_VENDOR_SPEC       0xff
0064 
0065 
0066 struct usb_device_descriptor {
0067     __u8  bLength;
0068     __u8  bDescriptorType;
0069     __u16 bcdUSB;
0070     __u8  bDeviceClass;
0071     __u8  bDeviceSubClass;
0072     __u8  bDeviceProtocol;
0073     __u8  bMaxPacketSize0;
0074     __u16 idVendor;
0075     __u16 idProduct;
0076     __u16 bcdDevice;
0077     __u8  iManufacturer;
0078     __u8  iProduct;
0079     __u8  iSerialNumber;
0080     __u8  bNumConfigurations;
0081 } __attribute__ ((packed));
0082 
0083 struct usb_interface_descriptor {
0084     __u8  bLength;
0085     __u8  bDescriptorType;
0086 
0087     __u8  bInterfaceNumber;
0088     __u8  bAlternateSetting;
0089     __u8  bNumEndpoints;
0090     __u8  bInterfaceClass;
0091     __u8  bInterfaceSubClass;
0092     __u8  bInterfaceProtocol;
0093     __u8  iInterface;
0094 } __attribute__ ((packed));
0095 
0096 enum usb_device_speed {
0097     USB_SPEED_UNKNOWN = 0,          /* enumerating */
0098     USB_SPEED_LOW, USB_SPEED_FULL,      /* usb 1.1 */
0099     USB_SPEED_HIGH,             /* usb 2.0 */
0100     USB_SPEED_WIRELESS,         /* wireless (usb 2.5) */
0101     USB_SPEED_SUPER,            /* usb 3.0 */
0102     USB_SPEED_SUPER_PLUS,           /* usb 3.1 */
0103 };
0104 
0105 /*-------------------------------------------------------------------------*/
0106 
0107 static char *speed (enum usb_device_speed s)
0108 {
0109     switch (s) {
0110     case USB_SPEED_UNKNOWN:     return "unknown";
0111     case USB_SPEED_LOW:     return "low";
0112     case USB_SPEED_FULL:        return "full";
0113     case USB_SPEED_HIGH:        return "high";
0114     case USB_SPEED_WIRELESS:    return "wireless";
0115     case USB_SPEED_SUPER:       return "super";
0116     case USB_SPEED_SUPER_PLUS:  return "super-plus";
0117     default:            return "??";
0118     }
0119 }
0120 
0121 struct testdev {
0122     struct testdev      *next;
0123     char            *name;
0124     pthread_t       thread;
0125     enum usb_device_speed   speed;
0126     unsigned        ifnum : 8;
0127     unsigned        forever : 1;
0128     int         test;
0129 
0130     struct usbtest_param    param;
0131 };
0132 static struct testdev       *testdevs;
0133 
0134 static int testdev_ffs_ifnum(FILE *fd)
0135 {
0136     union {
0137         char buf[255];
0138         struct usb_interface_descriptor intf;
0139     } u;
0140 
0141     for (;;) {
0142         if (fread(u.buf, 1, 1, fd) != 1)
0143             return -1;
0144         if (fread(u.buf + 1, (unsigned char)u.buf[0] - 1, 1, fd) != 1)
0145             return -1;
0146 
0147         if (u.intf.bLength == sizeof u.intf
0148          && u.intf.bDescriptorType == USB_DT_INTERFACE
0149          && u.intf.bNumEndpoints == 2
0150          && u.intf.bInterfaceClass == USB_CLASS_VENDOR_SPEC
0151          && u.intf.bInterfaceSubClass == 0
0152          && u.intf.bInterfaceProtocol == 0)
0153             return (unsigned char)u.intf.bInterfaceNumber;
0154     }
0155 }
0156 
0157 static int testdev_ifnum(FILE *fd)
0158 {
0159     struct usb_device_descriptor dev;
0160 
0161     if (fread(&dev, sizeof dev, 1, fd) != 1)
0162         return -1;
0163 
0164     if (dev.bLength != sizeof dev || dev.bDescriptorType != USB_DT_DEVICE)
0165         return -1;
0166 
0167     /* FX2 with (tweaked) bulksrc firmware */
0168     if (dev.idVendor == 0x0547 && dev.idProduct == 0x1002)
0169         return 0;
0170 
0171     /*----------------------------------------------------*/
0172 
0173     /* devices that start up using the EZ-USB default device and
0174      * which we can use after loading simple firmware.  hotplug
0175      * can fxload it, and then run this test driver.
0176      *
0177      * we return false positives in two cases:
0178      * - the device has a "real" driver (maybe usb-serial) that
0179      *   renumerates.  the device should vanish quickly.
0180      * - the device doesn't have the test firmware installed.
0181      */
0182 
0183     /* generic EZ-USB FX controller */
0184     if (dev.idVendor == 0x0547 && dev.idProduct == 0x2235)
0185         return 0;
0186 
0187     /* generic EZ-USB FX2 controller */
0188     if (dev.idVendor == 0x04b4 && dev.idProduct == 0x8613)
0189         return 0;
0190 
0191     /* CY3671 development board with EZ-USB FX */
0192     if (dev.idVendor == 0x0547 && dev.idProduct == 0x0080)
0193         return 0;
0194 
0195     /* Keyspan 19Qi uses an21xx (original EZ-USB) */
0196     if (dev.idVendor == 0x06cd && dev.idProduct == 0x010b)
0197         return 0;
0198 
0199     /*----------------------------------------------------*/
0200 
0201     /* "gadget zero", Linux-USB test software */
0202     if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a0)
0203         return 0;
0204 
0205     /* user mode subset of that */
0206     if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a4)
0207         return testdev_ffs_ifnum(fd);
0208         /* return 0; */
0209 
0210     /* iso version of usermode code */
0211     if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a3)
0212         return 0;
0213 
0214     /* some GPL'd test firmware uses these IDs */
0215 
0216     if (dev.idVendor == 0xfff0 && dev.idProduct == 0xfff0)
0217         return 0;
0218 
0219     /*----------------------------------------------------*/
0220 
0221     /* iBOT2 high speed webcam */
0222     if (dev.idVendor == 0x0b62 && dev.idProduct == 0x0059)
0223         return 0;
0224 
0225     /*----------------------------------------------------*/
0226 
0227     /* the FunctionFS gadget can have the source/sink interface
0228      * anywhere.  We look for an interface descriptor that match
0229      * what we expect.  We ignore configuratiens thou. */
0230 
0231     if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4ac
0232      && (dev.bDeviceClass == USB_CLASS_PER_INTERFACE
0233       || dev.bDeviceClass == USB_CLASS_VENDOR_SPEC))
0234         return testdev_ffs_ifnum(fd);
0235 
0236     return -1;
0237 }
0238 
0239 static int find_testdev(const char *name, const struct stat *sb, int flag)
0240 {
0241     FILE                *fd;
0242     int             ifnum;
0243     struct testdev          *entry;
0244 
0245     (void)sb; /* unused */
0246 
0247     if (flag != FTW_F)
0248         return 0;
0249 
0250     fd = fopen(name, "rb");
0251     if (!fd) {
0252         perror(name);
0253         return 0;
0254     }
0255 
0256     ifnum = testdev_ifnum(fd);
0257     fclose(fd);
0258     if (ifnum < 0)
0259         return 0;
0260 
0261     entry = calloc(1, sizeof *entry);
0262     if (!entry)
0263         goto nomem;
0264 
0265     entry->name = strdup(name);
0266     if (!entry->name) {
0267         free(entry);
0268 nomem:
0269         perror("malloc");
0270         return 0;
0271     }
0272 
0273     entry->ifnum = ifnum;
0274     entry->next = testdevs;
0275     testdevs = entry;
0276     return 0;
0277 }
0278 
0279 static int
0280 usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
0281 {
0282     struct usbdevfs_ioctl   wrapper;
0283 
0284     wrapper.ifno = ifno;
0285     wrapper.ioctl_code = request;
0286     wrapper.data = param;
0287 
0288     return ioctl (fd, USBDEVFS_IOCTL, &wrapper);
0289 }
0290 
0291 static void *handle_testdev (void *arg)
0292 {
0293     struct testdev      *dev = arg;
0294     int         fd, i;
0295     int         status;
0296 
0297     if ((fd = open (dev->name, O_RDWR)) < 0) {
0298         perror ("can't open dev file r/w");
0299         return 0;
0300     }
0301 
0302     status  =  ioctl(fd, USBDEVFS_GET_SPEED, NULL);
0303     if (status < 0)
0304         fprintf(stderr, "USBDEVFS_GET_SPEED failed %d\n", status);
0305     else
0306         dev->speed = status;
0307     fprintf(stderr, "%s speed\t%s\t%u\n",
0308             speed(dev->speed), dev->name, dev->ifnum);
0309 
0310 restart:
0311     for (i = 0; i < TEST_CASES; i++) {
0312         if (dev->test != -1 && dev->test != i)
0313             continue;
0314         dev->param.test_num = i;
0315 
0316         status = usbdev_ioctl (fd, dev->ifnum,
0317                 USBTEST_REQUEST, &dev->param);
0318         if (status < 0 && errno == EOPNOTSUPP)
0319             continue;
0320 
0321         /* FIXME need a "syslog it" option for background testing */
0322 
0323         /* NOTE: each thread emits complete lines; no fragments! */
0324         if (status < 0) {
0325             char    buf [80];
0326             int err = errno;
0327 
0328             if (strerror_r (errno, buf, sizeof buf)) {
0329                 snprintf (buf, sizeof buf, "error %d", err);
0330                 errno = err;
0331             }
0332             printf ("%s test %d --> %d (%s)\n",
0333                 dev->name, i, errno, buf);
0334         } else
0335             printf ("%s test %d, %4d.%.06d secs\n", dev->name, i,
0336                 (int) dev->param.duration.tv_sec,
0337                 (int) dev->param.duration.tv_usec);
0338 
0339         fflush (stdout);
0340     }
0341     if (dev->forever)
0342         goto restart;
0343 
0344     close (fd);
0345     return arg;
0346 }
0347 
0348 static const char *usb_dir_find(void)
0349 {
0350     static char udev_usb_path[] = "/dev/bus/usb";
0351 
0352     if (access(udev_usb_path, F_OK) == 0)
0353         return udev_usb_path;
0354 
0355     return NULL;
0356 }
0357 
0358 static int parse_num(unsigned *num, const char *str)
0359 {
0360     unsigned long val;
0361     char *end;
0362 
0363     errno = 0;
0364     val = strtoul(str, &end, 0);
0365     if (errno || *end || val > UINT_MAX)
0366         return -1;
0367     *num = val;
0368     return 0;
0369 }
0370 
0371 int main (int argc, char **argv)
0372 {
0373 
0374     int         c;
0375     struct testdev      *entry;
0376     char            *device;
0377     const char      *usb_dir = NULL;
0378     int         all = 0, forever = 0, not = 0;
0379     int         test = -1 /* all */;
0380     struct usbtest_param    param;
0381 
0382     /* pick defaults that works with all speeds, without short packets.
0383      *
0384      * Best per-frame data rates:
0385      *     super speed,bulk      1024 * 16 * 8 = 131072
0386      *                 interrupt 1024 *  3 * 8 =  24576
0387      *     high speed, bulk       512 * 13 * 8 =  53248
0388      *                 interrupt 1024 *  3 * 8 =  24576
0389      *     full speed, bulk/intr   64 * 19     =   1216
0390      *                 interrupt   64 *  1     =     64
0391      *      low speed, interrupt    8 *  1     =      8
0392      */
0393     param.iterations = 1000;
0394     param.length = 1024;
0395     param.vary = 1024;
0396     param.sglen = 32;
0397 
0398     /* for easy use when hotplugging */
0399     device = getenv ("DEVICE");
0400 
0401     while ((c = getopt (argc, argv, "D:aA:c:g:hlns:t:v:")) != EOF)
0402     switch (c) {
0403     case 'D':   /* device, if only one */
0404         device = optarg;
0405         continue;
0406     case 'A':   /* use all devices with specified USB dir */
0407         usb_dir = optarg;
0408         /* FALL THROUGH */
0409     case 'a':   /* use all devices */
0410         device = NULL;
0411         all = 1;
0412         continue;
0413     case 'c':   /* count iterations */
0414         if (parse_num(&param.iterations, optarg))
0415             goto usage;
0416         continue;
0417     case 'g':   /* scatter/gather entries */
0418         if (parse_num(&param.sglen, optarg))
0419             goto usage;
0420         continue;
0421     case 'l':   /* loop forever */
0422         forever = 1;
0423         continue;
0424     case 'n':   /* no test running! */
0425         not = 1;
0426         continue;
0427     case 's':   /* size of packet */
0428         if (parse_num(&param.length, optarg))
0429             goto usage;
0430         continue;
0431     case 't':   /* run just one test */
0432         test = atoi (optarg);
0433         if (test < 0)
0434             goto usage;
0435         continue;
0436     case 'v':   /* vary packet size by ... */
0437         if (parse_num(&param.vary, optarg))
0438             goto usage;
0439         continue;
0440     case '?':
0441     case 'h':
0442     default:
0443 usage:
0444         fprintf (stderr,
0445             "usage: %s [options]\n"
0446             "Options:\n"
0447             "\t-D dev       only test specific device\n"
0448             "\t-A usb-dir\n"
0449             "\t-a       test all recognized devices\n"
0450             "\t-l       loop forever(for stress test)\n"
0451             "\t-t testnum   only run specified case\n"
0452             "\t-n       no test running, show devices to be tested\n"
0453             "Case arguments:\n"
0454             "\t-c iterations        default 1000\n"
0455             "\t-s transfer length   default 1024\n"
0456             "\t-g sglen     default 32\n"
0457             "\t-v vary          default 1024\n",
0458             argv[0]);
0459         return 1;
0460     }
0461     if (optind != argc)
0462         goto usage;
0463     if (!all && !device) {
0464         fprintf (stderr, "must specify '-a' or '-D dev', "
0465             "or DEVICE=/dev/bus/usb/BBB/DDD in env\n");
0466         goto usage;
0467     }
0468 
0469     /* Find usb device subdirectory */
0470     if (!usb_dir) {
0471         usb_dir = usb_dir_find();
0472         if (!usb_dir) {
0473             fputs ("USB device files are missing\n", stderr);
0474             return -1;
0475         }
0476     }
0477 
0478     /* collect and list the test devices */
0479     if (ftw (usb_dir, find_testdev, 3) != 0) {
0480         fputs ("ftw failed; are USB device files missing?\n", stderr);
0481         return -1;
0482     }
0483 
0484     /* quit, run single test, or create test threads */
0485     if (!testdevs && !device) {
0486         fputs ("no test devices recognized\n", stderr);
0487         return -1;
0488     }
0489     if (not)
0490         return 0;
0491     if (testdevs && !testdevs->next && !device)
0492         device = testdevs->name;
0493     for (entry = testdevs; entry; entry = entry->next) {
0494         int status;
0495 
0496         entry->param = param;
0497         entry->forever = forever;
0498         entry->test = test;
0499 
0500         if (device) {
0501             if (strcmp (entry->name, device))
0502                 continue;
0503             return handle_testdev (entry) != entry;
0504         }
0505         status = pthread_create (&entry->thread, 0, handle_testdev, entry);
0506         if (status)
0507             perror ("pthread_create");
0508     }
0509     if (device) {
0510         struct testdev      dev;
0511 
0512         /* kernel can recognize test devices we don't */
0513         fprintf (stderr, "%s: %s may see only control tests\n",
0514                 argv [0], device);
0515 
0516         memset (&dev, 0, sizeof dev);
0517         dev.name = device;
0518         dev.param = param;
0519         dev.forever = forever;
0520         dev.test = test;
0521         return handle_testdev (&dev) != &dev;
0522     }
0523 
0524     /* wait for tests to complete */
0525     for (entry = testdevs; entry; entry = entry->next) {
0526         void    *retval;
0527 
0528         if (pthread_join (entry->thread, &retval))
0529             perror ("pthread_join");
0530         /* testing errors discarded! */
0531     }
0532 
0533     return 0;
0534 }