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 USB_SPEED_WIRELESS, /* wireless (usb 2.5) */ 101 USB_SPEED_SUPER, /* usb 3.0 */ 102 USB_SPEED_SUPER_PLUS, /* usb 3.1 */ 103 }; 104 105 /*-------------------------------------------------------------------------*/ 106 107 static char *speed (enum usb_device_speed s) 108 { 109 switch (s) { 110 case USB_SPEED_UNKNOWN: return "unknown"; 111 case USB_SPEED_LOW: return "low"; 112 case USB_SPEED_FULL: return "full"; 113 case USB_SPEED_HIGH: return "high"; 114 case USB_SPEED_WIRELESS: return "wireless"; 115 case USB_SPEED_SUPER: return "super"; 116 case USB_SPEED_SUPER_PLUS: return "super-plus"; 117 default: return "??"; 118 } 119 } 120 121 struct testdev { 122 struct testdev *next; 123 char *name; 124 pthread_t thread; 125 enum usb_device_speed speed; 126 unsigned ifnum : 8; 127 unsigned forever : 1; 128 int test; 129 130 struct usbtest_param param; 131 }; 132 static struct testdev *testdevs; 133 134 static int testdev_ffs_ifnum(FILE *fd) 135 { 136 union { 137 char buf[255]; 138 struct usb_interface_descriptor intf; 139 } u; 140 141 for (;;) { 142 if (fread(u.buf, 1, 1, fd) != 1) 143 return -1; 144 if (fread(u.buf + 1, (unsigned char)u.buf[0] - 1, 1, fd) != 1) 145 return -1; 146 147 if (u.intf.bLength == sizeof u.intf 148 && u.intf.bDescriptorType == USB_DT_INTERFACE 149 && u.intf.bNumEndpoints == 2 150 && u.intf.bInterfaceClass == USB_CLASS_VENDOR_SPEC 151 && u.intf.bInterfaceSubClass == 0 152 && u.intf.bInterfaceProtocol == 0) 153 return (unsigned char)u.intf.bInterfaceNumber; 154 } 155 } 156 157 static int testdev_ifnum(FILE *fd) 158 { 159 struct usb_device_descriptor dev; 160 161 if (fread(&dev, sizeof dev, 1, fd) != 1) 162 return -1; 163 164 if (dev.bLength != sizeof dev || dev.bDescriptorType != USB_DT_DEVICE) 165 return -1; 166 167 /* FX2 with (tweaked) bulksrc firmware */ 168 if (dev.idVendor == 0x0547 && dev.idProduct == 0x1002) 169 return 0; 170 171 /*----------------------------------------------------*/ 172 173 /* devices that start up using the EZ-USB default device and 174 * which we can use after loading simple firmware. hotplug 175 * can fxload it, and then run this test driver. 176 * 177 * we return false positives in two cases: 178 * - the device has a "real" driver (maybe usb-serial) that 179 * renumerates. the device should vanish quickly. 180 * - the device doesn't have the test firmware installed. 181 */ 182 183 /* generic EZ-USB FX controller */ 184 if (dev.idVendor == 0x0547 && dev.idProduct == 0x2235) 185 return 0; 186 187 /* generic EZ-USB FX2 controller */ 188 if (dev.idVendor == 0x04b4 && dev.idProduct == 0x8613) 189 return 0; 190 191 /* CY3671 development board with EZ-USB FX */ 192 if (dev.idVendor == 0x0547 && dev.idProduct == 0x0080) 193 return 0; 194 195 /* Keyspan 19Qi uses an21xx (original EZ-USB) */ 196 if (dev.idVendor == 0x06cd && dev.idProduct == 0x010b) 197 return 0; 198 199 /*----------------------------------------------------*/ 200 201 /* "gadget zero", Linux-USB test software */ 202 if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a0) 203 return 0; 204 205 /* user mode subset of that */ 206 if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a4) 207 return testdev_ffs_ifnum(fd); 208 /* return 0; */ 209 210 /* iso version of usermode code */ 211 if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a3) 212 return 0; 213 214 /* some GPL'd test firmware uses these IDs */ 215 216 if (dev.idVendor == 0xfff0 && dev.idProduct == 0xfff0) 217 return 0; 218 219 /*----------------------------------------------------*/ 220 221 /* iBOT2 high speed webcam */ 222 if (dev.idVendor == 0x0b62 && dev.idProduct == 0x0059) 223 return 0; 224 225 /*----------------------------------------------------*/ 226 227 /* the FunctionFS gadget can have the source/sink interface 228 * anywhere. We look for an interface descriptor that match 229 * what we expect. We ignore configuratiens thou. */ 230 231 if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4ac 232 && (dev.bDeviceClass == USB_CLASS_PER_INTERFACE 233 || dev.bDeviceClass == USB_CLASS_VENDOR_SPEC)) 234 return testdev_ffs_ifnum(fd); 235 236 return -1; 237 } 238 239 static int find_testdev(const char *name, const struct stat *sb, int flag) 240 { 241 FILE *fd; 242 int ifnum; 243 struct testdev *entry; 244 245 (void)sb; /* unused */ 246 247 if (flag != FTW_F) 248 return 0; 249 250 fd = fopen(name, "rb"); 251 if (!fd) { 252 perror(name); 253 return 0; 254 } 255 256 ifnum = testdev_ifnum(fd); 257 fclose(fd); 258 if (ifnum < 0) 259 return 0; 260 261 entry = calloc(1, sizeof *entry); 262 if (!entry) 263 goto nomem; 264 265 entry->name = strdup(name); 266 if (!entry->name) { 267 free(entry); 268 nomem: 269 perror("malloc"); 270 return 0; 271 } 272 273 entry->ifnum = ifnum; 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 status = ioctl(fd, USBDEVFS_GET_SPEED, NULL); 303 if (status < 0) 304 fprintf(stderr, "USBDEVFS_GET_SPEED failed %d\n", status); 305 else 306 dev->speed = status; 307 fprintf(stderr, "%s speed\t%s\t%u\n", 308 speed(dev->speed), dev->name, dev->ifnum); 309 310 restart: 311 for (i = 0; i < TEST_CASES; i++) { 312 if (dev->test != -1 && dev->test != i) 313 continue; 314 dev->param.test_num = i; 315 316 status = usbdev_ioctl (fd, dev->ifnum, 317 USBTEST_REQUEST, &dev->param); 318 if (status < 0 && errno == EOPNOTSUPP) 319 continue; 320 321 /* FIXME need a "syslog it" option for background testing */ 322 323 /* NOTE: each thread emits complete lines; no fragments! */ 324 if (status < 0) { 325 char buf [80]; 326 int err = errno; 327 328 if (strerror_r (errno, buf, sizeof buf)) { 329 snprintf (buf, sizeof buf, "error %d", err); 330 errno = err; 331 } 332 printf ("%s test %d --> %d (%s)\n", 333 dev->name, i, errno, buf); 334 } else 335 printf ("%s test %d, %4d.%.06d secs\n", dev->name, i, 336 (int) dev->param.duration.tv_sec, 337 (int) dev->param.duration.tv_usec); 338 339 fflush (stdout); 340 } 341 if (dev->forever) 342 goto restart; 343 344 close (fd); 345 return arg; 346 } 347 348 static const char *usb_dir_find(void) 349 { 350 static char udev_usb_path[] = "/dev/bus/usb"; 351 352 if (access(udev_usb_path, F_OK) == 0) 353 return udev_usb_path; 354 355 return NULL; 356 } 357 358 static int parse_num(unsigned *num, const char *str) 359 { 360 unsigned long val; 361 char *end; 362 363 errno = 0; 364 val = strtoul(str, &end, 0); 365 if (errno || *end || val > UINT_MAX) 366 return -1; 367 *num = val; 368 return 0; 369 } 370 371 int main (int argc, char **argv) 372 { 373 374 int c; 375 struct testdev *entry; 376 char *device; 377 const char *usb_dir = NULL; 378 int all = 0, forever = 0, not = 0; 379 int test = -1 /* all */; 380 struct usbtest_param param; 381 382 /* pick defaults that works with all speeds, without short packets. 383 * 384 * Best per-frame data rates: 385 * super speed,bulk 1024 * 16 * 8 = 131072 386 * interrupt 1024 * 3 * 8 = 24576 387 * high speed, bulk 512 * 13 * 8 = 53248 388 * interrupt 1024 * 3 * 8 = 24576 389 * full speed, bulk/intr 64 * 19 = 1216 390 * interrupt 64 * 1 = 64 391 * low speed, interrupt 8 * 1 = 8 392 */ 393 param.iterations = 1000; 394 param.length = 1024; 395 param.vary = 1024; 396 param.sglen = 32; 397 398 /* for easy use when hotplugging */ 399 device = getenv ("DEVICE"); 400 401 while ((c = getopt (argc, argv, "D:aA:c:g:hlns:t:v:")) != EOF) 402 switch (c) { 403 case 'D': /* device, if only one */ 404 device = optarg; 405 continue; 406 case 'A': /* use all devices with specified USB dir */ 407 usb_dir = optarg; 408 /* FALL THROUGH */ 409 case 'a': /* use all devices */ 410 device = NULL; 411 all = 1; 412 continue; 413 case 'c': /* count iterations */ 414 if (parse_num(¶m.iterations, optarg)) 415 goto usage; 416 continue; 417 case 'g': /* scatter/gather entries */ 418 if (parse_num(¶m.sglen, optarg)) 419 goto usage; 420 continue; 421 case 'l': /* loop forever */ 422 forever = 1; 423 continue; 424 case 'n': /* no test running! */ 425 not = 1; 426 continue; 427 case 's': /* size of packet */ 428 if (parse_num(¶m.length, optarg)) 429 goto usage; 430 continue; 431 case 't': /* run just one test */ 432 test = atoi (optarg); 433 if (test < 0) 434 goto usage; 435 continue; 436 case 'v': /* vary packet size by ... */ 437 if (parse_num(¶m.vary, optarg)) 438 goto usage; 439 continue; 440 case '?': 441 case 'h': 442 default: 443 usage: 444 fprintf (stderr, 445 "usage: %s [options]\n" 446 "Options:\n" 447 "\t-D dev only test specific device\n" 448 "\t-A usb-dir\n" 449 "\t-a test all recognized devices\n" 450 "\t-l loop forever(for stress test)\n" 451 "\t-t testnum only run specified case\n" 452 "\t-n no test running, show devices to be tested\n" 453 "Case arguments:\n" 454 "\t-c iterations default 1000\n" 455 "\t-s transfer length default 1024\n" 456 "\t-g sglen default 32\n" 457 "\t-v vary default 1024\n", 458 argv[0]); 459 return 1; 460 } 461 if (optind != argc) 462 goto usage; 463 if (!all && !device) { 464 fprintf (stderr, "must specify '-a' or '-D dev', " 465 "or DEVICE=/dev/bus/usb/BBB/DDD in env\n"); 466 goto usage; 467 } 468 469 /* Find usb device subdirectory */ 470 if (!usb_dir) { 471 usb_dir = usb_dir_find(); 472 if (!usb_dir) { 473 fputs ("USB device files are missing\n", stderr); 474 return -1; 475 } 476 } 477 478 /* collect and list the test devices */ 479 if (ftw (usb_dir, find_testdev, 3) != 0) { 480 fputs ("ftw failed; are USB device files missing?\n", stderr); 481 return -1; 482 } 483 484 /* quit, run single test, or create test threads */ 485 if (!testdevs && !device) { 486 fputs ("no test devices recognized\n", stderr); 487 return -1; 488 } 489 if (not) 490 return 0; 491 if (testdevs && !testdevs->next && !device) 492 device = testdevs->name; 493 for (entry = testdevs; entry; entry = entry->next) { 494 int status; 495 496 entry->param = param; 497 entry->forever = forever; 498 entry->test = test; 499 500 if (device) { 501 if (strcmp (entry->name, device)) 502 continue; 503 return handle_testdev (entry) != entry; 504 } 505 status = pthread_create (&entry->thread, 0, handle_testdev, entry); 506 if (status) 507 perror ("pthread_create"); 508 } 509 if (device) { 510 struct testdev dev; 511 512 /* kernel can recognize test devices we don't */ 513 fprintf (stderr, "%s: %s may see only control tests\n", 514 argv [0], device); 515 516 memset (&dev, 0, sizeof dev); 517 dev.name = device; 518 dev.param = param; 519 dev.forever = forever; 520 dev.test = test; 521 return handle_testdev (&dev) != &dev; 522 } 523 524 /* wait for tests to complete */ 525 for (entry = testdevs; entry; entry = entry->next) { 526 void *retval; 527 528 if (pthread_join (entry->thread, &retval)) 529 perror ("pthread_join"); 530 /* testing errors discarded! */ 531 } 532 533 return 0; 534 } 535
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.