1129a2703SSascha Wildner /* $FreeBSD: head/tools/tools/usbtest/usb_modem_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 
41129a2703SSascha Wildner #include <bus/u4b/usb_endian.h>
42129a2703SSascha Wildner #include <bus/u4b/usb.h>
43129a2703SSascha Wildner #include <bus/u4b/usb_cdc.h>
4457bed822SMarkus Pfeiffer 
4557bed822SMarkus Pfeiffer #include "usbtest.h"
4657bed822SMarkus Pfeiffer 
4757bed822SMarkus Pfeiffer static struct modem {
4857bed822SMarkus Pfeiffer 	struct libusb20_transfer *xfer_in;
4957bed822SMarkus Pfeiffer 	struct libusb20_transfer *xfer_out;
5057bed822SMarkus Pfeiffer 	struct libusb20_device *usb_dev;
5157bed822SMarkus Pfeiffer 
5257bed822SMarkus Pfeiffer 	struct bps rx_bytes;
5357bed822SMarkus Pfeiffer 	struct bps tx_bytes;
5457bed822SMarkus Pfeiffer 	uint32_t c0;
5557bed822SMarkus Pfeiffer 	uint32_t c1;
5657bed822SMarkus Pfeiffer 	uint32_t out_state;
5757bed822SMarkus Pfeiffer 	uint32_t in_last;
5857bed822SMarkus Pfeiffer 	uint32_t in_synced;
5957bed822SMarkus Pfeiffer 	uint32_t duration;
6057bed822SMarkus Pfeiffer 	uint32_t errors;
6157bed822SMarkus Pfeiffer 
6257bed822SMarkus Pfeiffer 	uint8_t use_vendor_specific;
6357bed822SMarkus Pfeiffer 	uint8_t	loop_data;
6457bed822SMarkus Pfeiffer 	uint8_t	modem_at_mode;
6557bed822SMarkus Pfeiffer 	uint8_t	data_stress_test;
6657bed822SMarkus Pfeiffer 	uint8_t	control_ep_test;
6757bed822SMarkus Pfeiffer 	uint8_t	usb_iface;
6857bed822SMarkus Pfeiffer 	uint8_t	random_tx_length;
6957bed822SMarkus Pfeiffer 	uint8_t	random_tx_delay;
7057bed822SMarkus Pfeiffer 
7157bed822SMarkus Pfeiffer }	modem;
7257bed822SMarkus Pfeiffer 
7357bed822SMarkus Pfeiffer static void
set_defaults(struct modem * p)7457bed822SMarkus Pfeiffer set_defaults(struct modem *p)
7557bed822SMarkus Pfeiffer {
7657bed822SMarkus Pfeiffer 	memset(p, 0, sizeof(*p));
7757bed822SMarkus Pfeiffer 
7857bed822SMarkus Pfeiffer 	p->data_stress_test = 1;
7957bed822SMarkus Pfeiffer 	p->control_ep_test = 1;
8057bed822SMarkus Pfeiffer 	p->duration = 60;		/* seconds */
8157bed822SMarkus Pfeiffer }
8257bed822SMarkus Pfeiffer 
8357bed822SMarkus Pfeiffer void
do_bps(const char * desc,struct bps * bps,uint32_t len)8457bed822SMarkus Pfeiffer do_bps(const char *desc, struct bps *bps, uint32_t len)
8557bed822SMarkus Pfeiffer {
8657bed822SMarkus Pfeiffer 	bps->bytes += len;
8757bed822SMarkus Pfeiffer }
8857bed822SMarkus Pfeiffer 
8957bed822SMarkus Pfeiffer static void
modem_out_state(uint8_t * buf)9057bed822SMarkus Pfeiffer modem_out_state(uint8_t *buf)
9157bed822SMarkus Pfeiffer {
9257bed822SMarkus Pfeiffer 	if (modem.modem_at_mode) {
9357bed822SMarkus Pfeiffer 		switch (modem.out_state & 3) {
9457bed822SMarkus Pfeiffer 		case 0:
9557bed822SMarkus Pfeiffer 			*buf = 'A';
9657bed822SMarkus Pfeiffer 			break;
9757bed822SMarkus Pfeiffer 		case 1:
9857bed822SMarkus Pfeiffer 			*buf = 'T';
9957bed822SMarkus Pfeiffer 			break;
10057bed822SMarkus Pfeiffer 		case 2:
10157bed822SMarkus Pfeiffer 			*buf = '\r';
10257bed822SMarkus Pfeiffer 			break;
10357bed822SMarkus Pfeiffer 		default:
10457bed822SMarkus Pfeiffer 			*buf = '\n';
10557bed822SMarkus Pfeiffer 			modem.c0++;
10657bed822SMarkus Pfeiffer 			break;
10757bed822SMarkus Pfeiffer 		}
10857bed822SMarkus Pfeiffer 		modem.out_state++;
10957bed822SMarkus Pfeiffer 	} else {
11057bed822SMarkus Pfeiffer 		*buf = modem.out_state;
11157bed822SMarkus Pfeiffer 		modem.out_state++;
11257bed822SMarkus Pfeiffer 		modem.out_state %= 255;
11357bed822SMarkus Pfeiffer 	}
11457bed822SMarkus Pfeiffer }
11557bed822SMarkus Pfeiffer 
11657bed822SMarkus Pfeiffer static void
modem_in_state(uint8_t buf,uint32_t counter)11757bed822SMarkus Pfeiffer modem_in_state(uint8_t buf, uint32_t counter)
11857bed822SMarkus Pfeiffer {
11957bed822SMarkus Pfeiffer 	if ((modem.in_last == 'O') && (buf == 'K')) {
12057bed822SMarkus Pfeiffer 		modem.c1++;
12157bed822SMarkus Pfeiffer 		modem.in_last = buf;
12257bed822SMarkus Pfeiffer 	} else if (buf == modem.in_last) {
12357bed822SMarkus Pfeiffer 		modem.c1++;
12457bed822SMarkus Pfeiffer 		modem.in_last++;
12557bed822SMarkus Pfeiffer 		modem.in_last %= 255;
12657bed822SMarkus Pfeiffer 		if (modem.in_synced == 0) {
12757bed822SMarkus Pfeiffer 			if (modem.errors < 64) {
12857bed822SMarkus Pfeiffer 				printf("Got sync\n");
12957bed822SMarkus Pfeiffer 			}
13057bed822SMarkus Pfeiffer 			modem.in_synced = 1;
13157bed822SMarkus Pfeiffer 		}
13257bed822SMarkus Pfeiffer 	} else {
13357bed822SMarkus Pfeiffer 		if (modem.in_synced) {
13457bed822SMarkus Pfeiffer 			if (modem.errors < 64) {
13557bed822SMarkus Pfeiffer 				printf("Lost sync @ %d, 0x%02x != 0x%02x\n",
13657bed822SMarkus Pfeiffer 				    counter % 512, buf, modem.in_last);
13757bed822SMarkus Pfeiffer 			}
13857bed822SMarkus Pfeiffer 			modem.in_synced = 0;
13957bed822SMarkus Pfeiffer 			modem.errors++;
14057bed822SMarkus Pfeiffer 		}
14157bed822SMarkus Pfeiffer 		modem.in_last = buf;
14257bed822SMarkus Pfeiffer 		modem.in_last++;
14357bed822SMarkus Pfeiffer 		modem.in_last %= 255;
14457bed822SMarkus Pfeiffer 	}
14557bed822SMarkus Pfeiffer }
14657bed822SMarkus Pfeiffer 
14757bed822SMarkus Pfeiffer static void
modem_write(uint8_t * buf,uint32_t len)14857bed822SMarkus Pfeiffer modem_write(uint8_t *buf, uint32_t len)
14957bed822SMarkus Pfeiffer {
15057bed822SMarkus Pfeiffer 	uint32_t n;
15157bed822SMarkus Pfeiffer 
15257bed822SMarkus Pfeiffer 	for (n = 0; n != len; n++) {
15357bed822SMarkus Pfeiffer 		modem_out_state(buf + n);
15457bed822SMarkus Pfeiffer 	}
15557bed822SMarkus Pfeiffer 
15657bed822SMarkus Pfeiffer 	do_bps("transmitted", &modem.tx_bytes, len);
15757bed822SMarkus Pfeiffer }
15857bed822SMarkus Pfeiffer 
15957bed822SMarkus Pfeiffer static void
modem_read(uint8_t * buf,uint32_t len)16057bed822SMarkus Pfeiffer modem_read(uint8_t *buf, uint32_t len)
16157bed822SMarkus Pfeiffer {
16257bed822SMarkus Pfeiffer 	uint32_t n;
16357bed822SMarkus Pfeiffer 
16457bed822SMarkus Pfeiffer 	for (n = 0; n != len; n++) {
16557bed822SMarkus Pfeiffer 		modem_in_state(buf[n], n);
16657bed822SMarkus Pfeiffer 	}
16757bed822SMarkus Pfeiffer 
16857bed822SMarkus Pfeiffer 	do_bps("received", &modem.rx_bytes, len);
16957bed822SMarkus Pfeiffer }
17057bed822SMarkus Pfeiffer 
17157bed822SMarkus Pfeiffer static void
usb_modem_control_ep_test(struct modem * p,uint32_t duration,uint8_t flag)17257bed822SMarkus Pfeiffer usb_modem_control_ep_test(struct modem *p, uint32_t duration, uint8_t flag)
17357bed822SMarkus Pfeiffer {
17457bed822SMarkus Pfeiffer 	struct timeval sub_tv;
17557bed822SMarkus Pfeiffer 	struct timeval ref_tv;
17657bed822SMarkus Pfeiffer 	struct timeval res_tv;
17757bed822SMarkus Pfeiffer 	struct LIBUSB20_CONTROL_SETUP_DECODED setup;
17857bed822SMarkus Pfeiffer 	struct usb_cdc_abstract_state ast;
17957bed822SMarkus Pfeiffer 	struct usb_cdc_line_state ls;
18057bed822SMarkus Pfeiffer 	uint16_t feature = UCDC_ABSTRACT_STATE;
18157bed822SMarkus Pfeiffer 	uint16_t state = UCDC_DATA_MULTIPLEXED;
18257bed822SMarkus Pfeiffer 	uint8_t iface_no;
18357bed822SMarkus Pfeiffer 	uint8_t buf[4];
18457bed822SMarkus Pfeiffer 	int id = 0;
18557bed822SMarkus Pfeiffer 	int iter = 0;
18657bed822SMarkus Pfeiffer 
18757bed822SMarkus Pfeiffer 	time_t last_sec;
18857bed822SMarkus Pfeiffer 
18957bed822SMarkus Pfeiffer 	iface_no = p->usb_iface - 1;
19057bed822SMarkus Pfeiffer 
19157bed822SMarkus Pfeiffer 	gettimeofday(&ref_tv, 0);
19257bed822SMarkus Pfeiffer 
19357bed822SMarkus Pfeiffer 	last_sec = ref_tv.tv_sec;
19457bed822SMarkus Pfeiffer 
19557bed822SMarkus Pfeiffer 	printf("\nTest=%d\n", (int)flag);
19657bed822SMarkus Pfeiffer 
19757bed822SMarkus Pfeiffer 	while (1) {
19857bed822SMarkus Pfeiffer 
19957bed822SMarkus Pfeiffer 		gettimeofday(&sub_tv, 0);
20057bed822SMarkus Pfeiffer 
20157bed822SMarkus Pfeiffer 		if (last_sec != sub_tv.tv_sec) {
20257bed822SMarkus Pfeiffer 
20357bed822SMarkus Pfeiffer 			printf("STATUS: ID=%u, COUNT=%u tests/sec ERR=%u\n",
20457bed822SMarkus Pfeiffer 			    (int)id,
20557bed822SMarkus Pfeiffer 			    (int)iter,
20657bed822SMarkus Pfeiffer 			    (int)p->errors);
20757bed822SMarkus Pfeiffer 
20857bed822SMarkus Pfeiffer 			fflush(stdout);
20957bed822SMarkus Pfeiffer 
21057bed822SMarkus Pfeiffer 			last_sec = sub_tv.tv_sec;
21157bed822SMarkus Pfeiffer 
21257bed822SMarkus Pfeiffer 			id++;
21357bed822SMarkus Pfeiffer 
21457bed822SMarkus Pfeiffer 			iter = 0;
21557bed822SMarkus Pfeiffer 		}
21657bed822SMarkus Pfeiffer 		timersub(&sub_tv, &ref_tv, &res_tv);
21757bed822SMarkus Pfeiffer 
218129a2703SSascha Wildner 		if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
21957bed822SMarkus Pfeiffer 			break;
22057bed822SMarkus Pfeiffer 
22157bed822SMarkus Pfeiffer 		LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup);
22257bed822SMarkus Pfeiffer 
22357bed822SMarkus Pfeiffer 		if (flag & 1) {
22457bed822SMarkus Pfeiffer 			setup.bmRequestType = UT_READ_CLASS_INTERFACE;
22557bed822SMarkus Pfeiffer 			setup.bRequest = 0x03;
22657bed822SMarkus Pfeiffer 			setup.wValue = 0x0001;
22757bed822SMarkus Pfeiffer 			setup.wIndex = iface_no;
22857bed822SMarkus Pfeiffer 			setup.wLength = 0x0002;
22957bed822SMarkus Pfeiffer 
23057bed822SMarkus Pfeiffer 			if (libusb20_dev_request_sync(p->usb_dev, &setup, buf, NULL, 250, 0)) {
23157bed822SMarkus Pfeiffer 				p->errors++;
23257bed822SMarkus Pfeiffer 			}
23357bed822SMarkus Pfeiffer 		}
23457bed822SMarkus Pfeiffer 		if (flag & 2) {
23557bed822SMarkus Pfeiffer 			setup.bmRequestType = UT_WRITE_CLASS_INTERFACE;
23657bed822SMarkus Pfeiffer 			setup.bRequest = UCDC_SET_COMM_FEATURE;
23757bed822SMarkus Pfeiffer 			setup.wValue = feature;
23857bed822SMarkus Pfeiffer 			setup.wIndex = iface_no;
23957bed822SMarkus Pfeiffer 			setup.wLength = UCDC_ABSTRACT_STATE_LENGTH;
24057bed822SMarkus Pfeiffer 			USETW(ast.wState, state);
24157bed822SMarkus Pfeiffer 
24257bed822SMarkus Pfeiffer 			if (libusb20_dev_request_sync(p->usb_dev, &setup, &ast, NULL, 250, 0)) {
24357bed822SMarkus Pfeiffer 				p->errors++;
24457bed822SMarkus Pfeiffer 			}
24557bed822SMarkus Pfeiffer 		}
24657bed822SMarkus Pfeiffer 		if (flag & 4) {
24757bed822SMarkus Pfeiffer 			USETDW(ls.dwDTERate, 115200);
24857bed822SMarkus Pfeiffer 			ls.bCharFormat = UCDC_STOP_BIT_1;
24957bed822SMarkus Pfeiffer 			ls.bParityType = UCDC_PARITY_NONE;
25057bed822SMarkus Pfeiffer 			ls.bDataBits = 8;
25157bed822SMarkus Pfeiffer 
25257bed822SMarkus Pfeiffer 			setup.bmRequestType = UT_WRITE_CLASS_INTERFACE;
25357bed822SMarkus Pfeiffer 			setup.bRequest = UCDC_SET_LINE_CODING;
25457bed822SMarkus Pfeiffer 			setup.wValue = 0;
25557bed822SMarkus Pfeiffer 			setup.wIndex = iface_no;
25657bed822SMarkus Pfeiffer 			setup.wLength = sizeof(ls);
25757bed822SMarkus Pfeiffer 
25857bed822SMarkus Pfeiffer 			if (libusb20_dev_request_sync(p->usb_dev, &setup, &ls, NULL, 250, 0)) {
25957bed822SMarkus Pfeiffer 				p->errors++;
26057bed822SMarkus Pfeiffer 			}
26157bed822SMarkus Pfeiffer 		}
26257bed822SMarkus Pfeiffer 		iter++;
26357bed822SMarkus Pfeiffer 	}
26457bed822SMarkus Pfeiffer 
26557bed822SMarkus Pfeiffer 	printf("\nModem control endpoint test done!\n");
26657bed822SMarkus Pfeiffer }
26757bed822SMarkus Pfeiffer 
26857bed822SMarkus Pfeiffer static void
usb_modem_data_stress_test(struct modem * p,uint32_t duration)26957bed822SMarkus Pfeiffer usb_modem_data_stress_test(struct modem *p, uint32_t duration)
27057bed822SMarkus Pfeiffer {
27157bed822SMarkus Pfeiffer 	struct timeval sub_tv;
27257bed822SMarkus Pfeiffer 	struct timeval ref_tv;
27357bed822SMarkus Pfeiffer 	struct timeval res_tv;
27457bed822SMarkus Pfeiffer 
27557bed822SMarkus Pfeiffer 	time_t last_sec;
27657bed822SMarkus Pfeiffer 
27757bed822SMarkus Pfeiffer 	uint8_t in_pending = 0;
27857bed822SMarkus Pfeiffer 	uint8_t in_ready = 0;
27957bed822SMarkus Pfeiffer 	uint8_t out_pending = 0;
28057bed822SMarkus Pfeiffer 
28157bed822SMarkus Pfeiffer 	uint32_t id = 0;
28257bed822SMarkus Pfeiffer 
28357bed822SMarkus Pfeiffer 	uint32_t in_max;
28457bed822SMarkus Pfeiffer 	uint32_t out_max;
28557bed822SMarkus Pfeiffer 	uint32_t io_max;
28657bed822SMarkus Pfeiffer 
287*d9c2dd8bSSascha Wildner 	uint8_t *in_buffer = NULL;
288*d9c2dd8bSSascha Wildner 	uint8_t *out_buffer = NULL;
28957bed822SMarkus Pfeiffer 
29057bed822SMarkus Pfeiffer 	gettimeofday(&ref_tv, 0);
29157bed822SMarkus Pfeiffer 
29257bed822SMarkus Pfeiffer 	last_sec = ref_tv.tv_sec;
29357bed822SMarkus Pfeiffer 
29457bed822SMarkus Pfeiffer 	printf("\n");
29557bed822SMarkus Pfeiffer 
29657bed822SMarkus Pfeiffer 	in_max = libusb20_tr_get_max_total_length(p->xfer_in);
29757bed822SMarkus Pfeiffer 	out_max = libusb20_tr_get_max_total_length(p->xfer_out);
29857bed822SMarkus Pfeiffer 
29957bed822SMarkus Pfeiffer 	/* get the smallest buffer size and use that */
30057bed822SMarkus Pfeiffer 	io_max = (in_max < out_max) ? in_max : out_max;
30157bed822SMarkus Pfeiffer 
30257bed822SMarkus Pfeiffer 	if (in_max != out_max)
30357bed822SMarkus Pfeiffer 		printf("WARNING: Buffer sizes are un-equal: %u vs %u\n", in_max, out_max);
30457bed822SMarkus Pfeiffer 
30557bed822SMarkus Pfeiffer 	in_buffer = malloc(io_max);
30657bed822SMarkus Pfeiffer 	if (in_buffer == NULL)
30757bed822SMarkus Pfeiffer 		goto fail;
30857bed822SMarkus Pfeiffer 
30957bed822SMarkus Pfeiffer 	out_buffer = malloc(io_max);
31057bed822SMarkus Pfeiffer 	if (out_buffer == NULL)
31157bed822SMarkus Pfeiffer 		goto fail;
31257bed822SMarkus Pfeiffer 
31357bed822SMarkus Pfeiffer 	while (1) {
31457bed822SMarkus Pfeiffer 
31557bed822SMarkus Pfeiffer 		gettimeofday(&sub_tv, 0);
31657bed822SMarkus Pfeiffer 
31757bed822SMarkus Pfeiffer 		if (last_sec != sub_tv.tv_sec) {
31857bed822SMarkus Pfeiffer 
31957bed822SMarkus Pfeiffer 			printf("STATUS: ID=%u, RX=%u bytes/sec, TX=%u bytes/sec, ERR=%d\n",
32057bed822SMarkus Pfeiffer 			    (int)id,
32157bed822SMarkus Pfeiffer 			    (int)p->rx_bytes.bytes,
32257bed822SMarkus Pfeiffer 			    (int)p->tx_bytes.bytes,
32357bed822SMarkus Pfeiffer 			    (int)p->errors);
32457bed822SMarkus Pfeiffer 
32557bed822SMarkus Pfeiffer 			p->rx_bytes.bytes = 0;
32657bed822SMarkus Pfeiffer 			p->tx_bytes.bytes = 0;
32757bed822SMarkus Pfeiffer 
32857bed822SMarkus Pfeiffer 			fflush(stdout);
32957bed822SMarkus Pfeiffer 
33057bed822SMarkus Pfeiffer 			last_sec = sub_tv.tv_sec;
33157bed822SMarkus Pfeiffer 
33257bed822SMarkus Pfeiffer 			id++;
33357bed822SMarkus Pfeiffer 		}
33457bed822SMarkus Pfeiffer 		timersub(&sub_tv, &ref_tv, &res_tv);
33557bed822SMarkus Pfeiffer 
336129a2703SSascha Wildner 		if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
33757bed822SMarkus Pfeiffer 			break;
33857bed822SMarkus Pfeiffer 
33957bed822SMarkus Pfeiffer 		libusb20_dev_process(p->usb_dev);
34057bed822SMarkus Pfeiffer 
34157bed822SMarkus Pfeiffer 		if (!libusb20_tr_pending(p->xfer_in)) {
34257bed822SMarkus Pfeiffer 			if (in_pending) {
34357bed822SMarkus Pfeiffer 				if (libusb20_tr_get_status(p->xfer_in) == 0) {
34457bed822SMarkus Pfeiffer 					modem_read(in_buffer, libusb20_tr_get_length(p->xfer_in, 0));
34557bed822SMarkus Pfeiffer 				} else {
34657bed822SMarkus Pfeiffer 					p->errors++;
34757bed822SMarkus Pfeiffer 					usleep(10000);
34857bed822SMarkus Pfeiffer 				}
34957bed822SMarkus Pfeiffer 				in_pending = 0;
35057bed822SMarkus Pfeiffer 				in_ready = 1;
35157bed822SMarkus Pfeiffer 			}
35257bed822SMarkus Pfeiffer 			if (p->loop_data == 0) {
35357bed822SMarkus Pfeiffer 				libusb20_tr_setup_bulk(p->xfer_in, in_buffer, io_max, 0);
35457bed822SMarkus Pfeiffer 				libusb20_tr_start(p->xfer_in);
35557bed822SMarkus Pfeiffer 				in_pending = 1;
35657bed822SMarkus Pfeiffer 				in_ready = 0;
35757bed822SMarkus Pfeiffer 			}
35857bed822SMarkus Pfeiffer 		}
35957bed822SMarkus Pfeiffer 		if (!libusb20_tr_pending(p->xfer_out)) {
36057bed822SMarkus Pfeiffer 
36157bed822SMarkus Pfeiffer 			uint32_t len;
36257bed822SMarkus Pfeiffer 			uint32_t dly;
36357bed822SMarkus Pfeiffer 
36457bed822SMarkus Pfeiffer 			if (out_pending) {
36557bed822SMarkus Pfeiffer 				if (libusb20_tr_get_status(p->xfer_out) != 0) {
36657bed822SMarkus Pfeiffer 					p->errors++;
36757bed822SMarkus Pfeiffer 					usleep(10000);
36857bed822SMarkus Pfeiffer 				}
36957bed822SMarkus Pfeiffer 			}
37057bed822SMarkus Pfeiffer 			if (p->random_tx_length) {
37157bed822SMarkus Pfeiffer 				len = ((uint32_t)usb_ts_rand_noise()) % ((uint32_t)io_max);
37257bed822SMarkus Pfeiffer 			} else {
37357bed822SMarkus Pfeiffer 				len = io_max;
37457bed822SMarkus Pfeiffer 			}
37557bed822SMarkus Pfeiffer 
37657bed822SMarkus Pfeiffer 			if (p->random_tx_delay) {
37757bed822SMarkus Pfeiffer 				dly = ((uint32_t)usb_ts_rand_noise()) % 16000U;
37857bed822SMarkus Pfeiffer 			} else {
37957bed822SMarkus Pfeiffer 				dly = 0;
38057bed822SMarkus Pfeiffer 			}
38157bed822SMarkus Pfeiffer 
38257bed822SMarkus Pfeiffer 			if (p->loop_data != 0) {
38357bed822SMarkus Pfeiffer 				if (in_ready != 0) {
38457bed822SMarkus Pfeiffer 					len = libusb20_tr_get_length(p->xfer_in, 0);
38557bed822SMarkus Pfeiffer 					memcpy(out_buffer, in_buffer, len);
38657bed822SMarkus Pfeiffer 					in_ready = 0;
38757bed822SMarkus Pfeiffer 				} else {
38857bed822SMarkus Pfeiffer 					len = io_max + 1;
38957bed822SMarkus Pfeiffer 				}
39057bed822SMarkus Pfeiffer 				if (!libusb20_tr_pending(p->xfer_in)) {
39157bed822SMarkus Pfeiffer 					libusb20_tr_setup_bulk(p->xfer_in, in_buffer, io_max, 0);
39257bed822SMarkus Pfeiffer 					libusb20_tr_start(p->xfer_in);
39357bed822SMarkus Pfeiffer 					in_pending = 1;
39457bed822SMarkus Pfeiffer 				}
39557bed822SMarkus Pfeiffer 			} else {
39657bed822SMarkus Pfeiffer 				modem_write(out_buffer, len);
39757bed822SMarkus Pfeiffer 			}
39857bed822SMarkus Pfeiffer 
39957bed822SMarkus Pfeiffer 			if (len <= io_max) {
40057bed822SMarkus Pfeiffer 				libusb20_tr_setup_bulk(p->xfer_out, out_buffer, len, 0);
40157bed822SMarkus Pfeiffer 
40257bed822SMarkus Pfeiffer 				if (dly != 0)
40357bed822SMarkus Pfeiffer 					usleep(dly);
40457bed822SMarkus Pfeiffer 
40557bed822SMarkus Pfeiffer 				libusb20_tr_start(p->xfer_out);
40657bed822SMarkus Pfeiffer 
40757bed822SMarkus Pfeiffer 				out_pending = 1;
40857bed822SMarkus Pfeiffer 			}
40957bed822SMarkus Pfeiffer 		}
41057bed822SMarkus Pfeiffer 		libusb20_dev_wait_process(p->usb_dev, 500);
41157bed822SMarkus Pfeiffer 
41257bed822SMarkus Pfeiffer 		if (libusb20_dev_check_connected(p->usb_dev) != 0) {
41357bed822SMarkus Pfeiffer 			printf("Device disconnected\n");
41457bed822SMarkus Pfeiffer 			break;
41557bed822SMarkus Pfeiffer 		}
41657bed822SMarkus Pfeiffer 	}
41757bed822SMarkus Pfeiffer 
41857bed822SMarkus Pfeiffer 	libusb20_tr_stop(p->xfer_in);
41957bed822SMarkus Pfeiffer 	libusb20_tr_stop(p->xfer_out);
42057bed822SMarkus Pfeiffer 
42157bed822SMarkus Pfeiffer 	printf("\nData stress test done!\n");
42257bed822SMarkus Pfeiffer 
42357bed822SMarkus Pfeiffer fail:
42457bed822SMarkus Pfeiffer 	if (in_buffer)
42557bed822SMarkus Pfeiffer 		free(in_buffer);
42657bed822SMarkus Pfeiffer 	if (out_buffer)
42757bed822SMarkus Pfeiffer 		free(out_buffer);
42857bed822SMarkus Pfeiffer }
42957bed822SMarkus Pfeiffer 
43057bed822SMarkus Pfeiffer static void
exec_host_modem_test(struct modem * p,uint16_t vid,uint16_t pid)43157bed822SMarkus Pfeiffer exec_host_modem_test(struct modem *p, uint16_t vid, uint16_t pid)
43257bed822SMarkus Pfeiffer {
43357bed822SMarkus Pfeiffer 	struct libusb20_device *pdev;
43457bed822SMarkus Pfeiffer 
43557bed822SMarkus Pfeiffer 	uint8_t ntest = 0;
43657bed822SMarkus Pfeiffer 	uint8_t x;
43757bed822SMarkus Pfeiffer 	uint8_t in_ep;
43857bed822SMarkus Pfeiffer 	uint8_t out_ep;
43957bed822SMarkus Pfeiffer 	uint8_t iface;
44057bed822SMarkus Pfeiffer 
44157bed822SMarkus Pfeiffer 	int error;
44257bed822SMarkus Pfeiffer 
44357bed822SMarkus Pfeiffer 	pdev = find_usb_device(vid, pid);
44457bed822SMarkus Pfeiffer 	if (pdev == NULL) {
44557bed822SMarkus Pfeiffer 		printf("USB device not found\n");
44657bed822SMarkus Pfeiffer 		return;
44757bed822SMarkus Pfeiffer 	}
44857bed822SMarkus Pfeiffer 
44957bed822SMarkus Pfeiffer 	if (p->use_vendor_specific)
45057bed822SMarkus Pfeiffer 		find_usb_endpoints(pdev, 255, 255, 255, 0, &iface, &in_ep, &out_ep, 0);
45157bed822SMarkus Pfeiffer 	else
45257bed822SMarkus Pfeiffer 		find_usb_endpoints(pdev, 2, 2, 1, 0, &iface, &in_ep, &out_ep, 1);
45357bed822SMarkus Pfeiffer 
45457bed822SMarkus Pfeiffer 	if ((in_ep == 0) || (out_ep == 0)) {
45557bed822SMarkus Pfeiffer 		printf("Could not find USB endpoints\n");
45657bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
45757bed822SMarkus Pfeiffer 		return;
45857bed822SMarkus Pfeiffer 	}
45957bed822SMarkus Pfeiffer 	printf("Attaching to: %s @ iface %d\n",
46057bed822SMarkus Pfeiffer 	    libusb20_dev_get_desc(pdev), iface);
46157bed822SMarkus Pfeiffer 
46257bed822SMarkus Pfeiffer 	if (libusb20_dev_open(pdev, 2)) {
46357bed822SMarkus Pfeiffer 		printf("Could not open USB device\n");
46457bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
46557bed822SMarkus Pfeiffer 		return;
46657bed822SMarkus Pfeiffer 	}
46757bed822SMarkus Pfeiffer 	if (libusb20_dev_detach_kernel_driver(pdev, iface)) {
46857bed822SMarkus Pfeiffer 		printf("WARNING: Could not detach kernel driver\n");
46957bed822SMarkus Pfeiffer 	}
47057bed822SMarkus Pfeiffer 	p->xfer_in = libusb20_tr_get_pointer(pdev, 0);
47157bed822SMarkus Pfeiffer 	error = libusb20_tr_open(p->xfer_in, 65536 / 4, 1, in_ep);
47257bed822SMarkus Pfeiffer 	if (error) {
47357bed822SMarkus Pfeiffer 		printf("Could not open USB endpoint %d\n", in_ep);
47457bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
47557bed822SMarkus Pfeiffer 		return;
47657bed822SMarkus Pfeiffer 	}
47757bed822SMarkus Pfeiffer 	p->xfer_out = libusb20_tr_get_pointer(pdev, 1);
47857bed822SMarkus Pfeiffer 	error = libusb20_tr_open(p->xfer_out, 65536 / 4, 1, out_ep);
47957bed822SMarkus Pfeiffer 	if (error) {
48057bed822SMarkus Pfeiffer 		printf("Could not open USB endpoint %d\n", out_ep);
48157bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
48257bed822SMarkus Pfeiffer 		return;
48357bed822SMarkus Pfeiffer 	}
48457bed822SMarkus Pfeiffer 	p->usb_dev = pdev;
48557bed822SMarkus Pfeiffer 	p->usb_iface = iface;
48657bed822SMarkus Pfeiffer 	p->errors = 0;
48757bed822SMarkus Pfeiffer 
48857bed822SMarkus Pfeiffer 	if (p->control_ep_test)
48957bed822SMarkus Pfeiffer 		ntest += 7;
49057bed822SMarkus Pfeiffer 
49157bed822SMarkus Pfeiffer 	if (p->data_stress_test)
49257bed822SMarkus Pfeiffer 		ntest += 1;
49357bed822SMarkus Pfeiffer 
49457bed822SMarkus Pfeiffer 	if (ntest == 0) {
49557bed822SMarkus Pfeiffer 		printf("No tests selected\n");
49657bed822SMarkus Pfeiffer 	} else {
49757bed822SMarkus Pfeiffer 
49857bed822SMarkus Pfeiffer 		if (p->control_ep_test) {
49957bed822SMarkus Pfeiffer 			for (x = 1; x != 8; x++) {
50057bed822SMarkus Pfeiffer 				usb_modem_control_ep_test(p,
50157bed822SMarkus Pfeiffer 				    (p->duration + ntest - 1) / ntest, x);
50257bed822SMarkus Pfeiffer 			}
50357bed822SMarkus Pfeiffer 		}
50457bed822SMarkus Pfeiffer 		if (p->data_stress_test) {
50557bed822SMarkus Pfeiffer 			usb_modem_data_stress_test(p,
50657bed822SMarkus Pfeiffer 			    (p->duration + ntest - 1) / ntest);
50757bed822SMarkus Pfeiffer 		}
50857bed822SMarkus Pfeiffer 	}
50957bed822SMarkus Pfeiffer 
51057bed822SMarkus Pfeiffer 	printf("\nDone\n");
51157bed822SMarkus Pfeiffer 
51257bed822SMarkus Pfeiffer 	libusb20_dev_free(pdev);
51357bed822SMarkus Pfeiffer }
51457bed822SMarkus Pfeiffer 
51557bed822SMarkus Pfeiffer void
show_host_modem_test(uint8_t level,uint16_t vid,uint16_t pid,uint32_t duration)51657bed822SMarkus Pfeiffer show_host_modem_test(uint8_t level, uint16_t vid, uint16_t pid, uint32_t duration)
51757bed822SMarkus Pfeiffer {
51857bed822SMarkus Pfeiffer 	uint8_t retval;
51957bed822SMarkus Pfeiffer 
52057bed822SMarkus Pfeiffer 	set_defaults(&modem);
52157bed822SMarkus Pfeiffer 
52257bed822SMarkus Pfeiffer 	modem.duration = duration;
52357bed822SMarkus Pfeiffer 
52457bed822SMarkus Pfeiffer 	while (1) {
52557bed822SMarkus Pfeiffer 
52657bed822SMarkus Pfeiffer 		retval = usb_ts_show_menu(level, "Modem Test Parameters",
52757bed822SMarkus Pfeiffer 		    " 1) Execute Data Stress Test: <%s>\n"
52857bed822SMarkus Pfeiffer 		    " 2) Execute Modem Control Endpoint Test: <%s>\n"
52957bed822SMarkus Pfeiffer 		    " 3) Use random transmit length: <%s>\n"
53057bed822SMarkus Pfeiffer 		    " 4) Use random transmit delay: <%s> ms\n"
53157bed822SMarkus Pfeiffer 		    " 5) Use vendor specific interface: <%s>\n"
53257bed822SMarkus Pfeiffer 		    "10) Loop data: <%s>\n"
53357bed822SMarkus Pfeiffer 		    "13) Set test duration: <%d> seconds\n"
53457bed822SMarkus Pfeiffer 		    "20) Reset parameters\n"
53557bed822SMarkus Pfeiffer 		    "30) Start test (VID=0x%04x, PID=0x%04x)\n"
53657bed822SMarkus Pfeiffer 		    "40) Select another device\n"
53757bed822SMarkus Pfeiffer 		    " x) Return to previous menu \n",
53857bed822SMarkus Pfeiffer 		    (modem.data_stress_test ? "YES" : "NO"),
53957bed822SMarkus Pfeiffer 		    (modem.control_ep_test ? "YES" : "NO"),
54057bed822SMarkus Pfeiffer 		    (modem.random_tx_length ? "YES" : "NO"),
54157bed822SMarkus Pfeiffer 		    (modem.random_tx_delay ? "16" : "0"),
54257bed822SMarkus Pfeiffer 		    (modem.use_vendor_specific ? "YES" : "NO"),
54357bed822SMarkus Pfeiffer 		    (modem.loop_data ? "YES" : "NO"),
54457bed822SMarkus Pfeiffer 		    (int)(modem.duration),
54557bed822SMarkus Pfeiffer 		    (int)vid, (int)pid);
54657bed822SMarkus Pfeiffer 
54757bed822SMarkus Pfeiffer 		switch (retval) {
54857bed822SMarkus Pfeiffer 		case 0:
54957bed822SMarkus Pfeiffer 			break;
55057bed822SMarkus Pfeiffer 		case 1:
55157bed822SMarkus Pfeiffer 			modem.data_stress_test ^= 1;
55257bed822SMarkus Pfeiffer 			break;
55357bed822SMarkus Pfeiffer 		case 2:
55457bed822SMarkus Pfeiffer 			modem.control_ep_test ^= 1;
55557bed822SMarkus Pfeiffer 			break;
55657bed822SMarkus Pfeiffer 		case 3:
55757bed822SMarkus Pfeiffer 			modem.random_tx_length ^= 1;
55857bed822SMarkus Pfeiffer 			break;
55957bed822SMarkus Pfeiffer 		case 4:
56057bed822SMarkus Pfeiffer 			modem.random_tx_delay ^= 1;
56157bed822SMarkus Pfeiffer 			break;
56257bed822SMarkus Pfeiffer 		case 5:
56357bed822SMarkus Pfeiffer 			modem.use_vendor_specific ^= 1;
56457bed822SMarkus Pfeiffer 			modem.control_ep_test = 0;
56557bed822SMarkus Pfeiffer 			break;
56657bed822SMarkus Pfeiffer 		case 10:
56757bed822SMarkus Pfeiffer 			modem.loop_data ^= 1;
56857bed822SMarkus Pfeiffer 			break;
56957bed822SMarkus Pfeiffer 		case 13:
57057bed822SMarkus Pfeiffer 			modem.duration = get_integer();
57157bed822SMarkus Pfeiffer 			break;
57257bed822SMarkus Pfeiffer 		case 20:
57357bed822SMarkus Pfeiffer 			set_defaults(&modem);
57457bed822SMarkus Pfeiffer 			break;
57557bed822SMarkus Pfeiffer 		case 30:
57657bed822SMarkus Pfeiffer 			exec_host_modem_test(&modem, vid, pid);
57757bed822SMarkus Pfeiffer 			break;
57857bed822SMarkus Pfeiffer 		case 40:
57957bed822SMarkus Pfeiffer 			show_host_device_selection(level + 1, &vid, &pid);
58057bed822SMarkus Pfeiffer 			break;
58157bed822SMarkus Pfeiffer 		default:
58257bed822SMarkus Pfeiffer 			return;
58357bed822SMarkus Pfeiffer 		}
58457bed822SMarkus Pfeiffer 	}
58557bed822SMarkus Pfeiffer }
586