1*129a2703SSascha Wildner /* $FreeBSD: head/tools/tools/usbtest/usb_control_ep_test.c 254241 2013-08-12 09:15:33Z hselasky $ */
257bed822SMarkus Pfeiffer /*-
357bed822SMarkus Pfeiffer  * Copyright (c) 2007-2010 Hans Petter Selasky. All rights reserved.
457bed822SMarkus Pfeiffer  *
557bed822SMarkus Pfeiffer  * Redistribution and use in source and binary forms, with or without
657bed822SMarkus Pfeiffer  * modification, are permitted provided that the following conditions
757bed822SMarkus Pfeiffer  * are met:
857bed822SMarkus Pfeiffer  * 1. Redistributions of source code must retain the above copyright
957bed822SMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer.
1057bed822SMarkus Pfeiffer  * 2. Redistributions in binary form must reproduce the above copyright
1157bed822SMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer in the
1257bed822SMarkus Pfeiffer  *    documentation and/or other materials provided with the distribution.
1357bed822SMarkus Pfeiffer  *
1457bed822SMarkus Pfeiffer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1557bed822SMarkus Pfeiffer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1657bed822SMarkus Pfeiffer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1757bed822SMarkus Pfeiffer  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1857bed822SMarkus Pfeiffer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1957bed822SMarkus Pfeiffer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2057bed822SMarkus Pfeiffer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2157bed822SMarkus Pfeiffer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2257bed822SMarkus Pfeiffer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2357bed822SMarkus Pfeiffer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2457bed822SMarkus Pfeiffer  * SUCH DAMAGE.
2557bed822SMarkus Pfeiffer  */
2657bed822SMarkus Pfeiffer 
2757bed822SMarkus Pfeiffer #include <stdio.h>
2857bed822SMarkus Pfeiffer #include <stdint.h>
2957bed822SMarkus Pfeiffer #include <stdlib.h>
3057bed822SMarkus Pfeiffer #include <err.h>
3157bed822SMarkus Pfeiffer #include <string.h>
3257bed822SMarkus Pfeiffer #include <errno.h>
3357bed822SMarkus Pfeiffer #include <unistd.h>
3457bed822SMarkus Pfeiffer 
3557bed822SMarkus Pfeiffer #include <sys/sysctl.h>
3657bed822SMarkus Pfeiffer #include <sys/time.h>
3757bed822SMarkus Pfeiffer 
3857bed822SMarkus Pfeiffer #include <libusb20.h>
3957bed822SMarkus Pfeiffer #include <libusb20_desc.h>
4057bed822SMarkus Pfeiffer 
41*129a2703SSascha Wildner #include <bus/u4b/usb_endian.h>
42*129a2703SSascha Wildner #include <bus/u4b/usb.h>
43*129a2703SSascha Wildner #include <bus/u4b/usb_cdc.h>
4457bed822SMarkus Pfeiffer 
4557bed822SMarkus Pfeiffer #include "usbtest.h"
4657bed822SMarkus Pfeiffer 
4757bed822SMarkus Pfeiffer static void
set_ctrl_ep_fail(int bus,int dev,int ds_fail,int ss_fail)4857bed822SMarkus Pfeiffer set_ctrl_ep_fail(int bus, int dev, int ds_fail, int ss_fail)
4957bed822SMarkus Pfeiffer {
5057bed822SMarkus Pfeiffer 	int error;
5157bed822SMarkus Pfeiffer 
5257bed822SMarkus Pfeiffer 	error = sysctlbyname("hw.usb.ctrl_bus_fail", NULL, NULL,
5357bed822SMarkus Pfeiffer 	    &bus, sizeof(bus));
5457bed822SMarkus Pfeiffer 	if (error != 0)
5557bed822SMarkus Pfeiffer 		goto emissing;
5657bed822SMarkus Pfeiffer 
5757bed822SMarkus Pfeiffer 	error = sysctlbyname("hw.usb.ctrl_dev_fail", NULL, NULL,
5857bed822SMarkus Pfeiffer 	    &dev, sizeof(dev));
5957bed822SMarkus Pfeiffer 	if (error != 0)
6057bed822SMarkus Pfeiffer 		goto emissing;
6157bed822SMarkus Pfeiffer 
6257bed822SMarkus Pfeiffer 	error = sysctlbyname("hw.usb.ctrl_ds_fail", NULL, NULL,
6357bed822SMarkus Pfeiffer 	    &ds_fail, sizeof(ds_fail));
6457bed822SMarkus Pfeiffer 	if (error != 0)
6557bed822SMarkus Pfeiffer 		goto emissing;
6657bed822SMarkus Pfeiffer 
6757bed822SMarkus Pfeiffer 	error = sysctlbyname("hw.usb.ctrl_ss_fail", NULL, NULL,
6857bed822SMarkus Pfeiffer 	    &ss_fail, sizeof(ss_fail));
6957bed822SMarkus Pfeiffer 	if (error != 0)
7057bed822SMarkus Pfeiffer 		goto emissing;
7157bed822SMarkus Pfeiffer 	return;
7257bed822SMarkus Pfeiffer 
7357bed822SMarkus Pfeiffer emissing:
7457bed822SMarkus Pfeiffer 	printf("Cannot set USB sysctl, missing USB_REQ_DEBUG option?\n");
7557bed822SMarkus Pfeiffer }
7657bed822SMarkus Pfeiffer 
7757bed822SMarkus Pfeiffer void
usb_control_ep_error_test(uint16_t vid,uint16_t pid)7857bed822SMarkus Pfeiffer usb_control_ep_error_test(uint16_t vid, uint16_t pid)
7957bed822SMarkus Pfeiffer {
8057bed822SMarkus Pfeiffer 	struct LIBUSB20_CONTROL_SETUP_DECODED req;
8157bed822SMarkus Pfeiffer 	struct libusb20_device *pdev;
8257bed822SMarkus Pfeiffer 	uint8_t buffer[256];
8357bed822SMarkus Pfeiffer 	int error;
8457bed822SMarkus Pfeiffer 	int fail = 0;
8557bed822SMarkus Pfeiffer 	int bus;
8657bed822SMarkus Pfeiffer 	int dev;
8757bed822SMarkus Pfeiffer 	int cfg;
8857bed822SMarkus Pfeiffer 
8957bed822SMarkus Pfeiffer 	pdev = find_usb_device(vid, pid);
9057bed822SMarkus Pfeiffer 	if (pdev == NULL) {
9157bed822SMarkus Pfeiffer 		printf("USB device not found\n");
9257bed822SMarkus Pfeiffer 		return;
9357bed822SMarkus Pfeiffer 	}
9457bed822SMarkus Pfeiffer 	error = libusb20_dev_open(pdev, 0);
9557bed822SMarkus Pfeiffer 	if (error) {
9657bed822SMarkus Pfeiffer 		printf("Could not open USB device\n");
9757bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
9857bed822SMarkus Pfeiffer 		return;
9957bed822SMarkus Pfeiffer 	}
10057bed822SMarkus Pfeiffer 
10157bed822SMarkus Pfeiffer 	bus = libusb20_dev_get_bus_number(pdev);
10257bed822SMarkus Pfeiffer 	dev = libusb20_dev_get_address(pdev);
10357bed822SMarkus Pfeiffer 
10457bed822SMarkus Pfeiffer 	for (cfg = 0; cfg != 255; cfg++) {
10557bed822SMarkus Pfeiffer 
10657bed822SMarkus Pfeiffer 		LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
10757bed822SMarkus Pfeiffer 		req.bmRequestType = 0x80; /* read */
10857bed822SMarkus Pfeiffer 		req.bRequest = 0x06; /* descriptor */
10957bed822SMarkus Pfeiffer 		req.wValue = 0x0200 | cfg; /* config descriptor */
11057bed822SMarkus Pfeiffer 		req.wIndex = 0;
11157bed822SMarkus Pfeiffer 		req.wLength = 255;
11257bed822SMarkus Pfeiffer 
11357bed822SMarkus Pfeiffer 		printf("Test #%d.1/3 ...\n", cfg);
11457bed822SMarkus Pfeiffer 
11557bed822SMarkus Pfeiffer 		set_ctrl_ep_fail(-1,-1,0,0);
11657bed822SMarkus Pfeiffer 
11757bed822SMarkus Pfeiffer 		error = libusb20_dev_request_sync(pdev, &req, buffer,
11857bed822SMarkus Pfeiffer 		    NULL, 1000, 0);
11957bed822SMarkus Pfeiffer 		if (error != 0) {
12057bed822SMarkus Pfeiffer 			printf("Last configuration index is: %d\n", cfg - 1);
12157bed822SMarkus Pfeiffer 			break;
12257bed822SMarkus Pfeiffer 		}
12357bed822SMarkus Pfeiffer 
12457bed822SMarkus Pfeiffer 		printf("Test #%d.2/3 ...\n", cfg);
12557bed822SMarkus Pfeiffer 
12657bed822SMarkus Pfeiffer 		set_ctrl_ep_fail(bus,dev,1,1);
12757bed822SMarkus Pfeiffer 
12857bed822SMarkus Pfeiffer 		error = libusb20_dev_request_sync(pdev, &req, buffer,
12957bed822SMarkus Pfeiffer 		    NULL, 1000, 0);
13057bed822SMarkus Pfeiffer 
13157bed822SMarkus Pfeiffer 		set_ctrl_ep_fail(-1,-1,0,0);
13257bed822SMarkus Pfeiffer 
13357bed822SMarkus Pfeiffer 		error = libusb20_dev_request_sync(pdev, &req, buffer,
13457bed822SMarkus Pfeiffer 		    NULL, 1000, 0);
13557bed822SMarkus Pfeiffer 		if (error != 0) {
13657bed822SMarkus Pfeiffer 			printf("Cannot fetch descriptor (unexpected)\n");
13757bed822SMarkus Pfeiffer 			fail++;
13857bed822SMarkus Pfeiffer 		}
13957bed822SMarkus Pfeiffer 
14057bed822SMarkus Pfeiffer 		printf("Test #%d.3/3 ...\n", cfg);
14157bed822SMarkus Pfeiffer 
14257bed822SMarkus Pfeiffer 		set_ctrl_ep_fail(bus,dev,0,1);
14357bed822SMarkus Pfeiffer 
14457bed822SMarkus Pfeiffer 		error = libusb20_dev_request_sync(pdev, &req, buffer,
14557bed822SMarkus Pfeiffer 		    NULL, 1000, 0);
14657bed822SMarkus Pfeiffer 
14757bed822SMarkus Pfeiffer 		set_ctrl_ep_fail(-1,-1,0,0);
14857bed822SMarkus Pfeiffer 
14957bed822SMarkus Pfeiffer 		error = libusb20_dev_request_sync(pdev, &req, buffer,
15057bed822SMarkus Pfeiffer 		    NULL, 1000, 0);
15157bed822SMarkus Pfeiffer 		if (error != 0) {
15257bed822SMarkus Pfeiffer 			printf("Cannot fetch descriptor (unexpected)\n");
15357bed822SMarkus Pfeiffer 			fail++;
15457bed822SMarkus Pfeiffer 		}
15557bed822SMarkus Pfeiffer 	}
15657bed822SMarkus Pfeiffer 
15757bed822SMarkus Pfeiffer 	libusb20_dev_close(pdev);
15857bed822SMarkus Pfeiffer 	libusb20_dev_free(pdev);
15957bed822SMarkus Pfeiffer 
16057bed822SMarkus Pfeiffer 	printf("Test completed detecting %d failures\nDone\n\n", fail);
16157bed822SMarkus Pfeiffer }
16257bed822SMarkus Pfeiffer 
16357bed822SMarkus Pfeiffer void
usb_get_string_desc_test(uint16_t vid,uint16_t pid)16457bed822SMarkus Pfeiffer usb_get_string_desc_test(uint16_t vid, uint16_t pid)
16557bed822SMarkus Pfeiffer {
16657bed822SMarkus Pfeiffer 	struct libusb20_device *pdev;
16757bed822SMarkus Pfeiffer 	uint32_t x;
16857bed822SMarkus Pfeiffer 	uint32_t y;
16957bed822SMarkus Pfeiffer 	uint32_t valid;
17057bed822SMarkus Pfeiffer 	uint8_t *buf;
17157bed822SMarkus Pfeiffer 	int error;
17257bed822SMarkus Pfeiffer 
17357bed822SMarkus Pfeiffer 	pdev = find_usb_device(vid, pid);
17457bed822SMarkus Pfeiffer 	if (pdev == NULL) {
17557bed822SMarkus Pfeiffer 		printf("USB device not found\n");
17657bed822SMarkus Pfeiffer 		return;
17757bed822SMarkus Pfeiffer 	}
17857bed822SMarkus Pfeiffer 	error = libusb20_dev_open(pdev, 0);
17957bed822SMarkus Pfeiffer 	if (error) {
18057bed822SMarkus Pfeiffer 		printf("Could not open USB device\n");
18157bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
18257bed822SMarkus Pfeiffer 		return;
18357bed822SMarkus Pfeiffer 	}
18457bed822SMarkus Pfeiffer 	buf = malloc(256);
18557bed822SMarkus Pfeiffer 	if (buf == NULL) {
18657bed822SMarkus Pfeiffer 		printf("Cannot allocate memory\n");
18757bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
18857bed822SMarkus Pfeiffer 		return;
18957bed822SMarkus Pfeiffer 	}
19057bed822SMarkus Pfeiffer 	valid = 0;
19157bed822SMarkus Pfeiffer 
19257bed822SMarkus Pfeiffer 	printf("Starting string descriptor test for "
19357bed822SMarkus Pfeiffer 	    "VID=0x%04x PID=0x%04x\n", vid, pid);
19457bed822SMarkus Pfeiffer 
19557bed822SMarkus Pfeiffer 	for (x = 0; x != 256; x++) {
19657bed822SMarkus Pfeiffer 
19757bed822SMarkus Pfeiffer 		if (libusb20_dev_check_connected(pdev) != 0) {
19857bed822SMarkus Pfeiffer 			printf("Device disconnected\n");
19957bed822SMarkus Pfeiffer 			break;
20057bed822SMarkus Pfeiffer 		}
20157bed822SMarkus Pfeiffer 		printf("%d .. ", (int)x);
20257bed822SMarkus Pfeiffer 
20357bed822SMarkus Pfeiffer 		fflush(stdout);
20457bed822SMarkus Pfeiffer 
20557bed822SMarkus Pfeiffer 		error = libusb20_dev_req_string_simple_sync(pdev, x, buf, 255);
20657bed822SMarkus Pfeiffer 
20757bed822SMarkus Pfeiffer 		if (error == 0) {
20857bed822SMarkus Pfeiffer 			printf("\nINDEX=%d, STRING='%s' (Default language)\n", (int)x, buf);
20957bed822SMarkus Pfeiffer 			fflush(stdout);
21057bed822SMarkus Pfeiffer 		} else {
21157bed822SMarkus Pfeiffer 			continue;
21257bed822SMarkus Pfeiffer 		}
21357bed822SMarkus Pfeiffer 
21457bed822SMarkus Pfeiffer 		valid = 0;
21557bed822SMarkus Pfeiffer 
21657bed822SMarkus Pfeiffer 		for (y = 0; y != 65536; y++) {
21757bed822SMarkus Pfeiffer 
21857bed822SMarkus Pfeiffer 			if (libusb20_dev_check_connected(pdev) != 0) {
21957bed822SMarkus Pfeiffer 				printf("Device disconnected\n");
22057bed822SMarkus Pfeiffer 				break;
22157bed822SMarkus Pfeiffer 			}
22257bed822SMarkus Pfeiffer 			error = libusb20_dev_req_string_sync(pdev, x, y, buf, 256);
22357bed822SMarkus Pfeiffer 			if (error == 0)
22457bed822SMarkus Pfeiffer 				valid++;
22557bed822SMarkus Pfeiffer 		}
22657bed822SMarkus Pfeiffer 
22757bed822SMarkus Pfeiffer 		printf("String at INDEX=%d responds to %d "
22857bed822SMarkus Pfeiffer 		    "languages\n", (int)x, (int)valid);
22957bed822SMarkus Pfeiffer 	}
23057bed822SMarkus Pfeiffer 
23157bed822SMarkus Pfeiffer 	printf("\nDone\n");
23257bed822SMarkus Pfeiffer 
23357bed822SMarkus Pfeiffer 	free(buf);
23457bed822SMarkus Pfeiffer 
23557bed822SMarkus Pfeiffer 	libusb20_dev_free(pdev);
23657bed822SMarkus Pfeiffer }
23757bed822SMarkus Pfeiffer 
23857bed822SMarkus Pfeiffer void
usb_port_reset_test(uint16_t vid,uint16_t pid,uint32_t duration)23957bed822SMarkus Pfeiffer usb_port_reset_test(uint16_t vid, uint16_t pid, uint32_t duration)
24057bed822SMarkus Pfeiffer {
24157bed822SMarkus Pfeiffer 	struct timeval sub_tv;
24257bed822SMarkus Pfeiffer 	struct timeval ref_tv;
24357bed822SMarkus Pfeiffer 	struct timeval res_tv;
24457bed822SMarkus Pfeiffer 
24557bed822SMarkus Pfeiffer 	struct libusb20_device *pdev;
24657bed822SMarkus Pfeiffer 
24757bed822SMarkus Pfeiffer 	int error;
24857bed822SMarkus Pfeiffer 	int iter;
24957bed822SMarkus Pfeiffer 	int errcnt;
25057bed822SMarkus Pfeiffer 
25157bed822SMarkus Pfeiffer 	time_t last_sec;
25257bed822SMarkus Pfeiffer 
25357bed822SMarkus Pfeiffer 	/* sysctl() - no set config */
25457bed822SMarkus Pfeiffer 
25557bed822SMarkus Pfeiffer 	pdev = find_usb_device(vid, pid);
25657bed822SMarkus Pfeiffer 	if (pdev == NULL) {
25757bed822SMarkus Pfeiffer 		printf("USB device not found\n");
25857bed822SMarkus Pfeiffer 		return;
25957bed822SMarkus Pfeiffer 	}
26057bed822SMarkus Pfeiffer 	error = libusb20_dev_open(pdev, 0);
26157bed822SMarkus Pfeiffer 	if (error) {
26257bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
26357bed822SMarkus Pfeiffer 		printf("Could not open USB device\n");
26457bed822SMarkus Pfeiffer 		return;
26557bed822SMarkus Pfeiffer 	}
26657bed822SMarkus Pfeiffer 	iter = 0;
26757bed822SMarkus Pfeiffer 
26857bed822SMarkus Pfeiffer 	errcnt = 0;
26957bed822SMarkus Pfeiffer 
27057bed822SMarkus Pfeiffer 	gettimeofday(&ref_tv, 0);
27157bed822SMarkus Pfeiffer 
27257bed822SMarkus Pfeiffer 	last_sec = ref_tv.tv_sec;
27357bed822SMarkus Pfeiffer 
27457bed822SMarkus Pfeiffer 	while (1) {
27557bed822SMarkus Pfeiffer 
27657bed822SMarkus Pfeiffer 		gettimeofday(&sub_tv, 0);
27757bed822SMarkus Pfeiffer 
27857bed822SMarkus Pfeiffer 		if (last_sec != sub_tv.tv_sec) {
27957bed822SMarkus Pfeiffer 
28057bed822SMarkus Pfeiffer 			printf("STATUS: ID=%u, ERR=%u\n",
28157bed822SMarkus Pfeiffer 			    (int)iter, (int)errcnt);
28257bed822SMarkus Pfeiffer 
28357bed822SMarkus Pfeiffer 			fflush(stdout);
28457bed822SMarkus Pfeiffer 
28557bed822SMarkus Pfeiffer 			last_sec = sub_tv.tv_sec;
28657bed822SMarkus Pfeiffer 		}
28757bed822SMarkus Pfeiffer 		timersub(&sub_tv, &ref_tv, &res_tv);
28857bed822SMarkus Pfeiffer 
289*129a2703SSascha Wildner 		if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
29057bed822SMarkus Pfeiffer 			break;
29157bed822SMarkus Pfeiffer 
29257bed822SMarkus Pfeiffer 		if (libusb20_dev_reset(pdev)) {
29357bed822SMarkus Pfeiffer 			errcnt++;
29457bed822SMarkus Pfeiffer 			usleep(50000);
29557bed822SMarkus Pfeiffer 		}
29657bed822SMarkus Pfeiffer 		if (libusb20_dev_check_connected(pdev) != 0) {
29757bed822SMarkus Pfeiffer 			printf("Device disconnected\n");
29857bed822SMarkus Pfeiffer 			break;
29957bed822SMarkus Pfeiffer 		}
30057bed822SMarkus Pfeiffer 		iter++;
30157bed822SMarkus Pfeiffer 	}
30257bed822SMarkus Pfeiffer 
30357bed822SMarkus Pfeiffer 	libusb20_dev_reset(pdev);
30457bed822SMarkus Pfeiffer 
30557bed822SMarkus Pfeiffer 	libusb20_dev_free(pdev);
30657bed822SMarkus Pfeiffer }
30757bed822SMarkus Pfeiffer 
30857bed822SMarkus Pfeiffer void
usb_set_config_test(uint16_t vid,uint16_t pid,uint32_t duration)30957bed822SMarkus Pfeiffer usb_set_config_test(uint16_t vid, uint16_t pid, uint32_t duration)
31057bed822SMarkus Pfeiffer {
31157bed822SMarkus Pfeiffer 	struct libusb20_device *pdev;
31257bed822SMarkus Pfeiffer 	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
31357bed822SMarkus Pfeiffer 	int x;
31457bed822SMarkus Pfeiffer 	int error;
31557bed822SMarkus Pfeiffer 	int failed;
31657bed822SMarkus Pfeiffer 	int exp;
31757bed822SMarkus Pfeiffer 
31857bed822SMarkus Pfeiffer 	pdev = find_usb_device(vid, pid);
31957bed822SMarkus Pfeiffer 	if (pdev == NULL) {
32057bed822SMarkus Pfeiffer 		printf("USB device not found\n");
32157bed822SMarkus Pfeiffer 		return;
32257bed822SMarkus Pfeiffer 	}
32357bed822SMarkus Pfeiffer 	error = libusb20_dev_open(pdev, 0);
32457bed822SMarkus Pfeiffer 	if (error) {
32557bed822SMarkus Pfeiffer 		printf("Could not open USB device\n");
32657bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
32757bed822SMarkus Pfeiffer 		return;
32857bed822SMarkus Pfeiffer 	}
32957bed822SMarkus Pfeiffer 	failed = 0;
33057bed822SMarkus Pfeiffer 
33157bed822SMarkus Pfeiffer 	printf("Starting set config test for "
33257bed822SMarkus Pfeiffer 	    "VID=0x%04x PID=0x%04x\n", vid, pid);
33357bed822SMarkus Pfeiffer 
33457bed822SMarkus Pfeiffer 	for (x = 255; x > -1; x--) {
33557bed822SMarkus Pfeiffer 
33657bed822SMarkus Pfeiffer 		error = libusb20_dev_set_config_index(pdev, x);
33757bed822SMarkus Pfeiffer 		if (error == 0) {
33857bed822SMarkus Pfeiffer 			if (x == 255) {
33957bed822SMarkus Pfeiffer 				printf("Unconfiguring USB device "
34057bed822SMarkus Pfeiffer 				    "was successful\n");
34157bed822SMarkus Pfeiffer 			} else {
34257bed822SMarkus Pfeiffer 				printf("Setting configuration %d "
34357bed822SMarkus Pfeiffer 				    "was successful\n", x);
34457bed822SMarkus Pfeiffer 			}
34557bed822SMarkus Pfeiffer 		} else {
34657bed822SMarkus Pfeiffer 			failed++;
34757bed822SMarkus Pfeiffer 		}
34857bed822SMarkus Pfeiffer 	}
34957bed822SMarkus Pfeiffer 
35057bed822SMarkus Pfeiffer 	ddesc = libusb20_dev_get_device_desc(pdev);
35157bed822SMarkus Pfeiffer 	if (ddesc != NULL)
35257bed822SMarkus Pfeiffer 		exp = ddesc->bNumConfigurations + 1;
35357bed822SMarkus Pfeiffer 	else
35457bed822SMarkus Pfeiffer 		exp = 1;
35557bed822SMarkus Pfeiffer 
35657bed822SMarkus Pfeiffer 	printf("\n\n"
35757bed822SMarkus Pfeiffer 	    "Set configuration summary\n"
35857bed822SMarkus Pfeiffer 	    "Valid count:  %d/%d %s\n"
35957bed822SMarkus Pfeiffer 	    "Failed count: %d\n",
36057bed822SMarkus Pfeiffer 	    256 - failed, exp,
36157bed822SMarkus Pfeiffer 	    (exp == (256 - failed)) ? "(expected)" : "(unexpected)",
36257bed822SMarkus Pfeiffer 	    failed);
36357bed822SMarkus Pfeiffer 
36457bed822SMarkus Pfeiffer 	libusb20_dev_free(pdev);
36557bed822SMarkus Pfeiffer }
36657bed822SMarkus Pfeiffer 
36757bed822SMarkus Pfeiffer void
usb_get_descriptor_test(uint16_t vid,uint16_t pid,uint32_t duration)36857bed822SMarkus Pfeiffer usb_get_descriptor_test(uint16_t vid, uint16_t pid, uint32_t duration)
36957bed822SMarkus Pfeiffer {
37057bed822SMarkus Pfeiffer 	struct libusb20_device *pdev;
37157bed822SMarkus Pfeiffer 
37257bed822SMarkus Pfeiffer 	pdev = find_usb_device(vid, pid);
37357bed822SMarkus Pfeiffer 	if (pdev == NULL) {
37457bed822SMarkus Pfeiffer 		printf("USB device not found\n");
37557bed822SMarkus Pfeiffer 		return;
37657bed822SMarkus Pfeiffer 	}
37757bed822SMarkus Pfeiffer 	libusb20_dev_free(pdev);
37857bed822SMarkus Pfeiffer }
37957bed822SMarkus Pfeiffer 
38057bed822SMarkus Pfeiffer void
usb_suspend_resume_test(uint16_t vid,uint16_t pid,uint32_t duration)38157bed822SMarkus Pfeiffer usb_suspend_resume_test(uint16_t vid, uint16_t pid, uint32_t duration)
38257bed822SMarkus Pfeiffer {
38357bed822SMarkus Pfeiffer 	struct timeval sub_tv;
38457bed822SMarkus Pfeiffer 	struct timeval ref_tv;
38557bed822SMarkus Pfeiffer 	struct timeval res_tv;
38657bed822SMarkus Pfeiffer 
38757bed822SMarkus Pfeiffer 	struct libusb20_device *pdev;
38857bed822SMarkus Pfeiffer 
38957bed822SMarkus Pfeiffer 	time_t last_sec;
39057bed822SMarkus Pfeiffer 
39157bed822SMarkus Pfeiffer 	int iter;
39257bed822SMarkus Pfeiffer 	int error;
39357bed822SMarkus Pfeiffer 	int ptimo;
39457bed822SMarkus Pfeiffer 	int errcnt;
39557bed822SMarkus Pfeiffer 	int power_old;
39657bed822SMarkus Pfeiffer 
39757bed822SMarkus Pfeiffer 	ptimo = 1;			/* second(s) */
39857bed822SMarkus Pfeiffer 
39957bed822SMarkus Pfeiffer 	error = sysctlbyname("hw.usb.power_timeout", NULL, NULL,
40057bed822SMarkus Pfeiffer 	    &ptimo, sizeof(ptimo));
40157bed822SMarkus Pfeiffer 
40257bed822SMarkus Pfeiffer 	if (error != 0) {
40357bed822SMarkus Pfeiffer 		printf("WARNING: Could not set power "
40457bed822SMarkus Pfeiffer 		    "timeout to 1 (error=%d) \n", errno);
40557bed822SMarkus Pfeiffer 	}
40657bed822SMarkus Pfeiffer 	pdev = find_usb_device(vid, pid);
40757bed822SMarkus Pfeiffer 	if (pdev == NULL) {
40857bed822SMarkus Pfeiffer 		printf("USB device not found\n");
40957bed822SMarkus Pfeiffer 		return;
41057bed822SMarkus Pfeiffer 	}
41157bed822SMarkus Pfeiffer 	error = libusb20_dev_open(pdev, 0);
41257bed822SMarkus Pfeiffer 	if (error) {
41357bed822SMarkus Pfeiffer 		printf("Could not open USB device\n");
41457bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
41557bed822SMarkus Pfeiffer 		return;
41657bed822SMarkus Pfeiffer 	}
41757bed822SMarkus Pfeiffer 	power_old = libusb20_dev_get_power_mode(pdev);
41857bed822SMarkus Pfeiffer 
41957bed822SMarkus Pfeiffer 	printf("Starting suspend and resume "
42057bed822SMarkus Pfeiffer 	    "test for VID=0x%04x PID=0x%04x\n", vid, pid);
42157bed822SMarkus Pfeiffer 
42257bed822SMarkus Pfeiffer 	iter = 0;
42357bed822SMarkus Pfeiffer 	errcnt = 0;
42457bed822SMarkus Pfeiffer 
42557bed822SMarkus Pfeiffer 	gettimeofday(&ref_tv, 0);
42657bed822SMarkus Pfeiffer 
42757bed822SMarkus Pfeiffer 	last_sec = ref_tv.tv_sec;
42857bed822SMarkus Pfeiffer 
42957bed822SMarkus Pfeiffer 	while (1) {
43057bed822SMarkus Pfeiffer 
43157bed822SMarkus Pfeiffer 		if (libusb20_dev_check_connected(pdev) != 0) {
43257bed822SMarkus Pfeiffer 			printf("Device disconnected\n");
43357bed822SMarkus Pfeiffer 			break;
43457bed822SMarkus Pfeiffer 		}
43557bed822SMarkus Pfeiffer 		gettimeofday(&sub_tv, 0);
43657bed822SMarkus Pfeiffer 
43757bed822SMarkus Pfeiffer 		if (last_sec != sub_tv.tv_sec) {
43857bed822SMarkus Pfeiffer 
43957bed822SMarkus Pfeiffer 			printf("STATUS: ID=%u, ERR=%u\n",
44057bed822SMarkus Pfeiffer 			    (int)iter, (int)errcnt);
44157bed822SMarkus Pfeiffer 
44257bed822SMarkus Pfeiffer 			fflush(stdout);
44357bed822SMarkus Pfeiffer 
44457bed822SMarkus Pfeiffer 			last_sec = sub_tv.tv_sec;
44557bed822SMarkus Pfeiffer 		}
44657bed822SMarkus Pfeiffer 		timersub(&sub_tv, &ref_tv, &res_tv);
44757bed822SMarkus Pfeiffer 
448*129a2703SSascha Wildner 		if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
44957bed822SMarkus Pfeiffer 			break;
45057bed822SMarkus Pfeiffer 
45157bed822SMarkus Pfeiffer 		error = libusb20_dev_set_power_mode(pdev, (iter & 1) ?
45257bed822SMarkus Pfeiffer 		    LIBUSB20_POWER_ON : LIBUSB20_POWER_SAVE);
45357bed822SMarkus Pfeiffer 
45457bed822SMarkus Pfeiffer 		if (error)
45557bed822SMarkus Pfeiffer 			errcnt++;
45657bed822SMarkus Pfeiffer 
45757bed822SMarkus Pfeiffer 		/* wait before switching power mode */
45857bed822SMarkus Pfeiffer 		usleep(4100000 +
45957bed822SMarkus Pfeiffer 		    (((uint32_t)usb_ts_rand_noise()) % 2000000U));
46057bed822SMarkus Pfeiffer 
46157bed822SMarkus Pfeiffer 		iter++;
46257bed822SMarkus Pfeiffer 	}
46357bed822SMarkus Pfeiffer 
46457bed822SMarkus Pfeiffer 	/* restore default power mode */
46557bed822SMarkus Pfeiffer 	libusb20_dev_set_power_mode(pdev, power_old);
46657bed822SMarkus Pfeiffer 
46757bed822SMarkus Pfeiffer 	libusb20_dev_free(pdev);
46857bed822SMarkus Pfeiffer }
46957bed822SMarkus Pfeiffer 
47057bed822SMarkus Pfeiffer void
usb_set_and_clear_stall_test(uint16_t vid,uint16_t pid)47157bed822SMarkus Pfeiffer usb_set_and_clear_stall_test(uint16_t vid, uint16_t pid)
47257bed822SMarkus Pfeiffer {
47357bed822SMarkus Pfeiffer 	struct libusb20_device *pdev;
47457bed822SMarkus Pfeiffer 	struct libusb20_transfer *pxfer;
47557bed822SMarkus Pfeiffer 
47657bed822SMarkus Pfeiffer 	int iter;
47757bed822SMarkus Pfeiffer 	int error;
47857bed822SMarkus Pfeiffer 	int errcnt;
47957bed822SMarkus Pfeiffer 	int ep;
48057bed822SMarkus Pfeiffer 
48157bed822SMarkus Pfeiffer 	pdev = find_usb_device(vid, pid);
48257bed822SMarkus Pfeiffer 	if (pdev == NULL) {
48357bed822SMarkus Pfeiffer 		printf("USB device not found\n");
48457bed822SMarkus Pfeiffer 		return;
48557bed822SMarkus Pfeiffer 	}
48657bed822SMarkus Pfeiffer 	error = libusb20_dev_open(pdev, 1);
48757bed822SMarkus Pfeiffer 	if (error) {
48857bed822SMarkus Pfeiffer 		printf("Could not open USB device\n");
48957bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
49057bed822SMarkus Pfeiffer 		return;
49157bed822SMarkus Pfeiffer 	}
49257bed822SMarkus Pfeiffer 	printf("Starting set and clear stall test "
49357bed822SMarkus Pfeiffer 	    "for VID=0x%04x PID=0x%04x\n", vid, pid);
49457bed822SMarkus Pfeiffer 
49557bed822SMarkus Pfeiffer 	iter = 0;
49657bed822SMarkus Pfeiffer 	errcnt = 0;
49757bed822SMarkus Pfeiffer 
49857bed822SMarkus Pfeiffer 	for (ep = 2; ep != 32; ep++) {
49957bed822SMarkus Pfeiffer 
50057bed822SMarkus Pfeiffer 		struct LIBUSB20_CONTROL_SETUP_DECODED setup_set_stall;
50157bed822SMarkus Pfeiffer 		struct LIBUSB20_CONTROL_SETUP_DECODED setup_get_status;
50257bed822SMarkus Pfeiffer 
50357bed822SMarkus Pfeiffer 		uint8_t epno = ((ep / 2) | ((ep & 1) << 7));
50457bed822SMarkus Pfeiffer 		uint8_t buf[1];
50557bed822SMarkus Pfeiffer 
50657bed822SMarkus Pfeiffer 		LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup_set_stall);
50757bed822SMarkus Pfeiffer 		setup_set_stall.bmRequestType = 0x02;	/* write endpoint */
50857bed822SMarkus Pfeiffer 		setup_set_stall.bRequest = 0x03;	/* set feature */
50957bed822SMarkus Pfeiffer 		setup_set_stall.wValue = 0x00;	/* UF_ENDPOINT_HALT */
51057bed822SMarkus Pfeiffer 		setup_set_stall.wIndex = epno;
51157bed822SMarkus Pfeiffer 		setup_set_stall.wLength = 0;
51257bed822SMarkus Pfeiffer 
51357bed822SMarkus Pfeiffer 		LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup_get_status);
51457bed822SMarkus Pfeiffer 		setup_get_status.bmRequestType = 0x82;	/* read endpoint */
51557bed822SMarkus Pfeiffer 		setup_get_status.bRequest = 0x00;	/* get status */
51657bed822SMarkus Pfeiffer 		setup_get_status.wValue = 0x00;
51757bed822SMarkus Pfeiffer 		setup_get_status.wIndex = epno;
51857bed822SMarkus Pfeiffer 		setup_get_status.wLength = 1;
51957bed822SMarkus Pfeiffer 
52057bed822SMarkus Pfeiffer 		if (libusb20_dev_check_connected(pdev) != 0) {
52157bed822SMarkus Pfeiffer 			printf("Device disconnected\n");
52257bed822SMarkus Pfeiffer 			break;
52357bed822SMarkus Pfeiffer 		}
52457bed822SMarkus Pfeiffer 		pxfer = libusb20_tr_get_pointer(pdev, 0);
52557bed822SMarkus Pfeiffer 
52657bed822SMarkus Pfeiffer 		error = libusb20_tr_open(pxfer, 1, 1, epno);
52757bed822SMarkus Pfeiffer 
52857bed822SMarkus Pfeiffer 		if (error != 0) {
52957bed822SMarkus Pfeiffer 			printf("Endpoint 0x%02x does not exist "
53057bed822SMarkus Pfeiffer 			    "in current setting. (%s, ignored)\n",
53157bed822SMarkus Pfeiffer 			    epno, libusb20_strerror(error));
53257bed822SMarkus Pfeiffer 			continue;
53357bed822SMarkus Pfeiffer 		}
53457bed822SMarkus Pfeiffer 		printf("Stalling endpoint 0x%02x\n", epno);
53557bed822SMarkus Pfeiffer 
53657bed822SMarkus Pfeiffer 		/* set stall */
53757bed822SMarkus Pfeiffer 		error = libusb20_dev_request_sync(pdev,
53857bed822SMarkus Pfeiffer 		    &setup_set_stall, NULL, NULL, 250, 0);
53957bed822SMarkus Pfeiffer 
54057bed822SMarkus Pfeiffer 		if (error != 0) {
54157bed822SMarkus Pfeiffer 			printf("Endpoint 0x%02x does not allow "
54257bed822SMarkus Pfeiffer 			    "setting of stall. (%s)\n",
54357bed822SMarkus Pfeiffer 			    epno, libusb20_strerror(error));
54457bed822SMarkus Pfeiffer 			errcnt++;
54557bed822SMarkus Pfeiffer 		}
54657bed822SMarkus Pfeiffer 		/* get EP status */
54757bed822SMarkus Pfeiffer 		buf[0] = 0;
54857bed822SMarkus Pfeiffer 		error = libusb20_dev_request_sync(pdev,
54957bed822SMarkus Pfeiffer 		    &setup_get_status, buf, NULL, 250, 0);
55057bed822SMarkus Pfeiffer 
55157bed822SMarkus Pfeiffer 		if (error != 0) {
55257bed822SMarkus Pfeiffer 			printf("Endpoint 0x%02x does not allow "
55357bed822SMarkus Pfeiffer 			    "reading status. (%s)\n",
55457bed822SMarkus Pfeiffer 			    epno, libusb20_strerror(error));
55557bed822SMarkus Pfeiffer 			errcnt++;
55657bed822SMarkus Pfeiffer 		} else {
55757bed822SMarkus Pfeiffer 			if (!(buf[0] & 1)) {
55857bed822SMarkus Pfeiffer 				printf("Endpoint 0x%02x status is "
55957bed822SMarkus Pfeiffer 				    "not set to stalled\n", epno);
56057bed822SMarkus Pfeiffer 				errcnt++;
56157bed822SMarkus Pfeiffer 			}
56257bed822SMarkus Pfeiffer 		}
56357bed822SMarkus Pfeiffer 
56457bed822SMarkus Pfeiffer 		buf[0] = 0;
56557bed822SMarkus Pfeiffer 		error = libusb20_tr_bulk_intr_sync(pxfer, buf, 1, NULL, 250);
56657bed822SMarkus Pfeiffer 		if (error != LIBUSB20_TRANSFER_STALL) {
56757bed822SMarkus Pfeiffer 			printf("Endpoint 0x%02x does not appear to "
56857bed822SMarkus Pfeiffer 			    "have stalled. Missing stall PID!\n", epno);
56957bed822SMarkus Pfeiffer 			errcnt++;
57057bed822SMarkus Pfeiffer 		}
57157bed822SMarkus Pfeiffer 		printf("Unstalling endpoint 0x%02x\n", epno);
57257bed822SMarkus Pfeiffer 
57357bed822SMarkus Pfeiffer 		libusb20_tr_clear_stall_sync(pxfer);
57457bed822SMarkus Pfeiffer 
57557bed822SMarkus Pfeiffer 		/* get EP status */
57657bed822SMarkus Pfeiffer 		buf[0] = 0;
57757bed822SMarkus Pfeiffer 		error = libusb20_dev_request_sync(pdev,
57857bed822SMarkus Pfeiffer 		    &setup_get_status, buf, NULL, 250, 0);
57957bed822SMarkus Pfeiffer 
58057bed822SMarkus Pfeiffer 		if (error != 0) {
58157bed822SMarkus Pfeiffer 			printf("Endpoint 0x%02x does not allow "
58257bed822SMarkus Pfeiffer 			    "reading status. (%s)\n",
58357bed822SMarkus Pfeiffer 			    epno, libusb20_strerror(error));
58457bed822SMarkus Pfeiffer 			errcnt++;
58557bed822SMarkus Pfeiffer 		} else {
58657bed822SMarkus Pfeiffer 			if (buf[0] & 1) {
58757bed822SMarkus Pfeiffer 				printf("Endpoint 0x%02x status is "
58857bed822SMarkus Pfeiffer 				    "still stalled\n", epno);
58957bed822SMarkus Pfeiffer 				errcnt++;
59057bed822SMarkus Pfeiffer 			}
59157bed822SMarkus Pfeiffer 		}
59257bed822SMarkus Pfeiffer 
59357bed822SMarkus Pfeiffer 		libusb20_tr_close(pxfer);
59457bed822SMarkus Pfeiffer 		iter++;
59557bed822SMarkus Pfeiffer 	}
59657bed822SMarkus Pfeiffer 
59757bed822SMarkus Pfeiffer 	libusb20_dev_free(pdev);
59857bed822SMarkus Pfeiffer 
59957bed822SMarkus Pfeiffer 	printf("\n"
60057bed822SMarkus Pfeiffer 	    "Test summary\n"
60157bed822SMarkus Pfeiffer 	    "============\n"
60257bed822SMarkus Pfeiffer 	    "Endpoints tested: %d\n"
60357bed822SMarkus Pfeiffer 	    "Errors: %d\n", iter, errcnt);
60457bed822SMarkus Pfeiffer }
60557bed822SMarkus Pfeiffer 
60657bed822SMarkus Pfeiffer void
usb_set_alt_interface_test(uint16_t vid,uint16_t pid)60757bed822SMarkus Pfeiffer usb_set_alt_interface_test(uint16_t vid, uint16_t pid)
60857bed822SMarkus Pfeiffer {
60957bed822SMarkus Pfeiffer 	struct libusb20_device *pdev;
61057bed822SMarkus Pfeiffer 	struct libusb20_config *config;
61157bed822SMarkus Pfeiffer 
61257bed822SMarkus Pfeiffer 	int iter;
61357bed822SMarkus Pfeiffer 	int error;
61457bed822SMarkus Pfeiffer 	int errcnt;
61557bed822SMarkus Pfeiffer 	int n;
61657bed822SMarkus Pfeiffer 	int m;
61757bed822SMarkus Pfeiffer 
61857bed822SMarkus Pfeiffer 	pdev = find_usb_device(vid, pid);
61957bed822SMarkus Pfeiffer 	if (pdev == NULL) {
62057bed822SMarkus Pfeiffer 		printf("USB device not found\n");
62157bed822SMarkus Pfeiffer 		return;
62257bed822SMarkus Pfeiffer 	}
62357bed822SMarkus Pfeiffer 	printf("Starting set alternate setting test "
62457bed822SMarkus Pfeiffer 	    "for VID=0x%04x PID=0x%04x\n", vid, pid);
62557bed822SMarkus Pfeiffer 
62657bed822SMarkus Pfeiffer 	config = libusb20_dev_alloc_config(pdev,
62757bed822SMarkus Pfeiffer 	    libusb20_dev_get_config_index(pdev));
62857bed822SMarkus Pfeiffer 	if (config == NULL) {
62957bed822SMarkus Pfeiffer 		printf("Could not get configuration descriptor\n");
63057bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
63157bed822SMarkus Pfeiffer 		return;
63257bed822SMarkus Pfeiffer 	}
63357bed822SMarkus Pfeiffer 	iter = 0;
63457bed822SMarkus Pfeiffer 	errcnt = 0;
63557bed822SMarkus Pfeiffer 
63657bed822SMarkus Pfeiffer 	for (n = 0; n != config->num_interface; n++) {
63757bed822SMarkus Pfeiffer 		/* detach kernel driver */
63857bed822SMarkus Pfeiffer 		libusb20_dev_detach_kernel_driver(pdev, n);
63957bed822SMarkus Pfeiffer 
64057bed822SMarkus Pfeiffer 		error = libusb20_dev_open(pdev, 0);
64157bed822SMarkus Pfeiffer 		if (error)
64257bed822SMarkus Pfeiffer 			printf("ERROR could not open device\n");
64357bed822SMarkus Pfeiffer 
64457bed822SMarkus Pfeiffer 		/* Try the alternate settings */
64557bed822SMarkus Pfeiffer 		for (m = 0; m != config->interface[n].num_altsetting; m++) {
64657bed822SMarkus Pfeiffer 
64757bed822SMarkus Pfeiffer 			iter++;
64857bed822SMarkus Pfeiffer 
64957bed822SMarkus Pfeiffer 			if (libusb20_dev_set_alt_index(pdev, n, m + 1)) {
65057bed822SMarkus Pfeiffer 				printf("ERROR on interface %d alt %d\n", n, m + 1);
65157bed822SMarkus Pfeiffer 				errcnt++;
65257bed822SMarkus Pfeiffer 			}
65357bed822SMarkus Pfeiffer 		}
65457bed822SMarkus Pfeiffer 
65557bed822SMarkus Pfeiffer 		/* Restore to default */
65657bed822SMarkus Pfeiffer 
65757bed822SMarkus Pfeiffer 		iter++;
65857bed822SMarkus Pfeiffer 
65957bed822SMarkus Pfeiffer 		if (libusb20_dev_set_alt_index(pdev, n, 0)) {
66057bed822SMarkus Pfeiffer 			printf("ERROR on interface %d alt %d\n", n, 0);
66157bed822SMarkus Pfeiffer 			errcnt++;
66257bed822SMarkus Pfeiffer 		}
66357bed822SMarkus Pfeiffer 		libusb20_dev_close(pdev);
66457bed822SMarkus Pfeiffer 	}
66557bed822SMarkus Pfeiffer 
66657bed822SMarkus Pfeiffer 	libusb20_dev_free(pdev);
66757bed822SMarkus Pfeiffer 
66857bed822SMarkus Pfeiffer 	printf("\n"
66957bed822SMarkus Pfeiffer 	    "Test summary\n"
67057bed822SMarkus Pfeiffer 	    "============\n"
67157bed822SMarkus Pfeiffer 	    "Interfaces tested: %d\n"
67257bed822SMarkus Pfeiffer 	    "Errors: %d\n", iter, errcnt);
67357bed822SMarkus Pfeiffer }
674