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