testusb.c (12395B)
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(¶m.iterations, optarg)) 409 goto usage; 410 continue; 411 case 'g': /* scatter/gather entries */ 412 if (parse_num(¶m.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(¶m.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(¶m.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 && !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}