root/tools/usb/testusb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. speed
  2. testdev_ffs_ifnum
  3. testdev_ifnum
  4. find_testdev
  5. usbdev_ioctl
  6. handle_testdev
  7. usb_dir_find
  8. parse_num
  9. main

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* $(CROSS_COMPILE)cc -Wall -Wextra -g -lpthread -o testusb testusb.c */
   3 
   4 /*
   5  * Copyright (c) 2002 by David Brownell
   6  * Copyright (c) 2010 by Samsung Electronics
   7  * Author: Michal Nazarewicz <mina86@mina86.com>
   8  */
   9 
  10 /*
  11  * This program issues ioctls to perform the tests implemented by the
  12  * kernel driver.  It can generate a variety of transfer patterns; you
  13  * should make sure to test both regular streaming and mixes of
  14  * transfer sizes (including short transfers).
  15  *
  16  * For more information on how this can be used and on USB testing
  17  * refer to <URL:http://www.linux-usb.org/usbtest/>.
  18  */
  19 
  20 #include <stdio.h>
  21 #include <string.h>
  22 #include <ftw.h>
  23 #include <stdlib.h>
  24 #include <pthread.h>
  25 #include <unistd.h>
  26 #include <errno.h>
  27 #include <limits.h>
  28 
  29 #include <sys/types.h>
  30 #include <sys/stat.h>
  31 #include <fcntl.h>
  32 
  33 #include <sys/ioctl.h>
  34 #include <linux/usbdevice_fs.h>
  35 
  36 /*-------------------------------------------------------------------------*/
  37 
  38 #define TEST_CASES      30
  39 
  40 // FIXME make these public somewhere; usbdevfs.h?
  41 
  42 struct usbtest_param {
  43         // inputs
  44         unsigned                test_num;       /* 0..(TEST_CASES-1) */
  45         unsigned                iterations;
  46         unsigned                length;
  47         unsigned                vary;
  48         unsigned                sglen;
  49 
  50         // outputs
  51         struct timeval          duration;
  52 };
  53 #define USBTEST_REQUEST _IOWR('U', 100, struct usbtest_param)
  54 
  55 /*-------------------------------------------------------------------------*/
  56 
  57 /* #include <linux/usb_ch9.h> */
  58 
  59 #define USB_DT_DEVICE                   0x01
  60 #define USB_DT_INTERFACE                0x04
  61 
  62 #define USB_CLASS_PER_INTERFACE         0       /* for DeviceClass */
  63 #define USB_CLASS_VENDOR_SPEC           0xff
  64 
  65 
  66 struct usb_device_descriptor {
  67         __u8  bLength;
  68         __u8  bDescriptorType;
  69         __u16 bcdUSB;
  70         __u8  bDeviceClass;
  71         __u8  bDeviceSubClass;
  72         __u8  bDeviceProtocol;
  73         __u8  bMaxPacketSize0;
  74         __u16 idVendor;
  75         __u16 idProduct;
  76         __u16 bcdDevice;
  77         __u8  iManufacturer;
  78         __u8  iProduct;
  79         __u8  iSerialNumber;
  80         __u8  bNumConfigurations;
  81 } __attribute__ ((packed));
  82 
  83 struct usb_interface_descriptor {
  84         __u8  bLength;
  85         __u8  bDescriptorType;
  86 
  87         __u8  bInterfaceNumber;
  88         __u8  bAlternateSetting;
  89         __u8  bNumEndpoints;
  90         __u8  bInterfaceClass;
  91         __u8  bInterfaceSubClass;
  92         __u8  bInterfaceProtocol;
  93         __u8  iInterface;
  94 } __attribute__ ((packed));
  95 
  96 enum usb_device_speed {
  97         USB_SPEED_UNKNOWN = 0,                  /* enumerating */
  98         USB_SPEED_LOW, USB_SPEED_FULL,          /* usb 1.1 */
  99         USB_SPEED_HIGH                          /* usb 2.0 */
 100 };
 101 
 102 /*-------------------------------------------------------------------------*/
 103 
 104 static char *speed (enum usb_device_speed s)
 105 {
 106         switch (s) {
 107         case USB_SPEED_UNKNOWN: return "unknown";
 108         case USB_SPEED_LOW:     return "low";
 109         case USB_SPEED_FULL:    return "full";
 110         case USB_SPEED_HIGH:    return "high";
 111         default:                return "??";
 112         }
 113 }
 114 
 115 struct testdev {
 116         struct testdev          *next;
 117         char                    *name;
 118         pthread_t               thread;
 119         enum usb_device_speed   speed;
 120         unsigned                ifnum : 8;
 121         unsigned                forever : 1;
 122         int                     test;
 123 
 124         struct usbtest_param    param;
 125 };
 126 static struct testdev           *testdevs;
 127 
 128 static int testdev_ffs_ifnum(FILE *fd)
 129 {
 130         union {
 131                 char buf[255];
 132                 struct usb_interface_descriptor intf;
 133         } u;
 134 
 135         for (;;) {
 136                 if (fread(u.buf, 1, 1, fd) != 1)
 137                         return -1;
 138                 if (fread(u.buf + 1, (unsigned char)u.buf[0] - 1, 1, fd) != 1)
 139                         return -1;
 140 
 141                 if (u.intf.bLength == sizeof u.intf
 142                  && u.intf.bDescriptorType == USB_DT_INTERFACE
 143                  && u.intf.bNumEndpoints == 2
 144                  && u.intf.bInterfaceClass == USB_CLASS_VENDOR_SPEC
 145                  && u.intf.bInterfaceSubClass == 0
 146                  && u.intf.bInterfaceProtocol == 0)
 147                         return (unsigned char)u.intf.bInterfaceNumber;
 148         }
 149 }
 150 
 151 static int testdev_ifnum(FILE *fd)
 152 {
 153         struct usb_device_descriptor dev;
 154 
 155         if (fread(&dev, sizeof dev, 1, fd) != 1)
 156                 return -1;
 157 
 158         if (dev.bLength != sizeof dev || dev.bDescriptorType != USB_DT_DEVICE)
 159                 return -1;
 160 
 161         /* FX2 with (tweaked) bulksrc firmware */
 162         if (dev.idVendor == 0x0547 && dev.idProduct == 0x1002)
 163                 return 0;
 164 
 165         /*----------------------------------------------------*/
 166 
 167         /* devices that start up using the EZ-USB default device and
 168          * which we can use after loading simple firmware.  hotplug
 169          * can fxload it, and then run this test driver.
 170          *
 171          * we return false positives in two cases:
 172          * - the device has a "real" driver (maybe usb-serial) that
 173          *   renumerates.  the device should vanish quickly.
 174          * - the device doesn't have the test firmware installed.
 175          */
 176 
 177         /* generic EZ-USB FX controller */
 178         if (dev.idVendor == 0x0547 && dev.idProduct == 0x2235)
 179                 return 0;
 180 
 181         /* generic EZ-USB FX2 controller */
 182         if (dev.idVendor == 0x04b4 && dev.idProduct == 0x8613)
 183                 return 0;
 184 
 185         /* CY3671 development board with EZ-USB FX */
 186         if (dev.idVendor == 0x0547 && dev.idProduct == 0x0080)
 187                 return 0;
 188 
 189         /* Keyspan 19Qi uses an21xx (original EZ-USB) */
 190         if (dev.idVendor == 0x06cd && dev.idProduct == 0x010b)
 191                 return 0;
 192 
 193         /*----------------------------------------------------*/
 194 
 195         /* "gadget zero", Linux-USB test software */
 196         if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a0)
 197                 return 0;
 198 
 199         /* user mode subset of that */
 200         if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a4)
 201                 return testdev_ffs_ifnum(fd);
 202                 /* return 0; */
 203 
 204         /* iso version of usermode code */
 205         if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a3)
 206                 return 0;
 207 
 208         /* some GPL'd test firmware uses these IDs */
 209 
 210         if (dev.idVendor == 0xfff0 && dev.idProduct == 0xfff0)
 211                 return 0;
 212 
 213         /*----------------------------------------------------*/
 214 
 215         /* iBOT2 high speed webcam */
 216         if (dev.idVendor == 0x0b62 && dev.idProduct == 0x0059)
 217                 return 0;
 218 
 219         /*----------------------------------------------------*/
 220 
 221         /* the FunctionFS gadget can have the source/sink interface
 222          * anywhere.  We look for an interface descriptor that match
 223          * what we expect.  We ignore configuratiens thou. */
 224 
 225         if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4ac
 226          && (dev.bDeviceClass == USB_CLASS_PER_INTERFACE
 227           || dev.bDeviceClass == USB_CLASS_VENDOR_SPEC))
 228                 return testdev_ffs_ifnum(fd);
 229 
 230         return -1;
 231 }
 232 
 233 static int find_testdev(const char *name, const struct stat *sb, int flag)
 234 {
 235         FILE                            *fd;
 236         int                             ifnum;
 237         struct testdev                  *entry;
 238 
 239         (void)sb; /* unused */
 240 
 241         if (flag != FTW_F)
 242                 return 0;
 243 
 244         fd = fopen(name, "rb");
 245         if (!fd) {
 246                 perror(name);
 247                 return 0;
 248         }
 249 
 250         ifnum = testdev_ifnum(fd);
 251         fclose(fd);
 252         if (ifnum < 0)
 253                 return 0;
 254 
 255         entry = calloc(1, sizeof *entry);
 256         if (!entry)
 257                 goto nomem;
 258 
 259         entry->name = strdup(name);
 260         if (!entry->name) {
 261                 free(entry);
 262 nomem:
 263                 perror("malloc");
 264                 return 0;
 265         }
 266 
 267         entry->ifnum = ifnum;
 268 
 269         /* FIXME update USBDEVFS_CONNECTINFO so it tells about high speed etc */
 270 
 271         fprintf(stderr, "%s speed\t%s\t%u\n",
 272                 speed(entry->speed), entry->name, entry->ifnum);
 273 
 274         entry->next = testdevs;
 275         testdevs = entry;
 276         return 0;
 277 }
 278 
 279 static int
 280 usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
 281 {
 282         struct usbdevfs_ioctl   wrapper;
 283 
 284         wrapper.ifno = ifno;
 285         wrapper.ioctl_code = request;
 286         wrapper.data = param;
 287 
 288         return ioctl (fd, USBDEVFS_IOCTL, &wrapper);
 289 }
 290 
 291 static void *handle_testdev (void *arg)
 292 {
 293         struct testdev          *dev = arg;
 294         int                     fd, i;
 295         int                     status;
 296 
 297         if ((fd = open (dev->name, O_RDWR)) < 0) {
 298                 perror ("can't open dev file r/w");
 299                 return 0;
 300         }
 301 
 302 restart:
 303         for (i = 0; i < TEST_CASES; i++) {
 304                 if (dev->test != -1 && dev->test != i)
 305                         continue;
 306                 dev->param.test_num = i;
 307 
 308                 status = usbdev_ioctl (fd, dev->ifnum,
 309                                 USBTEST_REQUEST, &dev->param);
 310                 if (status < 0 && errno == EOPNOTSUPP)
 311                         continue;
 312 
 313                 /* FIXME need a "syslog it" option for background testing */
 314 
 315                 /* NOTE: each thread emits complete lines; no fragments! */
 316                 if (status < 0) {
 317                         char    buf [80];
 318                         int     err = errno;
 319 
 320                         if (strerror_r (errno, buf, sizeof buf)) {
 321                                 snprintf (buf, sizeof buf, "error %d", err);
 322                                 errno = err;
 323                         }
 324                         printf ("%s test %d --> %d (%s)\n",
 325                                 dev->name, i, errno, buf);
 326                 } else
 327                         printf ("%s test %d, %4d.%.06d secs\n", dev->name, i,
 328                                 (int) dev->param.duration.tv_sec,
 329                                 (int) dev->param.duration.tv_usec);
 330 
 331                 fflush (stdout);
 332         }
 333         if (dev->forever)
 334                 goto restart;
 335 
 336         close (fd);
 337         return arg;
 338 }
 339 
 340 static const char *usb_dir_find(void)
 341 {
 342         static char udev_usb_path[] = "/dev/bus/usb";
 343 
 344         if (access(udev_usb_path, F_OK) == 0)
 345                 return udev_usb_path;
 346 
 347         return NULL;
 348 }
 349 
 350 static int parse_num(unsigned *num, const char *str)
 351 {
 352         unsigned long val;
 353         char *end;
 354 
 355         errno = 0;
 356         val = strtoul(str, &end, 0);
 357         if (errno || *end || val > UINT_MAX)
 358                 return -1;
 359         *num = val;
 360         return 0;
 361 }
 362 
 363 int main (int argc, char **argv)
 364 {
 365 
 366         int                     c;
 367         struct testdev          *entry;
 368         char                    *device;
 369         const char              *usb_dir = NULL;
 370         int                     all = 0, forever = 0, not = 0;
 371         int                     test = -1 /* all */;
 372         struct usbtest_param    param;
 373 
 374         /* pick defaults that works with all speeds, without short packets.
 375          *
 376          * Best per-frame data rates:
 377          *     super speed,bulk      1024 * 16 * 8 = 131072
 378          *                 interrupt 1024 *  3 * 8 =  24576
 379          *     high speed, bulk       512 * 13 * 8 =  53248
 380          *                 interrupt 1024 *  3 * 8 =  24576
 381          *     full speed, bulk/intr   64 * 19     =   1216
 382          *                 interrupt   64 *  1     =     64
 383          *      low speed, interrupt    8 *  1     =      8
 384          */
 385         param.iterations = 1000;
 386         param.length = 1024;
 387         param.vary = 1024;
 388         param.sglen = 32;
 389 
 390         /* for easy use when hotplugging */
 391         device = getenv ("DEVICE");
 392 
 393         while ((c = getopt (argc, argv, "D:aA:c:g:hlns:t:v:")) != EOF)
 394         switch (c) {
 395         case 'D':       /* device, if only one */
 396                 device = optarg;
 397                 continue;
 398         case 'A':       /* use all devices with specified USB dir */
 399                 usb_dir = optarg;
 400                 /* FALL THROUGH */
 401         case 'a':       /* use all devices */
 402                 device = NULL;
 403                 all = 1;
 404                 continue;
 405         case 'c':       /* count iterations */
 406                 if (parse_num(&param.iterations, optarg))
 407                         goto usage;
 408                 continue;
 409         case 'g':       /* scatter/gather entries */
 410                 if (parse_num(&param.sglen, optarg))
 411                         goto usage;
 412                 continue;
 413         case 'l':       /* loop forever */
 414                 forever = 1;
 415                 continue;
 416         case 'n':       /* no test running! */
 417                 not = 1;
 418                 continue;
 419         case 's':       /* size of packet */
 420                 if (parse_num(&param.length, optarg))
 421                         goto usage;
 422                 continue;
 423         case 't':       /* run just one test */
 424                 test = atoi (optarg);
 425                 if (test < 0)
 426                         goto usage;
 427                 continue;
 428         case 'v':       /* vary packet size by ... */
 429                 if (parse_num(&param.vary, optarg))
 430                         goto usage;
 431                 continue;
 432         case '?':
 433         case 'h':
 434         default:
 435 usage:
 436                 fprintf (stderr,
 437                         "usage: %s [options]\n"
 438                         "Options:\n"
 439                         "\t-D dev               only test specific device\n"
 440                         "\t-A usb-dir\n"
 441                         "\t-a           test all recognized devices\n"
 442                         "\t-l           loop forever(for stress test)\n"
 443                         "\t-t testnum   only run specified case\n"
 444                         "\t-n           no test running, show devices to be tested\n"
 445                         "Case arguments:\n"
 446                         "\t-c iterations                default 1000\n"
 447                         "\t-s transfer length   default 1024\n"
 448                         "\t-g sglen             default 32\n"
 449                         "\t-v vary                      default 1024\n",
 450                         argv[0]);
 451                 return 1;
 452         }
 453         if (optind != argc)
 454                 goto usage;
 455         if (!all && !device) {
 456                 fprintf (stderr, "must specify '-a' or '-D dev', "
 457                         "or DEVICE=/dev/bus/usb/BBB/DDD in env\n");
 458                 goto usage;
 459         }
 460 
 461         /* Find usb device subdirectory */
 462         if (!usb_dir) {
 463                 usb_dir = usb_dir_find();
 464                 if (!usb_dir) {
 465                         fputs ("USB device files are missing\n", stderr);
 466                         return -1;
 467                 }
 468         }
 469 
 470         /* collect and list the test devices */
 471         if (ftw (usb_dir, find_testdev, 3) != 0) {
 472                 fputs ("ftw failed; are USB device files missing?\n", stderr);
 473                 return -1;
 474         }
 475 
 476         /* quit, run single test, or create test threads */
 477         if (!testdevs && !device) {
 478                 fputs ("no test devices recognized\n", stderr);
 479                 return -1;
 480         }
 481         if (not)
 482                 return 0;
 483         if (testdevs && testdevs->next == 0 && !device)
 484                 device = testdevs->name;
 485         for (entry = testdevs; entry; entry = entry->next) {
 486                 int     status;
 487 
 488                 entry->param = param;
 489                 entry->forever = forever;
 490                 entry->test = test;
 491 
 492                 if (device) {
 493                         if (strcmp (entry->name, device))
 494                                 continue;
 495                         return handle_testdev (entry) != entry;
 496                 }
 497                 status = pthread_create (&entry->thread, 0, handle_testdev, entry);
 498                 if (status)
 499                         perror ("pthread_create");
 500         }
 501         if (device) {
 502                 struct testdev          dev;
 503 
 504                 /* kernel can recognize test devices we don't */
 505                 fprintf (stderr, "%s: %s may see only control tests\n",
 506                                 argv [0], device);
 507 
 508                 memset (&dev, 0, sizeof dev);
 509                 dev.name = device;
 510                 dev.param = param;
 511                 dev.forever = forever;
 512                 dev.test = test;
 513                 return handle_testdev (&dev) != &dev;
 514         }
 515 
 516         /* wait for tests to complete */
 517         for (entry = testdevs; entry; entry = entry->next) {
 518                 void    *retval;
 519 
 520                 if (pthread_join (entry->thread, &retval))
 521                         perror ("pthread_join");
 522                 /* testing errors discarded! */
 523         }
 524 
 525         return 0;
 526 }

/* [<][>][^][v][top][bottom][index][help] */