1 /* $(CROSS_COMPILE)cc -Wall -g -lpthread -o testusb testusb.c */
4 * Copyright (c) 2002 by David Brownell
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <sys/types.h>
33 #include <sys/ioctl.h>
34 #include <linux/usbdevice_fs.h>
36 /*-------------------------------------------------------------------------*/
40 // FIXME make these public somewhere; usbdevfs.h?
42 struct usbtest_param
{
44 unsigned test_num
; /* 0..(TEST_CASES-1) */
51 struct timeval duration
;
53 #define USBTEST_REQUEST _IOWR('U', 100, struct usbtest_param)
55 /*-------------------------------------------------------------------------*/
57 /* #include <linux/usb_ch9.h> */
59 struct usb_device_descriptor
{
73 __u8 bNumConfigurations
;
74 } __attribute__ ((packed
));
76 enum usb_device_speed
{
77 USB_SPEED_UNKNOWN
= 0, /* enumerating */
78 USB_SPEED_LOW
, USB_SPEED_FULL
, /* usb 1.1 */
79 USB_SPEED_HIGH
/* usb 2.0 */
82 /*-------------------------------------------------------------------------*/
84 static char *speed (enum usb_device_speed s
)
87 case USB_SPEED_UNKNOWN
: return "unknown";
88 case USB_SPEED_LOW
: return "low";
89 case USB_SPEED_FULL
: return "full";
90 case USB_SPEED_HIGH
: return "high";
99 enum usb_device_speed speed
;
101 unsigned forever
: 1;
104 struct usbtest_param param
;
106 static struct testdev
*testdevs
;
108 static int is_testdev (struct usb_device_descriptor
*dev
)
110 /* FX2 with (tweaked) bulksrc firmware */
111 if (dev
->idVendor
== 0x0547 && dev
->idProduct
== 0x1002)
114 /*----------------------------------------------------*/
116 /* devices that start up using the EZ-USB default device and
117 * which we can use after loading simple firmware. hotplug
118 * can fxload it, and then run this test driver.
120 * we return false positives in two cases:
121 * - the device has a "real" driver (maybe usb-serial) that
122 * renumerates. the device should vanish quickly.
123 * - the device doesn't have the test firmware installed.
126 /* generic EZ-USB FX controller */
127 if (dev
->idVendor
== 0x0547 && dev
->idProduct
== 0x2235)
130 /* generic EZ-USB FX2 controller */
131 if (dev
->idVendor
== 0x04b4 && dev
->idProduct
== 0x8613)
134 /* CY3671 development board with EZ-USB FX */
135 if (dev
->idVendor
== 0x0547 && dev
->idProduct
== 0x0080)
138 /* Keyspan 19Qi uses an21xx (original EZ-USB) */
139 if (dev
->idVendor
== 0x06cd && dev
->idProduct
== 0x010b)
142 /*----------------------------------------------------*/
144 /* "gadget zero", Linux-USB test software */
145 if (dev
->idVendor
== 0x0525 && dev
->idProduct
== 0xa4a0)
148 /* user mode subset of that */
149 if (dev
->idVendor
== 0x0525 && dev
->idProduct
== 0xa4a4)
152 /* iso version of usermode code */
153 if (dev
->idVendor
== 0x0525 && dev
->idProduct
== 0xa4a3)
156 /* some GPL'd test firmware uses these IDs */
158 if (dev
->idVendor
== 0xfff0 && dev
->idProduct
== 0xfff0)
161 /*----------------------------------------------------*/
163 /* iBOT2 high speed webcam */
164 if (dev
->idVendor
== 0x0b62 && dev
->idProduct
== 0x0059)
170 static int find_testdev (const char *name
, const struct stat
*sb
, int flag
)
173 struct usb_device_descriptor dev
;
177 /* ignore /proc/bus/usb/{devices,drivers} */
178 if (strrchr (name
, '/')[1] == 'd')
181 if ((fd
= open (name
, O_RDONLY
)) < 0) {
182 perror ("can't open dev file r/o");
185 if (read (fd
, &dev
, sizeof dev
) != sizeof dev
)
186 fputs ("short devfile read!\n", stderr
);
187 else if (is_testdev (&dev
)) {
188 struct testdev
*entry
;
190 if ((entry
= calloc (1, sizeof *entry
)) == 0) {
191 fputs ("no mem!\n", stderr
);
194 entry
->name
= strdup (name
);
200 // FIXME better to look at each interface and ask if it's
201 // bound to 'usbtest', rather than assume interface 0
204 // FIXME ask usbfs what speed; update USBDEVFS_CONNECTINFO
205 // so it tells about high speed etc
207 fprintf (stderr
, "%s speed\t%s\n",
208 speed (entry
->speed
), entry
->name
);
210 entry
->next
= testdevs
;
220 usbdev_ioctl (int fd
, int ifno
, unsigned request
, void *param
)
222 struct usbdevfs_ioctl wrapper
;
225 wrapper
.ioctl_code
= request
;
226 wrapper
.data
= param
;
228 return ioctl (fd
, USBDEVFS_IOCTL
, &wrapper
);
231 static void *handle_testdev (void *arg
)
233 struct testdev
*dev
= arg
;
237 if ((fd
= open (dev
->name
, O_RDWR
)) < 0) {
238 perror ("can't open dev file r/w");
243 for (i
= 0; i
< TEST_CASES
; i
++) {
244 if (dev
->test
!= -1 && dev
->test
!= i
)
246 dev
->param
.test_num
= i
;
248 status
= usbdev_ioctl (fd
, dev
->ifnum
,
249 USBTEST_REQUEST
, &dev
->param
);
250 if (status
< 0 && errno
== EOPNOTSUPP
)
253 /* FIXME need a "syslog it" option for background testing */
255 /* NOTE: each thread emits complete lines; no fragments! */
260 if (strerror_r (errno
, buf
, sizeof buf
)) {
261 snprintf (buf
, sizeof buf
, "error %d", err
);
264 printf ("%s test %d --> %d (%s)\n",
265 dev
->name
, i
, errno
, buf
);
267 printf ("%s test %d, %4d.%.06d secs\n", dev
->name
, i
,
268 (int) dev
->param
.duration
.tv_sec
,
269 (int) dev
->param
.duration
.tv_usec
);
280 int main (int argc
, char **argv
)
283 struct testdev
*entry
;
285 int all
= 0, forever
= 0, not = 0;
286 int test
= -1 /* all */;
287 struct usbtest_param param
;
289 /* pick defaults that works with all speeds, without short packets.
291 * Best per-frame data rates:
292 * high speed, bulk 512 * 13 * 8 = 53248
293 * interrupt 1024 * 3 * 8 = 24576
294 * full speed, bulk/intr 64 * 19 = 1216
295 * interrupt 64 * 1 = 64
296 * low speed, interrupt 8 * 1 = 8
298 param
.iterations
= 1000;
303 /* for easy use when hotplugging */
304 device
= getenv ("DEVICE");
306 while ((c
= getopt (argc
, argv
, "D:ac:g:hns:t:v:")) != EOF
)
308 case 'D': /* device, if only one */
311 case 'a': /* use all devices */
315 case 'c': /* count iterations */
316 param
.iterations
= atoi (optarg
);
317 if (param
.iterations
< 0)
320 case 'g': /* scatter/gather entries */
321 param
.sglen
= atoi (optarg
);
325 case 'l': /* loop forever */
328 case 'n': /* no test running! */
331 case 's': /* size of packet */
332 param
.length
= atoi (optarg
);
333 if (param
.length
< 0)
336 case 't': /* run just one test */
337 test
= atoi (optarg
);
341 case 'v': /* vary packet size by ... */
342 param
.vary
= atoi (optarg
);
350 fprintf (stderr
, "usage: %s [-an] [-D dev]\n"
351 "\t[-c iterations] [-t testnum]\n"
352 "\t[-s packetsize] [-g sglen] [-v vary]\n",
358 if (!all
&& !device
) {
359 fprintf (stderr
, "must specify '-a' or '-D dev', "
360 "or DEVICE=/proc/bus/usb/BBB/DDD in env\n");
364 if ((c
= open ("/proc/bus/usb/devices", O_RDONLY
)) < 0) {
365 fputs ("usbfs files are missing\n", stderr
);
369 /* collect and list the test devices */
370 if (ftw ("/proc/bus/usb", find_testdev
, 3) != 0) {
371 fputs ("ftw failed; is usbfs missing?\n", stderr
);
375 /* quit, run single test, or create test threads */
376 if (!testdevs
&& !device
) {
377 fputs ("no test devices recognized\n", stderr
);
382 if (testdevs
&& testdevs
->next
== 0 && !device
)
383 device
= testdevs
->name
;
384 for (entry
= testdevs
; entry
; entry
= entry
->next
) {
387 entry
->param
= param
;
388 entry
->forever
= forever
;
392 if (strcmp (entry
->name
, device
))
394 return handle_testdev (entry
) != entry
;
396 status
= pthread_create (&entry
->thread
, 0, handle_testdev
, entry
);
398 perror ("pthread_create");
405 /* kernel can recognize test devices we don't */
406 fprintf (stderr
, "%s: %s may see only control tests\n",
409 memset (&dev
, 0, sizeof dev
);
412 dev
.forever
= forever
;
414 return handle_testdev (&dev
) != &dev
;
417 /* wait for tests to complete */
418 for (entry
= testdevs
; entry
; entry
= entry
->next
) {
421 if (pthread_join (entry
->thread
, &retval
))
422 perror ("pthread_join");
423 /* testing errors discarded! */