Index: dev/usb/uhub.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/usb/uhub.c,v
retrieving revision 1.54
diff -u -r1.54 uhub.c
--- dev/usb/uhub.c	24 Aug 2003 17:55:55 -0000	1.54
+++ dev/usb/uhub.c	23 Mar 2004 07:36:46 -0000
@@ -93,6 +93,8 @@
 #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 @@
 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 @@
 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),
@@ -575,6 +581,106 @@
 }
 
 #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;
+	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);
+		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)
Index: dev/usb/usb_subr.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/usb/usb_subr.c,v
retrieving revision 1.62
diff -u -r1.62 usb_subr.c
--- dev/usb/usb_subr.c	20 Mar 2004 07:31:11 -0000	1.62
+++ dev/usb/usb_subr.c	23 Mar 2004 08:46:28 -0000
@@ -825,6 +825,7 @@
 	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__)
@@ -856,14 +857,20 @@
 
 	/* 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"));
@@ -903,6 +910,15 @@
 #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++) {
@@ -910,12 +926,14 @@
 				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 */
@@ -928,6 +946,8 @@
 				device_set_ivars(bdev, &uaa);
 				device_quiet(bdev);
 #endif
+			} else {
+				dev->subdevs[found] = 0;
 			}
 		}
 		if (found != 0) {
@@ -937,8 +957,11 @@
 #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. */
 
@@ -952,14 +975,18 @@
 	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);
 	}
 
 	/*
@@ -1343,6 +1373,8 @@
 		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);
 }
 
Index: dev/usb/usbdivar.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/usb/usbdivar.h,v
retrieving revision 1.40
diff -u -r1.40 usbdivar.h
--- dev/usb/usbdivar.h	15 Jul 2003 22:42:37 -0000	1.40
+++ dev/usb/usbdivar.h	22 Mar 2004 15:39:42 -0000
@@ -150,6 +150,7 @@
 	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 {
Index: kern/subr_bus.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/subr_bus.c,v
retrieving revision 1.140
diff -u -r1.140 subr_bus.c
--- kern/subr_bus.c	24 Feb 2004 19:31:30 -0000	1.140
+++ kern/subr_bus.c	23 Mar 2004 16:24:44 -0000
@@ -477,7 +477,25 @@
 static void
 devadded(device_t dev)
 {
-	devaddq("+", device_get_nameunit(dev), dev);
+	char *pnp = NULL;
+	char *tmp = NULL;
+
+	pnp = malloc(1024, M_BUS, M_NOWAIT);
+	if (pnp == NULL)
+		goto fail;
+	tmp = malloc(1024, M_BUS, M_NOWAIT);
+	if (tmp == NULL)
+		goto fail;
+	*pnp = '\0';
+	bus_child_pnpinfo_str(dev, pnp, 1024);
+	snprintf(tmp, 1024, "%s %s", device_get_nameunit(dev), pnp);
+	devaddq("+", tmp, dev);
+fail:
+	if (pnp != NULL)
+		free(pnp, M_BUS);
+	if (tmp != NULL)
+		free(tmp, M_BUS);
+	return;
 }
 
 /*
@@ -487,7 +505,25 @@
 static void
 devremoved(device_t dev)
 {
-	devaddq("-", device_get_nameunit(dev), dev);
+	char *pnp = NULL;
+	char *tmp = NULL;
+
+	pnp = malloc(1024, M_BUS, M_NOWAIT);
+	if (pnp == NULL)
+		goto fail;
+	tmp = malloc(1024, M_BUS, M_NOWAIT);
+	if (tmp == NULL)
+		goto fail;
+	*pnp = '\0';
+	bus_child_pnpinfo_str(dev, pnp, 1024);
+	snprintf(tmp, 1024, "%s %s", device_get_nameunit(dev), pnp);
+	devaddq("-", tmp, dev);
+fail:
+	if (pnp != NULL)
+		free(pnp, M_BUS);
+	if (tmp != NULL)
+		free(tmp, M_BUS);
+	return;
 }
 
 /*
