Index: lib/libusb/libusb20_ugen20.c =================================================================== --- lib/libusb/libusb20_ugen20.c +++ lib/libusb/libusb20_ugen20.c @@ -27,6 +27,7 @@ #ifdef LIBUSB_GLOBAL_INCLUDE_FILE #include LIBUSB_GLOBAL_INCLUDE_FILE #else +#include #include #include #include @@ -50,6 +51,21 @@ #define IOUSB(a) a #endif +struct usb_product_info { + TAILQ_ENTRY(usb_product_info) link; + int id; + char *desc; +}; + +struct usb_vendor_info { + TAILQ_ENTRY(usb_vendor_info) link; + TAILQ_HEAD(,usb_product_info) devs; + int id; + char *desc; +}; + +TAILQ_HEAD(usb_vendors, usb_vendor_info); + static libusb20_init_backend_t ugen20_init_backend; static libusb20_open_device_t ugen20_open_device; static libusb20_close_device_t ugen20_close_device; @@ -129,12 +145,16 @@ } static int -ugen20_enumerate(struct libusb20_device *pdev, const char *id) +ugen20_enumerate(struct libusb20_device *pdev, const char *id, + struct usb_vendors *uvendors) { const char *tmp = id; struct usb_device_descriptor ddesc; struct usb_device_info devinfo; + struct usb_vendor_info *vi; + struct usb_product_info *pi; uint32_t plugtime; + const char *vendor, *product; char buf[64]; int f; int error; @@ -210,12 +230,30 @@ pdev->parent_address = devinfo.udi_hubindex; pdev->parent_port = devinfo.udi_hubport; + vendor = devinfo.udi_vendor; + product = devinfo.udi_product; + if (uvendors != NULL) { + TAILQ_FOREACH(vi, uvendors, link) { + if (vi->id == pdev->ddesc.idVendor) { + vendor = vi->desc; + break; + } + } + if (vi != NULL) { + TAILQ_FOREACH(pi, &vi->devs, link) { + if (pi->id == pdev->ddesc.idProduct) { + product = pi->desc; + break; + } + } + } + } + /* generate a nice description for printout */ snprintf(pdev->usb_desc, sizeof(pdev->usb_desc), USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number, - pdev->device_address, devinfo.udi_product, - devinfo.udi_vendor, pdev->bus_number); + pdev->device_address, product, vendor, pdev->bus_number); error = 0; done: @@ -271,11 +309,117 @@ return (0); } +static struct usb_vendors * +load_vendors(void) +{ + const char *dbf; + FILE *db; + struct usb_vendor_info *cv; + struct usb_product_info *cd; + struct usb_vendors *usb_vendors; + char buf[1024], str[1024]; + char *ch; + int id, error; + + if ((dbf = getenv("USB_VENDOR_DATABASE")) == NULL) + dbf = "/usr/local/share/usbids/usb.ids"; + if ((db = fopen(dbf, "r")) == NULL) { + dbf = "/usr/share/misc/usb_vendors"; + if ((db = fopen(dbf, "r")) == NULL) + return (NULL); + } + usb_vendors = malloc(sizeof(*usb_vendors)); + TAILQ_INIT(usb_vendors); + cv = NULL; + cd = NULL; + error = 0; + + for (;;) { + if (fgets(buf, sizeof(buf), db) == NULL) + break; + + if ((ch = strchr(buf, '#')) != NULL) + *ch = '\0'; + ch = strchr(buf, '\0') - 1; + while (ch > buf && isspace(*ch)) + *ch-- = '\0'; + if (ch <= buf) + continue; + + /* Can't handle subvendor / subdevice entries yet */ + if (buf[0] == '\t' && buf[1] == '\t') + continue; + + /* Check for vendor entry */ + if (buf[0] != '\t' && sscanf(buf, "%04x %[^\n]", &id, str) == 2) { + if ((id == 0) || (strlen(str) < 1)) + continue; + if ((cv = malloc(sizeof(struct usb_vendor_info))) == NULL) { + error = 1; + break; + } + if ((cv->desc = strdup(str)) == NULL) { + free(cv); + error = 1; + break; + } + cv->id = id; + TAILQ_INIT(&cv->devs); + TAILQ_INSERT_TAIL(usb_vendors, cv, link); + continue; + } + + /* Check for device entry */ + if (buf[0] == '\t' && sscanf(buf + 1, "%04x %[^\n]", &id, str) == 2) { + if ((id == 0) || (strlen(str) < 1)) + continue; + if (cv == NULL) + continue; + if ((cd = malloc(sizeof(struct usb_product_info))) == NULL) { + error = 1; + break; + } + if ((cd->desc = strdup(str)) == NULL) { + free(cd); + error = 1; + break; + } + cd->id = id; + TAILQ_INSERT_TAIL(&cv->devs, cd, link); + continue; + } + } + if (ferror(db)) + error = 1; + + fclose(db); + /* cleanup */ + return (usb_vendors); +} + +static void +unload_vendors(struct usb_vendors *uvendors) +{ + struct usb_vendor_info *vi, *vitmp; + struct usb_product_info *pi, *pitmp; + + TAILQ_FOREACH_SAFE(vi, uvendors, link, vitmp) { + TAILQ_FOREACH_SAFE(pi, &vi->devs, link, pitmp) { + free(pi->desc); + TAILQ_REMOVE(&vi->devs, pi, link); + } + free(vi->desc); + TAILQ_REMOVE(uvendors, vi, link); + } + free(uvendors); +} + static int ugen20_init_backend(struct libusb20_backend *pbe) { struct ugen20_urd_state state; struct libusb20_device *pdev; + struct usb_vendors *uvendors = NULL; memset(&state, 0, sizeof(state)); @@ -283,6 +427,7 @@ if (state.f < 0) return (LIBUSB20_ERROR_OTHER); + uvendors = load_vendors(); while (ugen20_readdir(&state) == 0) { if ((state.src[0] != 'u') || @@ -295,13 +440,15 @@ if (pdev == NULL) { continue; } - if (ugen20_enumerate(pdev, state.src + 4)) { + if (ugen20_enumerate(pdev, state.src + 4, uvendors)) { libusb20_dev_free(pdev); continue; } /* put the device on the backend list */ libusb20_be_enqueue_device(pbe, pdev); } + if (uvendors) + unload_vendors(uvendors); close(state.f); return (0); /* success */ }