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