linux/tools/usb/testusb.c
<<
>>
Prefs
   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
  42struct 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
  66struct 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
  83struct 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
  96enum 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
 104static 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
 115struct 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};
 126static struct testdev           *testdevs;
 127
 128static 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
 151static 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
 233static 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);
 262nomem:
 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
 279static int
 280usbdev_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
 291static 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
 302restart:
 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
 340static 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
 350static 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
 363int 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:
 435usage:
 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}
 527