18030839bSHans Petter Selasky /*-
216346e14SHans Petter Selasky  * Copyright (c) 2007-2022 Hans Petter Selasky
38030839bSHans Petter Selasky  *
48030839bSHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
58030839bSHans Petter Selasky  * modification, are permitted provided that the following conditions
68030839bSHans Petter Selasky  * are met:
78030839bSHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
88030839bSHans Petter Selasky  *    notice, this list of conditions and the following disclaimer.
98030839bSHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
108030839bSHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
118030839bSHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
128030839bSHans Petter Selasky  *
138030839bSHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
148030839bSHans Petter Selasky  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
158030839bSHans Petter Selasky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
168030839bSHans Petter Selasky  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
178030839bSHans Petter Selasky  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
188030839bSHans Petter Selasky  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
198030839bSHans Petter Selasky  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
208030839bSHans Petter Selasky  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
218030839bSHans Petter Selasky  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
228030839bSHans Petter Selasky  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
238030839bSHans Petter Selasky  * SUCH DAMAGE.
248030839bSHans Petter Selasky  */
258030839bSHans Petter Selasky 
268030839bSHans Petter Selasky #include <stdio.h>
278030839bSHans Petter Selasky #include <stdint.h>
288030839bSHans Petter Selasky #include <stdlib.h>
298030839bSHans Petter Selasky #include <err.h>
308030839bSHans Petter Selasky #include <string.h>
318030839bSHans Petter Selasky #include <errno.h>
328030839bSHans Petter Selasky #include <unistd.h>
338030839bSHans Petter Selasky 
348030839bSHans Petter Selasky #include <sys/sysctl.h>
358030839bSHans Petter Selasky #include <sys/time.h>
368030839bSHans Petter Selasky 
378030839bSHans Petter Selasky #include <libusb20.h>
388030839bSHans Petter Selasky #include <libusb20_desc.h>
398030839bSHans Petter Selasky 
408030839bSHans Petter Selasky #include <dev/usb/usb_endian.h>
418030839bSHans Petter Selasky #include <dev/usb/usb.h>
428030839bSHans Petter Selasky #include <dev/usb/usb_cdc.h>
438030839bSHans Petter Selasky 
448030839bSHans Petter Selasky #include "usbtest.h"
458030839bSHans Petter Selasky 
468030839bSHans Petter Selasky static void
set_ctrl_ep_fail(int bus,int dev,int ds_fail,int ss_fail)478030839bSHans Petter Selasky set_ctrl_ep_fail(int bus, int dev, int ds_fail, int ss_fail)
488030839bSHans Petter Selasky {
498030839bSHans Petter Selasky 	int error;
508030839bSHans Petter Selasky 
518030839bSHans Petter Selasky 	error = sysctlbyname("hw.usb.ctrl_bus_fail", NULL, NULL,
528030839bSHans Petter Selasky 	    &bus, sizeof(bus));
538030839bSHans Petter Selasky 	if (error != 0)
548030839bSHans Petter Selasky 		goto emissing;
558030839bSHans Petter Selasky 
568030839bSHans Petter Selasky 	error = sysctlbyname("hw.usb.ctrl_dev_fail", NULL, NULL,
578030839bSHans Petter Selasky 	    &dev, sizeof(dev));
588030839bSHans Petter Selasky 	if (error != 0)
598030839bSHans Petter Selasky 		goto emissing;
608030839bSHans Petter Selasky 
618030839bSHans Petter Selasky 	error = sysctlbyname("hw.usb.ctrl_ds_fail", NULL, NULL,
628030839bSHans Petter Selasky 	    &ds_fail, sizeof(ds_fail));
638030839bSHans Petter Selasky 	if (error != 0)
648030839bSHans Petter Selasky 		goto emissing;
658030839bSHans Petter Selasky 
668030839bSHans Petter Selasky 	error = sysctlbyname("hw.usb.ctrl_ss_fail", NULL, NULL,
678030839bSHans Petter Selasky 	    &ss_fail, sizeof(ss_fail));
688030839bSHans Petter Selasky 	if (error != 0)
698030839bSHans Petter Selasky 		goto emissing;
708030839bSHans Petter Selasky 	return;
718030839bSHans Petter Selasky 
728030839bSHans Petter Selasky emissing:
738030839bSHans Petter Selasky 	printf("Cannot set USB sysctl, missing USB_REQ_DEBUG option?\n");
748030839bSHans Petter Selasky }
758030839bSHans Petter Selasky 
768030839bSHans Petter Selasky void
usb_control_ep_error_test(struct uaddr uaddr)7716346e14SHans Petter Selasky usb_control_ep_error_test(struct uaddr uaddr)
788030839bSHans Petter Selasky {
798030839bSHans Petter Selasky 	struct LIBUSB20_CONTROL_SETUP_DECODED req;
808030839bSHans Petter Selasky 	struct libusb20_device *pdev;
818030839bSHans Petter Selasky 	uint8_t buffer[256];
828030839bSHans Petter Selasky 	int error;
838030839bSHans Petter Selasky 	int fail = 0;
848030839bSHans Petter Selasky 	int bus;
858030839bSHans Petter Selasky 	int dev;
868030839bSHans Petter Selasky 	int cfg;
878030839bSHans Petter Selasky 
8816346e14SHans Petter Selasky 	pdev = find_usb_device(uaddr);
898030839bSHans Petter Selasky 	if (pdev == NULL) {
908030839bSHans Petter Selasky 		printf("USB device not found\n");
918030839bSHans Petter Selasky 		return;
928030839bSHans Petter Selasky 	}
938030839bSHans Petter Selasky 	error = libusb20_dev_open(pdev, 0);
948030839bSHans Petter Selasky 	if (error) {
958030839bSHans Petter Selasky 		printf("Could not open USB device\n");
968030839bSHans Petter Selasky 		libusb20_dev_free(pdev);
978030839bSHans Petter Selasky 		return;
988030839bSHans Petter Selasky 	}
998030839bSHans Petter Selasky 
1008030839bSHans Petter Selasky 	bus = libusb20_dev_get_bus_number(pdev);
1018030839bSHans Petter Selasky 	dev = libusb20_dev_get_address(pdev);
1028030839bSHans Petter Selasky 
1038030839bSHans Petter Selasky 	for (cfg = 0; cfg != 255; cfg++) {
1048030839bSHans Petter Selasky 
1058030839bSHans Petter Selasky 		LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
1068030839bSHans Petter Selasky 		req.bmRequestType = 0x80; /* read */
1078030839bSHans Petter Selasky 		req.bRequest = 0x06; /* descriptor */
1088030839bSHans Petter Selasky 		req.wValue = 0x0200 | cfg; /* config descriptor */
1098030839bSHans Petter Selasky 		req.wIndex = 0;
1108030839bSHans Petter Selasky 		req.wLength = 255;
1118030839bSHans Petter Selasky 
1128030839bSHans Petter Selasky 		printf("Test #%d.1/3 ...\n", cfg);
1138030839bSHans Petter Selasky 
1148030839bSHans Petter Selasky 		set_ctrl_ep_fail(-1,-1,0,0);
1158030839bSHans Petter Selasky 
1168030839bSHans Petter Selasky 		error = libusb20_dev_request_sync(pdev, &req, buffer,
1178030839bSHans Petter Selasky 		    NULL, 1000, 0);
1188030839bSHans Petter Selasky 		if (error != 0) {
1198030839bSHans Petter Selasky 			printf("Last configuration index is: %d\n", cfg - 1);
1208030839bSHans Petter Selasky 			break;
1218030839bSHans Petter Selasky 		}
1228030839bSHans Petter Selasky 
1238030839bSHans Petter Selasky 		printf("Test #%d.2/3 ...\n", cfg);
1248030839bSHans Petter Selasky 
1258030839bSHans Petter Selasky 		set_ctrl_ep_fail(bus,dev,1,1);
1268030839bSHans Petter Selasky 
1278030839bSHans Petter Selasky 		error = libusb20_dev_request_sync(pdev, &req, buffer,
1288030839bSHans Petter Selasky 		    NULL, 1000, 0);
1298030839bSHans Petter Selasky 
1308030839bSHans Petter Selasky 		set_ctrl_ep_fail(-1,-1,0,0);
1318030839bSHans Petter Selasky 
1328030839bSHans Petter Selasky 		error = libusb20_dev_request_sync(pdev, &req, buffer,
1338030839bSHans Petter Selasky 		    NULL, 1000, 0);
1348030839bSHans Petter Selasky 		if (error != 0) {
1358030839bSHans Petter Selasky 			printf("Cannot fetch descriptor (unexpected)\n");
1368030839bSHans Petter Selasky 			fail++;
1378030839bSHans Petter Selasky 		}
1388030839bSHans Petter Selasky 
1398030839bSHans Petter Selasky 		printf("Test #%d.3/3 ...\n", cfg);
1408030839bSHans Petter Selasky 
1418030839bSHans Petter Selasky 		set_ctrl_ep_fail(bus,dev,0,1);
1428030839bSHans Petter Selasky 
1438030839bSHans Petter Selasky 		error = libusb20_dev_request_sync(pdev, &req, buffer,
1448030839bSHans Petter Selasky 		    NULL, 1000, 0);
1458030839bSHans Petter Selasky 
1468030839bSHans Petter Selasky 		set_ctrl_ep_fail(-1,-1,0,0);
1478030839bSHans Petter Selasky 
1488030839bSHans Petter Selasky 		error = libusb20_dev_request_sync(pdev, &req, buffer,
1498030839bSHans Petter Selasky 		    NULL, 1000, 0);
1508030839bSHans Petter Selasky 		if (error != 0) {
1518030839bSHans Petter Selasky 			printf("Cannot fetch descriptor (unexpected)\n");
1528030839bSHans Petter Selasky 			fail++;
1538030839bSHans Petter Selasky 		}
1548030839bSHans Petter Selasky 	}
1558030839bSHans Petter Selasky 
1568030839bSHans Petter Selasky 	libusb20_dev_close(pdev);
1578030839bSHans Petter Selasky 	libusb20_dev_free(pdev);
1588030839bSHans Petter Selasky 
1598030839bSHans Petter Selasky 	printf("Test completed detecting %d failures\nDone\n\n", fail);
1608030839bSHans Petter Selasky }
1618030839bSHans Petter Selasky 
1628030839bSHans Petter Selasky void
usb_get_string_desc_test(struct uaddr uaddr)16316346e14SHans Petter Selasky usb_get_string_desc_test(struct uaddr uaddr)
1648030839bSHans Petter Selasky {
1658030839bSHans Petter Selasky 	struct libusb20_device *pdev;
1668030839bSHans Petter Selasky 	uint32_t x;
1678030839bSHans Petter Selasky 	uint32_t y;
1688030839bSHans Petter Selasky 	uint32_t valid;
1698030839bSHans Petter Selasky 	uint8_t *buf;
1708030839bSHans Petter Selasky 	int error;
1718030839bSHans Petter Selasky 
17216346e14SHans Petter Selasky 	pdev = find_usb_device(uaddr);
1738030839bSHans Petter Selasky 	if (pdev == NULL) {
1748030839bSHans Petter Selasky 		printf("USB device not found\n");
1758030839bSHans Petter Selasky 		return;
1768030839bSHans Petter Selasky 	}
1778030839bSHans Petter Selasky 	error = libusb20_dev_open(pdev, 0);
1788030839bSHans Petter Selasky 	if (error) {
1798030839bSHans Petter Selasky 		printf("Could not open USB device\n");
1808030839bSHans Petter Selasky 		libusb20_dev_free(pdev);
1818030839bSHans Petter Selasky 		return;
1828030839bSHans Petter Selasky 	}
1838030839bSHans Petter Selasky 	buf = malloc(256);
1848030839bSHans Petter Selasky 	if (buf == NULL) {
1858030839bSHans Petter Selasky 		printf("Cannot allocate memory\n");
1868030839bSHans Petter Selasky 		libusb20_dev_free(pdev);
1878030839bSHans Petter Selasky 		return;
1888030839bSHans Petter Selasky 	}
1898030839bSHans Petter Selasky 	valid = 0;
1908030839bSHans Petter Selasky 
1918030839bSHans Petter Selasky 	printf("Starting string descriptor test for "
19216346e14SHans Petter Selasky 	    "VID=0x%04x PID=0x%04x\n", uaddr.vid, uaddr.pid);
1938030839bSHans Petter Selasky 
1948030839bSHans Petter Selasky 	for (x = 0; x != 256; x++) {
1958030839bSHans Petter Selasky 
1968030839bSHans Petter Selasky 		if (libusb20_dev_check_connected(pdev) != 0) {
1978030839bSHans Petter Selasky 			printf("Device disconnected\n");
1988030839bSHans Petter Selasky 			break;
1998030839bSHans Petter Selasky 		}
2008030839bSHans Petter Selasky 		printf("%d .. ", (int)x);
2018030839bSHans Petter Selasky 
2028030839bSHans Petter Selasky 		fflush(stdout);
2038030839bSHans Petter Selasky 
2048030839bSHans Petter Selasky 		error = libusb20_dev_req_string_simple_sync(pdev, x, buf, 255);
2058030839bSHans Petter Selasky 
2068030839bSHans Petter Selasky 		if (error == 0) {
2078030839bSHans Petter Selasky 			printf("\nINDEX=%d, STRING='%s' (Default language)\n", (int)x, buf);
2088030839bSHans Petter Selasky 			fflush(stdout);
2098030839bSHans Petter Selasky 		} else {
2108030839bSHans Petter Selasky 			continue;
2118030839bSHans Petter Selasky 		}
2128030839bSHans Petter Selasky 
2138030839bSHans Petter Selasky 		valid = 0;
2148030839bSHans Petter Selasky 
2158030839bSHans Petter Selasky 		for (y = 0; y != 65536; y++) {
2168030839bSHans Petter Selasky 
2178030839bSHans Petter Selasky 			if (libusb20_dev_check_connected(pdev) != 0) {
2188030839bSHans Petter Selasky 				printf("Device disconnected\n");
2198030839bSHans Petter Selasky 				break;
2208030839bSHans Petter Selasky 			}
2218030839bSHans Petter Selasky 			error = libusb20_dev_req_string_sync(pdev, x, y, buf, 256);
2228030839bSHans Petter Selasky 			if (error == 0)
2238030839bSHans Petter Selasky 				valid++;
2248030839bSHans Petter Selasky 		}
2258030839bSHans Petter Selasky 
2268030839bSHans Petter Selasky 		printf("String at INDEX=%d responds to %d "
2278030839bSHans Petter Selasky 		    "languages\n", (int)x, (int)valid);
2288030839bSHans Petter Selasky 	}
2298030839bSHans Petter Selasky 
2308030839bSHans Petter Selasky 	printf("\nDone\n");
2318030839bSHans Petter Selasky 
2328030839bSHans Petter Selasky 	free(buf);
2338030839bSHans Petter Selasky 
2348030839bSHans Petter Selasky 	libusb20_dev_free(pdev);
2358030839bSHans Petter Selasky }
2368030839bSHans Petter Selasky 
2378030839bSHans Petter Selasky void
usb_port_reset_test(struct uaddr uaddr,uint32_t duration)23816346e14SHans Petter Selasky usb_port_reset_test(struct uaddr uaddr, uint32_t duration)
2398030839bSHans Petter Selasky {
2408030839bSHans Petter Selasky 	struct timeval sub_tv;
2418030839bSHans Petter Selasky 	struct timeval ref_tv;
2428030839bSHans Petter Selasky 	struct timeval res_tv;
2438030839bSHans Petter Selasky 
2448030839bSHans Petter Selasky 	struct libusb20_device *pdev;
2458030839bSHans Petter Selasky 
2468030839bSHans Petter Selasky 	int error;
2478030839bSHans Petter Selasky 	int iter;
2488030839bSHans Petter Selasky 	int errcnt;
2498030839bSHans Petter Selasky 
2508030839bSHans Petter Selasky 	time_t last_sec;
2518030839bSHans Petter Selasky 
2528030839bSHans Petter Selasky 	/* sysctl() - no set config */
2538030839bSHans Petter Selasky 
25416346e14SHans Petter Selasky 	pdev = find_usb_device(uaddr);
2558030839bSHans Petter Selasky 	if (pdev == NULL) {
2568030839bSHans Petter Selasky 		printf("USB device not found\n");
2578030839bSHans Petter Selasky 		return;
2588030839bSHans Petter Selasky 	}
2598030839bSHans Petter Selasky 	error = libusb20_dev_open(pdev, 0);
2608030839bSHans Petter Selasky 	if (error) {
2618030839bSHans Petter Selasky 		libusb20_dev_free(pdev);
2628030839bSHans Petter Selasky 		printf("Could not open USB device\n");
2638030839bSHans Petter Selasky 		return;
2648030839bSHans Petter Selasky 	}
2658030839bSHans Petter Selasky 	iter = 0;
2668030839bSHans Petter Selasky 
2678030839bSHans Petter Selasky 	errcnt = 0;
2688030839bSHans Petter Selasky 
2698030839bSHans Petter Selasky 	gettimeofday(&ref_tv, 0);
2708030839bSHans Petter Selasky 
2718030839bSHans Petter Selasky 	last_sec = ref_tv.tv_sec;
2728030839bSHans Petter Selasky 
2738030839bSHans Petter Selasky 	while (1) {
2748030839bSHans Petter Selasky 
2758030839bSHans Petter Selasky 		gettimeofday(&sub_tv, 0);
2768030839bSHans Petter Selasky 
2778030839bSHans Petter Selasky 		if (last_sec != sub_tv.tv_sec) {
2788030839bSHans Petter Selasky 
2798030839bSHans Petter Selasky 			printf("STATUS: ID=%u, ERR=%u\n",
2808030839bSHans Petter Selasky 			    (int)iter, (int)errcnt);
2818030839bSHans Petter Selasky 
2828030839bSHans Petter Selasky 			fflush(stdout);
2838030839bSHans Petter Selasky 
2848030839bSHans Petter Selasky 			last_sec = sub_tv.tv_sec;
2858030839bSHans Petter Selasky 		}
2868030839bSHans Petter Selasky 		timersub(&sub_tv, &ref_tv, &res_tv);
2878030839bSHans Petter Selasky 
288f7b25aedSHans Petter Selasky 		if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
2898030839bSHans Petter Selasky 			break;
2908030839bSHans Petter Selasky 
2918030839bSHans Petter Selasky 		if (libusb20_dev_reset(pdev)) {
2928030839bSHans Petter Selasky 			errcnt++;
2938030839bSHans Petter Selasky 			usleep(50000);
2948030839bSHans Petter Selasky 		}
2958030839bSHans Petter Selasky 		if (libusb20_dev_check_connected(pdev) != 0) {
2968030839bSHans Petter Selasky 			printf("Device disconnected\n");
2978030839bSHans Petter Selasky 			break;
2988030839bSHans Petter Selasky 		}
2998030839bSHans Petter Selasky 		iter++;
3008030839bSHans Petter Selasky 	}
3018030839bSHans Petter Selasky 
3028030839bSHans Petter Selasky 	libusb20_dev_reset(pdev);
3038030839bSHans Petter Selasky 
3048030839bSHans Petter Selasky 	libusb20_dev_free(pdev);
3058030839bSHans Petter Selasky }
3068030839bSHans Petter Selasky 
3078030839bSHans Petter Selasky void
usb_set_config_test(struct uaddr uaddr,uint32_t duration)30816346e14SHans Petter Selasky usb_set_config_test(struct uaddr uaddr, uint32_t duration)
3098030839bSHans Petter Selasky {
3108030839bSHans Petter Selasky 	struct libusb20_device *pdev;
3118030839bSHans Petter Selasky 	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
3128030839bSHans Petter Selasky 	int x;
3138030839bSHans Petter Selasky 	int error;
3148030839bSHans Petter Selasky 	int failed;
3158030839bSHans Petter Selasky 	int exp;
3168030839bSHans Petter Selasky 
31716346e14SHans Petter Selasky 	pdev = find_usb_device(uaddr);
3188030839bSHans Petter Selasky 	if (pdev == NULL) {
3198030839bSHans Petter Selasky 		printf("USB device not found\n");
3208030839bSHans Petter Selasky 		return;
3218030839bSHans Petter Selasky 	}
3228030839bSHans Petter Selasky 	error = libusb20_dev_open(pdev, 0);
3238030839bSHans Petter Selasky 	if (error) {
3248030839bSHans Petter Selasky 		printf("Could not open USB device\n");
3258030839bSHans Petter Selasky 		libusb20_dev_free(pdev);
3268030839bSHans Petter Selasky 		return;
3278030839bSHans Petter Selasky 	}
3288030839bSHans Petter Selasky 	failed = 0;
3298030839bSHans Petter Selasky 
3308030839bSHans Petter Selasky 	printf("Starting set config test for "
33116346e14SHans Petter Selasky 	    "VID=0x%04x PID=0x%04x\n", uaddr.vid, uaddr.pid);
3328030839bSHans Petter Selasky 
3338030839bSHans Petter Selasky 	for (x = 255; x > -1; x--) {
3348030839bSHans Petter Selasky 
3358030839bSHans Petter Selasky 		error = libusb20_dev_set_config_index(pdev, x);
3368030839bSHans Petter Selasky 		if (error == 0) {
3378030839bSHans Petter Selasky 			if (x == 255) {
3388030839bSHans Petter Selasky 				printf("Unconfiguring USB device "
3398030839bSHans Petter Selasky 				    "was successful\n");
3408030839bSHans Petter Selasky 			} else {
3418030839bSHans Petter Selasky 				printf("Setting configuration %d "
3428030839bSHans Petter Selasky 				    "was successful\n", x);
3438030839bSHans Petter Selasky 			}
3448030839bSHans Petter Selasky 		} else {
3458030839bSHans Petter Selasky 			failed++;
3468030839bSHans Petter Selasky 		}
3478030839bSHans Petter Selasky 	}
3488030839bSHans Petter Selasky 
3498030839bSHans Petter Selasky 	ddesc = libusb20_dev_get_device_desc(pdev);
3508030839bSHans Petter Selasky 	if (ddesc != NULL)
3518030839bSHans Petter Selasky 		exp = ddesc->bNumConfigurations + 1;
3528030839bSHans Petter Selasky 	else
3538030839bSHans Petter Selasky 		exp = 1;
3548030839bSHans Petter Selasky 
3558030839bSHans Petter Selasky 	printf("\n\n"
3568030839bSHans Petter Selasky 	    "Set configuration summary\n"
3578030839bSHans Petter Selasky 	    "Valid count:  %d/%d %s\n"
3588030839bSHans Petter Selasky 	    "Failed count: %d\n",
3598030839bSHans Petter Selasky 	    256 - failed, exp,
3608030839bSHans Petter Selasky 	    (exp == (256 - failed)) ? "(expected)" : "(unexpected)",
3618030839bSHans Petter Selasky 	    failed);
3628030839bSHans Petter Selasky 
3638030839bSHans Petter Selasky 	libusb20_dev_free(pdev);
3648030839bSHans Petter Selasky }
3658030839bSHans Petter Selasky 
3668030839bSHans Petter Selasky void
usb_get_descriptor_test(struct uaddr uaddr,uint32_t duration)36716346e14SHans Petter Selasky usb_get_descriptor_test(struct uaddr uaddr, uint32_t duration)
3688030839bSHans Petter Selasky {
3698030839bSHans Petter Selasky 	struct libusb20_device *pdev;
3708030839bSHans Petter Selasky 
37116346e14SHans Petter Selasky 	pdev = find_usb_device(uaddr);
3728030839bSHans Petter Selasky 	if (pdev == NULL) {
3738030839bSHans Petter Selasky 		printf("USB device not found\n");
3748030839bSHans Petter Selasky 		return;
3758030839bSHans Petter Selasky 	}
3768030839bSHans Petter Selasky 	libusb20_dev_free(pdev);
3778030839bSHans Petter Selasky }
3788030839bSHans Petter Selasky 
3798030839bSHans Petter Selasky void
usb_suspend_resume_test(struct uaddr uaddr,uint32_t duration)38016346e14SHans Petter Selasky usb_suspend_resume_test(struct uaddr uaddr, uint32_t duration)
3818030839bSHans Petter Selasky {
3828030839bSHans Petter Selasky 	struct timeval sub_tv;
3838030839bSHans Petter Selasky 	struct timeval ref_tv;
3848030839bSHans Petter Selasky 	struct timeval res_tv;
3858030839bSHans Petter Selasky 
3868030839bSHans Petter Selasky 	struct libusb20_device *pdev;
3878030839bSHans Petter Selasky 
3888030839bSHans Petter Selasky 	time_t last_sec;
3898030839bSHans Petter Selasky 
3908030839bSHans Petter Selasky 	int iter;
3918030839bSHans Petter Selasky 	int error;
3928030839bSHans Petter Selasky 	int ptimo;
3938030839bSHans Petter Selasky 	int errcnt;
3948030839bSHans Petter Selasky 	int power_old;
3958030839bSHans Petter Selasky 
3968030839bSHans Petter Selasky 	ptimo = 1;			/* second(s) */
3978030839bSHans Petter Selasky 
3988030839bSHans Petter Selasky 	error = sysctlbyname("hw.usb.power_timeout", NULL, NULL,
3998030839bSHans Petter Selasky 	    &ptimo, sizeof(ptimo));
4008030839bSHans Petter Selasky 
4018030839bSHans Petter Selasky 	if (error != 0) {
4028030839bSHans Petter Selasky 		printf("WARNING: Could not set power "
4038030839bSHans Petter Selasky 		    "timeout to 1 (error=%d) \n", errno);
4048030839bSHans Petter Selasky 	}
40516346e14SHans Petter Selasky 	pdev = find_usb_device(uaddr);
4068030839bSHans Petter Selasky 	if (pdev == NULL) {
4078030839bSHans Petter Selasky 		printf("USB device not found\n");
4088030839bSHans Petter Selasky 		return;
4098030839bSHans Petter Selasky 	}
4108030839bSHans Petter Selasky 	error = libusb20_dev_open(pdev, 0);
4118030839bSHans Petter Selasky 	if (error) {
4128030839bSHans Petter Selasky 		printf("Could not open USB device\n");
4138030839bSHans Petter Selasky 		libusb20_dev_free(pdev);
4148030839bSHans Petter Selasky 		return;
4158030839bSHans Petter Selasky 	}
4168030839bSHans Petter Selasky 	power_old = libusb20_dev_get_power_mode(pdev);
4178030839bSHans Petter Selasky 
4188030839bSHans Petter Selasky 	printf("Starting suspend and resume "
41916346e14SHans Petter Selasky 	    "test for VID=0x%04x PID=0x%04x\n", uaddr.vid, uaddr.pid);
4208030839bSHans Petter Selasky 
4218030839bSHans Petter Selasky 	iter = 0;
4228030839bSHans Petter Selasky 	errcnt = 0;
4238030839bSHans Petter Selasky 
4248030839bSHans Petter Selasky 	gettimeofday(&ref_tv, 0);
4258030839bSHans Petter Selasky 
4268030839bSHans Petter Selasky 	last_sec = ref_tv.tv_sec;
4278030839bSHans Petter Selasky 
4288030839bSHans Petter Selasky 	while (1) {
4298030839bSHans Petter Selasky 
4308030839bSHans Petter Selasky 		if (libusb20_dev_check_connected(pdev) != 0) {
4318030839bSHans Petter Selasky 			printf("Device disconnected\n");
4328030839bSHans Petter Selasky 			break;
4338030839bSHans Petter Selasky 		}
4348030839bSHans Petter Selasky 		gettimeofday(&sub_tv, 0);
4358030839bSHans Petter Selasky 
4368030839bSHans Petter Selasky 		if (last_sec != sub_tv.tv_sec) {
4378030839bSHans Petter Selasky 
4388030839bSHans Petter Selasky 			printf("STATUS: ID=%u, ERR=%u\n",
4398030839bSHans Petter Selasky 			    (int)iter, (int)errcnt);
4408030839bSHans Petter Selasky 
4418030839bSHans Petter Selasky 			fflush(stdout);
4428030839bSHans Petter Selasky 
4438030839bSHans Petter Selasky 			last_sec = sub_tv.tv_sec;
4448030839bSHans Petter Selasky 		}
4458030839bSHans Petter Selasky 		timersub(&sub_tv, &ref_tv, &res_tv);
4468030839bSHans Petter Selasky 
447f7b25aedSHans Petter Selasky 		if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
4488030839bSHans Petter Selasky 			break;
4498030839bSHans Petter Selasky 
4508030839bSHans Petter Selasky 		error = libusb20_dev_set_power_mode(pdev, (iter & 1) ?
4518030839bSHans Petter Selasky 		    LIBUSB20_POWER_ON : LIBUSB20_POWER_SAVE);
4528030839bSHans Petter Selasky 
4538030839bSHans Petter Selasky 		if (error)
4548030839bSHans Petter Selasky 			errcnt++;
4558030839bSHans Petter Selasky 
4568030839bSHans Petter Selasky 		/* wait before switching power mode */
4578030839bSHans Petter Selasky 		usleep(4100000 +
4588030839bSHans Petter Selasky 		    (((uint32_t)usb_ts_rand_noise()) % 2000000U));
4598030839bSHans Petter Selasky 
4608030839bSHans Petter Selasky 		iter++;
4618030839bSHans Petter Selasky 	}
4628030839bSHans Petter Selasky 
4638030839bSHans Petter Selasky 	/* restore default power mode */
4648030839bSHans Petter Selasky 	libusb20_dev_set_power_mode(pdev, power_old);
4658030839bSHans Petter Selasky 
4668030839bSHans Petter Selasky 	libusb20_dev_free(pdev);
4678030839bSHans Petter Selasky }
4688030839bSHans Petter Selasky 
4698030839bSHans Petter Selasky void
usb_set_and_clear_stall_test(struct uaddr uaddr)47016346e14SHans Petter Selasky usb_set_and_clear_stall_test(struct uaddr uaddr)
4718030839bSHans Petter Selasky {
4728030839bSHans Petter Selasky 	struct libusb20_device *pdev;
4738030839bSHans Petter Selasky 	struct libusb20_transfer *pxfer;
4748030839bSHans Petter Selasky 
4758030839bSHans Petter Selasky 	int iter;
4768030839bSHans Petter Selasky 	int error;
4778030839bSHans Petter Selasky 	int errcnt;
4788030839bSHans Petter Selasky 	int ep;
4798030839bSHans Petter Selasky 
48016346e14SHans Petter Selasky 	pdev = find_usb_device(uaddr);
4818030839bSHans Petter Selasky 	if (pdev == NULL) {
4828030839bSHans Petter Selasky 		printf("USB device not found\n");
4838030839bSHans Petter Selasky 		return;
4848030839bSHans Petter Selasky 	}
4858030839bSHans Petter Selasky 	error = libusb20_dev_open(pdev, 1);
4868030839bSHans Petter Selasky 	if (error) {
4878030839bSHans Petter Selasky 		printf("Could not open USB device\n");
4888030839bSHans Petter Selasky 		libusb20_dev_free(pdev);
4898030839bSHans Petter Selasky 		return;
4908030839bSHans Petter Selasky 	}
4918030839bSHans Petter Selasky 	printf("Starting set and clear stall test "
49216346e14SHans Petter Selasky 	    "for VID=0x%04x PID=0x%04x\n", uaddr.vid, uaddr.pid);
4938030839bSHans Petter Selasky 
4948030839bSHans Petter Selasky 	iter = 0;
4958030839bSHans Petter Selasky 	errcnt = 0;
4968030839bSHans Petter Selasky 
4978030839bSHans Petter Selasky 	for (ep = 2; ep != 32; ep++) {
4988030839bSHans Petter Selasky 
4998030839bSHans Petter Selasky 		struct LIBUSB20_CONTROL_SETUP_DECODED setup_set_stall;
5008030839bSHans Petter Selasky 		struct LIBUSB20_CONTROL_SETUP_DECODED setup_get_status;
5018030839bSHans Petter Selasky 
5028030839bSHans Petter Selasky 		uint8_t epno = ((ep / 2) | ((ep & 1) << 7));
5038030839bSHans Petter Selasky 		uint8_t buf[1];
5048030839bSHans Petter Selasky 
5058030839bSHans Petter Selasky 		LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup_set_stall);
5068030839bSHans Petter Selasky 		setup_set_stall.bmRequestType = 0x02;	/* write endpoint */
5078030839bSHans Petter Selasky 		setup_set_stall.bRequest = 0x03;	/* set feature */
5088030839bSHans Petter Selasky 		setup_set_stall.wValue = 0x00;	/* UF_ENDPOINT_HALT */
5098030839bSHans Petter Selasky 		setup_set_stall.wIndex = epno;
5108030839bSHans Petter Selasky 		setup_set_stall.wLength = 0;
5118030839bSHans Petter Selasky 
5128030839bSHans Petter Selasky 		LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup_get_status);
5138030839bSHans Petter Selasky 		setup_get_status.bmRequestType = 0x82;	/* read endpoint */
5148030839bSHans Petter Selasky 		setup_get_status.bRequest = 0x00;	/* get status */
5158030839bSHans Petter Selasky 		setup_get_status.wValue = 0x00;
5168030839bSHans Petter Selasky 		setup_get_status.wIndex = epno;
5178030839bSHans Petter Selasky 		setup_get_status.wLength = 1;
5188030839bSHans Petter Selasky 
5198030839bSHans Petter Selasky 		if (libusb20_dev_check_connected(pdev) != 0) {
5208030839bSHans Petter Selasky 			printf("Device disconnected\n");
5218030839bSHans Petter Selasky 			break;
5228030839bSHans Petter Selasky 		}
5238030839bSHans Petter Selasky 		pxfer = libusb20_tr_get_pointer(pdev, 0);
5248030839bSHans Petter Selasky 
5258030839bSHans Petter Selasky 		error = libusb20_tr_open(pxfer, 1, 1, epno);
5268030839bSHans Petter Selasky 
5278030839bSHans Petter Selasky 		if (error != 0) {
5288030839bSHans Petter Selasky 			printf("Endpoint 0x%02x does not exist "
5298030839bSHans Petter Selasky 			    "in current setting. (%s, ignored)\n",
5308030839bSHans Petter Selasky 			    epno, libusb20_strerror(error));
5318030839bSHans Petter Selasky 			continue;
5328030839bSHans Petter Selasky 		}
5338030839bSHans Petter Selasky 		printf("Stalling endpoint 0x%02x\n", epno);
5348030839bSHans Petter Selasky 
5358030839bSHans Petter Selasky 		/* set stall */
5368030839bSHans Petter Selasky 		error = libusb20_dev_request_sync(pdev,
5378030839bSHans Petter Selasky 		    &setup_set_stall, NULL, NULL, 250, 0);
5388030839bSHans Petter Selasky 
5398030839bSHans Petter Selasky 		if (error != 0) {
5408030839bSHans Petter Selasky 			printf("Endpoint 0x%02x does not allow "
5418030839bSHans Petter Selasky 			    "setting of stall. (%s)\n",
5428030839bSHans Petter Selasky 			    epno, libusb20_strerror(error));
5438030839bSHans Petter Selasky 			errcnt++;
5448030839bSHans Petter Selasky 		}
5458030839bSHans Petter Selasky 		/* get EP status */
5468030839bSHans Petter Selasky 		buf[0] = 0;
5478030839bSHans Petter Selasky 		error = libusb20_dev_request_sync(pdev,
5488030839bSHans Petter Selasky 		    &setup_get_status, buf, NULL, 250, 0);
5498030839bSHans Petter Selasky 
5508030839bSHans Petter Selasky 		if (error != 0) {
5518030839bSHans Petter Selasky 			printf("Endpoint 0x%02x does not allow "
5528030839bSHans Petter Selasky 			    "reading status. (%s)\n",
5538030839bSHans Petter Selasky 			    epno, libusb20_strerror(error));
5548030839bSHans Petter Selasky 			errcnt++;
5558030839bSHans Petter Selasky 		} else {
5568030839bSHans Petter Selasky 			if (!(buf[0] & 1)) {
5578030839bSHans Petter Selasky 				printf("Endpoint 0x%02x status is "
5588030839bSHans Petter Selasky 				    "not set to stalled\n", epno);
5598030839bSHans Petter Selasky 				errcnt++;
5608030839bSHans Petter Selasky 			}
5618030839bSHans Petter Selasky 		}
5628030839bSHans Petter Selasky 
5638030839bSHans Petter Selasky 		buf[0] = 0;
5648030839bSHans Petter Selasky 		error = libusb20_tr_bulk_intr_sync(pxfer, buf, 1, NULL, 250);
5658030839bSHans Petter Selasky 		if (error != LIBUSB20_TRANSFER_STALL) {
5668030839bSHans Petter Selasky 			printf("Endpoint 0x%02x does not appear to "
5678030839bSHans Petter Selasky 			    "have stalled. Missing stall PID!\n", epno);
5688030839bSHans Petter Selasky 			errcnt++;
5698030839bSHans Petter Selasky 		}
5708030839bSHans Petter Selasky 		printf("Unstalling endpoint 0x%02x\n", epno);
5718030839bSHans Petter Selasky 
5728030839bSHans Petter Selasky 		libusb20_tr_clear_stall_sync(pxfer);
5738030839bSHans Petter Selasky 
5748030839bSHans Petter Selasky 		/* get EP status */
5758030839bSHans Petter Selasky 		buf[0] = 0;
5768030839bSHans Petter Selasky 		error = libusb20_dev_request_sync(pdev,
5778030839bSHans Petter Selasky 		    &setup_get_status, buf, NULL, 250, 0);
5788030839bSHans Petter Selasky 
5798030839bSHans Petter Selasky 		if (error != 0) {
5808030839bSHans Petter Selasky 			printf("Endpoint 0x%02x does not allow "
5818030839bSHans Petter Selasky 			    "reading status. (%s)\n",
5828030839bSHans Petter Selasky 			    epno, libusb20_strerror(error));
5838030839bSHans Petter Selasky 			errcnt++;
5848030839bSHans Petter Selasky 		} else {
5858030839bSHans Petter Selasky 			if (buf[0] & 1) {
5868030839bSHans Petter Selasky 				printf("Endpoint 0x%02x status is "
5878030839bSHans Petter Selasky 				    "still stalled\n", epno);
5888030839bSHans Petter Selasky 				errcnt++;
5898030839bSHans Petter Selasky 			}
5908030839bSHans Petter Selasky 		}
5918030839bSHans Petter Selasky 
5928030839bSHans Petter Selasky 		libusb20_tr_close(pxfer);
5938030839bSHans Petter Selasky 		iter++;
5948030839bSHans Petter Selasky 	}
5958030839bSHans Petter Selasky 
5968030839bSHans Petter Selasky 	libusb20_dev_free(pdev);
5978030839bSHans Petter Selasky 
5988030839bSHans Petter Selasky 	printf("\n"
5998030839bSHans Petter Selasky 	    "Test summary\n"
6008030839bSHans Petter Selasky 	    "============\n"
6018030839bSHans Petter Selasky 	    "Endpoints tested: %d\n"
6028030839bSHans Petter Selasky 	    "Errors: %d\n", iter, errcnt);
6038030839bSHans Petter Selasky }
6048030839bSHans Petter Selasky 
6058030839bSHans Petter Selasky void
usb_set_alt_interface_test(struct uaddr uaddr)60616346e14SHans Petter Selasky usb_set_alt_interface_test(struct uaddr uaddr)
6078030839bSHans Petter Selasky {
6088030839bSHans Petter Selasky 	struct libusb20_device *pdev;
6098030839bSHans Petter Selasky 	struct libusb20_config *config;
6108030839bSHans Petter Selasky 
6118030839bSHans Petter Selasky 	int iter;
6128030839bSHans Petter Selasky 	int error;
6138030839bSHans Petter Selasky 	int errcnt;
6148030839bSHans Petter Selasky 	int n;
6158030839bSHans Petter Selasky 	int m;
6168030839bSHans Petter Selasky 
61716346e14SHans Petter Selasky 	pdev = find_usb_device(uaddr);
6188030839bSHans Petter Selasky 	if (pdev == NULL) {
6198030839bSHans Petter Selasky 		printf("USB device not found\n");
6208030839bSHans Petter Selasky 		return;
6218030839bSHans Petter Selasky 	}
6228030839bSHans Petter Selasky 	printf("Starting set alternate setting test "
62316346e14SHans Petter Selasky 	    "for VID=0x%04x PID=0x%04x\n", uaddr.vid, uaddr.pid);
6248030839bSHans Petter Selasky 
6258030839bSHans Petter Selasky 	config = libusb20_dev_alloc_config(pdev,
6268030839bSHans Petter Selasky 	    libusb20_dev_get_config_index(pdev));
6278030839bSHans Petter Selasky 	if (config == NULL) {
6288030839bSHans Petter Selasky 		printf("Could not get configuration descriptor\n");
6298030839bSHans Petter Selasky 		libusb20_dev_free(pdev);
6308030839bSHans Petter Selasky 		return;
6318030839bSHans Petter Selasky 	}
6328030839bSHans Petter Selasky 	iter = 0;
6338030839bSHans Petter Selasky 	errcnt = 0;
6348030839bSHans Petter Selasky 
6358030839bSHans Petter Selasky 	for (n = 0; n != config->num_interface; n++) {
6368030839bSHans Petter Selasky 		/* detach kernel driver */
6378030839bSHans Petter Selasky 		libusb20_dev_detach_kernel_driver(pdev, n);
6388030839bSHans Petter Selasky 
6398030839bSHans Petter Selasky 		error = libusb20_dev_open(pdev, 0);
6408030839bSHans Petter Selasky 		if (error)
6418030839bSHans Petter Selasky 			printf("ERROR could not open device\n");
6428030839bSHans Petter Selasky 
6438030839bSHans Petter Selasky 		/* Try the alternate settings */
6448030839bSHans Petter Selasky 		for (m = 0; m != config->interface[n].num_altsetting; m++) {
6458030839bSHans Petter Selasky 
6468030839bSHans Petter Selasky 			iter++;
6478030839bSHans Petter Selasky 
6488030839bSHans Petter Selasky 			if (libusb20_dev_set_alt_index(pdev, n, m + 1)) {
6498030839bSHans Petter Selasky 				printf("ERROR on interface %d alt %d\n", n, m + 1);
6508030839bSHans Petter Selasky 				errcnt++;
6518030839bSHans Petter Selasky 			}
6528030839bSHans Petter Selasky 		}
6538030839bSHans Petter Selasky 
6548030839bSHans Petter Selasky 		/* Restore to default */
6558030839bSHans Petter Selasky 
6568030839bSHans Petter Selasky 		iter++;
6578030839bSHans Petter Selasky 
6588030839bSHans Petter Selasky 		if (libusb20_dev_set_alt_index(pdev, n, 0)) {
6598030839bSHans Petter Selasky 			printf("ERROR on interface %d alt %d\n", n, 0);
6608030839bSHans Petter Selasky 			errcnt++;
6618030839bSHans Petter Selasky 		}
6628030839bSHans Petter Selasky 		libusb20_dev_close(pdev);
6638030839bSHans Petter Selasky 	}
6648030839bSHans Petter Selasky 
6658030839bSHans Petter Selasky 	libusb20_dev_free(pdev);
6668030839bSHans Petter Selasky 
6678030839bSHans Petter Selasky 	printf("\n"
6688030839bSHans Petter Selasky 	    "Test summary\n"
6698030839bSHans Petter Selasky 	    "============\n"
6708030839bSHans Petter Selasky 	    "Interfaces tested: %d\n"
6718030839bSHans Petter Selasky 	    "Errors: %d\n", iter, errcnt);
6728030839bSHans Petter Selasky }
673