dump.c revision 198833
1254885Sdumbbell/* $FreeBSD: head/usr.sbin/usbconfig/dump.c 198833 2009-11-02 23:50:12Z thompsa $ */
2254885Sdumbbell/*-
3254885Sdumbbell * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4254885Sdumbbell *
5254885Sdumbbell * Redistribution and use in source and binary forms, with or without
6254885Sdumbbell * modification, are permitted provided that the following conditions
7254885Sdumbbell * are met:
8254885Sdumbbell * 1. Redistributions of source code must retain the above copyright
9254885Sdumbbell *    notice, this list of conditions and the following disclaimer.
10254885Sdumbbell * 2. Redistributions in binary form must reproduce the above copyright
11254885Sdumbbell *    notice, this list of conditions and the following disclaimer in the
12254885Sdumbbell *    documentation and/or other materials provided with the distribution.
13254885Sdumbbell *
14254885Sdumbbell * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15254885Sdumbbell * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16254885Sdumbbell * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17254885Sdumbbell * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18254885Sdumbbell * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19254885Sdumbbell * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20254885Sdumbbell * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21254885Sdumbbell * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22254885Sdumbbell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23254885Sdumbbell * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24254885Sdumbbell * SUCH DAMAGE.
25254885Sdumbbell */
26254885Sdumbbell
27254885Sdumbbell#include <stdio.h>
28254885Sdumbbell#include <stdlib.h>
29254885Sdumbbell#include <stdint.h>
30254885Sdumbbell#include <err.h>
31254885Sdumbbell#include <string.h>
32254885Sdumbbell#include <pwd.h>
33254885Sdumbbell#include <grp.h>
34266594Sdumbbell#include <ctype.h>
35254885Sdumbbell
36266594Sdumbbell#include <libusb20.h>
37266594Sdumbbell#include <libusb20_desc.h>
38266594Sdumbbell
39266594Sdumbbell#include "dump.h"
40266594Sdumbbell
41254885Sdumbbell#define	DUMP0(n,type,field,...) dump_field(pdev, "  ", #field, n->field);
42254885Sdumbbell#define	DUMP1(n,type,field,...) dump_field(pdev, "    ", #field, n->field);
43254885Sdumbbell#define	DUMP2(n,type,field,...) dump_field(pdev, "      ", #field, n->field);
44254885Sdumbbell#define	DUMP3(n,type,field,...) dump_field(pdev, "        ", #field, n->field);
45254885Sdumbbell
46254885Sdumbbellconst char *
47254885Sdumbbelldump_mode(uint8_t value)
48254885Sdumbbell{
49254885Sdumbbell	if (value == LIBUSB20_MODE_HOST)
50254885Sdumbbell		return ("HOST");
51254885Sdumbbell	return ("DEVICE");
52254885Sdumbbell}
53254885Sdumbbell
54254885Sdumbbellconst char *
55254885Sdumbbelldump_speed(uint8_t value)
56254885Sdumbbell{
57254885Sdumbbell	;				/* style fix */
58254885Sdumbbell	switch (value) {
59254885Sdumbbell	case LIBUSB20_SPEED_LOW:
60254885Sdumbbell		return ("LOW (1.5Mbps)");
61254885Sdumbbell	case LIBUSB20_SPEED_FULL:
62254885Sdumbbell		return ("FULL (12Mbps)");
63254885Sdumbbell	case LIBUSB20_SPEED_HIGH:
64254885Sdumbbell		return ("HIGH (480Mbps)");
65254885Sdumbbell	case LIBUSB20_SPEED_VARIABLE:
66266594Sdumbbell		return ("VARIABLE (52-480Mbps)");
67266594Sdumbbell	case LIBUSB20_SPEED_SUPER:
68254885Sdumbbell		return ("SUPER (4.8Gbps)");
69266594Sdumbbell	default:
70266594Sdumbbell		break;
71254885Sdumbbell	}
72266594Sdumbbell	return ("unknown");
73254885Sdumbbell}
74266594Sdumbbell
75266594Sdumbbellconst char *
76266594Sdumbbelldump_power_mode(uint8_t value)
77266594Sdumbbell{
78266594Sdumbbell	;				/* style fix */
79266594Sdumbbell	switch (value) {
80266594Sdumbbell	case LIBUSB20_POWER_OFF:
81266594Sdumbbell		return ("OFF");
82266594Sdumbbell	case LIBUSB20_POWER_ON:
83266594Sdumbbell		return ("ON");
84266594Sdumbbell	case LIBUSB20_POWER_SAVE:
85266594Sdumbbell		return ("SAVE");
86266594Sdumbbell	case LIBUSB20_POWER_SUSPEND:
87266594Sdumbbell		return ("SUSPEND");
88266594Sdumbbell	case LIBUSB20_POWER_RESUME:
89266594Sdumbbell		return ("RESUME");
90266594Sdumbbell	default:
91266594Sdumbbell		return ("UNKNOWN");
92266594Sdumbbell	}
93266594Sdumbbell}
94266594Sdumbbell
95254885Sdumbbellstatic void
96266594Sdumbbelldump_field(struct libusb20_device *pdev, const char *plevel,
97254885Sdumbbell    const char *field, uint32_t value)
98254885Sdumbbell{
99254885Sdumbbell	uint8_t temp_string[256];
100254885Sdumbbell
101254885Sdumbbell	printf("%s%s = 0x%04x ", plevel, field, value);
102254885Sdumbbell
103254885Sdumbbell	if (strlen(plevel) == 8) {
104254885Sdumbbell		/* Endpoint Descriptor */
105254885Sdumbbell
106254885Sdumbbell		if (strcmp(field, "bEndpointAddress") == 0) {
107254885Sdumbbell			if (value & 0x80)
108266594Sdumbbell				printf(" <IN>\n");
109266594Sdumbbell			else
110254885Sdumbbell				printf(" <OUT>\n");
111266594Sdumbbell			return;
112266594Sdumbbell		}
113254885Sdumbbell
114266594Sdumbbell		if (strcmp(field, "bmAttributes") == 0) {
115254885Sdumbbell			switch (value & 0x03) {
116266594Sdumbbell			case 0:
117266594Sdumbbell				printf(" <CONTROL>\n");
118266594Sdumbbell				break;
119266594Sdumbbell			case 1:
120266594Sdumbbell				switch (value & 0x0C) {
121266594Sdumbbell				case 0x00:
122254885Sdumbbell					printf(" <ISOCHRONOUS>\n");
123266594Sdumbbell					break;
124254885Sdumbbell				case 0x04:
125254885Sdumbbell					printf(" <ASYNC-ISOCHRONOUS>\n");
126254885Sdumbbell					break;
127254885Sdumbbell				case 0x08:
128254885Sdumbbell					printf(" <ADAPT-ISOCHRONOUS>\n");
129254885Sdumbbell					break;
130266594Sdumbbell				default:
131266594Sdumbbell					printf(" <SYNC-ISOCHRONOUS>\n");
132254885Sdumbbell					break;
133254885Sdumbbell				}
134266594Sdumbbell				break;
135254885Sdumbbell			case 2:
136266594Sdumbbell				printf(" <BULK>\n");
137254885Sdumbbell				break;
138266594Sdumbbell			default:
139254885Sdumbbell				printf(" <INTERRUPT>\n");
140254885Sdumbbell				break;
141254885Sdumbbell			}
142254885Sdumbbell			return;
143254885Sdumbbell		}
144254885Sdumbbell	}
145254885Sdumbbell
146254885Sdumbbell	if ((field[0] == 'i') && (field[1] != 'd')) {
147254885Sdumbbell		/* Indirect String Descriptor */
148254885Sdumbbell		if (value == 0) {
149254885Sdumbbell			printf(" <no string>\n");
150254885Sdumbbell			return;
151254885Sdumbbell		}
152254885Sdumbbell		if (libusb20_dev_req_string_simple_sync(pdev, value,
153254885Sdumbbell		    temp_string, sizeof(temp_string))) {
154254885Sdumbbell			printf(" <retrieving string failed>\n");
155254885Sdumbbell			return;
156266594Sdumbbell		}
157266594Sdumbbell		printf(" <%s>\n", temp_string);
158254885Sdumbbell		return;
159266594Sdumbbell	}
160266594Sdumbbell
161266594Sdumbbell	/* No additional information */
162266594Sdumbbell	printf("\n");
163254885Sdumbbell}
164266594Sdumbbell
165266594Sdumbbellstatic void
166254885Sdumbbelldump_extra(struct libusb20_me_struct *str, const char *plevel)
167266594Sdumbbell{
168254885Sdumbbell	const uint8_t *ptr;
169266594Sdumbbell	uint8_t x;
170266594Sdumbbell
171266594Sdumbbell	ptr = NULL;
172266594Sdumbbell
173266594Sdumbbell	while ((ptr = libusb20_desc_foreach(str, ptr))) {
174266594Sdumbbell		printf("\n" "%sAdditional Descriptor\n\n", plevel);
175266594Sdumbbell		printf("%sbLength = 0x%02x\n", plevel, ptr[0]);
176266594Sdumbbell		printf("%sbDescriptorType = 0x%02x\n", plevel, ptr[1]);
177266594Sdumbbell		if (ptr[0] > 1)
178266594Sdumbbell			printf("%sbDescriptorSubType = 0x%02x\n",
179266594Sdumbbell			    plevel, ptr[2]);
180254885Sdumbbell		printf("%s RAW dump: ", plevel);
181266594Sdumbbell		for (x = 0; x != ptr[0]; x++) {
182254885Sdumbbell			if ((x % 8) == 0) {
183254885Sdumbbell				printf("\n%s 0x%02x | ", plevel, x);
184254885Sdumbbell			}
185254885Sdumbbell			printf("0x%02x%s", ptr[x],
186254885Sdumbbell			    (x != (ptr[0] - 1)) ? ", " : (x % 8) ? "\n" : "");
187254885Sdumbbell		}
188254885Sdumbbell		printf("\n");
189254885Sdumbbell	}
190254885Sdumbbell	return;
191254885Sdumbbell}
192254885Sdumbbell
193266594Sdumbbellstatic void
194266594Sdumbbelldump_endpoint(struct libusb20_device *pdev,
195254885Sdumbbell    struct libusb20_endpoint *ep)
196266594Sdumbbell{
197266594Sdumbbell	struct LIBUSB20_ENDPOINT_DESC_DECODED *edesc;
198254885Sdumbbell
199266594Sdumbbell	edesc = &ep->desc;
200254885Sdumbbell	LIBUSB20_ENDPOINT_DESC(DUMP3, edesc);
201266594Sdumbbell	dump_extra(&ep->extra, "  " "  " "  ");
202266594Sdumbbell	return;
203266594Sdumbbell}
204266594Sdumbbell
205266594Sdumbbellstatic void
206266594Sdumbbelldump_iface(struct libusb20_device *pdev,
207254885Sdumbbell    struct libusb20_interface *iface)
208266594Sdumbbell{
209254885Sdumbbell	struct LIBUSB20_INTERFACE_DESC_DECODED *idesc;
210254885Sdumbbell	uint8_t z;
211254885Sdumbbell
212254885Sdumbbell	idesc = &iface->desc;
213254885Sdumbbell	LIBUSB20_INTERFACE_DESC(DUMP2, idesc);
214254885Sdumbbell	dump_extra(&iface->extra, "  " "  " "  ");
215254885Sdumbbell
216254885Sdumbbell	for (z = 0; z != iface->num_endpoints; z++) {
217254885Sdumbbell		printf("\n     Endpoint %u\n", z);
218266594Sdumbbell		dump_endpoint(pdev, iface->endpoints + z);
219266594Sdumbbell	}
220254885Sdumbbell	return;
221266594Sdumbbell}
222266594Sdumbbell
223254885Sdumbbellvoid
224266594Sdumbbelldump_device_info(struct libusb20_device *pdev, uint8_t show_ifdrv)
225254885Sdumbbell{
226266594Sdumbbell	char buf[128];
227266594Sdumbbell	uint8_t n;
228266594Sdumbbell
229266594Sdumbbell	printf("%s, cfg=%u md=%s spd=%s pwr=%s\n",
230254885Sdumbbell	    libusb20_dev_get_desc(pdev),
231266594Sdumbbell	    libusb20_dev_get_config_index(pdev),
232254885Sdumbbell	    dump_mode(libusb20_dev_get_mode(pdev)),
233254885Sdumbbell	    dump_speed(libusb20_dev_get_speed(pdev)),
234254885Sdumbbell	    dump_power_mode(libusb20_dev_get_power_mode(pdev)));
235254885Sdumbbell
236254885Sdumbbell	if (!show_ifdrv)
237254885Sdumbbell		return;
238254885Sdumbbell
239266594Sdumbbell	for (n = 0; n != 255; n++) {
240266594Sdumbbell		if (libusb20_dev_get_iface_desc(pdev, n, buf, sizeof(buf)))
241254885Sdumbbell			break;
242266594Sdumbbell		if (buf[0] == 0)
243266594Sdumbbell			continue;
244254885Sdumbbell		printf("ugen%u.%u.%u: %s\n",
245266594Sdumbbell		    libusb20_dev_get_bus_number(pdev),
246254885Sdumbbell		    libusb20_dev_get_address(pdev), n, buf);
247266594Sdumbbell	}
248266594Sdumbbell}
249254885Sdumbbell
250266594Sdumbbellvoid
251254885Sdumbbelldump_be_quirk_names(struct libusb20_backend *pbe)
252254885Sdumbbell{
253254885Sdumbbell	struct libusb20_quirk q;
254254885Sdumbbell	uint16_t x;
255254885Sdumbbell	int error;
256254885Sdumbbell
257254885Sdumbbell	memset(&q, 0, sizeof(q));
258254885Sdumbbell
259254885Sdumbbell	printf("\nDumping list of supported quirks:\n\n");
260266594Sdumbbell
261266594Sdumbbell	for (x = 0; x != 0xFFFF; x++) {
262254885Sdumbbell
263266594Sdumbbell		error = libusb20_be_get_quirk_name(pbe, x, &q);
264266594Sdumbbell		if (error) {
265254885Sdumbbell			if (x == 0) {
266266594Sdumbbell				printf("No quirk names - maybe the USB quirk "
267254885Sdumbbell				    "module has not been loaded.\n");
268266594Sdumbbell			}
269266594Sdumbbell			break;
270266594Sdumbbell		}
271266594Sdumbbell		if (strcmp(q.quirkname, "UQ_NONE"))
272254885Sdumbbell			printf("%s\n", q.quirkname);
273266594Sdumbbell	}
274254885Sdumbbell	printf("\n");
275254885Sdumbbell	return;
276254885Sdumbbell}
277254885Sdumbbell
278254885Sdumbbellvoid
279254885Sdumbbelldump_be_dev_quirks(struct libusb20_backend *pbe)
280266594Sdumbbell{
281266594Sdumbbell	struct libusb20_quirk q;
282254885Sdumbbell	uint16_t x;
283266594Sdumbbell	int error;
284266594Sdumbbell
285254885Sdumbbell	memset(&q, 0, sizeof(q));
286266594Sdumbbell
287254885Sdumbbell	printf("\nDumping current device quirks:\n\n");
288266594Sdumbbell
289254885Sdumbbell	for (x = 0; x != 0xFFFF; x++) {
290266594Sdumbbell
291254885Sdumbbell		error = libusb20_be_get_dev_quirk(pbe, x, &q);
292254885Sdumbbell		if (error) {
293254885Sdumbbell			if (x == 0) {
294282199Sdumbbell				printf("No device quirks - maybe the USB quirk "
295254885Sdumbbell				    "module has not been loaded.\n");
296254885Sdumbbell			}
297254885Sdumbbell			break;
298254885Sdumbbell		}
299254885Sdumbbell		if (strcmp(q.quirkname, "UQ_NONE")) {
300266594Sdumbbell			printf("VID=0x%04x PID=0x%04x REVLO=0x%04x "
301266594Sdumbbell			    "REVHI=0x%04x QUIRK=%s\n",
302254885Sdumbbell			    q.vid, q.pid, q.bcdDeviceLow,
303266594Sdumbbell			    q.bcdDeviceHigh, q.quirkname);
304266594Sdumbbell		}
305254885Sdumbbell	}
306266594Sdumbbell	printf("\n");
307254885Sdumbbell	return;
308266594Sdumbbell}
309266594Sdumbbell
310254885Sdumbbellvoid
311266594Sdumbbelldump_device_desc(struct libusb20_device *pdev)
312254885Sdumbbell{
313282199Sdumbbell	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
314282199Sdumbbell
315282199Sdumbbell	ddesc = libusb20_dev_get_device_desc(pdev);
316254885Sdumbbell	LIBUSB20_DEVICE_DESC(DUMP0, ddesc);
317266594Sdumbbell	return;
318266594Sdumbbell}
319266594Sdumbbell
320266594Sdumbbellvoid
321266594Sdumbbelldump_config(struct libusb20_device *pdev, uint8_t all_cfg)
322266594Sdumbbell{
323266594Sdumbbell	struct LIBUSB20_CONFIG_DESC_DECODED *cdesc;
324266594Sdumbbell	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
325266594Sdumbbell	struct libusb20_config *pcfg = NULL;
326266594Sdumbbell	uint8_t cfg_index;
327266594Sdumbbell	uint8_t cfg_index_end;
328254885Sdumbbell	uint8_t x;
329282199Sdumbbell	uint8_t y;
330254885Sdumbbell
331266594Sdumbbell	ddesc = libusb20_dev_get_device_desc(pdev);
332
333	if (all_cfg) {
334		cfg_index = 0;
335		cfg_index_end = ddesc->bNumConfigurations;
336	} else {
337		cfg_index = libusb20_dev_get_config_index(pdev);
338		cfg_index_end = cfg_index + 1;
339	}
340
341	for (; cfg_index != cfg_index_end; cfg_index++) {
342
343		pcfg = libusb20_dev_alloc_config(pdev, cfg_index);
344		if (!pcfg) {
345			continue;
346		}
347		printf("\n Configuration index %u\n\n", cfg_index);
348		cdesc = &(pcfg->desc);
349		LIBUSB20_CONFIG_DESC(DUMP1, cdesc);
350		dump_extra(&(pcfg->extra), "  " "  ");
351
352		for (x = 0; x != pcfg->num_interface; x++) {
353			printf("\n    Interface %u\n", x);
354			dump_iface(pdev, pcfg->interface + x);
355			printf("\n");
356			for (y = 0; y != (pcfg->interface + x)->num_altsetting; y++) {
357				printf("\n    Interface %u Alt %u\n", x, y + 1);
358				dump_iface(pdev,
359				    (pcfg->interface + x)->altsetting + y);
360				printf("\n");
361			}
362		}
363		printf("\n");
364		free(pcfg);
365	}
366	return;
367}
368