1 /* $FreeBSD: head/tools/tools/usbtest/usb_control_ep_test.c 254241 2013-08-12 09:15:33Z hselasky $ */
2 /*-
3 * Copyright (c) 2007-2010 Hans Petter Selasky. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <stdio.h>
28 #include <stdint.h>
29 #include <stdlib.h>
30 #include <err.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <unistd.h>
34
35 #include <sys/sysctl.h>
36 #include <sys/time.h>
37
38 #include <libusb20.h>
39 #include <libusb20_desc.h>
40
41 #include <bus/u4b/usb_endian.h>
42 #include <bus/u4b/usb.h>
43 #include <bus/u4b/usb_cdc.h>
44
45 #include "usbtest.h"
46
47 static void
set_ctrl_ep_fail(int bus,int dev,int ds_fail,int ss_fail)48 set_ctrl_ep_fail(int bus, int dev, int ds_fail, int ss_fail)
49 {
50 int error;
51
52 error = sysctlbyname("hw.usb.ctrl_bus_fail", NULL, NULL,
53 &bus, sizeof(bus));
54 if (error != 0)
55 goto emissing;
56
57 error = sysctlbyname("hw.usb.ctrl_dev_fail", NULL, NULL,
58 &dev, sizeof(dev));
59 if (error != 0)
60 goto emissing;
61
62 error = sysctlbyname("hw.usb.ctrl_ds_fail", NULL, NULL,
63 &ds_fail, sizeof(ds_fail));
64 if (error != 0)
65 goto emissing;
66
67 error = sysctlbyname("hw.usb.ctrl_ss_fail", NULL, NULL,
68 &ss_fail, sizeof(ss_fail));
69 if (error != 0)
70 goto emissing;
71 return;
72
73 emissing:
74 printf("Cannot set USB sysctl, missing USB_REQ_DEBUG option?\n");
75 }
76
77 void
usb_control_ep_error_test(uint16_t vid,uint16_t pid)78 usb_control_ep_error_test(uint16_t vid, uint16_t pid)
79 {
80 struct LIBUSB20_CONTROL_SETUP_DECODED req;
81 struct libusb20_device *pdev;
82 uint8_t buffer[256];
83 int error;
84 int fail = 0;
85 int bus;
86 int dev;
87 int cfg;
88
89 pdev = find_usb_device(vid, pid);
90 if (pdev == NULL) {
91 printf("USB device not found\n");
92 return;
93 }
94 error = libusb20_dev_open(pdev, 0);
95 if (error) {
96 printf("Could not open USB device\n");
97 libusb20_dev_free(pdev);
98 return;
99 }
100
101 bus = libusb20_dev_get_bus_number(pdev);
102 dev = libusb20_dev_get_address(pdev);
103
104 for (cfg = 0; cfg != 255; cfg++) {
105
106 LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
107 req.bmRequestType = 0x80; /* read */
108 req.bRequest = 0x06; /* descriptor */
109 req.wValue = 0x0200 | cfg; /* config descriptor */
110 req.wIndex = 0;
111 req.wLength = 255;
112
113 printf("Test #%d.1/3 ...\n", cfg);
114
115 set_ctrl_ep_fail(-1,-1,0,0);
116
117 error = libusb20_dev_request_sync(pdev, &req, buffer,
118 NULL, 1000, 0);
119 if (error != 0) {
120 printf("Last configuration index is: %d\n", cfg - 1);
121 break;
122 }
123
124 printf("Test #%d.2/3 ...\n", cfg);
125
126 set_ctrl_ep_fail(bus,dev,1,1);
127
128 error = libusb20_dev_request_sync(pdev, &req, buffer,
129 NULL, 1000, 0);
130
131 set_ctrl_ep_fail(-1,-1,0,0);
132
133 error = libusb20_dev_request_sync(pdev, &req, buffer,
134 NULL, 1000, 0);
135 if (error != 0) {
136 printf("Cannot fetch descriptor (unexpected)\n");
137 fail++;
138 }
139
140 printf("Test #%d.3/3 ...\n", cfg);
141
142 set_ctrl_ep_fail(bus,dev,0,1);
143
144 error = libusb20_dev_request_sync(pdev, &req, buffer,
145 NULL, 1000, 0);
146
147 set_ctrl_ep_fail(-1,-1,0,0);
148
149 error = libusb20_dev_request_sync(pdev, &req, buffer,
150 NULL, 1000, 0);
151 if (error != 0) {
152 printf("Cannot fetch descriptor (unexpected)\n");
153 fail++;
154 }
155 }
156
157 libusb20_dev_close(pdev);
158 libusb20_dev_free(pdev);
159
160 printf("Test completed detecting %d failures\nDone\n\n", fail);
161 }
162
163 void
usb_get_string_desc_test(uint16_t vid,uint16_t pid)164 usb_get_string_desc_test(uint16_t vid, uint16_t pid)
165 {
166 struct libusb20_device *pdev;
167 uint32_t x;
168 uint32_t y;
169 uint32_t valid;
170 uint8_t *buf;
171 int error;
172
173 pdev = find_usb_device(vid, pid);
174 if (pdev == NULL) {
175 printf("USB device not found\n");
176 return;
177 }
178 error = libusb20_dev_open(pdev, 0);
179 if (error) {
180 printf("Could not open USB device\n");
181 libusb20_dev_free(pdev);
182 return;
183 }
184 buf = malloc(256);
185 if (buf == NULL) {
186 printf("Cannot allocate memory\n");
187 libusb20_dev_free(pdev);
188 return;
189 }
190 valid = 0;
191
192 printf("Starting string descriptor test for "
193 "VID=0x%04x PID=0x%04x\n", vid, pid);
194
195 for (x = 0; x != 256; x++) {
196
197 if (libusb20_dev_check_connected(pdev) != 0) {
198 printf("Device disconnected\n");
199 break;
200 }
201 printf("%d .. ", (int)x);
202
203 fflush(stdout);
204
205 error = libusb20_dev_req_string_simple_sync(pdev, x, buf, 255);
206
207 if (error == 0) {
208 printf("\nINDEX=%d, STRING='%s' (Default language)\n", (int)x, buf);
209 fflush(stdout);
210 } else {
211 continue;
212 }
213
214 valid = 0;
215
216 for (y = 0; y != 65536; y++) {
217
218 if (libusb20_dev_check_connected(pdev) != 0) {
219 printf("Device disconnected\n");
220 break;
221 }
222 error = libusb20_dev_req_string_sync(pdev, x, y, buf, 256);
223 if (error == 0)
224 valid++;
225 }
226
227 printf("String at INDEX=%d responds to %d "
228 "languages\n", (int)x, (int)valid);
229 }
230
231 printf("\nDone\n");
232
233 free(buf);
234
235 libusb20_dev_free(pdev);
236 }
237
238 void
usb_port_reset_test(uint16_t vid,uint16_t pid,uint32_t duration)239 usb_port_reset_test(uint16_t vid, uint16_t pid, uint32_t duration)
240 {
241 struct timeval sub_tv;
242 struct timeval ref_tv;
243 struct timeval res_tv;
244
245 struct libusb20_device *pdev;
246
247 int error;
248 int iter;
249 int errcnt;
250
251 time_t last_sec;
252
253 /* sysctl() - no set config */
254
255 pdev = find_usb_device(vid, pid);
256 if (pdev == NULL) {
257 printf("USB device not found\n");
258 return;
259 }
260 error = libusb20_dev_open(pdev, 0);
261 if (error) {
262 libusb20_dev_free(pdev);
263 printf("Could not open USB device\n");
264 return;
265 }
266 iter = 0;
267
268 errcnt = 0;
269
270 gettimeofday(&ref_tv, 0);
271
272 last_sec = ref_tv.tv_sec;
273
274 while (1) {
275
276 gettimeofday(&sub_tv, 0);
277
278 if (last_sec != sub_tv.tv_sec) {
279
280 printf("STATUS: ID=%u, ERR=%u\n",
281 (int)iter, (int)errcnt);
282
283 fflush(stdout);
284
285 last_sec = sub_tv.tv_sec;
286 }
287 timersub(&sub_tv, &ref_tv, &res_tv);
288
289 if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
290 break;
291
292 if (libusb20_dev_reset(pdev)) {
293 errcnt++;
294 usleep(50000);
295 }
296 if (libusb20_dev_check_connected(pdev) != 0) {
297 printf("Device disconnected\n");
298 break;
299 }
300 iter++;
301 }
302
303 libusb20_dev_reset(pdev);
304
305 libusb20_dev_free(pdev);
306 }
307
308 void
usb_set_config_test(uint16_t vid,uint16_t pid,uint32_t duration)309 usb_set_config_test(uint16_t vid, uint16_t pid, uint32_t duration)
310 {
311 struct libusb20_device *pdev;
312 struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
313 int x;
314 int error;
315 int failed;
316 int exp;
317
318 pdev = find_usb_device(vid, pid);
319 if (pdev == NULL) {
320 printf("USB device not found\n");
321 return;
322 }
323 error = libusb20_dev_open(pdev, 0);
324 if (error) {
325 printf("Could not open USB device\n");
326 libusb20_dev_free(pdev);
327 return;
328 }
329 failed = 0;
330
331 printf("Starting set config test for "
332 "VID=0x%04x PID=0x%04x\n", vid, pid);
333
334 for (x = 255; x > -1; x--) {
335
336 error = libusb20_dev_set_config_index(pdev, x);
337 if (error == 0) {
338 if (x == 255) {
339 printf("Unconfiguring USB device "
340 "was successful\n");
341 } else {
342 printf("Setting configuration %d "
343 "was successful\n", x);
344 }
345 } else {
346 failed++;
347 }
348 }
349
350 ddesc = libusb20_dev_get_device_desc(pdev);
351 if (ddesc != NULL)
352 exp = ddesc->bNumConfigurations + 1;
353 else
354 exp = 1;
355
356 printf("\n\n"
357 "Set configuration summary\n"
358 "Valid count: %d/%d %s\n"
359 "Failed count: %d\n",
360 256 - failed, exp,
361 (exp == (256 - failed)) ? "(expected)" : "(unexpected)",
362 failed);
363
364 libusb20_dev_free(pdev);
365 }
366
367 void
usb_get_descriptor_test(uint16_t vid,uint16_t pid,uint32_t duration)368 usb_get_descriptor_test(uint16_t vid, uint16_t pid, uint32_t duration)
369 {
370 struct libusb20_device *pdev;
371
372 pdev = find_usb_device(vid, pid);
373 if (pdev == NULL) {
374 printf("USB device not found\n");
375 return;
376 }
377 libusb20_dev_free(pdev);
378 }
379
380 void
usb_suspend_resume_test(uint16_t vid,uint16_t pid,uint32_t duration)381 usb_suspend_resume_test(uint16_t vid, uint16_t pid, uint32_t duration)
382 {
383 struct timeval sub_tv;
384 struct timeval ref_tv;
385 struct timeval res_tv;
386
387 struct libusb20_device *pdev;
388
389 time_t last_sec;
390
391 int iter;
392 int error;
393 int ptimo;
394 int errcnt;
395 int power_old;
396
397 ptimo = 1; /* second(s) */
398
399 error = sysctlbyname("hw.usb.power_timeout", NULL, NULL,
400 &ptimo, sizeof(ptimo));
401
402 if (error != 0) {
403 printf("WARNING: Could not set power "
404 "timeout to 1 (error=%d) \n", errno);
405 }
406 pdev = find_usb_device(vid, pid);
407 if (pdev == NULL) {
408 printf("USB device not found\n");
409 return;
410 }
411 error = libusb20_dev_open(pdev, 0);
412 if (error) {
413 printf("Could not open USB device\n");
414 libusb20_dev_free(pdev);
415 return;
416 }
417 power_old = libusb20_dev_get_power_mode(pdev);
418
419 printf("Starting suspend and resume "
420 "test for VID=0x%04x PID=0x%04x\n", vid, pid);
421
422 iter = 0;
423 errcnt = 0;
424
425 gettimeofday(&ref_tv, 0);
426
427 last_sec = ref_tv.tv_sec;
428
429 while (1) {
430
431 if (libusb20_dev_check_connected(pdev) != 0) {
432 printf("Device disconnected\n");
433 break;
434 }
435 gettimeofday(&sub_tv, 0);
436
437 if (last_sec != sub_tv.tv_sec) {
438
439 printf("STATUS: ID=%u, ERR=%u\n",
440 (int)iter, (int)errcnt);
441
442 fflush(stdout);
443
444 last_sec = sub_tv.tv_sec;
445 }
446 timersub(&sub_tv, &ref_tv, &res_tv);
447
448 if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
449 break;
450
451 error = libusb20_dev_set_power_mode(pdev, (iter & 1) ?
452 LIBUSB20_POWER_ON : LIBUSB20_POWER_SAVE);
453
454 if (error)
455 errcnt++;
456
457 /* wait before switching power mode */
458 usleep(4100000 +
459 (((uint32_t)usb_ts_rand_noise()) % 2000000U));
460
461 iter++;
462 }
463
464 /* restore default power mode */
465 libusb20_dev_set_power_mode(pdev, power_old);
466
467 libusb20_dev_free(pdev);
468 }
469
470 void
usb_set_and_clear_stall_test(uint16_t vid,uint16_t pid)471 usb_set_and_clear_stall_test(uint16_t vid, uint16_t pid)
472 {
473 struct libusb20_device *pdev;
474 struct libusb20_transfer *pxfer;
475
476 int iter;
477 int error;
478 int errcnt;
479 int ep;
480
481 pdev = find_usb_device(vid, pid);
482 if (pdev == NULL) {
483 printf("USB device not found\n");
484 return;
485 }
486 error = libusb20_dev_open(pdev, 1);
487 if (error) {
488 printf("Could not open USB device\n");
489 libusb20_dev_free(pdev);
490 return;
491 }
492 printf("Starting set and clear stall test "
493 "for VID=0x%04x PID=0x%04x\n", vid, pid);
494
495 iter = 0;
496 errcnt = 0;
497
498 for (ep = 2; ep != 32; ep++) {
499
500 struct LIBUSB20_CONTROL_SETUP_DECODED setup_set_stall;
501 struct LIBUSB20_CONTROL_SETUP_DECODED setup_get_status;
502
503 uint8_t epno = ((ep / 2) | ((ep & 1) << 7));
504 uint8_t buf[1];
505
506 LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup_set_stall);
507 setup_set_stall.bmRequestType = 0x02; /* write endpoint */
508 setup_set_stall.bRequest = 0x03; /* set feature */
509 setup_set_stall.wValue = 0x00; /* UF_ENDPOINT_HALT */
510 setup_set_stall.wIndex = epno;
511 setup_set_stall.wLength = 0;
512
513 LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup_get_status);
514 setup_get_status.bmRequestType = 0x82; /* read endpoint */
515 setup_get_status.bRequest = 0x00; /* get status */
516 setup_get_status.wValue = 0x00;
517 setup_get_status.wIndex = epno;
518 setup_get_status.wLength = 1;
519
520 if (libusb20_dev_check_connected(pdev) != 0) {
521 printf("Device disconnected\n");
522 break;
523 }
524 pxfer = libusb20_tr_get_pointer(pdev, 0);
525
526 error = libusb20_tr_open(pxfer, 1, 1, epno);
527
528 if (error != 0) {
529 printf("Endpoint 0x%02x does not exist "
530 "in current setting. (%s, ignored)\n",
531 epno, libusb20_strerror(error));
532 continue;
533 }
534 printf("Stalling endpoint 0x%02x\n", epno);
535
536 /* set stall */
537 error = libusb20_dev_request_sync(pdev,
538 &setup_set_stall, NULL, NULL, 250, 0);
539
540 if (error != 0) {
541 printf("Endpoint 0x%02x does not allow "
542 "setting of stall. (%s)\n",
543 epno, libusb20_strerror(error));
544 errcnt++;
545 }
546 /* get EP status */
547 buf[0] = 0;
548 error = libusb20_dev_request_sync(pdev,
549 &setup_get_status, buf, NULL, 250, 0);
550
551 if (error != 0) {
552 printf("Endpoint 0x%02x does not allow "
553 "reading status. (%s)\n",
554 epno, libusb20_strerror(error));
555 errcnt++;
556 } else {
557 if (!(buf[0] & 1)) {
558 printf("Endpoint 0x%02x status is "
559 "not set to stalled\n", epno);
560 errcnt++;
561 }
562 }
563
564 buf[0] = 0;
565 error = libusb20_tr_bulk_intr_sync(pxfer, buf, 1, NULL, 250);
566 if (error != LIBUSB20_TRANSFER_STALL) {
567 printf("Endpoint 0x%02x does not appear to "
568 "have stalled. Missing stall PID!\n", epno);
569 errcnt++;
570 }
571 printf("Unstalling endpoint 0x%02x\n", epno);
572
573 libusb20_tr_clear_stall_sync(pxfer);
574
575 /* get EP status */
576 buf[0] = 0;
577 error = libusb20_dev_request_sync(pdev,
578 &setup_get_status, buf, NULL, 250, 0);
579
580 if (error != 0) {
581 printf("Endpoint 0x%02x does not allow "
582 "reading status. (%s)\n",
583 epno, libusb20_strerror(error));
584 errcnt++;
585 } else {
586 if (buf[0] & 1) {
587 printf("Endpoint 0x%02x status is "
588 "still stalled\n", epno);
589 errcnt++;
590 }
591 }
592
593 libusb20_tr_close(pxfer);
594 iter++;
595 }
596
597 libusb20_dev_free(pdev);
598
599 printf("\n"
600 "Test summary\n"
601 "============\n"
602 "Endpoints tested: %d\n"
603 "Errors: %d\n", iter, errcnt);
604 }
605
606 void
usb_set_alt_interface_test(uint16_t vid,uint16_t pid)607 usb_set_alt_interface_test(uint16_t vid, uint16_t pid)
608 {
609 struct libusb20_device *pdev;
610 struct libusb20_config *config;
611
612 int iter;
613 int error;
614 int errcnt;
615 int n;
616 int m;
617
618 pdev = find_usb_device(vid, pid);
619 if (pdev == NULL) {
620 printf("USB device not found\n");
621 return;
622 }
623 printf("Starting set alternate setting test "
624 "for VID=0x%04x PID=0x%04x\n", vid, pid);
625
626 config = libusb20_dev_alloc_config(pdev,
627 libusb20_dev_get_config_index(pdev));
628 if (config == NULL) {
629 printf("Could not get configuration descriptor\n");
630 libusb20_dev_free(pdev);
631 return;
632 }
633 iter = 0;
634 errcnt = 0;
635
636 for (n = 0; n != config->num_interface; n++) {
637 /* detach kernel driver */
638 libusb20_dev_detach_kernel_driver(pdev, n);
639
640 error = libusb20_dev_open(pdev, 0);
641 if (error)
642 printf("ERROR could not open device\n");
643
644 /* Try the alternate settings */
645 for (m = 0; m != config->interface[n].num_altsetting; m++) {
646
647 iter++;
648
649 if (libusb20_dev_set_alt_index(pdev, n, m + 1)) {
650 printf("ERROR on interface %d alt %d\n", n, m + 1);
651 errcnt++;
652 }
653 }
654
655 /* Restore to default */
656
657 iter++;
658
659 if (libusb20_dev_set_alt_index(pdev, n, 0)) {
660 printf("ERROR on interface %d alt %d\n", n, 0);
661 errcnt++;
662 }
663 libusb20_dev_close(pdev);
664 }
665
666 libusb20_dev_free(pdev);
667
668 printf("\n"
669 "Test summary\n"
670 "============\n"
671 "Interfaces tested: %d\n"
672 "Errors: %d\n", iter, errcnt);
673 }
674