Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: testusb: testusb compatibility with FunctionFS gadget

The FunctionFS gadget may provide the source/sink interface
not as the first interface (with id == 0) but some different
interface hence a code to find the interface number is
required.

(Note that you will still configure the gadget to report
idProduct == 0xa4a4 (an "echo 0xa4a4
>/sys/module/g_ffs/parameters/usb_product" should suffice) or
configure host to handle 0x0525:0xa4ac devices using the
usbtest driver.)

Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Michal Nazarewicz and committed by
Greg Kroah-Hartman
5bc9661c 2201d6b1

+190 -70
+190 -70
tools/usb/testusb.c
··· 1 - /* $(CROSS_COMPILE)cc -Wall -g -lpthread -o testusb testusb.c */ 1 + /* $(CROSS_COMPILE)cc -Wall -Wextra -g -lpthread -o testusb testusb.c */ 2 2 3 3 /* 4 4 * Copyright (c) 2002 by David Brownell 5 + * Copyright (c) 2010 by Samsung Electronics 6 + * Author: Michal Nazarewicz <m.nazarewicz@samsung.com> 5 7 * 6 8 * This program is free software; you can redistribute it and/or modify it 7 9 * under the terms of the GNU General Public License as published by the ··· 20 18 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 19 */ 22 20 21 + /* 22 + * This program issues ioctls to perform the tests implemented by the 23 + * kernel driver. It can generate a variety of transfer patterns; you 24 + * should make sure to test both regular streaming and mixes of 25 + * transfer sizes (including short transfers). 26 + * 27 + * For more information on how this can be used and on USB testing 28 + * refer to <URL:http://www.linux-usb.org/usbtest/>. 29 + */ 30 + 23 31 #include <stdio.h> 24 32 #include <string.h> 25 33 #include <ftw.h> ··· 37 25 #include <pthread.h> 38 26 #include <unistd.h> 39 27 #include <errno.h> 28 + #include <limits.h> 40 29 41 30 #include <sys/types.h> 42 31 #include <sys/stat.h> ··· 69 56 70 57 /* #include <linux/usb_ch9.h> */ 71 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 + 72 66 struct usb_device_descriptor { 73 67 __u8 bLength; 74 68 __u8 bDescriptorType; ··· 91 71 __u8 iProduct; 92 72 __u8 iSerialNumber; 93 73 __u8 bNumConfigurations; 74 + } __attribute__ ((packed)); 75 + 76 + struct usb_interface_descriptor { 77 + __u8 bLength; 78 + __u8 bDescriptorType; 79 + 80 + __u8 bInterfaceNumber; 81 + __u8 bAlternateSetting; 82 + __u8 bNumEndpoints; 83 + __u8 bInterfaceClass; 84 + __u8 bInterfaceSubClass; 85 + __u8 bInterfaceProtocol; 86 + __u8 iInterface; 94 87 } __attribute__ ((packed)); 95 88 96 89 enum usb_device_speed { ··· 138 105 }; 139 106 static struct testdev *testdevs; 140 107 141 - static int is_testdev (struct usb_device_descriptor *dev) 108 + static int testdev_ffs_ifnum(FILE *fd) 142 109 { 110 + union { 111 + char buf[255]; 112 + struct usb_interface_descriptor intf; 113 + } u; 114 + 115 + for (;;) { 116 + if (fread(u.buf, 1, 1, fd) != 1) 117 + return -1; 118 + if (fread(u.buf + 1, (unsigned char)u.buf[0] - 1, 1, fd) != 1) 119 + return -1; 120 + 121 + if (u.intf.bLength == sizeof u.intf 122 + && u.intf.bDescriptorType == USB_DT_INTERFACE 123 + && u.intf.bNumEndpoints == 2 124 + && u.intf.bInterfaceClass == USB_CLASS_VENDOR_SPEC 125 + && u.intf.bInterfaceSubClass == 0 126 + && u.intf.bInterfaceProtocol == 0) 127 + return (unsigned char)u.intf.bInterfaceNumber; 128 + } 129 + } 130 + 131 + static int testdev_ifnum(FILE *fd) 132 + { 133 + struct usb_device_descriptor dev; 134 + 135 + if (fread(&dev, sizeof dev, 1, fd) != 1) 136 + return -1; 137 + 138 + if (dev.bLength != sizeof dev || dev.bDescriptorType != USB_DT_DEVICE) 139 + return -1; 140 + 143 141 /* FX2 with (tweaked) bulksrc firmware */ 144 - if (dev->idVendor == 0x0547 && dev->idProduct == 0x1002) 145 - return 1; 142 + if (dev.idVendor == 0x0547 && dev.idProduct == 0x1002) 143 + return 0; 146 144 147 145 /*----------------------------------------------------*/ 148 146 ··· 188 124 */ 189 125 190 126 /* generic EZ-USB FX controller */ 191 - if (dev->idVendor == 0x0547 && dev->idProduct == 0x2235) 192 - return 1; 127 + if (dev.idVendor == 0x0547 && dev.idProduct == 0x2235) 128 + return 0; 193 129 194 130 /* generic EZ-USB FX2 controller */ 195 - if (dev->idVendor == 0x04b4 && dev->idProduct == 0x8613) 196 - return 1; 131 + if (dev.idVendor == 0x04b4 && dev.idProduct == 0x8613) 132 + return 0; 197 133 198 134 /* CY3671 development board with EZ-USB FX */ 199 - if (dev->idVendor == 0x0547 && dev->idProduct == 0x0080) 200 - return 1; 135 + if (dev.idVendor == 0x0547 && dev.idProduct == 0x0080) 136 + return 0; 201 137 202 138 /* Keyspan 19Qi uses an21xx (original EZ-USB) */ 203 - if (dev->idVendor == 0x06cd && dev->idProduct == 0x010b) 204 - return 1; 139 + if (dev.idVendor == 0x06cd && dev.idProduct == 0x010b) 140 + return 0; 205 141 206 142 /*----------------------------------------------------*/ 207 143 208 144 /* "gadget zero", Linux-USB test software */ 209 - if (dev->idVendor == 0x0525 && dev->idProduct == 0xa4a0) 210 - return 1; 145 + if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a0) 146 + return 0; 211 147 212 148 /* user mode subset of that */ 213 - if (dev->idVendor == 0x0525 && dev->idProduct == 0xa4a4) 214 - return 1; 149 + if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a4) 150 + return testdev_ffs_ifnum(fd); 151 + /* return 0; */ 215 152 216 153 /* iso version of usermode code */ 217 - if (dev->idVendor == 0x0525 && dev->idProduct == 0xa4a3) 218 - return 1; 154 + if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a3) 155 + return 0; 219 156 220 157 /* some GPL'd test firmware uses these IDs */ 221 158 222 - if (dev->idVendor == 0xfff0 && dev->idProduct == 0xfff0) 223 - return 1; 159 + if (dev.idVendor == 0xfff0 && dev.idProduct == 0xfff0) 160 + return 0; 224 161 225 162 /*----------------------------------------------------*/ 226 163 227 164 /* iBOT2 high speed webcam */ 228 - if (dev->idVendor == 0x0b62 && dev->idProduct == 0x0059) 229 - return 1; 165 + if (dev.idVendor == 0x0b62 && dev.idProduct == 0x0059) 166 + return 0; 230 167 231 - return 0; 168 + /*----------------------------------------------------*/ 169 + 170 + /* the FunctionFS gadget can have the source/sink interface 171 + * anywhere. We look for an interface descriptor that match 172 + * what we expect. We ignore configuratiens thou. */ 173 + 174 + if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4ac 175 + && (dev.bDeviceClass == USB_CLASS_PER_INTERFACE 176 + || dev.bDeviceClass == USB_CLASS_VENDOR_SPEC)) 177 + return testdev_ffs_ifnum(fd); 178 + 179 + return -1; 232 180 } 233 181 234 - static int find_testdev (const char *name, const struct stat *sb, int flag) 182 + static int find_testdev(const char *name, const struct stat *sb, int flag) 235 183 { 236 - int fd; 237 - struct usb_device_descriptor dev; 184 + FILE *fd; 185 + int ifnum; 186 + struct testdev *entry; 187 + 188 + (void)sb; /* unused */ 238 189 239 190 if (flag != FTW_F) 240 191 return 0; 241 192 /* ignore /proc/bus/usb/{devices,drivers} */ 242 - if (strrchr (name, '/')[1] == 'd') 193 + if (strrchr(name, '/')[1] == 'd') 243 194 return 0; 244 195 245 - if ((fd = open (name, O_RDONLY)) < 0) { 246 - perror ("can't open dev file r/o"); 196 + fd = fopen(name, "rb"); 197 + if (!fd) { 198 + perror(name); 247 199 return 0; 248 200 } 249 - if (read (fd, &dev, sizeof dev) != sizeof dev) 250 - fputs ("short devfile read!\n", stderr); 251 - else if (is_testdev (&dev)) { 252 - struct testdev *entry; 253 201 254 - if ((entry = calloc (1, sizeof *entry)) == 0) { 255 - fputs ("no mem!\n", stderr); 256 - goto done; 257 - } 258 - entry->name = strdup (name); 259 - if (!entry->name) { 260 - free (entry); 261 - goto done; 262 - } 202 + ifnum = testdev_ifnum(fd); 203 + fclose(fd); 204 + if (ifnum < 0) 205 + return 0; 263 206 264 - // FIXME better to look at each interface and ask if it's 265 - // bound to 'usbtest', rather than assume interface 0 266 - entry->ifnum = 0; 207 + entry = calloc(1, sizeof *entry); 208 + if (!entry) 209 + goto nomem; 267 210 268 - // FIXME ask usbfs what speed; update USBDEVFS_CONNECTINFO 269 - // so it tells about high speed etc 270 - 271 - fprintf (stderr, "%s speed\t%s\n", 272 - speed (entry->speed), entry->name); 273 - 274 - entry->next = testdevs; 275 - testdevs = entry; 211 + entry->name = strdup(name); 212 + if (!entry->name) { 213 + free(entry); 214 + nomem: 215 + perror("malloc"); 216 + return 0; 276 217 } 277 218 278 - done: 279 - close (fd); 219 + entry->ifnum = ifnum; 220 + 221 + /* FIXME ask usbfs what speed; update USBDEVFS_CONNECTINFO so 222 + * it tells about high speed etc */ 223 + 224 + fprintf(stderr, "%s speed\t%s\t%u\n", 225 + speed(entry->speed), entry->name, entry->ifnum); 226 + 227 + entry->next = testdevs; 228 + testdevs = entry; 280 229 return 0; 281 230 } 282 231 ··· 354 277 return arg; 355 278 } 356 279 280 + static const char *usbfs_dir_find(void) 281 + { 282 + static char usbfs_path_0[] = "/dev/usb/devices"; 283 + static char usbfs_path_1[] = "/proc/bus/usb/devices"; 284 + 285 + static char *const usbfs_paths[] = { 286 + usbfs_path_0, usbfs_path_1 287 + }; 288 + 289 + static char *const * 290 + end = usbfs_paths + sizeof usbfs_paths / sizeof *usbfs_paths; 291 + 292 + char *const *it = usbfs_paths; 293 + do { 294 + int fd = open(*it, O_RDONLY); 295 + close(fd); 296 + if (fd >= 0) { 297 + strrchr(*it, '/')[0] = '\0'; 298 + return *it; 299 + } 300 + } while (++it != end); 301 + 302 + return NULL; 303 + } 304 + 305 + static int parse_num(unsigned *num, const char *str) 306 + { 307 + unsigned long val; 308 + char *end; 309 + 310 + errno = 0; 311 + val = strtoul(str, &end, 0); 312 + if (errno || *end || val > UINT_MAX) 313 + return -1; 314 + *num = val; 315 + return 0; 316 + } 317 + 357 318 int main (int argc, char **argv) 358 319 { 320 + 359 321 int c; 360 322 struct testdev *entry; 361 323 char *device; 324 + const char *usbfs_dir = NULL; 362 325 int all = 0, forever = 0, not = 0; 363 326 int test = -1 /* all */; 364 327 struct usbtest_param param; ··· 420 303 /* for easy use when hotplugging */ 421 304 device = getenv ("DEVICE"); 422 305 423 - while ((c = getopt (argc, argv, "D:ac:g:hns:t:v:")) != EOF) 306 + while ((c = getopt (argc, argv, "D:aA:c:g:hns:t:v:")) != EOF) 424 307 switch (c) { 425 308 case 'D': /* device, if only one */ 426 309 device = optarg; 427 310 continue; 311 + case 'A': /* use all devices with specified usbfs dir */ 312 + usbfs_dir = optarg; 313 + /* FALL THROUGH */ 428 314 case 'a': /* use all devices */ 429 - device = 0; 315 + device = NULL; 430 316 all = 1; 431 317 continue; 432 318 case 'c': /* count iterations */ 433 - param.iterations = atoi (optarg); 434 - if (param.iterations < 0) 319 + if (parse_num(&param.iterations, optarg)) 435 320 goto usage; 436 321 continue; 437 322 case 'g': /* scatter/gather entries */ 438 - param.sglen = atoi (optarg); 439 - if (param.sglen < 0) 323 + if (parse_num(&param.sglen, optarg)) 440 324 goto usage; 441 325 continue; 442 326 case 'l': /* loop forever */ ··· 447 329 not = 1; 448 330 continue; 449 331 case 's': /* size of packet */ 450 - param.length = atoi (optarg); 451 - if (param.length < 0) 332 + if (parse_num(&param.length, optarg)) 452 333 goto usage; 453 334 continue; 454 335 case 't': /* run just one test */ ··· 456 339 goto usage; 457 340 continue; 458 341 case 'v': /* vary packet size by ... */ 459 - param.vary = atoi (optarg); 460 - if (param.vary < 0) 342 + if (parse_num(&param.vary, optarg)) 461 343 goto usage; 462 344 continue; 463 345 case '?': 464 346 case 'h': 465 347 default: 466 348 usage: 467 - fprintf (stderr, "usage: %s [-an] [-D dev]\n" 349 + fprintf (stderr, "usage: %s [-n] [-D dev | -a | -A usbfs-dir]\n" 468 350 "\t[-c iterations] [-t testnum]\n" 469 351 "\t[-s packetsize] [-g sglen] [-v vary]\n", 470 352 argv [0]); ··· 477 361 goto usage; 478 362 } 479 363 480 - if ((c = open ("/proc/bus/usb/devices", O_RDONLY)) < 0) { 481 - fputs ("usbfs files are missing\n", stderr); 482 - return -1; 364 + /* Find usbfs mount point */ 365 + if (!usbfs_dir) { 366 + usbfs_dir = usbfs_dir_find(); 367 + if (!usbfs_dir) { 368 + fputs ("usbfs files are missing\n", stderr); 369 + return -1; 370 + } 483 371 } 484 372 485 373 /* collect and list the test devices */ 486 - if (ftw ("/proc/bus/usb", find_testdev, 3) != 0) { 374 + if (ftw (usbfs_dir, find_testdev, 3) != 0) { 487 375 fputs ("ftw failed; is usbfs missing?\n", stderr); 488 376 return -1; 489 377 }