1184610Salfred/* $FreeBSD$ */
2184610Salfred/*-
3184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4184610Salfred *
5184610Salfred * Redistribution and use in source and binary forms, with or without
6184610Salfred * modification, are permitted provided that the following conditions
7184610Salfred * are met:
8184610Salfred * 1. Redistributions of source code must retain the above copyright
9184610Salfred *    notice, this list of conditions and the following disclaimer.
10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer in the
12184610Salfred *    documentation and/or other materials provided with the distribution.
13184610Salfred *
14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24184610Salfred * SUCH DAMAGE.
25184610Salfred */
26184610Salfred
27184610Salfred#include <stdio.h>
28184610Salfred#include <stdlib.h>
29184610Salfred#include <stdint.h>
30184610Salfred#include <err.h>
31184610Salfred#include <string.h>
32184610Salfred#include <pwd.h>
33184610Salfred#include <grp.h>
34184610Salfred#include <ctype.h>
35184610Salfred
36184610Salfred#include <libusb20.h>
37184610Salfred#include <libusb20_desc.h>
38184610Salfred
39184610Salfred#include "dump.h"
40184610Salfred
41184610Salfred#define	DUMP0(n,type,field,...) dump_field(pdev, "  ", #field, n->field);
42184610Salfred#define	DUMP1(n,type,field,...) dump_field(pdev, "    ", #field, n->field);
43184610Salfred#define	DUMP2(n,type,field,...) dump_field(pdev, "      ", #field, n->field);
44184610Salfred#define	DUMP3(n,type,field,...) dump_field(pdev, "        ", #field, n->field);
45184610Salfred
46184610Salfredconst char *
47184610Salfreddump_mode(uint8_t value)
48184610Salfred{
49184610Salfred	if (value == LIBUSB20_MODE_HOST)
50184610Salfred		return ("HOST");
51184610Salfred	return ("DEVICE");
52184610Salfred}
53184610Salfred
54184610Salfredconst char *
55184610Salfreddump_speed(uint8_t value)
56184610Salfred{
57184610Salfred	;				/* style fix */
58184610Salfred	switch (value) {
59184610Salfred	case LIBUSB20_SPEED_LOW:
60184610Salfred		return ("LOW (1.5Mbps)");
61184610Salfred	case LIBUSB20_SPEED_FULL:
62184610Salfred		return ("FULL (12Mbps)");
63184610Salfred	case LIBUSB20_SPEED_HIGH:
64184610Salfred		return ("HIGH (480Mbps)");
65184610Salfred	case LIBUSB20_SPEED_VARIABLE:
66184610Salfred		return ("VARIABLE (52-480Mbps)");
67184610Salfred	case LIBUSB20_SPEED_SUPER:
68219048Shselasky		return ("SUPER (5.0Gbps)");
69184610Salfred	default:
70184610Salfred		break;
71184610Salfred	}
72219048Shselasky	return ("UNKNOWN ()");
73184610Salfred}
74184610Salfred
75184610Salfredconst char *
76184610Salfreddump_power_mode(uint8_t value)
77184610Salfred{
78184610Salfred	;				/* style fix */
79184610Salfred	switch (value) {
80184610Salfred	case LIBUSB20_POWER_OFF:
81184610Salfred		return ("OFF");
82184610Salfred	case LIBUSB20_POWER_ON:
83184610Salfred		return ("ON");
84184610Salfred	case LIBUSB20_POWER_SAVE:
85184610Salfred		return ("SAVE");
86184610Salfred	case LIBUSB20_POWER_SUSPEND:
87184610Salfred		return ("SUSPEND");
88184610Salfred	case LIBUSB20_POWER_RESUME:
89184610Salfred		return ("RESUME");
90184610Salfred	default:
91184610Salfred		return ("UNKNOWN");
92184610Salfred	}
93184610Salfred}
94184610Salfred
95184610Salfredstatic void
96184610Salfreddump_field(struct libusb20_device *pdev, const char *plevel,
97184610Salfred    const char *field, uint32_t value)
98184610Salfred{
99184610Salfred	uint8_t temp_string[256];
100184610Salfred
101184610Salfred	printf("%s%s = 0x%04x ", plevel, field, value);
102184610Salfred
103198833Sthompsa	if (strlen(plevel) == 8) {
104198833Sthompsa		/* Endpoint Descriptor */
105198833Sthompsa
106198833Sthompsa		if (strcmp(field, "bEndpointAddress") == 0) {
107198833Sthompsa			if (value & 0x80)
108198833Sthompsa				printf(" <IN>\n");
109198833Sthompsa			else
110198833Sthompsa				printf(" <OUT>\n");
111198833Sthompsa			return;
112198833Sthompsa		}
113198833Sthompsa
114198833Sthompsa		if (strcmp(field, "bmAttributes") == 0) {
115198833Sthompsa			switch (value & 0x03) {
116198833Sthompsa			case 0:
117198833Sthompsa				printf(" <CONTROL>\n");
118198833Sthompsa				break;
119198833Sthompsa			case 1:
120198833Sthompsa				switch (value & 0x0C) {
121198833Sthompsa				case 0x00:
122198833Sthompsa					printf(" <ISOCHRONOUS>\n");
123198833Sthompsa					break;
124198833Sthompsa				case 0x04:
125198833Sthompsa					printf(" <ASYNC-ISOCHRONOUS>\n");
126198833Sthompsa					break;
127198833Sthompsa				case 0x08:
128198833Sthompsa					printf(" <ADAPT-ISOCHRONOUS>\n");
129198833Sthompsa					break;
130198833Sthompsa				default:
131198833Sthompsa					printf(" <SYNC-ISOCHRONOUS>\n");
132198833Sthompsa					break;
133198833Sthompsa				}
134198833Sthompsa				break;
135198833Sthompsa			case 2:
136198833Sthompsa				printf(" <BULK>\n");
137198833Sthompsa				break;
138198833Sthompsa			default:
139198833Sthompsa				printf(" <INTERRUPT>\n");
140198833Sthompsa				break;
141198833Sthompsa			}
142198833Sthompsa			return;
143198833Sthompsa		}
144184610Salfred	}
145198833Sthompsa
146198833Sthompsa	if ((field[0] == 'i') && (field[1] != 'd')) {
147198833Sthompsa		/* Indirect String Descriptor */
148198833Sthompsa		if (value == 0) {
149198833Sthompsa			printf(" <no string>\n");
150198833Sthompsa			return;
151198833Sthompsa		}
152198833Sthompsa		if (libusb20_dev_req_string_simple_sync(pdev, value,
153198833Sthompsa		    temp_string, sizeof(temp_string))) {
154198833Sthompsa			printf(" <retrieving string failed>\n");
155198833Sthompsa			return;
156198833Sthompsa		}
157198833Sthompsa		printf(" <%s>\n", temp_string);
158184610Salfred		return;
159184610Salfred	}
160198833Sthompsa
161198833Sthompsa	/* No additional information */
162198833Sthompsa	printf("\n");
163184610Salfred}
164184610Salfred
165184610Salfredstatic void
166184610Salfreddump_extra(struct libusb20_me_struct *str, const char *plevel)
167184610Salfred{
168184610Salfred	const uint8_t *ptr;
169184610Salfred	uint8_t x;
170184610Salfred
171184610Salfred	ptr = NULL;
172184610Salfred
173184610Salfred	while ((ptr = libusb20_desc_foreach(str, ptr))) {
174184610Salfred		printf("\n" "%sAdditional Descriptor\n\n", plevel);
175184610Salfred		printf("%sbLength = 0x%02x\n", plevel, ptr[0]);
176184610Salfred		printf("%sbDescriptorType = 0x%02x\n", plevel, ptr[1]);
177184610Salfred		if (ptr[0] > 1)
178184610Salfred			printf("%sbDescriptorSubType = 0x%02x\n",
179184610Salfred			    plevel, ptr[2]);
180184610Salfred		printf("%s RAW dump: ", plevel);
181184610Salfred		for (x = 0; x != ptr[0]; x++) {
182184610Salfred			if ((x % 8) == 0) {
183184610Salfred				printf("\n%s 0x%02x | ", plevel, x);
184184610Salfred			}
185184610Salfred			printf("0x%02x%s", ptr[x],
186184610Salfred			    (x != (ptr[0] - 1)) ? ", " : (x % 8) ? "\n" : "");
187184610Salfred		}
188184610Salfred		printf("\n");
189184610Salfred	}
190184610Salfred	return;
191184610Salfred}
192184610Salfred
193184610Salfredstatic void
194184610Salfreddump_endpoint(struct libusb20_device *pdev,
195184610Salfred    struct libusb20_endpoint *ep)
196184610Salfred{
197184610Salfred	struct LIBUSB20_ENDPOINT_DESC_DECODED *edesc;
198184610Salfred
199184610Salfred	edesc = &ep->desc;
200184610Salfred	LIBUSB20_ENDPOINT_DESC(DUMP3, edesc);
201184610Salfred	dump_extra(&ep->extra, "  " "  " "  ");
202184610Salfred	return;
203184610Salfred}
204184610Salfred
205184610Salfredstatic void
206184610Salfreddump_iface(struct libusb20_device *pdev,
207184610Salfred    struct libusb20_interface *iface)
208184610Salfred{
209184610Salfred	struct LIBUSB20_INTERFACE_DESC_DECODED *idesc;
210184610Salfred	uint8_t z;
211184610Salfred
212184610Salfred	idesc = &iface->desc;
213184610Salfred	LIBUSB20_INTERFACE_DESC(DUMP2, idesc);
214184610Salfred	dump_extra(&iface->extra, "  " "  " "  ");
215184610Salfred
216184610Salfred	for (z = 0; z != iface->num_endpoints; z++) {
217184610Salfred		printf("\n     Endpoint %u\n", z);
218184610Salfred		dump_endpoint(pdev, iface->endpoints + z);
219184610Salfred	}
220184610Salfred	return;
221184610Salfred}
222184610Salfred
223184610Salfredvoid
224188622Sthompsadump_device_info(struct libusb20_device *pdev, uint8_t show_ifdrv)
225184610Salfred{
226188622Sthompsa	char buf[128];
227188622Sthompsa	uint8_t n;
228247475Shselasky	unsigned int usage;
229188622Sthompsa
230247475Shselasky	usage = libusb20_dev_get_power_usage(pdev);
231247475Shselasky
232247475Shselasky	printf("%s, cfg=%u md=%s spd=%s pwr=%s (%umA)\n",
233184610Salfred	    libusb20_dev_get_desc(pdev),
234184610Salfred	    libusb20_dev_get_config_index(pdev),
235184610Salfred	    dump_mode(libusb20_dev_get_mode(pdev)),
236184610Salfred	    dump_speed(libusb20_dev_get_speed(pdev)),
237247475Shselasky	    dump_power_mode(libusb20_dev_get_power_mode(pdev)),
238247475Shselasky	    usage);
239188622Sthompsa
240188622Sthompsa	if (!show_ifdrv)
241188622Sthompsa		return;
242188622Sthompsa
243188622Sthompsa	for (n = 0; n != 255; n++) {
244188622Sthompsa		if (libusb20_dev_get_iface_desc(pdev, n, buf, sizeof(buf)))
245188622Sthompsa			break;
246188622Sthompsa		if (buf[0] == 0)
247188622Sthompsa			continue;
248188622Sthompsa		printf("ugen%u.%u.%u: %s\n",
249188622Sthompsa		    libusb20_dev_get_bus_number(pdev),
250188622Sthompsa		    libusb20_dev_get_address(pdev), n, buf);
251188622Sthompsa	}
252184610Salfred}
253184610Salfred
254184610Salfredvoid
255184610Salfreddump_be_quirk_names(struct libusb20_backend *pbe)
256184610Salfred{
257184610Salfred	struct libusb20_quirk q;
258184610Salfred	uint16_t x;
259185087Salfred	int error;
260184610Salfred
261184610Salfred	memset(&q, 0, sizeof(q));
262184610Salfred
263184610Salfred	printf("\nDumping list of supported quirks:\n\n");
264184610Salfred
265184610Salfred	for (x = 0; x != 0xFFFF; x++) {
266184610Salfred
267185087Salfred		error = libusb20_be_get_quirk_name(pbe, x, &q);
268185087Salfred		if (error) {
269184610Salfred			if (x == 0) {
270184610Salfred				printf("No quirk names - maybe the USB quirk "
271184610Salfred				    "module has not been loaded.\n");
272184610Salfred			}
273184610Salfred			break;
274184610Salfred		}
275184610Salfred		if (strcmp(q.quirkname, "UQ_NONE"))
276184610Salfred			printf("%s\n", q.quirkname);
277184610Salfred	}
278184610Salfred	printf("\n");
279184610Salfred	return;
280184610Salfred}
281184610Salfred
282184610Salfredvoid
283184610Salfreddump_be_dev_quirks(struct libusb20_backend *pbe)
284184610Salfred{
285184610Salfred	struct libusb20_quirk q;
286184610Salfred	uint16_t x;
287185087Salfred	int error;
288184610Salfred
289184610Salfred	memset(&q, 0, sizeof(q));
290184610Salfred
291184610Salfred	printf("\nDumping current device quirks:\n\n");
292184610Salfred
293184610Salfred	for (x = 0; x != 0xFFFF; x++) {
294184610Salfred
295185087Salfred		error = libusb20_be_get_dev_quirk(pbe, x, &q);
296185087Salfred		if (error) {
297184610Salfred			if (x == 0) {
298184610Salfred				printf("No device quirks - maybe the USB quirk "
299184610Salfred				    "module has not been loaded.\n");
300184610Salfred			}
301184610Salfred			break;
302184610Salfred		}
303184610Salfred		if (strcmp(q.quirkname, "UQ_NONE")) {
304184610Salfred			printf("VID=0x%04x PID=0x%04x REVLO=0x%04x "
305184610Salfred			    "REVHI=0x%04x QUIRK=%s\n",
306184610Salfred			    q.vid, q.pid, q.bcdDeviceLow,
307184610Salfred			    q.bcdDeviceHigh, q.quirkname);
308184610Salfred		}
309184610Salfred	}
310184610Salfred	printf("\n");
311184610Salfred	return;
312184610Salfred}
313184610Salfred
314184610Salfredvoid
315184610Salfreddump_device_desc(struct libusb20_device *pdev)
316184610Salfred{
317184610Salfred	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
318184610Salfred
319184610Salfred	ddesc = libusb20_dev_get_device_desc(pdev);
320184610Salfred	LIBUSB20_DEVICE_DESC(DUMP0, ddesc);
321184610Salfred	return;
322184610Salfred}
323184610Salfred
324184610Salfredvoid
325184610Salfreddump_config(struct libusb20_device *pdev, uint8_t all_cfg)
326184610Salfred{
327184610Salfred	struct LIBUSB20_CONFIG_DESC_DECODED *cdesc;
328184610Salfred	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
329184610Salfred	struct libusb20_config *pcfg = NULL;
330184610Salfred	uint8_t cfg_index;
331184610Salfred	uint8_t cfg_index_end;
332184610Salfred	uint8_t x;
333184610Salfred	uint8_t y;
334184610Salfred
335184610Salfred	ddesc = libusb20_dev_get_device_desc(pdev);
336184610Salfred
337184610Salfred	if (all_cfg) {
338184610Salfred		cfg_index = 0;
339184610Salfred		cfg_index_end = ddesc->bNumConfigurations;
340184610Salfred	} else {
341184610Salfred		cfg_index = libusb20_dev_get_config_index(pdev);
342184610Salfred		cfg_index_end = cfg_index + 1;
343184610Salfred	}
344184610Salfred
345184610Salfred	for (; cfg_index != cfg_index_end; cfg_index++) {
346184610Salfred
347184610Salfred		pcfg = libusb20_dev_alloc_config(pdev, cfg_index);
348184610Salfred		if (!pcfg) {
349184610Salfred			continue;
350184610Salfred		}
351184610Salfred		printf("\n Configuration index %u\n\n", cfg_index);
352184610Salfred		cdesc = &(pcfg->desc);
353184610Salfred		LIBUSB20_CONFIG_DESC(DUMP1, cdesc);
354184610Salfred		dump_extra(&(pcfg->extra), "  " "  ");
355184610Salfred
356184610Salfred		for (x = 0; x != pcfg->num_interface; x++) {
357184610Salfred			printf("\n    Interface %u\n", x);
358184610Salfred			dump_iface(pdev, pcfg->interface + x);
359184610Salfred			printf("\n");
360184610Salfred			for (y = 0; y != (pcfg->interface + x)->num_altsetting; y++) {
361184610Salfred				printf("\n    Interface %u Alt %u\n", x, y + 1);
362184610Salfred				dump_iface(pdev,
363184610Salfred				    (pcfg->interface + x)->altsetting + y);
364184610Salfred				printf("\n");
365184610Salfred			}
366184610Salfred		}
367184610Salfred		printf("\n");
368184610Salfred		free(pcfg);
369184610Salfred	}
370184610Salfred	return;
371184610Salfred}
372201705Sthompsa
373201705Sthompsavoid
374201705Sthompsadump_string_by_index(struct libusb20_device *pdev, uint8_t str_index)
375201705Sthompsa{
376201705Sthompsa	char *pbuf;
377201705Sthompsa	uint8_t n;
378201705Sthompsa	uint8_t len;
379201705Sthompsa
380201705Sthompsa	pbuf = malloc(256);
381201705Sthompsa	if (pbuf == NULL)
382201705Sthompsa		err(1, "out of memory");
383201705Sthompsa
384201705Sthompsa	if (str_index == 0) {
385201705Sthompsa		/* language table */
386201705Sthompsa		if (libusb20_dev_req_string_sync(pdev,
387201705Sthompsa		    str_index, 0, pbuf, 256)) {
388201705Sthompsa			printf("STRING_0x%02x = <read error>\n", str_index);
389201705Sthompsa		} else {
390201705Sthompsa			printf("STRING_0x%02x = ", str_index);
391201705Sthompsa			len = (uint8_t)pbuf[0];
392201705Sthompsa			for (n = 0; n != len; n++) {
393201705Sthompsa				printf("0x%02x%s", (uint8_t)pbuf[n],
394201705Sthompsa				    (n != (len-1)) ? ", " : "");
395201705Sthompsa			}
396201705Sthompsa			printf("\n");
397201705Sthompsa		}
398201705Sthompsa	} else {
399201705Sthompsa		/* ordinary string */
400201705Sthompsa		if (libusb20_dev_req_string_simple_sync(pdev,
401201705Sthompsa		    str_index, pbuf, 256)) {
402201705Sthompsa			printf("STRING_0x%02x = <read error>\n", str_index);
403201705Sthompsa		} else {
404201705Sthompsa			printf("STRING_0x%02x = <%s>\n", str_index, pbuf);
405201705Sthompsa		}
406201705Sthompsa	}
407201705Sthompsa	free(pbuf);
408201705Sthompsa}
409