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