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