1eabe30fcSAlfred Perlstein /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 4eabe30fcSAlfred Perlstein * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 5*8fe86d92SBaptiste Daroussin * Copyright (c) 2024 Baptiste Daroussin <bapt@FreeBSD.org> 6eabe30fcSAlfred Perlstein * 7eabe30fcSAlfred Perlstein * Redistribution and use in source and binary forms, with or without 8eabe30fcSAlfred Perlstein * modification, are permitted provided that the following conditions 9eabe30fcSAlfred Perlstein * are met: 10eabe30fcSAlfred Perlstein * 1. Redistributions of source code must retain the above copyright 11eabe30fcSAlfred Perlstein * notice, this list of conditions and the following disclaimer. 12eabe30fcSAlfred Perlstein * 2. Redistributions in binary form must reproduce the above copyright 13eabe30fcSAlfred Perlstein * notice, this list of conditions and the following disclaimer in the 14eabe30fcSAlfred Perlstein * documentation and/or other materials provided with the distribution. 15eabe30fcSAlfred Perlstein * 16eabe30fcSAlfred Perlstein * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17eabe30fcSAlfred Perlstein * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18eabe30fcSAlfred Perlstein * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19eabe30fcSAlfred Perlstein * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20eabe30fcSAlfred Perlstein * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21eabe30fcSAlfred Perlstein * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22eabe30fcSAlfred Perlstein * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23eabe30fcSAlfred Perlstein * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24eabe30fcSAlfred Perlstein * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25eabe30fcSAlfred Perlstein * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26eabe30fcSAlfred Perlstein * SUCH DAMAGE. 27eabe30fcSAlfred Perlstein */ 28eabe30fcSAlfred Perlstein 29*8fe86d92SBaptiste Daroussin #include <sys/queue.h> 30*8fe86d92SBaptiste Daroussin 31eabe30fcSAlfred Perlstein #include <stdio.h> 32eabe30fcSAlfred Perlstein #include <stdlib.h> 33eabe30fcSAlfred Perlstein #include <stdint.h> 34eabe30fcSAlfred Perlstein #include <err.h> 35eabe30fcSAlfred Perlstein #include <string.h> 36eabe30fcSAlfred Perlstein #include <pwd.h> 37eabe30fcSAlfred Perlstein #include <grp.h> 38eabe30fcSAlfred Perlstein #include <ctype.h> 39eabe30fcSAlfred Perlstein 40eabe30fcSAlfred Perlstein #include <libusb20.h> 41eabe30fcSAlfred Perlstein #include <libusb20_desc.h> 42eabe30fcSAlfred Perlstein 43eabe30fcSAlfred Perlstein #include "dump.h" 44*8fe86d92SBaptiste Daroussin #include "pathnames.h" 45eabe30fcSAlfred Perlstein 46eabe30fcSAlfred Perlstein #define DUMP0(n,type,field,...) dump_field(pdev, " ", #field, n->field); 47eabe30fcSAlfred Perlstein #define DUMP1(n,type,field,...) dump_field(pdev, " ", #field, n->field); 48eabe30fcSAlfred Perlstein #define DUMP2(n,type,field,...) dump_field(pdev, " ", #field, n->field); 49eabe30fcSAlfred Perlstein #define DUMP3(n,type,field,...) dump_field(pdev, " ", #field, n->field); 50eabe30fcSAlfred Perlstein 51*8fe86d92SBaptiste Daroussin struct usb_product_info { 52*8fe86d92SBaptiste Daroussin STAILQ_ENTRY(usb_product_info) link; 53*8fe86d92SBaptiste Daroussin int id; 54*8fe86d92SBaptiste Daroussin char *desc; 55*8fe86d92SBaptiste Daroussin }; 56*8fe86d92SBaptiste Daroussin 57*8fe86d92SBaptiste Daroussin struct usb_vendor_info { 58*8fe86d92SBaptiste Daroussin STAILQ_ENTRY(usb_vendor_info) link; 59*8fe86d92SBaptiste Daroussin STAILQ_HEAD(,usb_product_info) devs; 60*8fe86d92SBaptiste Daroussin int id; 61*8fe86d92SBaptiste Daroussin char *desc; 62*8fe86d92SBaptiste Daroussin }; 63*8fe86d92SBaptiste Daroussin 64*8fe86d92SBaptiste Daroussin STAILQ_HEAD(usb_vendors, usb_vendor_info); 65*8fe86d92SBaptiste Daroussin 66eabe30fcSAlfred Perlstein const char * 67eabe30fcSAlfred Perlstein dump_mode(uint8_t value) 68eabe30fcSAlfred Perlstein { 69eabe30fcSAlfred Perlstein if (value == LIBUSB20_MODE_HOST) 70eabe30fcSAlfred Perlstein return ("HOST"); 71eabe30fcSAlfred Perlstein return ("DEVICE"); 72eabe30fcSAlfred Perlstein } 73eabe30fcSAlfred Perlstein 74eabe30fcSAlfred Perlstein const char * 75eabe30fcSAlfred Perlstein dump_speed(uint8_t value) 76eabe30fcSAlfred Perlstein { 77eabe30fcSAlfred Perlstein ; /* style fix */ 78eabe30fcSAlfred Perlstein switch (value) { 79eabe30fcSAlfred Perlstein case LIBUSB20_SPEED_LOW: 80eabe30fcSAlfred Perlstein return ("LOW (1.5Mbps)"); 81eabe30fcSAlfred Perlstein case LIBUSB20_SPEED_FULL: 82eabe30fcSAlfred Perlstein return ("FULL (12Mbps)"); 83eabe30fcSAlfred Perlstein case LIBUSB20_SPEED_HIGH: 84eabe30fcSAlfred Perlstein return ("HIGH (480Mbps)"); 85eabe30fcSAlfred Perlstein case LIBUSB20_SPEED_VARIABLE: 86eabe30fcSAlfred Perlstein return ("VARIABLE (52-480Mbps)"); 87eabe30fcSAlfred Perlstein case LIBUSB20_SPEED_SUPER: 88ccac019aSHans Petter Selasky return ("SUPER (5.0Gbps)"); 89eabe30fcSAlfred Perlstein default: 90eabe30fcSAlfred Perlstein break; 91eabe30fcSAlfred Perlstein } 92ccac019aSHans Petter Selasky return ("UNKNOWN ()"); 93eabe30fcSAlfred Perlstein } 94eabe30fcSAlfred Perlstein 95eabe30fcSAlfred Perlstein const char * 96eabe30fcSAlfred Perlstein dump_power_mode(uint8_t value) 97eabe30fcSAlfred Perlstein { 98eabe30fcSAlfred Perlstein ; /* style fix */ 99eabe30fcSAlfred Perlstein switch (value) { 100eabe30fcSAlfred Perlstein case LIBUSB20_POWER_OFF: 101eabe30fcSAlfred Perlstein return ("OFF"); 102eabe30fcSAlfred Perlstein case LIBUSB20_POWER_ON: 103eabe30fcSAlfred Perlstein return ("ON"); 104eabe30fcSAlfred Perlstein case LIBUSB20_POWER_SAVE: 105eabe30fcSAlfred Perlstein return ("SAVE"); 106eabe30fcSAlfred Perlstein case LIBUSB20_POWER_SUSPEND: 107eabe30fcSAlfred Perlstein return ("SUSPEND"); 108eabe30fcSAlfred Perlstein case LIBUSB20_POWER_RESUME: 109eabe30fcSAlfred Perlstein return ("RESUME"); 110eabe30fcSAlfred Perlstein default: 111eabe30fcSAlfred Perlstein return ("UNKNOWN"); 112eabe30fcSAlfred Perlstein } 113eabe30fcSAlfred Perlstein } 114eabe30fcSAlfred Perlstein 115eabe30fcSAlfred Perlstein static void 116eabe30fcSAlfred Perlstein dump_field(struct libusb20_device *pdev, const char *plevel, 117eabe30fcSAlfred Perlstein const char *field, uint32_t value) 118eabe30fcSAlfred Perlstein { 119eabe30fcSAlfred Perlstein uint8_t temp_string[256]; 120eabe30fcSAlfred Perlstein 121eabe30fcSAlfred Perlstein printf("%s%s = 0x%04x ", plevel, field, value); 122eabe30fcSAlfred Perlstein 123e975f97cSAndrew Thompson if (strlen(plevel) == 8) { 124e975f97cSAndrew Thompson /* Endpoint Descriptor */ 125e975f97cSAndrew Thompson 126e975f97cSAndrew Thompson if (strcmp(field, "bEndpointAddress") == 0) { 127e975f97cSAndrew Thompson if (value & 0x80) 128e975f97cSAndrew Thompson printf(" <IN>\n"); 129e975f97cSAndrew Thompson else 130e975f97cSAndrew Thompson printf(" <OUT>\n"); 131eabe30fcSAlfred Perlstein return; 132eabe30fcSAlfred Perlstein } 133e975f97cSAndrew Thompson if (strcmp(field, "bmAttributes") == 0) { 134e975f97cSAndrew Thompson switch (value & 0x03) { 135e975f97cSAndrew Thompson case 0: 136e975f97cSAndrew Thompson printf(" <CONTROL>\n"); 137e975f97cSAndrew Thompson break; 138e975f97cSAndrew Thompson case 1: 139e975f97cSAndrew Thompson switch (value & 0x0C) { 140e975f97cSAndrew Thompson case 0x00: 141e975f97cSAndrew Thompson printf(" <ISOCHRONOUS>\n"); 142e975f97cSAndrew Thompson break; 143e975f97cSAndrew Thompson case 0x04: 144e975f97cSAndrew Thompson printf(" <ASYNC-ISOCHRONOUS>\n"); 145e975f97cSAndrew Thompson break; 146e975f97cSAndrew Thompson case 0x08: 147e975f97cSAndrew Thompson printf(" <ADAPT-ISOCHRONOUS>\n"); 148e975f97cSAndrew Thompson break; 149e975f97cSAndrew Thompson default: 150e975f97cSAndrew Thompson printf(" <SYNC-ISOCHRONOUS>\n"); 151e975f97cSAndrew Thompson break; 152e975f97cSAndrew Thompson } 153e975f97cSAndrew Thompson break; 154e975f97cSAndrew Thompson case 2: 155e975f97cSAndrew Thompson printf(" <BULK>\n"); 156e975f97cSAndrew Thompson break; 157e975f97cSAndrew Thompson default: 158e975f97cSAndrew Thompson printf(" <INTERRUPT>\n"); 159e975f97cSAndrew Thompson break; 160e975f97cSAndrew Thompson } 161e975f97cSAndrew Thompson return; 162e975f97cSAndrew Thompson } 163e975f97cSAndrew Thompson } 164e975f97cSAndrew Thompson if ((field[0] == 'i') && (field[1] != 'd')) { 165e975f97cSAndrew Thompson /* Indirect String Descriptor */ 166eabe30fcSAlfred Perlstein if (value == 0) { 167eabe30fcSAlfred Perlstein printf(" <no string>\n"); 168eabe30fcSAlfred Perlstein return; 169eabe30fcSAlfred Perlstein } 1706f0e1ffdSAlfred Perlstein if (libusb20_dev_req_string_simple_sync(pdev, value, 1716f0e1ffdSAlfred Perlstein temp_string, sizeof(temp_string))) { 1726f0e1ffdSAlfred Perlstein printf(" <retrieving string failed>\n"); 1736f0e1ffdSAlfred Perlstein return; 174eabe30fcSAlfred Perlstein } 1756f0e1ffdSAlfred Perlstein printf(" <%s>\n", temp_string); 176eabe30fcSAlfred Perlstein return; 177eabe30fcSAlfred Perlstein } 1785bd38bcaSHans Petter Selasky if (strlen(plevel) == 2 || strlen(plevel) == 6) { 179eabe30fcSAlfred Perlstein 1805bd38bcaSHans Petter Selasky /* Device and Interface Descriptor class codes */ 1815bd38bcaSHans Petter Selasky 1825bd38bcaSHans Petter Selasky if (strcmp(field, "bInterfaceClass") == 0 || 1835bd38bcaSHans Petter Selasky strcmp(field, "bDeviceClass") == 0) { 1845bd38bcaSHans Petter Selasky 1855bd38bcaSHans Petter Selasky switch (value) { 1865bd38bcaSHans Petter Selasky case 0x00: 1875bd38bcaSHans Petter Selasky printf(" <Probed by interface class>\n"); 1885bd38bcaSHans Petter Selasky break; 1895bd38bcaSHans Petter Selasky case 0x01: 1905bd38bcaSHans Petter Selasky printf(" <Audio device>\n"); 1915bd38bcaSHans Petter Selasky break; 1925bd38bcaSHans Petter Selasky case 0x02: 1935bd38bcaSHans Petter Selasky printf(" <Communication device>\n"); 1945bd38bcaSHans Petter Selasky break; 1955bd38bcaSHans Petter Selasky case 0x03: 1965bd38bcaSHans Petter Selasky printf(" <HID device>\n"); 1975bd38bcaSHans Petter Selasky break; 1985bd38bcaSHans Petter Selasky case 0x05: 1995bd38bcaSHans Petter Selasky printf(" <Physical device>\n"); 2005bd38bcaSHans Petter Selasky break; 2015bd38bcaSHans Petter Selasky case 0x06: 2025bd38bcaSHans Petter Selasky printf(" <Still imaging>\n"); 2035bd38bcaSHans Petter Selasky break; 2045bd38bcaSHans Petter Selasky case 0x07: 2055bd38bcaSHans Petter Selasky printf(" <Printer device>\n"); 2065bd38bcaSHans Petter Selasky break; 2075bd38bcaSHans Petter Selasky case 0x08: 2085bd38bcaSHans Petter Selasky printf(" <Mass storage>\n"); 2095bd38bcaSHans Petter Selasky break; 2105bd38bcaSHans Petter Selasky case 0x09: 2115bd38bcaSHans Petter Selasky printf(" <HUB>\n"); 2125bd38bcaSHans Petter Selasky break; 2135bd38bcaSHans Petter Selasky case 0x0A: 2145bd38bcaSHans Petter Selasky printf(" <CDC-data>\n"); 2155bd38bcaSHans Petter Selasky break; 2165bd38bcaSHans Petter Selasky case 0x0B: 2175bd38bcaSHans Petter Selasky printf(" <Smart card>\n"); 2185bd38bcaSHans Petter Selasky break; 2195bd38bcaSHans Petter Selasky case 0x0D: 2205bd38bcaSHans Petter Selasky printf(" <Content security>\n"); 2215bd38bcaSHans Petter Selasky break; 2225bd38bcaSHans Petter Selasky case 0x0E: 2235bd38bcaSHans Petter Selasky printf(" <Video device>\n"); 2245bd38bcaSHans Petter Selasky break; 2255bd38bcaSHans Petter Selasky case 0x0F: 2265bd38bcaSHans Petter Selasky printf(" <Personal healthcare>\n"); 2275bd38bcaSHans Petter Selasky break; 2285bd38bcaSHans Petter Selasky case 0x10: 2295bd38bcaSHans Petter Selasky printf(" <Audio and video device>\n"); 2305bd38bcaSHans Petter Selasky break; 2315bd38bcaSHans Petter Selasky case 0x11: 2325bd38bcaSHans Petter Selasky printf(" <Billboard device>\n"); 2335bd38bcaSHans Petter Selasky break; 2345bd38bcaSHans Petter Selasky case 0xDC: 2355bd38bcaSHans Petter Selasky printf(" <Diagnostic device>\n"); 2365bd38bcaSHans Petter Selasky break; 2375bd38bcaSHans Petter Selasky case 0xE0: 2385bd38bcaSHans Petter Selasky printf(" <Wireless controller>\n"); 2395bd38bcaSHans Petter Selasky break; 2405bd38bcaSHans Petter Selasky case 0xEF: 2415bd38bcaSHans Petter Selasky printf(" <Miscellaneous device>\n"); 2425bd38bcaSHans Petter Selasky break; 2435bd38bcaSHans Petter Selasky case 0xFE: 2445bd38bcaSHans Petter Selasky printf(" <Application specific>\n"); 2455bd38bcaSHans Petter Selasky break; 2465bd38bcaSHans Petter Selasky case 0xFF: 2475bd38bcaSHans Petter Selasky printf(" <Vendor specific>\n"); 2485bd38bcaSHans Petter Selasky break; 2495bd38bcaSHans Petter Selasky default: 2505bd38bcaSHans Petter Selasky printf(" <Unknown>\n"); 2515bd38bcaSHans Petter Selasky break; 2525bd38bcaSHans Petter Selasky } 2535bd38bcaSHans Petter Selasky return; 2545bd38bcaSHans Petter Selasky } 2555bd38bcaSHans Petter Selasky } 256e975f97cSAndrew Thompson /* No additional information */ 257e975f97cSAndrew Thompson printf("\n"); 258e975f97cSAndrew Thompson } 259e975f97cSAndrew Thompson 260eabe30fcSAlfred Perlstein static void 261eabe30fcSAlfred Perlstein dump_extra(struct libusb20_me_struct *str, const char *plevel) 262eabe30fcSAlfred Perlstein { 263eabe30fcSAlfred Perlstein const uint8_t *ptr; 264eabe30fcSAlfred Perlstein uint8_t x; 265eabe30fcSAlfred Perlstein 266eabe30fcSAlfred Perlstein ptr = NULL; 267eabe30fcSAlfred Perlstein 268eabe30fcSAlfred Perlstein while ((ptr = libusb20_desc_foreach(str, ptr))) { 269eabe30fcSAlfred Perlstein printf("\n" "%sAdditional Descriptor\n\n", plevel); 270eabe30fcSAlfred Perlstein printf("%sbLength = 0x%02x\n", plevel, ptr[0]); 271eabe30fcSAlfred Perlstein printf("%sbDescriptorType = 0x%02x\n", plevel, ptr[1]); 272eabe30fcSAlfred Perlstein if (ptr[0] > 1) 273eabe30fcSAlfred Perlstein printf("%sbDescriptorSubType = 0x%02x\n", 274eabe30fcSAlfred Perlstein plevel, ptr[2]); 275eabe30fcSAlfred Perlstein printf("%s RAW dump: ", plevel); 276eabe30fcSAlfred Perlstein for (x = 0; x != ptr[0]; x++) { 277eabe30fcSAlfred Perlstein if ((x % 8) == 0) { 278eabe30fcSAlfred Perlstein printf("\n%s 0x%02x | ", plevel, x); 279eabe30fcSAlfred Perlstein } 280eabe30fcSAlfred Perlstein printf("0x%02x%s", ptr[x], 281eabe30fcSAlfred Perlstein (x != (ptr[0] - 1)) ? ", " : (x % 8) ? "\n" : ""); 282eabe30fcSAlfred Perlstein } 283eabe30fcSAlfred Perlstein printf("\n"); 284eabe30fcSAlfred Perlstein } 285eabe30fcSAlfred Perlstein } 286eabe30fcSAlfred Perlstein 287eabe30fcSAlfred Perlstein static void 288eabe30fcSAlfred Perlstein dump_endpoint(struct libusb20_device *pdev, 289eabe30fcSAlfred Perlstein struct libusb20_endpoint *ep) 290eabe30fcSAlfred Perlstein { 291eabe30fcSAlfred Perlstein struct LIBUSB20_ENDPOINT_DESC_DECODED *edesc; 292eabe30fcSAlfred Perlstein 293eabe30fcSAlfred Perlstein edesc = &ep->desc; 294eabe30fcSAlfred Perlstein LIBUSB20_ENDPOINT_DESC(DUMP3, edesc); 295eabe30fcSAlfred Perlstein dump_extra(&ep->extra, " " " " " "); 296eabe30fcSAlfred Perlstein } 297eabe30fcSAlfred Perlstein 298eabe30fcSAlfred Perlstein static void 299eabe30fcSAlfred Perlstein dump_iface(struct libusb20_device *pdev, 300eabe30fcSAlfred Perlstein struct libusb20_interface *iface) 301eabe30fcSAlfred Perlstein { 302eabe30fcSAlfred Perlstein struct LIBUSB20_INTERFACE_DESC_DECODED *idesc; 303eabe30fcSAlfred Perlstein uint8_t z; 304eabe30fcSAlfred Perlstein 305eabe30fcSAlfred Perlstein idesc = &iface->desc; 306eabe30fcSAlfred Perlstein LIBUSB20_INTERFACE_DESC(DUMP2, idesc); 307eabe30fcSAlfred Perlstein dump_extra(&iface->extra, " " " " " "); 308eabe30fcSAlfred Perlstein 309eabe30fcSAlfred Perlstein for (z = 0; z != iface->num_endpoints; z++) { 310eabe30fcSAlfred Perlstein printf("\n Endpoint %u\n", z); 311eabe30fcSAlfred Perlstein dump_endpoint(pdev, iface->endpoints + z); 312eabe30fcSAlfred Perlstein } 313eabe30fcSAlfred Perlstein } 314eabe30fcSAlfred Perlstein 315*8fe86d92SBaptiste Daroussin static struct usb_vendors * 316*8fe86d92SBaptiste Daroussin load_vendors(void) 317*8fe86d92SBaptiste Daroussin { 318*8fe86d92SBaptiste Daroussin const char *dbf; 319*8fe86d92SBaptiste Daroussin FILE *db = NULL; 320*8fe86d92SBaptiste Daroussin struct usb_vendor_info *cv; 321*8fe86d92SBaptiste Daroussin struct usb_product_info *cd; 322*8fe86d92SBaptiste Daroussin struct usb_vendors *usb_vendors; 323*8fe86d92SBaptiste Daroussin char buf[1024], str[1024]; 324*8fe86d92SBaptiste Daroussin char *ch; 325*8fe86d92SBaptiste Daroussin int id; 326*8fe86d92SBaptiste Daroussin 327*8fe86d92SBaptiste Daroussin usb_vendors = malloc(sizeof(*usb_vendors)); 328*8fe86d92SBaptiste Daroussin if (usb_vendors == NULL) 329*8fe86d92SBaptiste Daroussin err(1, "out of memory"); 330*8fe86d92SBaptiste Daroussin STAILQ_INIT(usb_vendors); 331*8fe86d92SBaptiste Daroussin if ((dbf = getenv("USB_VENDOR_DATABASE")) != NULL) 332*8fe86d92SBaptiste Daroussin db = fopen(dbf, "r"); 333*8fe86d92SBaptiste Daroussin if (db == NULL) { 334*8fe86d92SBaptiste Daroussin dbf = _PATH_LUSBVDB; 335*8fe86d92SBaptiste Daroussin if ((db = fopen(dbf, "r")) == NULL) { 336*8fe86d92SBaptiste Daroussin dbf = _PATH_USBVDB; 337*8fe86d92SBaptiste Daroussin if ((db = fopen(dbf, "r")) == NULL) 338*8fe86d92SBaptiste Daroussin return (usb_vendors); 339*8fe86d92SBaptiste Daroussin } 340*8fe86d92SBaptiste Daroussin } 341*8fe86d92SBaptiste Daroussin cv = NULL; 342*8fe86d92SBaptiste Daroussin cd = NULL; 343*8fe86d92SBaptiste Daroussin 344*8fe86d92SBaptiste Daroussin for (;;) { 345*8fe86d92SBaptiste Daroussin if (fgets(buf, sizeof(buf), db) == NULL) 346*8fe86d92SBaptiste Daroussin break; 347*8fe86d92SBaptiste Daroussin 348*8fe86d92SBaptiste Daroussin if ((ch = strchr(buf, '#')) != NULL) 349*8fe86d92SBaptiste Daroussin *ch = '\0'; 350*8fe86d92SBaptiste Daroussin if (ch == buf) 351*8fe86d92SBaptiste Daroussin continue; 352*8fe86d92SBaptiste Daroussin ch = strchr(buf, '\0') - 1; 353*8fe86d92SBaptiste Daroussin while (ch > buf && isspace(*ch)) 354*8fe86d92SBaptiste Daroussin *ch-- = '\0'; 355*8fe86d92SBaptiste Daroussin if (ch <= buf) 356*8fe86d92SBaptiste Daroussin continue; 357*8fe86d92SBaptiste Daroussin 358*8fe86d92SBaptiste Daroussin /* Can't handle subvendor / subdevice entries yet */ 359*8fe86d92SBaptiste Daroussin if (buf[0] == '\t' && buf[1] == '\t') 360*8fe86d92SBaptiste Daroussin continue; 361*8fe86d92SBaptiste Daroussin 362*8fe86d92SBaptiste Daroussin /* Check for vendor entry */ 363*8fe86d92SBaptiste Daroussin if (buf[0] != '\t' && sscanf(buf, "%04x %[^\n]", &id, str) == 2) { 364*8fe86d92SBaptiste Daroussin if ((id == 0) || (strlen(str) < 1)) 365*8fe86d92SBaptiste Daroussin continue; 366*8fe86d92SBaptiste Daroussin if ((cv = malloc(sizeof(struct usb_vendor_info))) == NULL) 367*8fe86d92SBaptiste Daroussin err(1, "out of memory"); 368*8fe86d92SBaptiste Daroussin if ((cv->desc = strdup(str)) == NULL) 369*8fe86d92SBaptiste Daroussin err(1, "out of memory"); 370*8fe86d92SBaptiste Daroussin cv->id = id; 371*8fe86d92SBaptiste Daroussin STAILQ_INIT(&cv->devs); 372*8fe86d92SBaptiste Daroussin STAILQ_INSERT_TAIL(usb_vendors, cv, link); 373*8fe86d92SBaptiste Daroussin continue; 374*8fe86d92SBaptiste Daroussin } 375*8fe86d92SBaptiste Daroussin 376*8fe86d92SBaptiste Daroussin /* Check for device entry */ 377*8fe86d92SBaptiste Daroussin if (buf[0] == '\t' && sscanf(buf + 1, "%04x %[^\n]", &id, str) == 2) { 378*8fe86d92SBaptiste Daroussin if ((id == 0) || (strlen(str) < 1)) 379*8fe86d92SBaptiste Daroussin continue; 380*8fe86d92SBaptiste Daroussin if (cv == NULL) 381*8fe86d92SBaptiste Daroussin continue; 382*8fe86d92SBaptiste Daroussin if ((cd = malloc(sizeof(struct usb_product_info))) == NULL) 383*8fe86d92SBaptiste Daroussin err(1, "out of memory"); 384*8fe86d92SBaptiste Daroussin if ((cd->desc = strdup(str)) == NULL) 385*8fe86d92SBaptiste Daroussin err(1, "out of memory"); 386*8fe86d92SBaptiste Daroussin cd->id = id; 387*8fe86d92SBaptiste Daroussin STAILQ_INSERT_TAIL(&cv->devs, cd, link); 388*8fe86d92SBaptiste Daroussin continue; 389*8fe86d92SBaptiste Daroussin } 390*8fe86d92SBaptiste Daroussin } 391*8fe86d92SBaptiste Daroussin if (ferror(db)) 392*8fe86d92SBaptiste Daroussin err(1, "error reading the usb id db"); 393*8fe86d92SBaptiste Daroussin 394*8fe86d92SBaptiste Daroussin fclose(db); 395*8fe86d92SBaptiste Daroussin /* cleanup */ 396*8fe86d92SBaptiste Daroussin return (usb_vendors); 397*8fe86d92SBaptiste Daroussin } 398*8fe86d92SBaptiste Daroussin 399*8fe86d92SBaptiste Daroussin static char * 400*8fe86d92SBaptiste Daroussin _device_desc(struct libusb20_device *pdev) 401*8fe86d92SBaptiste Daroussin { 402*8fe86d92SBaptiste Daroussin static struct usb_vendors *usb_vendors = NULL; 403*8fe86d92SBaptiste Daroussin char *desc = NULL; 404*8fe86d92SBaptiste Daroussin const char *vendor = NULL, *product = NULL; 405*8fe86d92SBaptiste Daroussin uint16_t vid = libusb20_dev_get_device_desc(pdev)->idVendor; 406*8fe86d92SBaptiste Daroussin uint16_t pid = libusb20_dev_get_device_desc(pdev)->idProduct; 407*8fe86d92SBaptiste Daroussin struct usb_vendor_info *vi; 408*8fe86d92SBaptiste Daroussin struct usb_product_info *pi; 409*8fe86d92SBaptiste Daroussin 410*8fe86d92SBaptiste Daroussin if (usb_vendors == NULL) 411*8fe86d92SBaptiste Daroussin usb_vendors = load_vendors(); 412*8fe86d92SBaptiste Daroussin 413*8fe86d92SBaptiste Daroussin STAILQ_FOREACH(vi, usb_vendors, link) { 414*8fe86d92SBaptiste Daroussin if (vi->id == vid) { 415*8fe86d92SBaptiste Daroussin vendor = vi->desc; 416*8fe86d92SBaptiste Daroussin break; 417*8fe86d92SBaptiste Daroussin } 418*8fe86d92SBaptiste Daroussin } 419*8fe86d92SBaptiste Daroussin if (vi != NULL) { 420*8fe86d92SBaptiste Daroussin STAILQ_FOREACH(pi, &vi->devs, link) { 421*8fe86d92SBaptiste Daroussin if (pi->id == pid) { 422*8fe86d92SBaptiste Daroussin product = pi->desc; 423*8fe86d92SBaptiste Daroussin break; 424*8fe86d92SBaptiste Daroussin } 425*8fe86d92SBaptiste Daroussin } 426*8fe86d92SBaptiste Daroussin } 427*8fe86d92SBaptiste Daroussin if (vendor == NULL || product == NULL) 428*8fe86d92SBaptiste Daroussin return (NULL); 429*8fe86d92SBaptiste Daroussin 430*8fe86d92SBaptiste Daroussin asprintf(&desc, "ugen%u.%u: <%s %s> at usbus%u", 431*8fe86d92SBaptiste Daroussin libusb20_dev_get_bus_number(pdev), 432*8fe86d92SBaptiste Daroussin libusb20_dev_get_address(pdev), 433*8fe86d92SBaptiste Daroussin product, vendor, 434*8fe86d92SBaptiste Daroussin libusb20_dev_get_bus_number(pdev)); 435*8fe86d92SBaptiste Daroussin 436*8fe86d92SBaptiste Daroussin 437*8fe86d92SBaptiste Daroussin return (desc); 438*8fe86d92SBaptiste Daroussin } 439*8fe86d92SBaptiste Daroussin 440eabe30fcSAlfred Perlstein void 44106d497c1SAndrew Thompson dump_device_info(struct libusb20_device *pdev, uint8_t show_ifdrv) 442eabe30fcSAlfred Perlstein { 44306d497c1SAndrew Thompson char buf[128]; 44406d497c1SAndrew Thompson uint8_t n; 445aafcb732SHans Petter Selasky unsigned int usage; 446*8fe86d92SBaptiste Daroussin char *desc; 44706d497c1SAndrew Thompson 448aafcb732SHans Petter Selasky usage = libusb20_dev_get_power_usage(pdev); 449aafcb732SHans Petter Selasky 450*8fe86d92SBaptiste Daroussin desc = _device_desc(pdev); 451*8fe86d92SBaptiste Daroussin 452aafcb732SHans Petter Selasky printf("%s, cfg=%u md=%s spd=%s pwr=%s (%umA)\n", 453*8fe86d92SBaptiste Daroussin desc ? desc : libusb20_dev_get_desc(pdev), 454eabe30fcSAlfred Perlstein libusb20_dev_get_config_index(pdev), 455eabe30fcSAlfred Perlstein dump_mode(libusb20_dev_get_mode(pdev)), 456eabe30fcSAlfred Perlstein dump_speed(libusb20_dev_get_speed(pdev)), 457aafcb732SHans Petter Selasky dump_power_mode(libusb20_dev_get_power_mode(pdev)), 458aafcb732SHans Petter Selasky usage); 459*8fe86d92SBaptiste Daroussin free(desc); 46006d497c1SAndrew Thompson 46106d497c1SAndrew Thompson if (!show_ifdrv) 462eabe30fcSAlfred Perlstein return; 46306d497c1SAndrew Thompson 46406d497c1SAndrew Thompson for (n = 0; n != 255; n++) { 46506d497c1SAndrew Thompson if (libusb20_dev_get_iface_desc(pdev, n, buf, sizeof(buf))) 46606d497c1SAndrew Thompson break; 46706d497c1SAndrew Thompson if (buf[0] == 0) 46806d497c1SAndrew Thompson continue; 46906d497c1SAndrew Thompson printf("ugen%u.%u.%u: %s\n", 47006d497c1SAndrew Thompson libusb20_dev_get_bus_number(pdev), 47106d497c1SAndrew Thompson libusb20_dev_get_address(pdev), n, buf); 47206d497c1SAndrew Thompson } 473eabe30fcSAlfred Perlstein } 474eabe30fcSAlfred Perlstein 475eabe30fcSAlfred Perlstein void 476eabe30fcSAlfred Perlstein dump_be_quirk_names(struct libusb20_backend *pbe) 477eabe30fcSAlfred Perlstein { 478eabe30fcSAlfred Perlstein struct libusb20_quirk q; 479eabe30fcSAlfred Perlstein uint16_t x; 4806f0e1ffdSAlfred Perlstein int error; 481eabe30fcSAlfred Perlstein 482eabe30fcSAlfred Perlstein memset(&q, 0, sizeof(q)); 483eabe30fcSAlfred Perlstein 484eabe30fcSAlfred Perlstein printf("\nDumping list of supported quirks:\n\n"); 485eabe30fcSAlfred Perlstein 486eabe30fcSAlfred Perlstein for (x = 0; x != 0xFFFF; x++) { 487eabe30fcSAlfred Perlstein 4886f0e1ffdSAlfred Perlstein error = libusb20_be_get_quirk_name(pbe, x, &q); 4896f0e1ffdSAlfred Perlstein if (error) { 490eabe30fcSAlfred Perlstein if (x == 0) { 491eabe30fcSAlfred Perlstein printf("No quirk names - maybe the USB quirk " 492eabe30fcSAlfred Perlstein "module has not been loaded.\n"); 493eabe30fcSAlfred Perlstein } 494eabe30fcSAlfred Perlstein break; 495eabe30fcSAlfred Perlstein } 496eabe30fcSAlfred Perlstein if (strcmp(q.quirkname, "UQ_NONE")) 497eabe30fcSAlfred Perlstein printf("%s\n", q.quirkname); 498eabe30fcSAlfred Perlstein } 499eabe30fcSAlfred Perlstein printf("\n"); 500eabe30fcSAlfred Perlstein } 501eabe30fcSAlfred Perlstein 502eabe30fcSAlfred Perlstein void 503eabe30fcSAlfred Perlstein dump_be_dev_quirks(struct libusb20_backend *pbe) 504eabe30fcSAlfred Perlstein { 505eabe30fcSAlfred Perlstein struct libusb20_quirk q; 506eabe30fcSAlfred Perlstein uint16_t x; 5076f0e1ffdSAlfred Perlstein int error; 508eabe30fcSAlfred Perlstein 509eabe30fcSAlfred Perlstein memset(&q, 0, sizeof(q)); 510eabe30fcSAlfred Perlstein 511eabe30fcSAlfred Perlstein printf("\nDumping current device quirks:\n\n"); 512eabe30fcSAlfred Perlstein 513eabe30fcSAlfred Perlstein for (x = 0; x != 0xFFFF; x++) { 514eabe30fcSAlfred Perlstein 5156f0e1ffdSAlfred Perlstein error = libusb20_be_get_dev_quirk(pbe, x, &q); 5166f0e1ffdSAlfred Perlstein if (error) { 517eabe30fcSAlfred Perlstein if (x == 0) { 518eabe30fcSAlfred Perlstein printf("No device quirks - maybe the USB quirk " 519eabe30fcSAlfred Perlstein "module has not been loaded.\n"); 520eabe30fcSAlfred Perlstein } 521eabe30fcSAlfred Perlstein break; 522eabe30fcSAlfred Perlstein } 523eabe30fcSAlfred Perlstein if (strcmp(q.quirkname, "UQ_NONE")) { 524eabe30fcSAlfred Perlstein printf("VID=0x%04x PID=0x%04x REVLO=0x%04x " 525eabe30fcSAlfred Perlstein "REVHI=0x%04x QUIRK=%s\n", 526eabe30fcSAlfred Perlstein q.vid, q.pid, q.bcdDeviceLow, 527eabe30fcSAlfred Perlstein q.bcdDeviceHigh, q.quirkname); 528eabe30fcSAlfred Perlstein } 529eabe30fcSAlfred Perlstein } 530eabe30fcSAlfred Perlstein printf("\n"); 531eabe30fcSAlfred Perlstein } 532eabe30fcSAlfred Perlstein 533eabe30fcSAlfred Perlstein void 534eabe30fcSAlfred Perlstein dump_device_desc(struct libusb20_device *pdev) 535eabe30fcSAlfred Perlstein { 536eabe30fcSAlfred Perlstein struct LIBUSB20_DEVICE_DESC_DECODED *ddesc; 537eabe30fcSAlfred Perlstein 538eabe30fcSAlfred Perlstein ddesc = libusb20_dev_get_device_desc(pdev); 539eabe30fcSAlfred Perlstein LIBUSB20_DEVICE_DESC(DUMP0, ddesc); 540eabe30fcSAlfred Perlstein } 541eabe30fcSAlfred Perlstein 542eabe30fcSAlfred Perlstein void 543eabe30fcSAlfred Perlstein dump_config(struct libusb20_device *pdev, uint8_t all_cfg) 544eabe30fcSAlfred Perlstein { 545eabe30fcSAlfred Perlstein struct LIBUSB20_CONFIG_DESC_DECODED *cdesc; 546eabe30fcSAlfred Perlstein struct LIBUSB20_DEVICE_DESC_DECODED *ddesc; 547eabe30fcSAlfred Perlstein struct libusb20_config *pcfg = NULL; 548eabe30fcSAlfred Perlstein uint8_t cfg_index; 549eabe30fcSAlfred Perlstein uint8_t cfg_index_end; 550eabe30fcSAlfred Perlstein uint8_t x; 551eabe30fcSAlfred Perlstein uint8_t y; 552eabe30fcSAlfred Perlstein 553eabe30fcSAlfred Perlstein ddesc = libusb20_dev_get_device_desc(pdev); 554eabe30fcSAlfred Perlstein 555eabe30fcSAlfred Perlstein if (all_cfg) { 556eabe30fcSAlfred Perlstein cfg_index = 0; 557eabe30fcSAlfred Perlstein cfg_index_end = ddesc->bNumConfigurations; 558eabe30fcSAlfred Perlstein } else { 559eabe30fcSAlfred Perlstein cfg_index = libusb20_dev_get_config_index(pdev); 560eabe30fcSAlfred Perlstein cfg_index_end = cfg_index + 1; 561eabe30fcSAlfred Perlstein } 562eabe30fcSAlfred Perlstein 563eabe30fcSAlfred Perlstein for (; cfg_index != cfg_index_end; cfg_index++) { 564eabe30fcSAlfred Perlstein 565eabe30fcSAlfred Perlstein pcfg = libusb20_dev_alloc_config(pdev, cfg_index); 566eabe30fcSAlfred Perlstein if (!pcfg) { 567eabe30fcSAlfred Perlstein continue; 568eabe30fcSAlfred Perlstein } 569eabe30fcSAlfred Perlstein printf("\n Configuration index %u\n\n", cfg_index); 570eabe30fcSAlfred Perlstein cdesc = &(pcfg->desc); 571eabe30fcSAlfred Perlstein LIBUSB20_CONFIG_DESC(DUMP1, cdesc); 572eabe30fcSAlfred Perlstein dump_extra(&(pcfg->extra), " " " "); 573eabe30fcSAlfred Perlstein 574eabe30fcSAlfred Perlstein for (x = 0; x != pcfg->num_interface; x++) { 575eabe30fcSAlfred Perlstein printf("\n Interface %u\n", x); 576eabe30fcSAlfred Perlstein dump_iface(pdev, pcfg->interface + x); 577eabe30fcSAlfred Perlstein printf("\n"); 578eabe30fcSAlfred Perlstein for (y = 0; y != (pcfg->interface + x)->num_altsetting; y++) { 579eabe30fcSAlfred Perlstein printf("\n Interface %u Alt %u\n", x, y + 1); 580eabe30fcSAlfred Perlstein dump_iface(pdev, 581eabe30fcSAlfred Perlstein (pcfg->interface + x)->altsetting + y); 582eabe30fcSAlfred Perlstein printf("\n"); 583eabe30fcSAlfred Perlstein } 584eabe30fcSAlfred Perlstein } 585eabe30fcSAlfred Perlstein printf("\n"); 586eabe30fcSAlfred Perlstein free(pcfg); 587eabe30fcSAlfred Perlstein } 588eabe30fcSAlfred Perlstein } 589cf109686SAndrew Thompson 590cf109686SAndrew Thompson void 591cf109686SAndrew Thompson dump_string_by_index(struct libusb20_device *pdev, uint8_t str_index) 592cf109686SAndrew Thompson { 593cf109686SAndrew Thompson char *pbuf; 594cf109686SAndrew Thompson uint8_t n; 595cf109686SAndrew Thompson uint8_t len; 596cf109686SAndrew Thompson 597cf109686SAndrew Thompson pbuf = malloc(256); 598cf109686SAndrew Thompson if (pbuf == NULL) 599cf109686SAndrew Thompson err(1, "out of memory"); 600cf109686SAndrew Thompson 601cf109686SAndrew Thompson if (str_index == 0) { 602cf109686SAndrew Thompson /* language table */ 603cf109686SAndrew Thompson if (libusb20_dev_req_string_sync(pdev, 604cf109686SAndrew Thompson str_index, 0, pbuf, 256)) { 605cf109686SAndrew Thompson printf("STRING_0x%02x = <read error>\n", str_index); 606cf109686SAndrew Thompson } else { 607cf109686SAndrew Thompson printf("STRING_0x%02x = ", str_index); 608cf109686SAndrew Thompson len = (uint8_t)pbuf[0]; 609cf109686SAndrew Thompson for (n = 0; n != len; n++) { 610cf109686SAndrew Thompson printf("0x%02x%s", (uint8_t)pbuf[n], 611cf109686SAndrew Thompson (n != (len - 1)) ? ", " : ""); 612cf109686SAndrew Thompson } 613cf109686SAndrew Thompson printf("\n"); 614cf109686SAndrew Thompson } 615cf109686SAndrew Thompson } else { 616cf109686SAndrew Thompson /* ordinary string */ 617cf109686SAndrew Thompson if (libusb20_dev_req_string_simple_sync(pdev, 618cf109686SAndrew Thompson str_index, pbuf, 256)) { 619cf109686SAndrew Thompson printf("STRING_0x%02x = <read error>\n", str_index); 620cf109686SAndrew Thompson } else { 621cf109686SAndrew Thompson printf("STRING_0x%02x = <%s>\n", str_index, pbuf); 622cf109686SAndrew Thompson } 623cf109686SAndrew Thompson } 624cf109686SAndrew Thompson free(pbuf); 625cf109686SAndrew Thompson } 626fa6d8b65SHans Petter Selasky 627fa6d8b65SHans Petter Selasky void 628fa6d8b65SHans Petter Selasky dump_device_stats(struct libusb20_device *pdev) 629fa6d8b65SHans Petter Selasky { 630fa6d8b65SHans Petter Selasky struct libusb20_device_stats st; 631fa6d8b65SHans Petter Selasky 632fa6d8b65SHans Petter Selasky if (libusb20_dev_get_stats(pdev, &st)) { 633fa6d8b65SHans Petter Selasky printf("{}\n"); 634fa6d8b65SHans Petter Selasky } else { 635fa6d8b65SHans Petter Selasky printf("{\n" 636fa6d8b65SHans Petter Selasky " UE_CONTROL_OK : %llu\n" 637fa6d8b65SHans Petter Selasky " UE_ISOCHRONOUS_OK : %llu\n" 638fa6d8b65SHans Petter Selasky " UE_BULK_OK : %llu\n" 639fa6d8b65SHans Petter Selasky " UE_INTERRUPT_OK : %llu\n" 640fa6d8b65SHans Petter Selasky " UE_CONTROL_FAIL : %llu\n" 641fa6d8b65SHans Petter Selasky " UE_ISOCHRONOUS_FAIL : %llu\n" 642fa6d8b65SHans Petter Selasky " UE_BULK_FAIL : %llu\n" 643fa6d8b65SHans Petter Selasky " UE_INTERRUPT_FAIL : %llu\n" 644fa6d8b65SHans Petter Selasky "}\n", 645fa6d8b65SHans Petter Selasky (unsigned long long)st.xfer_ok[0], 646fa6d8b65SHans Petter Selasky (unsigned long long)st.xfer_ok[1], 647fa6d8b65SHans Petter Selasky (unsigned long long)st.xfer_ok[2], 648fa6d8b65SHans Petter Selasky (unsigned long long)st.xfer_ok[3], 649fa6d8b65SHans Petter Selasky (unsigned long long)st.xfer_fail[0], 650fa6d8b65SHans Petter Selasky (unsigned long long)st.xfer_fail[1], 651fa6d8b65SHans Petter Selasky (unsigned long long)st.xfer_fail[2], 652fa6d8b65SHans Petter Selasky (unsigned long long)st.xfer_fail[3]); 653fa6d8b65SHans Petter Selasky } 654fa6d8b65SHans Petter Selasky } 655