Add pnpinfo and location information to uhub. We also keep track of

the subdevices of uhub better now to accomplish this.

Submitted by: Bernd Walter
This commit is contained in:
Warner Losh 2004-06-30 02:56:24 +00:00
parent 37b4e4f471
commit 1c91aaf9ab
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=131305
3 changed files with 151 additions and 14 deletions

View File

@ -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)

View File

@ -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);
}

View File

@ -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 {