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 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 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 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 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 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 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 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 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 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