diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c index e30218315bb8..77a2ead48475 100644 --- a/sys/dev/usb/uhub.c +++ b/sys/dev/usb/uhub.c @@ -93,6 +93,8 @@ Static void uhub_intr(usbd_xfer_handle, usbd_private_handle,usbd_status); #if defined(__FreeBSD__) Static bus_driver_added_t uhub_driver_added; Static bus_child_detached_t uhub_child_detached; +int uhub_child_location_str(device_t, device_t, char*, size_t); +int uhub_child_pnpinfo_str(device_t, device_t, char*, size_t); #endif @@ -112,6 +114,8 @@ CFATTACH_DECL(uhub_uhub, sizeof(struct uhub_softc), USB_DECLARE_DRIVER_INIT(uhub, DEVMETHOD(bus_driver_added, uhub_driver_added), DEVMETHOD(bus_child_detached, uhub_child_detached), + DEVMETHOD(bus_child_pnpinfo_str, uhub_child_pnpinfo_str), + DEVMETHOD(bus_child_location_str, uhub_child_location_str), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown) @@ -123,6 +127,8 @@ devclass_t uhubroot_devclass; Static device_method_t uhubroot_methods[] = { DEVMETHOD(device_probe, uhub_match), DEVMETHOD(device_attach, uhub_attach), + DEVMETHOD(bus_child_pnpinfo_str, uhub_child_pnpinfo_str), + DEVMETHOD(bus_child_location_str, uhub_child_location_str), /* detach is not allowed for a root hub */ DEVMETHOD(device_suspend, bus_generic_suspend), @@ -576,6 +582,107 @@ USB_DETACH(uhub) } #if defined(__FreeBSD__) +int +uhub_child_location_str(device_t cbdev, device_t child, char *buf, + size_t buflen) +{ + struct uhub_softc *sc = device_get_softc(cbdev); + usbd_device_handle devhub = sc->sc_hub; + usbd_device_handle dev; + int nports; + int port; + int i; + + nports = devhub->hub->hubdesc.bNbrPorts; + for (port = 0; port < nports; port++) { + dev = devhub->hub->ports[port].device; + if (dev && dev->subdevs) { + for (i = 0; dev->subdevs[i]; i++) { + if (dev->subdevs[i] == child) { + goto found_dev; + } + } + } + } + DPRINTFN(0,("uhub_child_location_str: device not on hub\n")); + buf[0] = '\0'; + return (0); + +found_dev: + if (dev->ifacenums == NULL) { + snprintf(buf, buflen, "port=%i", port); + } else { + snprintf(buf, buflen, "port=%i interface=%i", + port, dev->ifacenums[i]); + } + return (0); +} + +int +uhub_child_pnpinfo_str(device_t cbdev, device_t child, char *buf, + size_t buflen) +{ + struct uhub_softc *sc = device_get_softc(cbdev); + usbd_device_handle devhub = sc->sc_hub; + usbd_device_handle dev; + usb_string_descriptor_t us; + struct usbd_interface *iface; + char serial[128]; + int nports; + int port; + int i, j, size; + int err; + + nports = devhub->hub->hubdesc.bNbrPorts; + for (port = 0; port < nports; port++) { + dev = devhub->hub->ports[port].device; + if (dev && dev->subdevs) { + for (i = 0; dev->subdevs[i]; i++) { + if (dev->subdevs[i] == child) { + goto found_dev; + } + } + } + } + DPRINTFN(0,("uhub_child_pnpinfo_str: device not on hub\n")); + buf[0] = '\0'; + return (0); + +found_dev: + j = 0; + if (dev->ddesc.iSerialNumber != 0) { + err = usbd_get_string_desc(dev, dev->ddesc.iSerialNumber, 0, + &us, &size); + if (err == 0) { + do { + serial[j] = UGETW(us.bString[j]); + j++; + } while (j < ((us.bLength - 2) / 2)); + } + } + serial[j] = '\0'; + if (dev->ifacenums == NULL) { + snprintf(buf, buflen, "vendor=0x%04x product=0x%04x " + "devclass=0x%02x devsubclass=0x%02x " + "sernum=\"%s\"", + UGETW(dev->ddesc.idVendor), UGETW(dev->ddesc.idProduct), + dev->ddesc.bDeviceClass, dev->ddesc.bDeviceSubClass, + serial); + } else { + iface = &dev->ifaces[dev->ifacenums[i]]; + snprintf(buf, buflen, "vendor=0x%04x product=0x%04x " + "devclass=0x%02x devsubclass=0x%02x " + "sernum=\"%s\" " + "intclass=0x%02x intsubclass=0x%02x", + UGETW(dev->ddesc.idVendor), UGETW(dev->ddesc.idProduct), + dev->ddesc.bDeviceClass, dev->ddesc.bDeviceSubClass, + serial, + iface->idesc->bInterfaceClass, + iface->idesc->bInterfaceSubClass); + } + return (0); +} + /* Called when a device has been detached from it */ Static void uhub_child_detached(device_t self, device_t child) diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c index a8025165cdd1..52e363d68053 100644 --- a/sys/dev/usb/usb_subr.c +++ b/sys/dev/usb/usb_subr.c @@ -849,6 +849,7 @@ usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev, int found, i, confi, nifaces; usbd_status err; device_ptr_t dv; + device_ptr_t *tmpdv; usbd_interface_handle ifaces[256]; /* 256 is the absolute max */ #if defined(__FreeBSD__) @@ -880,14 +881,20 @@ usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev, /* First try with device specific drivers. */ DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n")); + + dev->ifacenums = NULL; + dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT); + if (dev->subdevs == NULL) + return (USBD_NOMEM); + dev->subdevs[0] = bdev; + dev->subdevs[1] = 0; dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch); if (dv) { - dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT); - if (dev->subdevs == NULL) - return (USBD_NOMEM); - dev->subdevs[0] = dv; - dev->subdevs[1] = 0; return (USBD_NORMAL_COMPLETION); + } else { + tmpdv = dev->subdevs; + dev->subdevs = NULL; + free(tmpdv, M_USB); } DPRINTF(("usbd_probe_and_attach: no device specific driver found\n")); @@ -927,6 +934,15 @@ usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev, #endif return (USBD_NOMEM); } + dev->ifacenums = malloc((nifaces) * sizeof(*dev->ifacenums), + M_USB,M_NOWAIT); + if (dev->ifacenums == NULL) { + free(tmpdv, M_USB); +#if defined(__FreeBSD__) + device_delete_child(parent, bdev); +#endif + return (USBD_NOMEM); + } found = 0; for (i = 0; i < nifaces; i++) { @@ -934,12 +950,14 @@ usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev, continue; /* interface already claimed */ uaa.iface = ifaces[i]; uaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber; + dev->subdevs[found] = bdev; + dev->subdevs[found + 1] = 0; + dev->ifacenums[found] = i; dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch); if (dv != NULL) { - dev->subdevs[found++] = dv; - dev->subdevs[found] = 0; ifaces[i] = 0; /* consumed */ + found++; #if defined(__FreeBSD__) /* create another child for the next iface */ @@ -952,6 +970,8 @@ usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev, device_set_ivars(bdev, &uaa); device_quiet(bdev); #endif + } else { + dev->subdevs[found] = 0; } } if (found != 0) { @@ -961,8 +981,11 @@ usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev, #endif return (USBD_NORMAL_COMPLETION); } - free(dev->subdevs, M_USB); - dev->subdevs = 0; + tmpdv = dev->subdevs; + dev->subdevs = NULL; + free(tmpdv, M_USB); + free(dev->ifacenums, M_USB); + dev->ifacenums = NULL; } /* No interfaces were attached in any of the configurations. */ @@ -976,14 +999,18 @@ usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev, uaa.usegeneric = 1; uaa.configno = UHUB_UNK_CONFIGURATION; uaa.ifaceno = UHUB_UNK_INTERFACE; + dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT); + if (dev->subdevs == 0) + return (USBD_NOMEM); + dev->subdevs[0] = bdev; + dev->subdevs[1] = 0; dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch); if (dv != NULL) { - dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT); - if (dev->subdevs == 0) - return (USBD_NOMEM); - dev->subdevs[0] = dv; - dev->subdevs[1] = 0; return (USBD_NORMAL_COMPLETION); + } else { + tmpdv = dev->subdevs; + dev->subdevs = 0; + free(tmpdv, M_USB); } /* @@ -1370,6 +1397,8 @@ usb_free_device(usbd_device_handle dev) free(dev->cdesc, M_USB); if (dev->subdevs != NULL) free(dev->subdevs, M_USB); + if (dev->ifacenums != NULL) + free(dev->ifacenums, M_USB); free(dev, M_USB); } diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h index ae2c092d436c..dafdc01b5e0f 100644 --- a/sys/dev/usb/usbdivar.h +++ b/sys/dev/usb/usbdivar.h @@ -150,6 +150,7 @@ struct usbd_device { const struct usbd_quirks *quirks; /* device quirks, always set */ struct usbd_hub *hub; /* only if this is a hub */ device_ptr_t *subdevs; /* sub-devices, 0 terminated */ + uint8_t *ifacenums; /* sub-device interfacenumbers */ }; struct usbd_interface {