PERFORCE change 130745 for review

Hans Petter Selasky hselasky at FreeBSD.org
Wed Dec 12 14:45:27 PST 2007


http://perforce.freebsd.org/chv.cgi?CH=130745

Change 130745 by hselasky at hselasky_laptop001 on 2007/12/12 22:45:07

	
	This commit is related to USB device side support.
	
	o In general: The code does almost the same like
	  before only that some functions have been
	  refactored.
	
	o Some small changes to support USB Device Mode.
	  See use of "USB_MODE_DEVICE" in the code.
	
	o Number of ports is now stored in "hub->nports".

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/uhub.c#25 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/uhub.c#25 (text+ko) ====

@@ -69,12 +69,17 @@
 #define	DPRINTF(...) do { } while (0)
 #endif
 
+struct uhub_current_state {
+	uint16_t port_change;
+	uint16_t port_status;
+};
+
 struct uhub_softc {
+	struct uhub_current_state sc_st;/* current state */
 	device_t sc_dev;		/* base device */
 	struct usbd_device *sc_udev;	/* USB device */
 	struct usbd_xfer *sc_xfer[2];	/* interrupt xfer */
 	uint8_t	sc_flags;
-#define	UHUB_FLAG_RUNNING 0x01
 #define	UHUB_FLAG_INTR_STALL 0x02
 	uint8_t	sc_name[32];
 };
@@ -179,7 +184,8 @@
 		 * event handler thread that we need
 		 * to be explored again:
 		 */
-		usb_needs_explore(sc->sc_udev);
+		usb_needs_explore(sc->sc_udev->bus,
+		    USB_BUS_EXPLORE_TREE);
 
 	case USBD_ST_SETUP:
 		if (sc->sc_flags & UHUB_FLAG_INTR_STALL) {
@@ -200,225 +206,306 @@
 	}
 }
 
-static struct usbd_device *
-uhub_port_to_sub_device(struct usbd_device *udev, struct usbd_port *up)
-{
-	if ((udev == NULL) || (up == NULL)) {
-		/* be NULL safe */
-		return (NULL);
-	}
-	if (up->device_addr == USB_START_ADDR) {
-		/* nothing to do */
-		return (NULL);
-	}
-	return (udev->bus->devices[up->device_addr]);
-}
-
+/*------------------------------------------------------------------------*
+ *	uhub_explore_sub - subroutine
+ *
+ * Return values:
+ *    0: Success
+ * Else: A control transaction failed
+ *------------------------------------------------------------------------*/
 static usbd_status_t
-uhub_explore_sub(device_t dev, struct usbd_device *udev, struct usbd_port *up)
+uhub_explore_sub(struct uhub_softc *sc, struct usbd_port *up)
 {
+	struct usbd_bus *bus;
 	struct usbd_device *child;
-	uint8_t refcount = usb_driver_added_refcount;
-	usbd_status_t err = 0;
+	uint8_t refcount;
+	usbd_status_t err;
+
+	bus = sc->sc_udev->bus;
+	err = 0;
 
-	child = uhub_port_to_sub_device(udev, up);
+	/* get driver added refcount from USB bus */
+	refcount = bus->driver_added_refcount;
 
+	/* get device assosiated with the given port */
+	child = usbd_bus_port_get_device(bus, up);
 	if (child == NULL) {
 		/* nothing to do */
-		return (0);
+		goto done;
 	}
 	/* check if probe and attach should be done */
 
 	if (child->driver_added_refcount != refcount) {
 		child->driver_added_refcount = refcount;
-		err = usbd_probe_and_attach(dev, child);
+		err = usbd_probe_and_attach(child,
+		    USB_IFACE_INDEX_ANY);
+		if (err) {
+			goto done;
+		}
+	}
+	/* start control transfer, if device mode */
+
+	if (child->flags.usb_mode == USB_MODE_DEVICE) {
+		usbd_default_transfer_setup(child);
 	}
 	/* if a HUB becomes present, do a recursive HUB explore */
 
 	if (child->hub) {
-		(child->hub->explore) (child);
+		err = (child->hub->explore) (child);
 	}
+done:
+	return (err);
+}
+
+/*------------------------------------------------------------------------*
+ *	uhub_read_port_status - factored out code
+ *------------------------------------------------------------------------*/
+static usbd_status_t
+uhub_read_port_status(struct uhub_softc *sc, uint8_t portno)
+{
+	usb_port_status_t ps;
+	usbd_status_t err;
+
+	err = usbreq_get_port_status(
+	    sc->sc_udev, &usb_global_lock, &ps, portno);
+
+	/* update status regardless of error */
+
+	sc->sc_st.port_status = UGETW(ps.wPortStatus);
+	sc->sc_st.port_change = UGETW(ps.wPortChange);
+
+	/* debugging print */
+
+	DPRINTF(sc, 3, "port %d, wPortStatus=0x%04x, "
+	    "wPortChange=0x%04x, err=%s\n",
+	    portno, sc->sc_st.port_status,
+	    sc->sc_st.port_change, usbd_errstr(err));
 	return (err);
 }
 
+/*------------------------------------------------------------------------*
+ *	uhub_reattach_port
+ *
+ * Returns:
+ *    0: Success
+ * Else: A control transaction failed
+ *------------------------------------------------------------------------*/
 static usbd_status_t
-uhub_explore(struct usbd_device *udev)
+uhub_reattach_port(struct uhub_softc *sc, uint8_t portno)
 {
-	usb_hub_descriptor_t *hd = &udev->hub->hubdesc;
-	struct uhub_softc *sc = udev->hub->hubsoftc;
 	struct usbd_device *child;
-	struct usbd_port *up;
+	struct usbd_device *udev;
 	usbd_status_t err;
-	uint16_t change;
-	uint16_t status;
-	uint8_t portno;
+	uint8_t timeout;
 	uint8_t speed;
-	uint8_t x;
+	uint8_t usb_mode;
+
+	DPRINTF(sc, 0, "reattaching port %d\n", portno);
+
+	err = 0;
+	timeout = 0;
+	udev = sc->sc_udev;
+	child = usbd_bus_port_get_device(udev->bus,
+	    udev->hub->ports + portno - 1);
+
+repeat:
+
+	/* first clear the port connection change bit */
+
+	err = usbreq_clear_port_feature
+	    (udev, &usb_global_lock, portno, UHF_C_PORT_CONNECTION);
+
+	if (err) {
+		goto error;
+	}
+	/* detach any existing devices */
+
+	if (child) {
+		usbd_detach_device(child, USB_IFACE_INDEX_ANY, 1);
+		usbd_free_device(child);
+		child = NULL;
+	}
+	/* get fresh status */
 
-	DPRINTF(sc, 10, "udev=%p addr=%d\n", udev, udev->address);
+	err = uhub_read_port_status(sc, portno);
+	if (err) {
+		goto error;
+	}
+	/* check if nothing is connected to the port */
 
-	if (!(sc->sc_flags & UHUB_FLAG_RUNNING)) {
-		return (USBD_NOT_STARTED);
+	if (!(sc->sc_st.port_status & UPS_CURRENT_CONNECT_STATUS)) {
+		goto error;
 	}
-	/* ignore hubs that are too deep */
-	if (udev->depth > USB_HUB_MAX_DEPTH) {
-		return (USBD_TOO_DEEP);
+	/* check if there is no power on the port and print a warning */
+
+	if (!(sc->sc_st.port_status & UPS_PORT_POWER)) {
+		DPRINTF(sc, 0, "WARNING: strange, connected port %d "
+		    "has no power\n", portno);
 	}
-	for (x = 0; x < hd->bNbrPorts; x++) {
-		up = udev->hub->ports + x;
-		portno = x + 1;
-		err = usbreq_get_port_status
-		    (udev, &usb_global_lock, &up->status, portno);
-		if (err) {
-			DPRINTF(sc, 0, "get port status failed, "
-			    "error=%s\n", usbd_errstr(err));
-			continue;
-		}
-		status = UGETW(up->status.wPortStatus);
-		change = UGETW(up->status.wPortChange);
-		DPRINTF(sc, 3, "port %d status 0x%04x 0x%04x\n",
-		    portno, status, change);
-		if (change & UPS_C_PORT_ENABLED) {
-			DPRINTF(sc, 0, "C_PORT_ENABLED 0x%x\n", change);
-			usbreq_clear_port_feature
-			    (udev, &usb_global_lock, portno, UHF_C_PORT_ENABLE);
-			if (change & UPS_C_CONNECT_STATUS) {
-				/*
-				 * ignore the port error if the device
-				 * vanished
-				 */
-			} else if (status & UPS_PORT_ENABLED) {
-				DPRINTF(sc, -1, "illegal enable change, "
-				    "port %d\n", portno);
-			} else {
-				/* port error condition */
-				if (up->restartcnt) {	/* no message first time */
-					DPRINTF(sc, -1, "port error, restarting "
-					    "port %d\n", portno);
-				}
-				if (up->restartcnt++ < USBD_RESTART_MAX) {
-					goto disconnect;
-				} else {
-					DPRINTF(sc, -1, "port error, giving up "
-					    "port %d\n", portno);
-				}
-			}
-		}
-		if (!(change & UPS_C_CONNECT_STATUS)) {
-			DPRINTF(sc, 3, "port=%d !C_CONNECT_"
-			    "STATUS\n", portno);
+	/* check if the device is in Host Mode */
+
+	if (!(sc->sc_st.port_status & UPS_PORT_MODE_DEVICE)) {
 
-			/* no status change, just do recursive explore */
-			err = uhub_explore_sub(sc->sc_dev, udev, up);
-			continue;
-		}
-		/* we have a connect status change, handle it */
+		DPRINTF(sc, 0, "Port %d is in Host Mode\n", portno);
 
-		DPRINTF(sc, 0, "status change hub=%d port=%d\n",
-		    udev->address, portno);
-		usbreq_clear_port_feature
-		    (udev, &usb_global_lock, portno, UHF_C_PORT_CONNECTION);
-		/*
-		 * usbreq_clear_port_feature (udev, &usb_global_lock,
-		 * portno, UHF_C_PORT_ENABLE);
-		 */
-		/*
-		 * If there is already a device on the port the change status
-		 * must mean that is has disconnected.  Looking at the
-		 * current connect status is not enough to figure this out
-		 * since a new unit may have been connected before we handle
-		 * the disconnect.
-		 */
-disconnect:
-		child = uhub_port_to_sub_device(udev, up);
-		if (child) {
-			/* disconnected */
-			DPRINTF(sc, 0, "device addr=%d disappeared "
-			    "on port %d\n", child->address,
-			    portno);
-			usbd_free_device(child, 1);
-			usbreq_clear_port_feature
-			    (udev, &usb_global_lock, portno, UHF_C_PORT_CONNECTION);
-		}
-		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
-			/* nothing connected, just ignore it */
-			DPRINTF(sc, 3, "port=%d !CURRENT_CONNECT_STATUS\n",
-			    portno);
-			continue;
-		}
-		/* connected */
+		/* USB Host Mode */
 
-		if (!(status & UPS_PORT_POWER)) {
-			DPRINTF(sc, -1, "strange, connected port %d "
-			    "has no power\n", portno);
-		}
 		/* wait for maximum device power up time */
+
 		usbd_delay_ms(udev, USB_PORT_POWERUP_DELAY);
 
 		/* reset port, which implies enabling it */
+
 		err = usbreq_reset_port
-		    (udev, &usb_global_lock, &up->status, portno);
+		    (udev, &usb_global_lock, portno);
 
 		if (err) {
 			DPRINTF(sc, -1, "port %d reset "
 			    "failed, error=%s\n",
 			    portno, usbd_errstr(err));
-			continue;
+			goto error;
 		}
 		/* get port status again, it might have changed during reset */
-		err = usbreq_get_port_status
-		    (udev, &usb_global_lock, &up->status, portno);
 
+		err = uhub_read_port_status(sc, portno);
 		if (err) {
-			DPRINTF(sc, 0, "get port status failed, "
-			    "error=%s\n", usbd_errstr(err));
-			continue;
+			goto error;
+		}
+		/* check if something changed during port reset */
+
+		if ((sc->sc_st.port_change & UPS_C_CONNECT_STATUS) ||
+		    (!(sc->sc_st.port_status & UPS_CURRENT_CONNECT_STATUS))) {
+			if (timeout) {
+				DPRINTF(sc, -1, "giving up port reset "
+				    "- device vanished!\n");
+				goto error;
+			}
+			timeout = 1;
+			goto repeat;
 		}
-		status = UGETW(up->status.wPortStatus);
-		change = UGETW(up->status.wPortChange);
-		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
-			/* nothing connected, just ignore it */
-			DPRINTF(sc, 1, "port %d, device disappeared "
-			    "after reset\n", portno);
-			continue;
+	} else {
+		DPRINTF(sc, 0, "Port %d is in Device Mode\n", portno);
+	}
+
+	/*
+	 * Figure out the device speed
+	 */
+	speed =
+	    (sc->sc_st.port_status & UPS_HIGH_SPEED) ? USB_SPEED_HIGH :
+	    (sc->sc_st.port_status & UPS_LOW_SPEED) ? USB_SPEED_LOW : USB_SPEED_FULL;
+
+	/*
+	 * Figure out the device mode
+	 *
+	 * NOTE: This part is currently FreeBSD specific.
+	 */
+	usb_mode =
+	    (sc->sc_st.port_status & UPS_PORT_MODE_DEVICE) ?
+	    USB_MODE_DEVICE : USB_MODE_HOST;
+
+	/* need to create a new child */
+
+	child = usbd_alloc_device(sc->sc_dev, udev->bus, udev,
+	    udev->depth + 1, portno - 1, portno, speed, usb_mode);
+	if (child == NULL) {
+		DPRINTF(sc, -1, "could not allocate new device!\n");
+		goto error;
+	}
+	return (0);			/* success */
+
+error:
+	if (child) {
+		usbd_detach_device(child, USB_IFACE_INDEX_ANY, 1);
+		usbd_free_device(child);
+		child = NULL;
+	}
+	if (err == 0) {
+		err = usbreq_clear_port_feature
+		    (sc->sc_udev, &usb_global_lock, portno, UHF_PORT_ENABLE);
+	}
+	if (err) {
+		DPRINTF(sc, -1, "device problem (%s), "
+		    "disabling port %d\n", usbd_errstr(err), portno);
+	}
+	return (err);
+}
+
+/*------------------------------------------------------------------------*
+ *	uhub_explore
+ *
+ * Returns:
+ *     0: Success
+ *  Else: Failure
+ *------------------------------------------------------------------------*/
+static usbd_status_t
+uhub_explore(struct usbd_device *udev)
+{
+	struct usbd_hub *hub;
+	struct uhub_softc *sc;
+	struct usbd_port *up;
+	usbd_status_t err;
+	uint8_t portno;
+	uint8_t x;
+
+	hub = udev->hub;
+	sc = hub->hubsoftc;
+
+	DPRINTF(sc, 10, "udev=%p addr=%d\n", udev, udev->address);
+
+	/* ignore hubs that are too deep */
+	if (udev->depth > USB_HUB_MAX_DEPTH) {
+		return (USBD_TOO_DEEP);
+	}
+	for (x = 0; x != hub->nports; x++) {
+		up = hub->ports + x;
+		portno = x + 1;
+
+		err = uhub_read_port_status(sc, portno);
+		if (err) {
+			/* most likely the HUB is gone */
+			break;
 		}
-		/* figure out device speed */
-		speed =
-		    (status & UPS_HIGH_SPEED) ? USB_SPEED_HIGH :
-		    (status & UPS_LOW_SPEED) ? USB_SPEED_LOW : USB_SPEED_FULL;
+		if (sc->sc_st.port_change & UPS_C_PORT_ENABLED) {
+			err = usbreq_clear_port_feature(
+			    udev, &usb_global_lock, portno, UHF_C_PORT_ENABLE);
+			if (err) {
+				/* most likely the HUB is gone */
+				break;
+			}
+			if (sc->sc_st.port_change & UPS_C_CONNECT_STATUS) {
+				/*
+				 * Ignore the port error if the device
+				 * has vanished !
+				 */
+			} else if (sc->sc_st.port_status & UPS_PORT_ENABLED) {
+				DPRINTF(sc, -1, "illegal enable change, "
+				    "port %d\n", portno);
+			} else {
 
-		/* get device info and set its address */
-		err = usbd_new_device(sc->sc_dev, udev->bus, udev,
-		    udev->depth + 1, speed, x, portno);
-		if (err == 0) {
-			err = uhub_explore_sub(sc->sc_dev, udev, up);
+				if (up->restartcnt == USBD_RESTART_MAX) {
+					/* XXX could try another speed ? */
+					DPRINTF(sc, -1, "port error, giving up "
+					    "port %d\n", portno);
+				} else {
+					sc->sc_st.port_change |= UPS_C_CONNECT_STATUS;
+					up->restartcnt++;
+				}
+			}
+		}
+		if (sc->sc_st.port_change & UPS_C_CONNECT_STATUS) {
+			err = uhub_reattach_port(sc, portno);
+			if (err) {
+				/* most likely the HUB is gone */
+				break;
+			}
 		}
+		err = uhub_explore_sub(sc, up);
 		if (err) {
-			DPRINTF(sc, -1, "usb_new_device failed, "
-			    "error=%s\n", usbd_errstr(err));
-			/* Avoid addressing problems by disabling. */
-			/*
-			 * usbreq_reset_port (udev, &usb_global_lock,
-			 * &up->status, portno);
-			 */
-
-			/*
-			 * The unit refused to accept a new address, or had
-			 * some other serious problem.  Since we cannot leave
-			 * at 0 we have to disable the port instead.
-			 */
-			DPRINTF(sc, -1, "device problem (%s), "
-			    "disabling port %d\n", usbd_errstr(err), portno);
-			usbreq_clear_port_feature
-			    (udev, &usb_global_lock, portno, UHF_PORT_ENABLE);
+			/* no device(s) present */
 			continue;
 		}
-		/*
-		 * The port setup succeeded, reset error count and do
-		 * recursive explore, if any:
-		 */
+		/* explore succeeded - reset restart counter */
 		up->restartcnt = 0;
-
 	}
 	return (USBD_NORMAL_COMPLETION);
 }
@@ -433,9 +520,8 @@
 		return (UMATCH_NONE);
 	}
 	/*
-	 * the subclass for hubs, is ignored,
-	 * because it is 0 for some
-	 * and 1 for others
+	 * The subclass for USB HUBs is ignored because it is 0 for some
+	 * and 1 for others.
 	 */
 
 	if ((uaa->iface == NULL) && (dd->bDeviceClass == UDCLASS_HUB)) {
@@ -484,18 +570,18 @@
 	DPRINTF(sc, 1, "depth=%d selfpowered=%d, parent=%p, "
 	    "parent->selfpowered=%d\n",
 	    udev->depth,
-	    udev->self_powered,
+	    udev->flags.self_powered,
 	    parent_hub,
 	    parent_hub ?
-	    parent_hub->self_powered : 0);
+	    parent_hub->flags.self_powered : 0);
 
 	if (udev->depth > USB_HUB_MAX_DEPTH) {
 		DPRINTF(sc, -1, "hub depth, %d, exceeded. HUB ignored!\n",
 		    USB_HUB_MAX_DEPTH);
 		goto error;
 	}
-	if (!udev->self_powered && parent_hub &&
-	    (!parent_hub->self_powered)) {
+	if (!udev->flags.self_powered && parent_hub &&
+	    (!parent_hub->flags.self_powered)) {
 		DPRINTF(sc, -1, "bus powered hub connected to "
 		    "bus powered hub. HUB ignored!\n");
 		goto error;
@@ -547,11 +633,11 @@
 	/* initialize HUB structure */
 	hub->hubsoftc = sc;
 	hub->explore = &uhub_explore;
-	hub->hubdesc = hubdesc;
+	hub->nports = hubdesc.bNbrPorts;
 	hub->hubudev = udev;
 
 	/* if self powered hub, give ports maximum current */
-	if (udev->self_powered) {
+	if (udev->flags.self_powered) {
 		hub->portpower = USB_MAX_POWER;
 	} else {
 		hub->portpower = USB_MIN_POWER;
@@ -599,11 +685,11 @@
 	pwrdly = ((hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR) +
 	    USB_EXTRA_POWER_UP_TIME);
 
-	for (x = 0; x < nports; x++) {
+	for (x = 0; x != nports; x++) {
 		/* set up data structures */
 		struct usbd_port *up = hub->ports + x;
 
-		up->device_addr = USB_START_ADDR;
+		up->device_index = 0;
 		up->restartcnt = 0;
 		portno = x + 1;
 
@@ -628,11 +714,7 @@
 
 	device_printf(dev, "%d port%s with %d "
 	    "removable, %s powered\n", nports, (nports != 1) ? "s" : "",
-	    removable, udev->self_powered ? "self" : "bus");
-
-	/* the usual exploration will finish the setup */
-
-	sc->sc_flags |= UHUB_FLAG_RUNNING;
+	    removable, udev->flags.self_powered ? "self" : "bus");
 
 	/* start the interrupt endpoint */
 
@@ -670,16 +752,17 @@
 	if (hub == NULL) {		/* must be partially working */
 		return (0);
 	}
-	for (x = 0; x < hub->hubdesc.bNbrPorts; x++) {
+	for (x = 0; x != hub->nports; x++) {
 
-		child = uhub_port_to_sub_device(sc->sc_udev, hub->ports + x);
+		child = usbd_bus_port_get_device(sc->sc_udev->bus, hub->ports + x);
 
 		/*
 		 * Subdevices are not freed, because the caller of
-		 * uhub_detach() will do that. The function we are calling
-		 * is NULL safe.
+		 * uhub_detach() will do that. The function we are
+		 * calling is NULL safe.
 		 */
-		usbd_free_device(child, 0);
+		usbd_detach_device(child, USB_IFACE_INDEX_ANY, 0);
+		usbd_free_device(child);
 	}
 
 	usbd_transfer_unsetup(sc->sc_xfer, 2);
@@ -696,59 +779,77 @@
 	return;
 }
 
+struct hub_result {
+	struct usbd_device *udev;
+	uint8_t	portno;
+	uint8_t	iface_index;
+};
+
+static void
+uhub_find_iface_index(struct usbd_hub *hub, device_t child,
+    struct hub_result *res)
+{
+	struct usbd_interface *iface;
+	struct usbd_device *udev;
+	uint8_t nports;
+	uint8_t x;
+	uint8_t i;
+
+	nports = hub->nports;
+	for (x = 0; x != nports; x++) {
+		udev = usbd_bus_port_get_device(hub->hubudev->bus,
+		    hub->ports + x);
+		if (!udev) {
+			continue;
+		}
+		if (udev->global_dev == child) {
+			res->iface_index = 0;
+			res->udev = udev;
+			res->portno = x + 1;
+			return;
+		}
+		for (i = 0; i != USB_MAX_INTERFACES; i++) {
+			iface = usbd_get_iface(udev, i);
+			if (iface &&
+			    (iface->subdev == child)) {
+				res->iface_index = i;
+				res->udev = udev;
+				res->portno = x + 1;
+				return;
+			}
+		}
+	}
+	res->iface_index = 0;
+	res->udev = NULL;
+	res->portno = 0;
+	return;
+}
+
 static int
 uhub_child_location_string(device_t parent, device_t child,
     char *buf, size_t buflen)
 {
 	struct uhub_softc *sc = device_get_softc(parent);
 	struct usbd_hub *hub = sc->sc_udev->hub;
-	struct usbd_device *udev;
-	uint8_t x;
-	uint8_t nports;
-	uint8_t iface_index;
+	struct hub_result res;
 
 	mtx_lock(&usb_global_lock);
-
-	nports = hub->hubdesc.bNbrPorts;
-	for (x = 0; x < nports; x++) {
-		udev = uhub_port_to_sub_device(sc->sc_udev, hub->ports + x);
-		if (udev) {
-			device_t *subdev =
-			&udev->subdevs[0];
-			device_t *subdev_end =
-			&udev->subdevs_end[0];
-
-			iface_index = 0;
-
-			while (subdev < subdev_end) {
-				if (subdev[0] == child) {
-					goto found;
-				}
-				subdev++;
-				iface_index++;
-			}
+	uhub_find_iface_index(hub, child, &res);
+	if (!res.udev) {
+		DPRINTF(sc, 0, "device not on hub\n");
+		if (buflen) {
+			buf[0] = '\0';
 		}
+		goto done;
 	}
-
-	mtx_unlock(&usb_global_lock);
-
-	DPRINTF(sc, 0, "device not on hub\n");
-
-	if (buflen) {
-		buf[0] = '\0';
-	}
-	return (0);
-
-
-found:
-
-	if (udev->probed == USBD_PROBED_IFACE_AND_FOUND) {
+	if (res.udev->probed == USBD_PROBED_IFACE_AND_FOUND) {
 		snprintf(buf, buflen, "port=%i interface=%i",
-		    x + 1, iface_index);
+		    res.portno, res.iface_index);
 	} else {
-		snprintf(buf, buflen, "port=%i", x + 1);
+		snprintf(buf, buflen, "port=%i", res.portno);
 	}
 
+done:
 	mtx_unlock(&usb_global_lock);
 
 	return (0);
@@ -761,71 +862,44 @@
 	struct uhub_softc *sc = device_get_softc(parent);
 	struct usbd_hub *hub = sc->sc_udev->hub;
 	struct usbd_interface *iface;
-	struct usbd_device *udev;
-	uint8_t x;
-	uint8_t nports;
-	uint8_t iface_index;
+	struct hub_result res;
 
 	mtx_lock(&usb_global_lock);
-
-	nports = hub->hubdesc.bNbrPorts;
-	for (x = 0; x < nports; x++) {
-		udev = uhub_port_to_sub_device(sc->sc_udev, hub->ports + x);
-		if (udev) {
-			device_t *subdev =
-			&udev->subdevs[0];
-			device_t *subdev_end =
-			&udev->subdevs_end[0];
-
-			iface_index = 0;
-
-			while (subdev < subdev_end) {
-				if (subdev[0] == child) {
-					goto found;
-				}
-				subdev++;
-				iface_index++;
-			}
+	uhub_find_iface_index(hub, child, &res);
+	if (!res.udev) {
+		DPRINTF(sc, 0, "device not on hub\n");
+		if (buflen) {
+			buf[0] = '\0';
 		}
+		goto done;
 	}
+	iface = usbd_get_iface(res.udev, res.iface_index);
 
-	mtx_unlock(&usb_global_lock);
-
-	DPRINTF(sc, 0, "device not on hub\n");
-
-	if (buflen) {
-		buf[0] = '\0';
-	}
-	return (0);
-
-found:
-
-	iface = usbd_get_iface(udev, iface_index);
-
-	if ((udev->probed == USBD_PROBED_IFACE_AND_FOUND) &&
+	if ((res.udev->probed == USBD_PROBED_IFACE_AND_FOUND) &&
 	    iface && iface->idesc) {
 		snprintf(buf, buflen, "vendor=0x%04x product=0x%04x "
 		    "devclass=0x%02x devsubclass=0x%02x "
 		    "sernum=\"%s\" "
 		    "intclass=0x%02x intsubclass=0x%02x",
-		    UGETW(udev->ddesc.idVendor),
-		    UGETW(udev->ddesc.idProduct),
-		    udev->ddesc.bDeviceClass,
-		    udev->ddesc.bDeviceSubClass,
-		    &udev->serial[0],
+		    UGETW(res.udev->ddesc.idVendor),
+		    UGETW(res.udev->ddesc.idProduct),
+		    res.udev->ddesc.bDeviceClass,
+		    res.udev->ddesc.bDeviceSubClass,
+		    res.udev->serial,
 		    iface->idesc->bInterfaceClass,
 		    iface->idesc->bInterfaceSubClass);
 	} else {
 		snprintf(buf, buflen, "vendor=0x%04x product=0x%04x "
 		    "devclass=0x%02x devsubclass=0x%02x "
 		    "sernum=\"%s\"",
-		    UGETW(udev->ddesc.idVendor),
-		    UGETW(udev->ddesc.idProduct),
-		    udev->ddesc.bDeviceClass,
-		    udev->ddesc.bDeviceSubClass,
-		    &udev->serial[0]);
+		    UGETW(res.udev->ddesc.idVendor),
+		    UGETW(res.udev->ddesc.idProduct),
+		    res.udev->ddesc.bDeviceClass,
+		    res.udev->ddesc.bDeviceSubClass,
+		    res.udev->serial);
 	}
 
+done:
 	mtx_unlock(&usb_global_lock);
 
 	return (0);


More information about the p4-projects mailing list