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