1 /* $FreeBSD$ */ 2 /*- 3 * Copyright (c) 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 <err.h> 30 #include <string.h> 31 #include <errno.h> 32 #include <stdarg.h> 33 #include <stdlib.h> 34 35 #include <sys/types.h> 36 #include <sys/sysctl.h> 37 38 #include <dev/usb/usb_ioctl.h> 39 40 #include "usbtest.h" 41 42 #include <g_keyboard.h> 43 #include <g_mouse.h> 44 #include <g_modem.h> 45 #include <g_audio.h> 46 47 static uint8_t usb_ts_select[USB_TS_MAX_LEVELS]; 48 49 const char *indent[USB_TS_MAX_LEVELS] = { 50 " ", 51 " ", 52 " ", 53 " ", 54 " ", 55 " ", 56 " ", 57 " ", 58 }; 59 60 /* a perceptual white noise generator (after HPS' invention) */ 61 62 int32_t 63 usb_ts_rand_noise(void) 64 { 65 uint32_t temp; 66 const uint32_t prime = 0xFFFF1D; 67 static uint32_t noise_rem = 1; 68 69 if (noise_rem & 1) { 70 noise_rem += prime; 71 } 72 noise_rem /= 2; 73 74 temp = noise_rem; 75 76 /* unsigned to signed conversion */ 77 78 temp ^= 0x800000; 79 if (temp & 0x800000) { 80 temp |= (-0x800000); 81 } 82 return temp; 83 } 84 85 uint8_t 86 usb_ts_show_menu(uint8_t level, const char *title, const char *fmt,...) 87 { 88 va_list args; 89 uint8_t x; 90 uint8_t retval; 91 char *pstr; 92 char buf[16]; 93 char menu[80 * 20]; 94 95 va_start(args, fmt); 96 vsnprintf(menu, sizeof(menu), fmt, args); 97 va_end(args); 98 99 printf("["); 100 101 for (x = 0; x != level; x++) { 102 if ((x + 1) == level) 103 printf("%d", usb_ts_select[x]); 104 else 105 printf("%d.", usb_ts_select[x]); 106 } 107 108 printf("] - %s:\n\n", title); 109 110 x = 1; 111 for (pstr = menu; *pstr; pstr++) { 112 if (x != 0) { 113 printf("%s", indent[level]); 114 x = 0; 115 } 116 printf("%c", *pstr); 117 118 if (*pstr == '\n') 119 x = 1; 120 } 121 122 printf("\n>"); 123 124 if (fgets(buf, sizeof(buf), stdin) == NULL) 125 err(1, "Cannot read input"); 126 127 if (buf[0] == 'x') 128 retval = 255; 129 else 130 retval = atoi(buf); 131 132 usb_ts_select[level] = retval; 133 134 return (retval); 135 } 136 137 void 138 get_string(char *ptr, int size) 139 { 140 printf("\nEnter string>"); 141 142 if (fgets(ptr, size, stdin) == NULL) 143 err(1, "Cannot read input"); 144 145 ptr[size - 1] = 0; 146 147 size = strlen(ptr); 148 149 /* strip trailing newline, if any */ 150 if (size == 0) 151 return; 152 else if (ptr[size - 1] == '\n') 153 ptr[size - 1] = 0; 154 } 155 156 int 157 get_integer(void) 158 { 159 char buf[32]; 160 161 printf("\nEnter integer value>"); 162 163 if (fgets(buf, sizeof(buf), stdin) == NULL) 164 err(1, "Cannot read input"); 165 166 if (strcmp(buf, "x\n") == 0) 167 return (-1); 168 if (strcmp(buf, "r\n") == 0) 169 return (-2); 170 171 return ((int)strtol(buf, 0, 0)); 172 } 173 174 static void 175 set_template(int template) 176 { 177 int error; 178 179 error = sysctlbyname("hw.usb.template", NULL, NULL, 180 &template, sizeof(template)); 181 182 if (error != 0) { 183 printf("WARNING: Could not set USB template " 184 "to %d (error=%d)\n", template, errno); 185 } 186 } 187 188 static void 189 show_default_audio_select(uint8_t level) 190 { 191 int error; 192 int retval; 193 int mode = 0; 194 int pattern_interval = 128; 195 int throughput = 0; 196 size_t len; 197 char pattern[G_AUDIO_MAX_STRLEN] = {"0123456789abcdef"}; 198 199 set_template(USB_TEMP_AUDIO); 200 201 while (1) { 202 203 error = sysctlbyname("hw.usb.g_audio.mode", NULL, NULL, 204 &mode, sizeof(mode)); 205 206 if (error != 0) { 207 printf("WARNING: Could not set audio mode " 208 "to %d (error=%d)\n", mode, errno); 209 } 210 error = sysctlbyname("hw.usb.g_audio.pattern_interval", NULL, NULL, 211 &pattern_interval, sizeof(pattern_interval)); 212 213 if (error != 0) { 214 printf("WARNING: Could not set pattern interval " 215 "to %d (error=%d)\n", pattern_interval, errno); 216 } 217 len = sizeof(throughput); 218 219 error = sysctlbyname("hw.usb.g_audio.throughput", 220 &throughput, &len, 0, 0); 221 222 if (error != 0) { 223 printf("WARNING: Could not get throughput " 224 "(error=%d)\n", errno); 225 } 226 error = sysctlbyname("hw.usb.g_audio.pattern", NULL, NULL, 227 &pattern, strlen(pattern)); 228 229 if (error != 0) { 230 printf("WARNING: Could not set audio pattern " 231 "to '%s' (error=%d)\n", pattern, errno); 232 } 233 retval = usb_ts_show_menu(level, "Default Audio Settings", 234 "1) Set Silent mode %s\n" 235 "2) Set Dump mode %s\n" 236 "3) Set Loop mode %s\n" 237 "4) Set Pattern mode %s\n" 238 "5) Change DTMF pattern: '%s'\n" 239 "6) Change pattern advance interval: %d ms\n" 240 "x) Return to previous menu\n" 241 "s: Ready for enumeration\n" 242 "t: Throughput: %d bytes/second\n", 243 (mode == G_AUDIO_MODE_SILENT) ? "(selected)" : "", 244 (mode == G_AUDIO_MODE_DUMP) ? "(selected)" : "", 245 (mode == G_AUDIO_MODE_LOOP) ? "(selected)" : "", 246 (mode == G_AUDIO_MODE_PATTERN) ? "(selected)" : "", 247 pattern, pattern_interval, throughput); 248 249 switch (retval) { 250 case 0: 251 break; 252 case 1: 253 mode = G_AUDIO_MODE_SILENT; 254 break; 255 case 2: 256 mode = G_AUDIO_MODE_DUMP; 257 break; 258 case 3: 259 mode = G_AUDIO_MODE_LOOP; 260 break; 261 case 4: 262 mode = G_AUDIO_MODE_PATTERN; 263 break; 264 case 5: 265 get_string(pattern, sizeof(pattern)); 266 break; 267 case 6: 268 pattern_interval = get_integer(); 269 break; 270 default: 271 return; 272 } 273 } 274 } 275 276 static void 277 show_device_audio_select(uint8_t level) 278 { 279 uint8_t retval; 280 281 while (1) { 282 283 retval = usb_ts_show_menu(level, "Select Audio Device Model", 284 "1) Generic Audio Device\n" 285 "x) Return to previous menu\n"); 286 287 switch (retval) { 288 case 0: 289 break; 290 case 1: 291 show_default_audio_select(level + 1); 292 break; 293 default: 294 return; 295 } 296 } 297 } 298 299 static void 300 show_device_msc_select(uint8_t level) 301 { 302 set_template(USB_TEMP_MSC); 303 } 304 305 static void 306 show_device_ethernet_select(uint8_t level) 307 { 308 set_template(USB_TEMP_CDCE); 309 } 310 311 static void 312 show_default_keyboard_select(uint8_t level) 313 { 314 int error; 315 int retval; 316 int mode = 0; 317 int interval = 1023; 318 char pattern[G_KEYBOARD_MAX_STRLEN] = {"abcdefpattern"}; 319 320 set_template(USB_TEMP_KBD); 321 322 while (1) { 323 324 error = sysctlbyname("hw.usb.g_keyboard.mode", NULL, NULL, 325 &mode, sizeof(mode)); 326 327 if (error != 0) { 328 printf("WARNING: Could not set keyboard mode " 329 " to %d (error=%d) \n", mode, errno); 330 } 331 error = sysctlbyname("hw.usb.g_keyboard.key_press_interval", NULL, NULL, 332 &interval, sizeof(interval)); 333 334 if (error != 0) { 335 printf("WARNING: Could not set key press interval " 336 "to %d (error=%d)\n", interval, errno); 337 } 338 error = sysctlbyname("hw.usb.g_keyboard.key_press_pattern", NULL, NULL, 339 &pattern, strlen(pattern)); 340 341 if (error != 0) { 342 printf("WARNING: Could not set key pattern " 343 "to '%s' (error=%d)\n", pattern, errno); 344 } 345 retval = usb_ts_show_menu(level, "Default Keyboard Settings", 346 "1) Set silent mode %s\n" 347 "2) Set pattern mode %s\n" 348 "3) Change pattern: '%s'\n" 349 "4) Change key press interval: %d ms\n" 350 "x) Return to previous menu\n" 351 "s: Ready for enumeration\n", 352 (mode == G_KEYBOARD_MODE_SILENT) ? "(selected)" : "", 353 (mode == G_KEYBOARD_MODE_PATTERN) ? "(selected)" : "", 354 pattern, interval); 355 356 switch (retval) { 357 case 0: 358 break; 359 case 1: 360 mode = G_KEYBOARD_MODE_SILENT; 361 break; 362 case 2: 363 mode = G_KEYBOARD_MODE_PATTERN; 364 break; 365 case 3: 366 get_string(pattern, sizeof(pattern)); 367 break; 368 case 4: 369 interval = get_integer(); 370 break; 371 default: 372 return; 373 } 374 } 375 } 376 377 static void 378 show_device_keyboard_select(uint8_t level) 379 { 380 uint8_t retval; 381 382 while (1) { 383 384 retval = usb_ts_show_menu(level, "Select Keyboard Model", 385 "1) Generic Keyboard \n" 386 "x) Return to previous menu \n"); 387 388 switch (retval) { 389 case 0: 390 break; 391 case 1: 392 show_default_keyboard_select(level + 1); 393 break; 394 default: 395 return; 396 } 397 } 398 } 399 400 static void 401 show_default_mouse_select(uint8_t level) 402 { 403 int error; 404 int retval; 405 int mode = 0; 406 int cursor_interval = 128; 407 int cursor_radius = 75; 408 int button_interval = 0; 409 410 set_template(USB_TEMP_MOUSE); 411 412 while (1) { 413 414 error = sysctlbyname("hw.usb.g_mouse.mode", NULL, NULL, 415 &mode, sizeof(mode)); 416 417 if (error != 0) { 418 printf("WARNING: Could not set mouse mode " 419 "to %d (error=%d)\n", mode, errno); 420 } 421 error = sysctlbyname("hw.usb.g_mouse.cursor_update_interval", NULL, NULL, 422 &cursor_interval, sizeof(cursor_interval)); 423 424 if (error != 0) { 425 printf("WARNING: Could not set cursor update interval " 426 "to %d (error=%d)\n", cursor_interval, errno); 427 } 428 error = sysctlbyname("hw.usb.g_mouse.button_press_interval", NULL, NULL, 429 &button_interval, sizeof(button_interval)); 430 431 if (error != 0) { 432 printf("WARNING: Could not set button press interval " 433 "to %d (error=%d)\n", button_interval, errno); 434 } 435 error = sysctlbyname("hw.usb.g_mouse.cursor_radius", NULL, NULL, 436 &cursor_radius, sizeof(cursor_radius)); 437 438 if (error != 0) { 439 printf("WARNING: Could not set cursor radius " 440 "to %d (error=%d)\n", cursor_radius, errno); 441 } 442 retval = usb_ts_show_menu(level, "Default Mouse Settings", 443 "1) Set Silent mode %s\n" 444 "2) Set Circle mode %s\n" 445 "3) Set Square mode %s\n" 446 "4) Set Spiral mode %s\n" 447 "5) Change cursor radius: %d pixels\n" 448 "6) Change cursor update interval: %d ms\n" 449 "7) Change button[0] press interval: %d ms\n" 450 "x) Return to previous menu\n" 451 "s: Ready for enumeration\n", 452 (mode == G_MOUSE_MODE_SILENT) ? "(selected)" : "", 453 (mode == G_MOUSE_MODE_CIRCLE) ? "(selected)" : "", 454 (mode == G_MOUSE_MODE_BOX) ? "(selected)" : "", 455 (mode == G_MOUSE_MODE_SPIRAL) ? "(selected)" : "", 456 cursor_radius, cursor_interval, button_interval); 457 458 switch (retval) { 459 case 0: 460 break; 461 case 1: 462 mode = G_MOUSE_MODE_SILENT; 463 break; 464 case 2: 465 mode = G_MOUSE_MODE_CIRCLE; 466 break; 467 case 3: 468 mode = G_MOUSE_MODE_BOX; 469 break; 470 case 4: 471 mode = G_MOUSE_MODE_SPIRAL; 472 break; 473 case 5: 474 cursor_radius = get_integer(); 475 break; 476 case 6: 477 cursor_interval = get_integer(); 478 break; 479 case 7: 480 button_interval = get_integer(); 481 break; 482 default: 483 return; 484 } 485 } 486 } 487 488 static void 489 show_device_mouse_select(uint8_t level) 490 { 491 uint8_t retval; 492 493 while (1) { 494 495 retval = usb_ts_show_menu(level, "Select Mouse Model", 496 "1) Generic Mouse\n" 497 "x) Return to previous menu\n"); 498 499 switch (retval) { 500 case 0: 501 break; 502 case 1: 503 show_default_mouse_select(level + 1); 504 break; 505 default: 506 return; 507 } 508 } 509 } 510 511 static void 512 show_device_mtp_select(uint8_t level) 513 { 514 set_template(USB_TEMP_MTP); 515 } 516 517 static void 518 show_default_modem_select(uint8_t level) 519 { 520 int error; 521 int retval; 522 int mode = 0; 523 int pattern_interval = 128; 524 int throughput = 0; 525 size_t len; 526 char pattern[G_MODEM_MAX_STRLEN] = {"abcdefpattern"}; 527 528 set_template(USB_TEMP_MODEM); 529 530 while (1) { 531 532 error = sysctlbyname("hw.usb.g_modem.mode", NULL, NULL, 533 &mode, sizeof(mode)); 534 535 if (error != 0) { 536 printf("WARNING: Could not set modem mode " 537 "to %d (error=%d)\n", mode, errno); 538 } 539 error = sysctlbyname("hw.usb.g_modem.pattern_interval", NULL, NULL, 540 &pattern_interval, sizeof(pattern_interval)); 541 542 if (error != 0) { 543 printf("WARNING: Could not set pattern interval " 544 "to %d (error=%d)\n", pattern_interval, errno); 545 } 546 len = sizeof(throughput); 547 548 error = sysctlbyname("hw.usb.g_modem.throughput", 549 &throughput, &len, 0, 0); 550 551 if (error != 0) { 552 printf("WARNING: Could not get throughput " 553 "(error=%d)\n", errno); 554 } 555 error = sysctlbyname("hw.usb.g_modem.pattern", NULL, NULL, 556 &pattern, strlen(pattern)); 557 558 if (error != 0) { 559 printf("WARNING: Could not set modem pattern " 560 "to '%s' (error=%d)\n", pattern, errno); 561 } 562 retval = usb_ts_show_menu(level, "Default Modem Settings", 563 "1) Set Silent mode %s\n" 564 "2) Set Dump mode %s\n" 565 "3) Set Loop mode %s\n" 566 "4) Set Pattern mode %s\n" 567 "5) Change test pattern: '%s'\n" 568 "6) Change data transmit interval: %d ms\n" 569 "x) Return to previous menu\n" 570 "s: Ready for enumeration\n" 571 "t: Throughput: %d bytes/second\n", 572 (mode == G_MODEM_MODE_SILENT) ? "(selected)" : "", 573 (mode == G_MODEM_MODE_DUMP) ? "(selected)" : "", 574 (mode == G_MODEM_MODE_LOOP) ? "(selected)" : "", 575 (mode == G_MODEM_MODE_PATTERN) ? "(selected)" : "", 576 pattern, pattern_interval, throughput); 577 578 switch (retval) { 579 case 0: 580 break; 581 case 1: 582 mode = G_MODEM_MODE_SILENT; 583 break; 584 case 2: 585 mode = G_MODEM_MODE_DUMP; 586 break; 587 case 3: 588 mode = G_MODEM_MODE_LOOP; 589 break; 590 case 4: 591 mode = G_MODEM_MODE_PATTERN; 592 break; 593 case 5: 594 get_string(pattern, sizeof(pattern)); 595 break; 596 case 6: 597 pattern_interval = get_integer(); 598 break; 599 default: 600 return; 601 } 602 } 603 } 604 605 static void 606 show_device_modem_select(uint8_t level) 607 { 608 uint8_t retval; 609 610 while (1) { 611 612 retval = usb_ts_show_menu(level, "Select Modem Model", 613 "1) Generic Modem\n" 614 "x) Return to previous menu\n"); 615 616 switch (retval) { 617 case 0: 618 break; 619 case 1: 620 show_default_modem_select(level + 1); 621 break; 622 default: 623 return; 624 } 625 } 626 } 627 628 static void 629 show_device_generic_select(uint8_t level) 630 { 631 } 632 633 static void 634 show_device_select(uint8_t level) 635 { 636 uint8_t retval; 637 638 while (1) { 639 640 retval = usb_ts_show_menu(level, "Select Device Mode Test Group", 641 "1) Audio (UAUDIO)\n" 642 "2) Mass Storage (MSC)\n" 643 "3) Ethernet (CDCE)\n" 644 "4) Keyboard Input Device (UKBD)\n" 645 "5) Mouse Input Device (UMS)\n" 646 "6) Message Transfer Protocol (MTP)\n" 647 "7) Modem (CDC)\n" 648 "8) Generic Endpoint Loopback (GENERIC)\n" 649 "x) Return to previous menu\n"); 650 651 switch (retval) { 652 case 0: 653 break; 654 case 1: 655 show_device_audio_select(level + 1); 656 break; 657 case 2: 658 show_device_msc_select(level + 1); 659 break; 660 case 3: 661 show_device_ethernet_select(level + 1); 662 break; 663 case 4: 664 show_device_keyboard_select(level + 1); 665 break; 666 case 5: 667 show_device_mouse_select(level + 1); 668 break; 669 case 6: 670 show_device_mtp_select(level + 1); 671 break; 672 case 7: 673 show_device_modem_select(level + 1); 674 break; 675 case 8: 676 show_device_generic_select(level + 1); 677 break; 678 default: 679 return; 680 } 681 } 682 } 683 684 static void 685 show_host_select(uint8_t level) 686 { 687 int force_fs = 0; 688 int error; 689 uint32_t duration = 60; 690 691 uint16_t dev_vid = 0; 692 uint16_t dev_pid = 0; 693 uint8_t retval; 694 695 while (1) { 696 697 error = sysctlbyname("hw.usb.ehci.no_hs", NULL, NULL, 698 &force_fs, sizeof(force_fs)); 699 700 if (error != 0) { 701 printf("WARNING: Could not set non-FS mode " 702 "to %d (error=%d)\n", force_fs, errno); 703 } 704 retval = usb_ts_show_menu(level, "Select Host Mode Test (via LibUSB)", 705 " 1) Select USB device (VID=0x%04x, PID=0x%04x)\n" 706 " 2) Manually enter USB vendor and product ID\n" 707 " 3) Force FULL speed operation: <%s>\n" 708 " 4) Mass Storage (UMASS)\n" 709 " 5) Modem (UMODEM)\n" 710 "10) Start String Descriptor Test\n" 711 "11) Start Port Reset Test\n" 712 "12) Start Set Config Test\n" 713 "13) Start Get Descriptor Test\n" 714 "14) Start Suspend and Resume Test\n" 715 "15) Start Set and Clear Endpoint Stall Test\n" 716 "16) Start Set Alternate Interface Setting Test\n" 717 "17) Start Invalid Control Request Test\n" 718 "30) Duration: <%d> seconds\n" 719 "x) Return to previous menu\n", 720 dev_vid, dev_pid, 721 force_fs ? "YES" : "NO", 722 (int)duration); 723 724 switch (retval) { 725 case 0: 726 break; 727 case 1: 728 show_host_device_selection(level + 1, &dev_vid, &dev_pid); 729 break; 730 case 2: 731 dev_vid = get_integer() & 0xFFFF; 732 dev_pid = get_integer() & 0xFFFF; 733 break; 734 case 3: 735 force_fs ^= 1; 736 break; 737 case 4: 738 show_host_msc_test(level + 1, dev_vid, dev_pid, duration); 739 break; 740 case 5: 741 show_host_modem_test(level + 1, dev_vid, dev_pid, duration); 742 break; 743 case 10: 744 usb_get_string_desc_test(dev_vid, dev_pid); 745 break; 746 case 11: 747 usb_port_reset_test(dev_vid, dev_pid, duration); 748 break; 749 case 12: 750 usb_set_config_test(dev_vid, dev_pid, duration); 751 break; 752 case 13: 753 usb_get_descriptor_test(dev_vid, dev_pid, duration); 754 break; 755 case 14: 756 usb_suspend_resume_test(dev_vid, dev_pid, duration); 757 break; 758 case 15: 759 usb_set_and_clear_stall_test(dev_vid, dev_pid); 760 break; 761 case 16: 762 usb_set_alt_interface_test(dev_vid, dev_pid); 763 break; 764 case 17: 765 usb_control_ep_error_test(dev_vid, dev_pid); 766 break; 767 case 30: 768 duration = get_integer(); 769 break; 770 default: 771 return; 772 } 773 } 774 } 775 776 static void 777 show_mode_select(uint8_t level) 778 { 779 uint8_t retval; 780 781 while (1) { 782 783 retval = usb_ts_show_menu(level, "Select Computer Mode", 784 "1) This computer is Running the Device Side\n" 785 "2) This computer is Running the Host Side\n" 786 "x) Return to previous menu\n"); 787 788 switch (retval) { 789 case 0: 790 break; 791 case 1: 792 show_device_select(level + 1); 793 break; 794 case 2: 795 show_host_select(level + 1); 796 break; 797 default: 798 return; 799 } 800 } 801 } 802 803 int 804 main(int argc, char **argv) 805 { 806 show_mode_select(1); 807 808 return (0); 809 } 810