xref: /freebsd-13-stable/usr.sbin/usbconfig/dump.c (revision 8ad303d68cec3ee1133550de37e0009502621e50)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <err.h>
32 #include <string.h>
33 #include <pwd.h>
34 #include <grp.h>
35 #include <ctype.h>
36 
37 #include <libusb20.h>
38 #include <libusb20_desc.h>
39 
40 #include "dump.h"
41 
42 #define	DUMP0(n,type,field,...) dump_field(pdev, "  ", #field, n->field);
43 #define	DUMP1(n,type,field,...) dump_field(pdev, "    ", #field, n->field);
44 #define	DUMP2(n,type,field,...) dump_field(pdev, "      ", #field, n->field);
45 #define	DUMP3(n,type,field,...) dump_field(pdev, "        ", #field, n->field);
46 
47 const char *
dump_mode(uint8_t value)48 dump_mode(uint8_t value)
49 {
50 	if (value == LIBUSB20_MODE_HOST)
51 		return ("HOST");
52 	return ("DEVICE");
53 }
54 
55 const char *
dump_speed(uint8_t value)56 dump_speed(uint8_t value)
57 {
58 	;				/* style fix */
59 	switch (value) {
60 	case LIBUSB20_SPEED_LOW:
61 		return ("LOW (1.5Mbps)");
62 	case LIBUSB20_SPEED_FULL:
63 		return ("FULL (12Mbps)");
64 	case LIBUSB20_SPEED_HIGH:
65 		return ("HIGH (480Mbps)");
66 	case LIBUSB20_SPEED_VARIABLE:
67 		return ("VARIABLE (52-480Mbps)");
68 	case LIBUSB20_SPEED_SUPER:
69 		return ("SUPER (5.0Gbps)");
70 	default:
71 		break;
72 	}
73 	return ("UNKNOWN ()");
74 }
75 
76 const char *
dump_power_mode(uint8_t value)77 dump_power_mode(uint8_t value)
78 {
79 	;				/* style fix */
80 	switch (value) {
81 	case LIBUSB20_POWER_OFF:
82 		return ("OFF");
83 	case LIBUSB20_POWER_ON:
84 		return ("ON");
85 	case LIBUSB20_POWER_SAVE:
86 		return ("SAVE");
87 	case LIBUSB20_POWER_SUSPEND:
88 		return ("SUSPEND");
89 	case LIBUSB20_POWER_RESUME:
90 		return ("RESUME");
91 	default:
92 		return ("UNKNOWN");
93 	}
94 }
95 
96 static void
dump_field(struct libusb20_device * pdev,const char * plevel,const char * field,uint32_t value)97 dump_field(struct libusb20_device *pdev, const char *plevel,
98     const char *field, uint32_t value)
99 {
100 	uint8_t temp_string[256];
101 
102 	printf("%s%s = 0x%04x ", plevel, field, value);
103 
104 	if (strlen(plevel) == 8) {
105 		/* Endpoint Descriptor */
106 
107 		if (strcmp(field, "bEndpointAddress") == 0) {
108 			if (value & 0x80)
109 				printf(" <IN>\n");
110 			else
111 				printf(" <OUT>\n");
112 			return;
113 		}
114 		if (strcmp(field, "bmAttributes") == 0) {
115 			switch (value & 0x03) {
116 			case 0:
117 				printf(" <CONTROL>\n");
118 				break;
119 			case 1:
120 				switch (value & 0x0C) {
121 				case 0x00:
122 					printf(" <ISOCHRONOUS>\n");
123 					break;
124 				case 0x04:
125 					printf(" <ASYNC-ISOCHRONOUS>\n");
126 					break;
127 				case 0x08:
128 					printf(" <ADAPT-ISOCHRONOUS>\n");
129 					break;
130 				default:
131 					printf(" <SYNC-ISOCHRONOUS>\n");
132 					break;
133 				}
134 				break;
135 			case 2:
136 				printf(" <BULK>\n");
137 				break;
138 			default:
139 				printf(" <INTERRUPT>\n");
140 				break;
141 			}
142 			return;
143 		}
144 	}
145 	if ((field[0] == 'i') && (field[1] != 'd')) {
146 		/* Indirect String Descriptor */
147 		if (value == 0) {
148 			printf(" <no string>\n");
149 			return;
150 		}
151 		if (libusb20_dev_req_string_simple_sync(pdev, value,
152 		    temp_string, sizeof(temp_string))) {
153 			printf(" <retrieving string failed>\n");
154 			return;
155 		}
156 		printf(" <%s>\n", temp_string);
157 		return;
158 	}
159 	if (strlen(plevel) == 2 || strlen(plevel) == 6) {
160 
161 		/* Device and Interface Descriptor class codes */
162 
163 		if (strcmp(field, "bInterfaceClass") == 0 ||
164 		    strcmp(field, "bDeviceClass") == 0) {
165 
166 			switch (value) {
167 			case 0x00:
168 				printf(" <Probed by interface class>\n");
169 				break;
170 			case 0x01:
171 				printf(" <Audio device>\n");
172 				break;
173 			case 0x02:
174 				printf(" <Communication device>\n");
175 				break;
176 			case 0x03:
177 				printf(" <HID device>\n");
178 				break;
179 			case 0x05:
180 				printf(" <Physical device>\n");
181 				break;
182 			case 0x06:
183 				printf(" <Still imaging>\n");
184 				break;
185 			case 0x07:
186 				printf(" <Printer device>\n");
187 				break;
188 			case 0x08:
189 				printf(" <Mass storage>\n");
190 				break;
191 			case 0x09:
192 				printf(" <HUB>\n");
193 				break;
194 			case 0x0A:
195 				printf(" <CDC-data>\n");
196 				break;
197 			case 0x0B:
198 				printf(" <Smart card>\n");
199 				break;
200 			case 0x0D:
201 				printf(" <Content security>\n");
202 				break;
203 			case 0x0E:
204 				printf(" <Video device>\n");
205 				break;
206 			case 0x0F:
207 				printf(" <Personal healthcare>\n");
208 				break;
209 			case 0x10:
210 				printf(" <Audio and video device>\n");
211 				break;
212 			case 0x11:
213 				printf(" <Billboard device>\n");
214 				break;
215 			case 0xDC:
216 				printf(" <Diagnostic device>\n");
217 				break;
218 			case 0xE0:
219 				printf(" <Wireless controller>\n");
220 				break;
221 			case 0xEF:
222 				printf(" <Miscellaneous device>\n");
223 				break;
224 			case 0xFE:
225 				printf(" <Application specific>\n");
226 				break;
227 			case 0xFF:
228 				printf(" <Vendor specific>\n");
229 				break;
230 			default:
231 				printf(" <Unknown>\n");
232 				break;
233 			}
234 			return;
235 		}
236 	}
237 	/* No additional information */
238 	printf("\n");
239 }
240 
241 static void
dump_extra(struct libusb20_me_struct * str,const char * plevel)242 dump_extra(struct libusb20_me_struct *str, const char *plevel)
243 {
244 	const uint8_t *ptr;
245 	uint8_t x;
246 
247 	ptr = NULL;
248 
249 	while ((ptr = libusb20_desc_foreach(str, ptr))) {
250 		printf("\n" "%sAdditional Descriptor\n\n", plevel);
251 		printf("%sbLength = 0x%02x\n", plevel, ptr[0]);
252 		printf("%sbDescriptorType = 0x%02x\n", plevel, ptr[1]);
253 		if (ptr[0] > 1)
254 			printf("%sbDescriptorSubType = 0x%02x\n",
255 			    plevel, ptr[2]);
256 		printf("%s RAW dump: ", plevel);
257 		for (x = 0; x != ptr[0]; x++) {
258 			if ((x % 8) == 0) {
259 				printf("\n%s 0x%02x | ", plevel, x);
260 			}
261 			printf("0x%02x%s", ptr[x],
262 			    (x != (ptr[0] - 1)) ? ", " : (x % 8) ? "\n" : "");
263 		}
264 		printf("\n");
265 	}
266 	return;
267 }
268 
269 static void
dump_endpoint(struct libusb20_device * pdev,struct libusb20_endpoint * ep)270 dump_endpoint(struct libusb20_device *pdev,
271     struct libusb20_endpoint *ep)
272 {
273 	struct LIBUSB20_ENDPOINT_DESC_DECODED *edesc;
274 
275 	edesc = &ep->desc;
276 	LIBUSB20_ENDPOINT_DESC(DUMP3, edesc);
277 	dump_extra(&ep->extra, "  " "  " "  ");
278 	return;
279 }
280 
281 static void
dump_iface(struct libusb20_device * pdev,struct libusb20_interface * iface)282 dump_iface(struct libusb20_device *pdev,
283     struct libusb20_interface *iface)
284 {
285 	struct LIBUSB20_INTERFACE_DESC_DECODED *idesc;
286 	uint8_t z;
287 
288 	idesc = &iface->desc;
289 	LIBUSB20_INTERFACE_DESC(DUMP2, idesc);
290 	dump_extra(&iface->extra, "  " "  " "  ");
291 
292 	for (z = 0; z != iface->num_endpoints; z++) {
293 		printf("\n     Endpoint %u\n", z);
294 		dump_endpoint(pdev, iface->endpoints + z);
295 	}
296 	return;
297 }
298 
299 void
dump_device_info(struct libusb20_device * pdev,uint8_t show_ifdrv)300 dump_device_info(struct libusb20_device *pdev, uint8_t show_ifdrv)
301 {
302 	char buf[128];
303 	uint8_t n;
304 	unsigned int usage;
305 
306 	usage = libusb20_dev_get_power_usage(pdev);
307 
308 	printf("%s, cfg=%u md=%s spd=%s pwr=%s (%umA)\n",
309 	    libusb20_dev_get_desc(pdev),
310 	    libusb20_dev_get_config_index(pdev),
311 	    dump_mode(libusb20_dev_get_mode(pdev)),
312 	    dump_speed(libusb20_dev_get_speed(pdev)),
313 	    dump_power_mode(libusb20_dev_get_power_mode(pdev)),
314 	    usage);
315 
316 	if (!show_ifdrv)
317 		return;
318 
319 	for (n = 0; n != 255; n++) {
320 		if (libusb20_dev_get_iface_desc(pdev, n, buf, sizeof(buf)))
321 			break;
322 		if (buf[0] == 0)
323 			continue;
324 		printf("ugen%u.%u.%u: %s\n",
325 		    libusb20_dev_get_bus_number(pdev),
326 		    libusb20_dev_get_address(pdev), n, buf);
327 	}
328 }
329 
330 void
dump_be_quirk_names(struct libusb20_backend * pbe)331 dump_be_quirk_names(struct libusb20_backend *pbe)
332 {
333 	struct libusb20_quirk q;
334 	uint16_t x;
335 	int error;
336 
337 	memset(&q, 0, sizeof(q));
338 
339 	printf("\nDumping list of supported quirks:\n\n");
340 
341 	for (x = 0; x != 0xFFFF; x++) {
342 
343 		error = libusb20_be_get_quirk_name(pbe, x, &q);
344 		if (error) {
345 			if (x == 0) {
346 				printf("No quirk names - maybe the USB quirk "
347 				    "module has not been loaded.\n");
348 			}
349 			break;
350 		}
351 		if (strcmp(q.quirkname, "UQ_NONE"))
352 			printf("%s\n", q.quirkname);
353 	}
354 	printf("\n");
355 	return;
356 }
357 
358 void
dump_be_dev_quirks(struct libusb20_backend * pbe)359 dump_be_dev_quirks(struct libusb20_backend *pbe)
360 {
361 	struct libusb20_quirk q;
362 	uint16_t x;
363 	int error;
364 
365 	memset(&q, 0, sizeof(q));
366 
367 	printf("\nDumping current device quirks:\n\n");
368 
369 	for (x = 0; x != 0xFFFF; x++) {
370 
371 		error = libusb20_be_get_dev_quirk(pbe, x, &q);
372 		if (error) {
373 			if (x == 0) {
374 				printf("No device quirks - maybe the USB quirk "
375 				    "module has not been loaded.\n");
376 			}
377 			break;
378 		}
379 		if (strcmp(q.quirkname, "UQ_NONE")) {
380 			printf("VID=0x%04x PID=0x%04x REVLO=0x%04x "
381 			    "REVHI=0x%04x QUIRK=%s\n",
382 			    q.vid, q.pid, q.bcdDeviceLow,
383 			    q.bcdDeviceHigh, q.quirkname);
384 		}
385 	}
386 	printf("\n");
387 	return;
388 }
389 
390 void
dump_device_desc(struct libusb20_device * pdev)391 dump_device_desc(struct libusb20_device *pdev)
392 {
393 	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
394 
395 	ddesc = libusb20_dev_get_device_desc(pdev);
396 	LIBUSB20_DEVICE_DESC(DUMP0, ddesc);
397 	return;
398 }
399 
400 void
dump_config(struct libusb20_device * pdev,uint8_t all_cfg)401 dump_config(struct libusb20_device *pdev, uint8_t all_cfg)
402 {
403 	struct LIBUSB20_CONFIG_DESC_DECODED *cdesc;
404 	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
405 	struct libusb20_config *pcfg = NULL;
406 	uint8_t cfg_index;
407 	uint8_t cfg_index_end;
408 	uint8_t x;
409 	uint8_t y;
410 
411 	ddesc = libusb20_dev_get_device_desc(pdev);
412 
413 	if (all_cfg) {
414 		cfg_index = 0;
415 		cfg_index_end = ddesc->bNumConfigurations;
416 	} else {
417 		cfg_index = libusb20_dev_get_config_index(pdev);
418 		cfg_index_end = cfg_index + 1;
419 	}
420 
421 	for (; cfg_index != cfg_index_end; cfg_index++) {
422 
423 		pcfg = libusb20_dev_alloc_config(pdev, cfg_index);
424 		if (!pcfg) {
425 			continue;
426 		}
427 		printf("\n Configuration index %u\n\n", cfg_index);
428 		cdesc = &(pcfg->desc);
429 		LIBUSB20_CONFIG_DESC(DUMP1, cdesc);
430 		dump_extra(&(pcfg->extra), "  " "  ");
431 
432 		for (x = 0; x != pcfg->num_interface; x++) {
433 			printf("\n    Interface %u\n", x);
434 			dump_iface(pdev, pcfg->interface + x);
435 			printf("\n");
436 			for (y = 0; y != (pcfg->interface + x)->num_altsetting; y++) {
437 				printf("\n    Interface %u Alt %u\n", x, y + 1);
438 				dump_iface(pdev,
439 				    (pcfg->interface + x)->altsetting + y);
440 				printf("\n");
441 			}
442 		}
443 		printf("\n");
444 		free(pcfg);
445 	}
446 	return;
447 }
448 
449 void
dump_string_by_index(struct libusb20_device * pdev,uint8_t str_index)450 dump_string_by_index(struct libusb20_device *pdev, uint8_t str_index)
451 {
452 	char *pbuf;
453 	uint8_t n;
454 	uint8_t len;
455 
456 	pbuf = malloc(256);
457 	if (pbuf == NULL)
458 		err(1, "out of memory");
459 
460 	if (str_index == 0) {
461 		/* language table */
462 		if (libusb20_dev_req_string_sync(pdev,
463 		    str_index, 0, pbuf, 256)) {
464 			printf("STRING_0x%02x = <read error>\n", str_index);
465 		} else {
466 			printf("STRING_0x%02x = ", str_index);
467 			len = (uint8_t)pbuf[0];
468 			for (n = 0; n != len; n++) {
469 				printf("0x%02x%s", (uint8_t)pbuf[n],
470 				    (n != (len - 1)) ? ", " : "");
471 			}
472 			printf("\n");
473 		}
474 	} else {
475 		/* ordinary string */
476 		if (libusb20_dev_req_string_simple_sync(pdev,
477 		    str_index, pbuf, 256)) {
478 			printf("STRING_0x%02x = <read error>\n", str_index);
479 		} else {
480 			printf("STRING_0x%02x = <%s>\n", str_index, pbuf);
481 		}
482 	}
483 	free(pbuf);
484 }
485 
486 void
dump_device_stats(struct libusb20_device * pdev)487 dump_device_stats(struct libusb20_device *pdev)
488 {
489 	struct libusb20_device_stats st;
490 
491 	if (libusb20_dev_get_stats(pdev, &st)) {
492 		printf("{}\n");
493 	} else {
494 		printf("{\n"
495 		    "    UE_CONTROL_OK       : %llu\n"
496 		    "    UE_ISOCHRONOUS_OK   : %llu\n"
497 		    "    UE_BULK_OK          : %llu\n"
498 		    "    UE_INTERRUPT_OK     : %llu\n"
499 		    "    UE_CONTROL_FAIL     : %llu\n"
500 		    "    UE_ISOCHRONOUS_FAIL : %llu\n"
501 		    "    UE_BULK_FAIL        : %llu\n"
502 		    "    UE_INTERRUPT_FAIL   : %llu\n"
503 		    "}\n",
504 		    (unsigned long long)st.xfer_ok[0],
505 		    (unsigned long long)st.xfer_ok[1],
506 		    (unsigned long long)st.xfer_ok[2],
507 	            (unsigned long long)st.xfer_ok[3],
508 		    (unsigned long long)st.xfer_fail[0],
509 		    (unsigned long long)st.xfer_fail[1],
510 		    (unsigned long long)st.xfer_fail[2],
511 		    (unsigned long long)st.xfer_fail[3]);
512 	}
513 }
514