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 struct modem {
478030839bSHans Petter Selasky 	struct libusb20_transfer *xfer_in;
488030839bSHans Petter Selasky 	struct libusb20_transfer *xfer_out;
498030839bSHans Petter Selasky 	struct libusb20_device *usb_dev;
508030839bSHans Petter Selasky 
518030839bSHans Petter Selasky 	struct bps rx_bytes;
528030839bSHans Petter Selasky 	struct bps tx_bytes;
538030839bSHans Petter Selasky 	uint32_t c0;
548030839bSHans Petter Selasky 	uint32_t c1;
558030839bSHans Petter Selasky 	uint32_t out_state;
568030839bSHans Petter Selasky 	uint32_t in_last;
578030839bSHans Petter Selasky 	uint32_t in_synced;
588030839bSHans Petter Selasky 	uint32_t duration;
598030839bSHans Petter Selasky 	uint32_t errors;
608030839bSHans Petter Selasky 
618030839bSHans Petter Selasky 	uint8_t use_vendor_specific;
628030839bSHans Petter Selasky 	uint8_t	loop_data;
638030839bSHans Petter Selasky 	uint8_t	modem_at_mode;
648030839bSHans Petter Selasky 	uint8_t	data_stress_test;
658030839bSHans Petter Selasky 	uint8_t	control_ep_test;
668030839bSHans Petter Selasky 	uint8_t	usb_iface;
678030839bSHans Petter Selasky 	uint8_t	random_tx_length;
688030839bSHans Petter Selasky 	uint8_t	random_tx_delay;
698030839bSHans Petter Selasky 
708030839bSHans Petter Selasky }	modem;
718030839bSHans Petter Selasky 
728030839bSHans Petter Selasky static void
set_defaults(struct modem * p)738030839bSHans Petter Selasky set_defaults(struct modem *p)
748030839bSHans Petter Selasky {
758030839bSHans Petter Selasky 	memset(p, 0, sizeof(*p));
768030839bSHans Petter Selasky 
778030839bSHans Petter Selasky 	p->data_stress_test = 1;
788030839bSHans Petter Selasky 	p->control_ep_test = 1;
798030839bSHans Petter Selasky 	p->duration = 60;		/* seconds */
808030839bSHans Petter Selasky }
818030839bSHans Petter Selasky 
828030839bSHans Petter Selasky void
do_bps(const char * desc,struct bps * bps,uint32_t len)838030839bSHans Petter Selasky do_bps(const char *desc, struct bps *bps, uint32_t len)
848030839bSHans Petter Selasky {
858030839bSHans Petter Selasky 	bps->bytes += len;
868030839bSHans Petter Selasky }
878030839bSHans Petter Selasky 
888030839bSHans Petter Selasky static void
modem_out_state(uint8_t * buf)898030839bSHans Petter Selasky modem_out_state(uint8_t *buf)
908030839bSHans Petter Selasky {
918030839bSHans Petter Selasky 	if (modem.modem_at_mode) {
928030839bSHans Petter Selasky 		switch (modem.out_state & 3) {
938030839bSHans Petter Selasky 		case 0:
948030839bSHans Petter Selasky 			*buf = 'A';
958030839bSHans Petter Selasky 			break;
968030839bSHans Petter Selasky 		case 1:
978030839bSHans Petter Selasky 			*buf = 'T';
988030839bSHans Petter Selasky 			break;
998030839bSHans Petter Selasky 		case 2:
1008030839bSHans Petter Selasky 			*buf = '\r';
1018030839bSHans Petter Selasky 			break;
1028030839bSHans Petter Selasky 		default:
1038030839bSHans Petter Selasky 			*buf = '\n';
1048030839bSHans Petter Selasky 			modem.c0++;
1058030839bSHans Petter Selasky 			break;
1068030839bSHans Petter Selasky 		}
1078030839bSHans Petter Selasky 		modem.out_state++;
1088030839bSHans Petter Selasky 	} else {
1098030839bSHans Petter Selasky 		*buf = modem.out_state;
1108030839bSHans Petter Selasky 		modem.out_state++;
1118030839bSHans Petter Selasky 		modem.out_state %= 255;
1128030839bSHans Petter Selasky 	}
1138030839bSHans Petter Selasky }
1148030839bSHans Petter Selasky 
1158030839bSHans Petter Selasky static void
modem_in_state(uint8_t buf,uint32_t counter)1168030839bSHans Petter Selasky modem_in_state(uint8_t buf, uint32_t counter)
1178030839bSHans Petter Selasky {
1188030839bSHans Petter Selasky 	if ((modem.in_last == 'O') && (buf == 'K')) {
1198030839bSHans Petter Selasky 		modem.c1++;
1208030839bSHans Petter Selasky 		modem.in_last = buf;
1218030839bSHans Petter Selasky 	} else if (buf == modem.in_last) {
1228030839bSHans Petter Selasky 		modem.c1++;
1238030839bSHans Petter Selasky 		modem.in_last++;
1248030839bSHans Petter Selasky 		modem.in_last %= 255;
1258030839bSHans Petter Selasky 		if (modem.in_synced == 0) {
1268030839bSHans Petter Selasky 			if (modem.errors < 64) {
1278030839bSHans Petter Selasky 				printf("Got sync\n");
1288030839bSHans Petter Selasky 			}
1298030839bSHans Petter Selasky 			modem.in_synced = 1;
1308030839bSHans Petter Selasky 		}
1318030839bSHans Petter Selasky 	} else {
1328030839bSHans Petter Selasky 		if (modem.in_synced) {
1338030839bSHans Petter Selasky 			if (modem.errors < 64) {
1348030839bSHans Petter Selasky 				printf("Lost sync @ %d, 0x%02x != 0x%02x\n",
1358030839bSHans Petter Selasky 				    counter % 512, buf, modem.in_last);
1368030839bSHans Petter Selasky 			}
1378030839bSHans Petter Selasky 			modem.in_synced = 0;
1388030839bSHans Petter Selasky 			modem.errors++;
1398030839bSHans Petter Selasky 		}
1408030839bSHans Petter Selasky 		modem.in_last = buf;
1418030839bSHans Petter Selasky 		modem.in_last++;
1428030839bSHans Petter Selasky 		modem.in_last %= 255;
1438030839bSHans Petter Selasky 	}
1448030839bSHans Petter Selasky }
1458030839bSHans Petter Selasky 
1468030839bSHans Petter Selasky static void
modem_write(uint8_t * buf,uint32_t len)1478030839bSHans Petter Selasky modem_write(uint8_t *buf, uint32_t len)
1488030839bSHans Petter Selasky {
1498030839bSHans Petter Selasky 	uint32_t n;
1508030839bSHans Petter Selasky 
1518030839bSHans Petter Selasky 	for (n = 0; n != len; n++) {
1528030839bSHans Petter Selasky 		modem_out_state(buf + n);
1538030839bSHans Petter Selasky 	}
1548030839bSHans Petter Selasky 
1558030839bSHans Petter Selasky 	do_bps("transmitted", &modem.tx_bytes, len);
1568030839bSHans Petter Selasky }
1578030839bSHans Petter Selasky 
1588030839bSHans Petter Selasky static void
modem_read(uint8_t * buf,uint32_t len)1598030839bSHans Petter Selasky modem_read(uint8_t *buf, uint32_t len)
1608030839bSHans Petter Selasky {
1618030839bSHans Petter Selasky 	uint32_t n;
1628030839bSHans Petter Selasky 
1638030839bSHans Petter Selasky 	for (n = 0; n != len; n++) {
1648030839bSHans Petter Selasky 		modem_in_state(buf[n], n);
1658030839bSHans Petter Selasky 	}
1668030839bSHans Petter Selasky 
1678030839bSHans Petter Selasky 	do_bps("received", &modem.rx_bytes, len);
1688030839bSHans Petter Selasky }
1698030839bSHans Petter Selasky 
1708030839bSHans Petter Selasky static void
usb_modem_control_ep_test(struct modem * p,uint32_t duration,uint8_t flag)1718030839bSHans Petter Selasky usb_modem_control_ep_test(struct modem *p, uint32_t duration, uint8_t flag)
1728030839bSHans Petter Selasky {
1738030839bSHans Petter Selasky 	struct timeval sub_tv;
1748030839bSHans Petter Selasky 	struct timeval ref_tv;
1758030839bSHans Petter Selasky 	struct timeval res_tv;
1768030839bSHans Petter Selasky 	struct LIBUSB20_CONTROL_SETUP_DECODED setup;
1778030839bSHans Petter Selasky 	struct usb_cdc_abstract_state ast;
1788030839bSHans Petter Selasky 	struct usb_cdc_line_state ls;
1798030839bSHans Petter Selasky 	uint16_t feature = UCDC_ABSTRACT_STATE;
1808030839bSHans Petter Selasky 	uint16_t state = UCDC_DATA_MULTIPLEXED;
1818030839bSHans Petter Selasky 	uint8_t iface_no;
1828030839bSHans Petter Selasky 	uint8_t buf[4];
1838030839bSHans Petter Selasky 	int id = 0;
1848030839bSHans Petter Selasky 	int iter = 0;
1858030839bSHans Petter Selasky 
1868030839bSHans Petter Selasky 	time_t last_sec;
1878030839bSHans Petter Selasky 
1888030839bSHans Petter Selasky 	iface_no = p->usb_iface - 1;
1898030839bSHans Petter Selasky 
1908030839bSHans Petter Selasky 	gettimeofday(&ref_tv, 0);
1918030839bSHans Petter Selasky 
1928030839bSHans Petter Selasky 	last_sec = ref_tv.tv_sec;
1938030839bSHans Petter Selasky 
1948030839bSHans Petter Selasky 	printf("\nTest=%d\n", (int)flag);
1958030839bSHans Petter Selasky 
1968030839bSHans Petter Selasky 	while (1) {
1978030839bSHans Petter Selasky 
1988030839bSHans Petter Selasky 		gettimeofday(&sub_tv, 0);
1998030839bSHans Petter Selasky 
2008030839bSHans Petter Selasky 		if (last_sec != sub_tv.tv_sec) {
2018030839bSHans Petter Selasky 
2028030839bSHans Petter Selasky 			printf("STATUS: ID=%u, COUNT=%u tests/sec ERR=%u\n",
2038030839bSHans Petter Selasky 			    (int)id,
2048030839bSHans Petter Selasky 			    (int)iter,
2058030839bSHans Petter Selasky 			    (int)p->errors);
2068030839bSHans Petter Selasky 
2078030839bSHans Petter Selasky 			fflush(stdout);
2088030839bSHans Petter Selasky 
2098030839bSHans Petter Selasky 			last_sec = sub_tv.tv_sec;
2108030839bSHans Petter Selasky 
2118030839bSHans Petter Selasky 			id++;
2128030839bSHans Petter Selasky 
2138030839bSHans Petter Selasky 			iter = 0;
2148030839bSHans Petter Selasky 		}
2158030839bSHans Petter Selasky 		timersub(&sub_tv, &ref_tv, &res_tv);
2168030839bSHans Petter Selasky 
217f7b25aedSHans Petter Selasky 		if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
2188030839bSHans Petter Selasky 			break;
2198030839bSHans Petter Selasky 
2208030839bSHans Petter Selasky 		LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup);
2218030839bSHans Petter Selasky 
2228030839bSHans Petter Selasky 		if (flag & 1) {
2238030839bSHans Petter Selasky 			setup.bmRequestType = UT_READ_CLASS_INTERFACE;
2248030839bSHans Petter Selasky 			setup.bRequest = 0x03;
2258030839bSHans Petter Selasky 			setup.wValue = 0x0001;
2268030839bSHans Petter Selasky 			setup.wIndex = iface_no;
2278030839bSHans Petter Selasky 			setup.wLength = 0x0002;
2288030839bSHans Petter Selasky 
2298030839bSHans Petter Selasky 			if (libusb20_dev_request_sync(p->usb_dev, &setup, buf, NULL, 250, 0)) {
2308030839bSHans Petter Selasky 				p->errors++;
2318030839bSHans Petter Selasky 			}
2328030839bSHans Petter Selasky 		}
2338030839bSHans Petter Selasky 		if (flag & 2) {
2348030839bSHans Petter Selasky 			setup.bmRequestType = UT_WRITE_CLASS_INTERFACE;
2358030839bSHans Petter Selasky 			setup.bRequest = UCDC_SET_COMM_FEATURE;
2368030839bSHans Petter Selasky 			setup.wValue = feature;
2378030839bSHans Petter Selasky 			setup.wIndex = iface_no;
2388030839bSHans Petter Selasky 			setup.wLength = UCDC_ABSTRACT_STATE_LENGTH;
2398030839bSHans Petter Selasky 			USETW(ast.wState, state);
2408030839bSHans Petter Selasky 
2418030839bSHans Petter Selasky 			if (libusb20_dev_request_sync(p->usb_dev, &setup, &ast, NULL, 250, 0)) {
2428030839bSHans Petter Selasky 				p->errors++;
2438030839bSHans Petter Selasky 			}
2448030839bSHans Petter Selasky 		}
2458030839bSHans Petter Selasky 		if (flag & 4) {
2468030839bSHans Petter Selasky 			USETDW(ls.dwDTERate, 115200);
2478030839bSHans Petter Selasky 			ls.bCharFormat = UCDC_STOP_BIT_1;
2488030839bSHans Petter Selasky 			ls.bParityType = UCDC_PARITY_NONE;
2498030839bSHans Petter Selasky 			ls.bDataBits = 8;
2508030839bSHans Petter Selasky 
2518030839bSHans Petter Selasky 			setup.bmRequestType = UT_WRITE_CLASS_INTERFACE;
2528030839bSHans Petter Selasky 			setup.bRequest = UCDC_SET_LINE_CODING;
2538030839bSHans Petter Selasky 			setup.wValue = 0;
2548030839bSHans Petter Selasky 			setup.wIndex = iface_no;
2558030839bSHans Petter Selasky 			setup.wLength = sizeof(ls);
2568030839bSHans Petter Selasky 
2578030839bSHans Petter Selasky 			if (libusb20_dev_request_sync(p->usb_dev, &setup, &ls, NULL, 250, 0)) {
2588030839bSHans Petter Selasky 				p->errors++;
2598030839bSHans Petter Selasky 			}
2608030839bSHans Petter Selasky 		}
2618030839bSHans Petter Selasky 		iter++;
2628030839bSHans Petter Selasky 	}
2638030839bSHans Petter Selasky 
2648030839bSHans Petter Selasky 	printf("\nModem control endpoint test done!\n");
2658030839bSHans Petter Selasky }
2668030839bSHans Petter Selasky 
2678030839bSHans Petter Selasky static void
usb_modem_data_stress_test(struct modem * p,uint32_t duration)2688030839bSHans Petter Selasky usb_modem_data_stress_test(struct modem *p, uint32_t duration)
2698030839bSHans Petter Selasky {
2708030839bSHans Petter Selasky 	struct timeval sub_tv;
2718030839bSHans Petter Selasky 	struct timeval ref_tv;
2728030839bSHans Petter Selasky 	struct timeval res_tv;
2738030839bSHans Petter Selasky 
2748030839bSHans Petter Selasky 	time_t last_sec;
2758030839bSHans Petter Selasky 
2768030839bSHans Petter Selasky 	uint8_t in_pending = 0;
2778030839bSHans Petter Selasky 	uint8_t in_ready = 0;
2788030839bSHans Petter Selasky 	uint8_t out_pending = 0;
2798030839bSHans Petter Selasky 
2808030839bSHans Petter Selasky 	uint32_t id = 0;
2818030839bSHans Petter Selasky 
2828030839bSHans Petter Selasky 	uint32_t in_max;
2838030839bSHans Petter Selasky 	uint32_t out_max;
2848030839bSHans Petter Selasky 	uint32_t io_max;
2858030839bSHans Petter Selasky 
2868030839bSHans Petter Selasky 	uint8_t *in_buffer = 0;
2878030839bSHans Petter Selasky 	uint8_t *out_buffer = 0;
2888030839bSHans Petter Selasky 
2898030839bSHans Petter Selasky 	gettimeofday(&ref_tv, 0);
2908030839bSHans Petter Selasky 
2918030839bSHans Petter Selasky 	last_sec = ref_tv.tv_sec;
2928030839bSHans Petter Selasky 
2938030839bSHans Petter Selasky 	printf("\n");
2948030839bSHans Petter Selasky 
2958030839bSHans Petter Selasky 	in_max = libusb20_tr_get_max_total_length(p->xfer_in);
2968030839bSHans Petter Selasky 	out_max = libusb20_tr_get_max_total_length(p->xfer_out);
2978030839bSHans Petter Selasky 
2988030839bSHans Petter Selasky 	/* get the smallest buffer size and use that */
2998030839bSHans Petter Selasky 	io_max = (in_max < out_max) ? in_max : out_max;
3008030839bSHans Petter Selasky 
3018030839bSHans Petter Selasky 	if (in_max != out_max)
3028030839bSHans Petter Selasky 		printf("WARNING: Buffer sizes are un-equal: %u vs %u\n", in_max, out_max);
3038030839bSHans Petter Selasky 
3048030839bSHans Petter Selasky 	in_buffer = malloc(io_max);
3058030839bSHans Petter Selasky 	if (in_buffer == NULL)
3068030839bSHans Petter Selasky 		goto fail;
3078030839bSHans Petter Selasky 
3088030839bSHans Petter Selasky 	out_buffer = malloc(io_max);
3098030839bSHans Petter Selasky 	if (out_buffer == NULL)
3108030839bSHans Petter Selasky 		goto fail;
3118030839bSHans Petter Selasky 
3128030839bSHans Petter Selasky 	while (1) {
3138030839bSHans Petter Selasky 
3148030839bSHans Petter Selasky 		gettimeofday(&sub_tv, 0);
3158030839bSHans Petter Selasky 
3168030839bSHans Petter Selasky 		if (last_sec != sub_tv.tv_sec) {
3178030839bSHans Petter Selasky 
3188030839bSHans Petter Selasky 			printf("STATUS: ID=%u, RX=%u bytes/sec, TX=%u bytes/sec, ERR=%d\n",
3198030839bSHans Petter Selasky 			    (int)id,
3208030839bSHans Petter Selasky 			    (int)p->rx_bytes.bytes,
3218030839bSHans Petter Selasky 			    (int)p->tx_bytes.bytes,
3228030839bSHans Petter Selasky 			    (int)p->errors);
3238030839bSHans Petter Selasky 
3248030839bSHans Petter Selasky 			p->rx_bytes.bytes = 0;
3258030839bSHans Petter Selasky 			p->tx_bytes.bytes = 0;
3268030839bSHans Petter Selasky 
3278030839bSHans Petter Selasky 			fflush(stdout);
3288030839bSHans Petter Selasky 
3298030839bSHans Petter Selasky 			last_sec = sub_tv.tv_sec;
3308030839bSHans Petter Selasky 
3318030839bSHans Petter Selasky 			id++;
3328030839bSHans Petter Selasky 		}
3338030839bSHans Petter Selasky 		timersub(&sub_tv, &ref_tv, &res_tv);
3348030839bSHans Petter Selasky 
335f7b25aedSHans Petter Selasky 		if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
3368030839bSHans Petter Selasky 			break;
3378030839bSHans Petter Selasky 
3388030839bSHans Petter Selasky 		libusb20_dev_process(p->usb_dev);
3398030839bSHans Petter Selasky 
3408030839bSHans Petter Selasky 		if (!libusb20_tr_pending(p->xfer_in)) {
3418030839bSHans Petter Selasky 			if (in_pending) {
3428030839bSHans Petter Selasky 				if (libusb20_tr_get_status(p->xfer_in) == 0) {
3438030839bSHans Petter Selasky 					modem_read(in_buffer, libusb20_tr_get_length(p->xfer_in, 0));
3448030839bSHans Petter Selasky 				} else {
3458030839bSHans Petter Selasky 					p->errors++;
3468030839bSHans Petter Selasky 					usleep(10000);
3478030839bSHans Petter Selasky 				}
3488030839bSHans Petter Selasky 				in_pending = 0;
3498030839bSHans Petter Selasky 				in_ready = 1;
3508030839bSHans Petter Selasky 			}
3518030839bSHans Petter Selasky 			if (p->loop_data == 0) {
3528030839bSHans Petter Selasky 				libusb20_tr_setup_bulk(p->xfer_in, in_buffer, io_max, 0);
3538030839bSHans Petter Selasky 				libusb20_tr_start(p->xfer_in);
3548030839bSHans Petter Selasky 				in_pending = 1;
3558030839bSHans Petter Selasky 				in_ready = 0;
3568030839bSHans Petter Selasky 			}
3578030839bSHans Petter Selasky 		}
3588030839bSHans Petter Selasky 		if (!libusb20_tr_pending(p->xfer_out)) {
3598030839bSHans Petter Selasky 
3608030839bSHans Petter Selasky 			uint32_t len;
3618030839bSHans Petter Selasky 			uint32_t dly;
3628030839bSHans Petter Selasky 
3638030839bSHans Petter Selasky 			if (out_pending) {
3648030839bSHans Petter Selasky 				if (libusb20_tr_get_status(p->xfer_out) != 0) {
3658030839bSHans Petter Selasky 					p->errors++;
3668030839bSHans Petter Selasky 					usleep(10000);
3678030839bSHans Petter Selasky 				}
3688030839bSHans Petter Selasky 			}
3698030839bSHans Petter Selasky 			if (p->random_tx_length) {
3708030839bSHans Petter Selasky 				len = ((uint32_t)usb_ts_rand_noise()) % ((uint32_t)io_max);
3718030839bSHans Petter Selasky 			} else {
3728030839bSHans Petter Selasky 				len = io_max;
3738030839bSHans Petter Selasky 			}
3748030839bSHans Petter Selasky 
3758030839bSHans Petter Selasky 			if (p->random_tx_delay) {
3768030839bSHans Petter Selasky 				dly = ((uint32_t)usb_ts_rand_noise()) % 16000U;
3778030839bSHans Petter Selasky 			} else {
3788030839bSHans Petter Selasky 				dly = 0;
3798030839bSHans Petter Selasky 			}
3808030839bSHans Petter Selasky 
3818030839bSHans Petter Selasky 			if (p->loop_data != 0) {
3828030839bSHans Petter Selasky 				if (in_ready != 0) {
3838030839bSHans Petter Selasky 					len = libusb20_tr_get_length(p->xfer_in, 0);
3848030839bSHans Petter Selasky 					memcpy(out_buffer, in_buffer, len);
3858030839bSHans Petter Selasky 					in_ready = 0;
3868030839bSHans Petter Selasky 				} else {
3878030839bSHans Petter Selasky 					len = io_max + 1;
3888030839bSHans Petter Selasky 				}
3898030839bSHans Petter Selasky 				if (!libusb20_tr_pending(p->xfer_in)) {
3908030839bSHans Petter Selasky 					libusb20_tr_setup_bulk(p->xfer_in, in_buffer, io_max, 0);
3918030839bSHans Petter Selasky 					libusb20_tr_start(p->xfer_in);
3928030839bSHans Petter Selasky 					in_pending = 1;
3938030839bSHans Petter Selasky 				}
3948030839bSHans Petter Selasky 			} else {
3958030839bSHans Petter Selasky 				modem_write(out_buffer, len);
3968030839bSHans Petter Selasky 			}
3978030839bSHans Petter Selasky 
3988030839bSHans Petter Selasky 			if (len <= io_max) {
3998030839bSHans Petter Selasky 				libusb20_tr_setup_bulk(p->xfer_out, out_buffer, len, 0);
4008030839bSHans Petter Selasky 
4018030839bSHans Petter Selasky 				if (dly != 0)
4028030839bSHans Petter Selasky 					usleep(dly);
4038030839bSHans Petter Selasky 
4048030839bSHans Petter Selasky 				libusb20_tr_start(p->xfer_out);
4058030839bSHans Petter Selasky 
4068030839bSHans Petter Selasky 				out_pending = 1;
4078030839bSHans Petter Selasky 			}
4088030839bSHans Petter Selasky 		}
4098030839bSHans Petter Selasky 		libusb20_dev_wait_process(p->usb_dev, 500);
4108030839bSHans Petter Selasky 
4118030839bSHans Petter Selasky 		if (libusb20_dev_check_connected(p->usb_dev) != 0) {
4128030839bSHans Petter Selasky 			printf("Device disconnected\n");
4138030839bSHans Petter Selasky 			break;
4148030839bSHans Petter Selasky 		}
4158030839bSHans Petter Selasky 	}
4168030839bSHans Petter Selasky 
4178030839bSHans Petter Selasky 	libusb20_tr_stop(p->xfer_in);
4188030839bSHans Petter Selasky 	libusb20_tr_stop(p->xfer_out);
4198030839bSHans Petter Selasky 
4208030839bSHans Petter Selasky 	printf("\nData stress test done!\n");
4218030839bSHans Petter Selasky 
4228030839bSHans Petter Selasky fail:
4238030839bSHans Petter Selasky 	if (in_buffer)
4248030839bSHans Petter Selasky 		free(in_buffer);
4258030839bSHans Petter Selasky 	if (out_buffer)
4268030839bSHans Petter Selasky 		free(out_buffer);
4278030839bSHans Petter Selasky }
4288030839bSHans Petter Selasky 
4298030839bSHans Petter Selasky static void
exec_host_modem_test(struct modem * p,struct uaddr uaddr)43016346e14SHans Petter Selasky exec_host_modem_test(struct modem *p, struct uaddr uaddr)
4318030839bSHans Petter Selasky {
4328030839bSHans Petter Selasky 	struct libusb20_device *pdev;
4338030839bSHans Petter Selasky 
4348030839bSHans Petter Selasky 	uint8_t ntest = 0;
4358030839bSHans Petter Selasky 	uint8_t x;
4368030839bSHans Petter Selasky 	uint8_t in_ep;
4378030839bSHans Petter Selasky 	uint8_t out_ep;
4388030839bSHans Petter Selasky 	uint8_t iface;
4398030839bSHans Petter Selasky 
4408030839bSHans Petter Selasky 	int error;
4418030839bSHans Petter Selasky 
44216346e14SHans Petter Selasky 	pdev = find_usb_device(uaddr);
4438030839bSHans Petter Selasky 	if (pdev == NULL) {
4448030839bSHans Petter Selasky 		printf("USB device not found\n");
4458030839bSHans Petter Selasky 		return;
4468030839bSHans Petter Selasky 	}
4478030839bSHans Petter Selasky 
4488030839bSHans Petter Selasky 	if (p->use_vendor_specific)
4498030839bSHans Petter Selasky 		find_usb_endpoints(pdev, 255, 255, 255, 0, &iface, &in_ep, &out_ep, 0);
4508030839bSHans Petter Selasky 	else
4518030839bSHans Petter Selasky 		find_usb_endpoints(pdev, 2, 2, 1, 0, &iface, &in_ep, &out_ep, 1);
4528030839bSHans Petter Selasky 
4538030839bSHans Petter Selasky 	if ((in_ep == 0) || (out_ep == 0)) {
4548030839bSHans Petter Selasky 		printf("Could not find USB endpoints\n");
4558030839bSHans Petter Selasky 		libusb20_dev_free(pdev);
4568030839bSHans Petter Selasky 		return;
4578030839bSHans Petter Selasky 	}
4588030839bSHans Petter Selasky 	printf("Attaching to: %s @ iface %d\n",
4598030839bSHans Petter Selasky 	    libusb20_dev_get_desc(pdev), iface);
4608030839bSHans Petter Selasky 
4618030839bSHans Petter Selasky 	if (libusb20_dev_open(pdev, 2)) {
4628030839bSHans Petter Selasky 		printf("Could not open USB device\n");
4638030839bSHans Petter Selasky 		libusb20_dev_free(pdev);
4648030839bSHans Petter Selasky 		return;
4658030839bSHans Petter Selasky 	}
4668030839bSHans Petter Selasky 	if (libusb20_dev_detach_kernel_driver(pdev, iface)) {
4678030839bSHans Petter Selasky 		printf("WARNING: Could not detach kernel driver\n");
4688030839bSHans Petter Selasky 	}
4698030839bSHans Petter Selasky 	p->xfer_in = libusb20_tr_get_pointer(pdev, 0);
4708030839bSHans Petter Selasky 	error = libusb20_tr_open(p->xfer_in, 65536 / 4, 1, in_ep);
4718030839bSHans Petter Selasky 	if (error) {
4728030839bSHans Petter Selasky 		printf("Could not open USB endpoint %d\n", in_ep);
4738030839bSHans Petter Selasky 		libusb20_dev_free(pdev);
4748030839bSHans Petter Selasky 		return;
4758030839bSHans Petter Selasky 	}
4768030839bSHans Petter Selasky 	p->xfer_out = libusb20_tr_get_pointer(pdev, 1);
4778030839bSHans Petter Selasky 	error = libusb20_tr_open(p->xfer_out, 65536 / 4, 1, out_ep);
4788030839bSHans Petter Selasky 	if (error) {
4798030839bSHans Petter Selasky 		printf("Could not open USB endpoint %d\n", out_ep);
4808030839bSHans Petter Selasky 		libusb20_dev_free(pdev);
4818030839bSHans Petter Selasky 		return;
4828030839bSHans Petter Selasky 	}
4838030839bSHans Petter Selasky 	p->usb_dev = pdev;
4848030839bSHans Petter Selasky 	p->usb_iface = iface;
4858030839bSHans Petter Selasky 	p->errors = 0;
4868030839bSHans Petter Selasky 
4878030839bSHans Petter Selasky 	if (p->control_ep_test)
4888030839bSHans Petter Selasky 		ntest += 7;
4898030839bSHans Petter Selasky 
4908030839bSHans Petter Selasky 	if (p->data_stress_test)
4918030839bSHans Petter Selasky 		ntest += 1;
4928030839bSHans Petter Selasky 
4938030839bSHans Petter Selasky 	if (ntest == 0) {
4948030839bSHans Petter Selasky 		printf("No tests selected\n");
4958030839bSHans Petter Selasky 	} else {
4968030839bSHans Petter Selasky 
4978030839bSHans Petter Selasky 		if (p->control_ep_test) {
4988030839bSHans Petter Selasky 			for (x = 1; x != 8; x++) {
4998030839bSHans Petter Selasky 				usb_modem_control_ep_test(p,
5008030839bSHans Petter Selasky 				    (p->duration + ntest - 1) / ntest, x);
5018030839bSHans Petter Selasky 			}
5028030839bSHans Petter Selasky 		}
5038030839bSHans Petter Selasky 		if (p->data_stress_test) {
5048030839bSHans Petter Selasky 			usb_modem_data_stress_test(p,
5058030839bSHans Petter Selasky 			    (p->duration + ntest - 1) / ntest);
5068030839bSHans Petter Selasky 		}
5078030839bSHans Petter Selasky 	}
5088030839bSHans Petter Selasky 
5098030839bSHans Petter Selasky 	printf("\nDone\n");
5108030839bSHans Petter Selasky 
5118030839bSHans Petter Selasky 	libusb20_dev_free(pdev);
5128030839bSHans Petter Selasky }
5138030839bSHans Petter Selasky 
5148030839bSHans Petter Selasky void
show_host_modem_test(uint8_t level,struct uaddr uaddr,uint32_t duration)51516346e14SHans Petter Selasky show_host_modem_test(uint8_t level, struct uaddr uaddr, uint32_t duration)
5168030839bSHans Petter Selasky {
5178030839bSHans Petter Selasky 	uint8_t retval;
5188030839bSHans Petter Selasky 
5198030839bSHans Petter Selasky 	set_defaults(&modem);
5208030839bSHans Petter Selasky 
5218030839bSHans Petter Selasky 	modem.duration = duration;
5228030839bSHans Petter Selasky 
5238030839bSHans Petter Selasky 	while (1) {
5248030839bSHans Petter Selasky 
5258030839bSHans Petter Selasky 		retval = usb_ts_show_menu(level, "Modem Test Parameters",
5268030839bSHans Petter Selasky 		    " 1) Execute Data Stress Test: <%s>\n"
5278030839bSHans Petter Selasky 		    " 2) Execute Modem Control Endpoint Test: <%s>\n"
5288030839bSHans Petter Selasky 		    " 3) Use random transmit length: <%s>\n"
5298030839bSHans Petter Selasky 		    " 4) Use random transmit delay: <%s> ms\n"
5308030839bSHans Petter Selasky 		    " 5) Use vendor specific interface: <%s>\n"
5318030839bSHans Petter Selasky 		    "10) Loop data: <%s>\n"
5328030839bSHans Petter Selasky 		    "13) Set test duration: <%d> seconds\n"
5338030839bSHans Petter Selasky 		    "20) Reset parameters\n"
5348030839bSHans Petter Selasky 		    "30) Start test (VID=0x%04x, PID=0x%04x)\n"
5358030839bSHans Petter Selasky 		    "40) Select another device\n"
5368030839bSHans Petter Selasky 		    " x) Return to previous menu \n",
5378030839bSHans Petter Selasky 		    (modem.data_stress_test ? "YES" : "NO"),
5388030839bSHans Petter Selasky 		    (modem.control_ep_test ? "YES" : "NO"),
5398030839bSHans Petter Selasky 		    (modem.random_tx_length ? "YES" : "NO"),
5408030839bSHans Petter Selasky 		    (modem.random_tx_delay ? "16" : "0"),
5418030839bSHans Petter Selasky 		    (modem.use_vendor_specific ? "YES" : "NO"),
5428030839bSHans Petter Selasky 		    (modem.loop_data ? "YES" : "NO"),
5438030839bSHans Petter Selasky 		    (int)(modem.duration),
54416346e14SHans Petter Selasky 		    (int)uaddr.vid, (int)uaddr.pid);
5458030839bSHans Petter Selasky 
5468030839bSHans Petter Selasky 		switch (retval) {
5478030839bSHans Petter Selasky 		case 0:
5488030839bSHans Petter Selasky 			break;
5498030839bSHans Petter Selasky 		case 1:
5508030839bSHans Petter Selasky 			modem.data_stress_test ^= 1;
5518030839bSHans Petter Selasky 			break;
5528030839bSHans Petter Selasky 		case 2:
5538030839bSHans Petter Selasky 			modem.control_ep_test ^= 1;
5548030839bSHans Petter Selasky 			break;
5558030839bSHans Petter Selasky 		case 3:
5568030839bSHans Petter Selasky 			modem.random_tx_length ^= 1;
5578030839bSHans Petter Selasky 			break;
5588030839bSHans Petter Selasky 		case 4:
5598030839bSHans Petter Selasky 			modem.random_tx_delay ^= 1;
5608030839bSHans Petter Selasky 			break;
5618030839bSHans Petter Selasky 		case 5:
5628030839bSHans Petter Selasky 			modem.use_vendor_specific ^= 1;
5638030839bSHans Petter Selasky 			modem.control_ep_test = 0;
5648030839bSHans Petter Selasky 			break;
5658030839bSHans Petter Selasky 		case 10:
5668030839bSHans Petter Selasky 			modem.loop_data ^= 1;
5678030839bSHans Petter Selasky 			break;
5688030839bSHans Petter Selasky 		case 13:
5698030839bSHans Petter Selasky 			modem.duration = get_integer();
5708030839bSHans Petter Selasky 			break;
5718030839bSHans Petter Selasky 		case 20:
5728030839bSHans Petter Selasky 			set_defaults(&modem);
5738030839bSHans Petter Selasky 			break;
5748030839bSHans Petter Selasky 		case 30:
57516346e14SHans Petter Selasky 			exec_host_modem_test(&modem, uaddr);
5768030839bSHans Petter Selasky 			break;
5778030839bSHans Petter Selasky 		case 40:
57816346e14SHans Petter Selasky 			show_host_device_selection(level + 1, &uaddr);
5798030839bSHans Petter Selasky 			break;
5808030839bSHans Petter Selasky 		default:
5818030839bSHans Petter Selasky 			return;
5828030839bSHans Petter Selasky 		}
5838030839bSHans Petter Selasky 	}
5848030839bSHans Petter Selasky }
585