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        entry->next = testdevs;
 269        testdevs = entry;
 270        return 0;
 271}
 272
 273static int
 274usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
 275{
 276        struct usbdevfs_ioctl   wrapper;
 277
 278        wrapper.ifno = ifno;
 279        wrapper.ioctl_code = request;
 280        wrapper.data = param;
 281
 282        return ioctl (fd, USBDEVFS_IOCTL, &wrapper);
 283}
 284
 285static void *handle_testdev (void *arg)
 286{
 287        struct testdev          *dev = arg;
 288        int                     fd, i;
 289        int                     status;
 290
 291        if ((fd = open (dev->name, O_RDWR)) < 0) {
 292                perror ("can't open dev file r/w");
 293                return 0;
 294        }
 295
 296        status  =  ioctl(fd, USBDEVFS_GET_SPEED, NULL);
 297        if (status < 0)
 298                fprintf(stderr, "USBDEVFS_GET_SPEED failed %d\n", status);
 299        else
 300                dev->speed = status;
 301        fprintf(stderr, "%s speed\t%s\t%u\n",
 302                        speed(dev->speed), dev->name, dev->ifnum);
 303
 304restart:
 305        for (i = 0; i < TEST_CASES; i++) {
 306                if (dev->test != -1 && dev->test != i)
 307                        continue;
 308                dev->param.test_num = i;
 309
 310                status = usbdev_ioctl (fd, dev->ifnum,
 311                                USBTEST_REQUEST, &dev->param);
 312                if (status < 0 && errno == EOPNOTSUPP)
 313                        continue;
 314
 315                /* FIXME need a "syslog it" option for background testing */
 316
 317                /* NOTE: each thread emits complete lines; no fragments! */
 318                if (status < 0) {
 319                        char    buf [80];
 320                        int     err = errno;
 321
 322                        if (strerror_r (errno, buf, sizeof buf)) {
 323                                snprintf (buf, sizeof buf, "error %d", err);
 324                                errno = err;
 325                        }
 326                        printf ("%s test %d --> %d (%s)\n",
 327                                dev->name, i, errno, buf);
 328                } else
 329                        printf ("%s test %d, %4d.%.06d secs\n", dev->name, i,
 330                                (int) dev->param.duration.tv_sec,
 331                                (int) dev->param.duration.tv_usec);
 332
 333                fflush (stdout);
 334        }
 335        if (dev->forever)
 336                goto restart;
 337
 338        close (fd);
 339        return arg;
 340}
 341
 342static const char *usb_dir_find(void)
 343{
 344        static char udev_usb_path[] = "/dev/bus/usb";
 345
 346        if (access(udev_usb_path, F_OK) == 0)
 347                return udev_usb_path;
 348
 349        return NULL;
 350}
 351
 352static int parse_num(unsigned *num, const char *str)
 353{
 354        unsigned long val;
 355        char *end;
 356
 357        errno = 0;
 358        val = strtoul(str, &end, 0);
 359        if (errno || *end || val > UINT_MAX)
 360                return -1;
 361        *num = val;
 362        return 0;
 363}
 364
 365int main (int argc, char **argv)
 366{
 367
 368        int                     c;
 369        struct testdev          *entry;
 370        char                    *device;
 371        const char              *usb_dir = NULL;
 372        int                     all = 0, forever = 0, not = 0;
 373        int                     test = -1 /* all */;
 374        struct usbtest_param    param;
 375
 376        /* pick defaults that works with all speeds, without short packets.
 377         *
 378         * Best per-frame data rates:
 379         *     super speed,bulk      1024 * 16 * 8 = 131072
 380         *                 interrupt 1024 *  3 * 8 =  24576
 381         *     high speed, bulk       512 * 13 * 8 =  53248
 382         *                 interrupt 1024 *  3 * 8 =  24576
 383         *     full speed, bulk/intr   64 * 19     =   1216
 384         *                 interrupt   64 *  1     =     64
 385         *      low speed, interrupt    8 *  1     =      8
 386         */
 387        param.iterations = 1000;
 388        param.length = 1024;
 389        param.vary = 1024;
 390        param.sglen = 32;
 391
 392        /* for easy use when hotplugging */
 393        device = getenv ("DEVICE");
 394
 395        while ((c = getopt (argc, argv, "D:aA:c:g:hlns:t:v:")) != EOF)
 396        switch (c) {
 397        case 'D':       /* device, if only one */
 398                device = optarg;
 399                continue;
 400        case 'A':       /* use all devices with specified USB dir */
 401                usb_dir = optarg;
 402                /* FALL THROUGH */
 403        case 'a':       /* use all devices */
 404                device = NULL;
 405                all = 1;
 406                continue;
 407        case 'c':       /* count iterations */
 408                if (parse_num(&param.iterations, optarg))
 409                        goto usage;
 410                continue;
 411        case 'g':       /* scatter/gather entries */
 412                if (parse_num(&param.sglen, optarg))
 413                        goto usage;
 414                continue;
 415        case 'l':       /* loop forever */
 416                forever = 1;
 417                continue;
 418        case 'n':       /* no test running! */
 419                not = 1;
 420                continue;
 421        case 's':       /* size of packet */
 422                if (parse_num(&param.length, optarg))
 423                        goto usage;
 424                continue;
 425        case 't':       /* run just one test */
 426                test = atoi (optarg);
 427                if (test < 0)
 428                        goto usage;
 429                continue;
 430        case 'v':       /* vary packet size by ... */
 431                if (parse_num(&param.vary, optarg))
 432                        goto usage;
 433                continue;
 434        case '?':
 435        case 'h':
 436        default:
 437usage:
 438                fprintf (stderr,
 439                        "usage: %s [options]\n"
 440                        "Options:\n"
 441                        "\t-D dev               only test specific device\n"
 442                        "\t-A usb-dir\n"
 443                        "\t-a           test all recognized devices\n"
 444                        "\t-l           loop forever(for stress test)\n"
 445                        "\t-t testnum   only run specified case\n"
 446                        "\t-n           no test running, show devices to be tested\n"
 447                        "Case arguments:\n"
 448                        "\t-c iterations                default 1000\n"
 449                        "\t-s transfer length   default 1024\n"
 450                        "\t-g sglen             default 32\n"
 451                        "\t-v vary                      default 1024\n",
 452                        argv[0]);
 453                return 1;
 454        }
 455        if (optind != argc)
 456                goto usage;
 457        if (!all && !device) {
 458                fprintf (stderr, "must specify '-a' or '-D dev', "
 459                        "or DEVICE=/dev/bus/usb/BBB/DDD in env\n");
 460                goto usage;
 461        }
 462
 463        /* Find usb device subdirectory */
 464        if (!usb_dir) {
 465                usb_dir = usb_dir_find();
 466                if (!usb_dir) {
 467                        fputs ("USB device files are missing\n", stderr);
 468                        return -1;
 469                }
 470        }
 471
 472        /* collect and list the test devices */
 473        if (ftw (usb_dir, find_testdev, 3) != 0) {
 474                fputs ("ftw failed; are USB device files missing?\n", stderr);
 475                return -1;
 476        }
 477
 478        /* quit, run single test, or create test threads */
 479        if (!testdevs && !device) {
 480                fputs ("no test devices recognized\n", stderr);
 481                return -1;
 482        }
 483        if (not)
 484                return 0;
 485        if (testdevs && testdevs->next == 0 && !device)
 486                device = testdevs->name;
 487        for (entry = testdevs; entry; entry = entry->next) {
 488                int     status;
 489
 490                entry->param = param;
 491                entry->forever = forever;
 492                entry->test = test;
 493
 494                if (device) {
 495                        if (strcmp (entry->name, device))
 496                                continue;
 497                        return handle_testdev (entry) != entry;
 498                }
 499                status = pthread_create (&entry->thread, 0, handle_testdev, entry);
 500                if (status)
 501                        perror ("pthread_create");
 502        }
 503        if (device) {
 504                struct testdev          dev;
 505
 506                /* kernel can recognize test devices we don't */
 507                fprintf (stderr, "%s: %s may see only control tests\n",
 508                                argv [0], device);
 509
 510                memset (&dev, 0, sizeof dev);
 511                dev.name = device;
 512                dev.param = param;
 513                dev.forever = forever;
 514                dev.test = test;
 515                return handle_testdev (&dev) != &dev;
 516        }
 517
 518        /* wait for tests to complete */
 519        for (entry = testdevs; entry; entry = entry->next) {
 520                void    *retval;
 521
 522                if (pthread_join (entry->thread, &retval))
 523                        perror ("pthread_join");
 524                /* testing errors discarded! */
 525        }
 526
 527        return 0;
 528}
 529