Module Name:    src
Committed By:   skrll
Date:           Sat Jan  2 14:04:41 UTC 2016

Modified Files:
        src/sys/dev/usb [nick-nhusb]: uhub.c

Log Message:
Generalise the hub status change notification and registering of
pending changes while exploring.

Notifications could be lost before


To generate a diff of this commit:
cvs rdiff -u -r1.126.2.17 -r1.126.2.18 src/sys/dev/usb/uhub.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/usb/uhub.c
diff -u src/sys/dev/usb/uhub.c:1.126.2.17 src/sys/dev/usb/uhub.c:1.126.2.18
--- src/sys/dev/usb/uhub.c:1.126.2.17	Sat Jan  2 13:54:38 2016
+++ src/sys/dev/usb/uhub.c	Sat Jan  2 14:04:41 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: uhub.c,v 1.126.2.17 2016/01/02 13:54:38 skrll Exp $	*/
+/*	$NetBSD: uhub.c,v 1.126.2.18 2016/01/02 14:04:41 skrll Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $	*/
 /*	$OpenBSD: uhub.c,v 1.86 2015/06/29 18:27:40 mpi Exp $ */
 
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.126.2.17 2016/01/02 13:54:38 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.126.2.18 2016/01/02 14:04:41 skrll Exp $");
 
 #include <sys/param.h>
 
@@ -103,13 +103,13 @@ struct uhub_softc {
 	int			sc_proto;	/* device protocol */
 	struct usbd_pipe *	sc_ipipe;	/* interrupt pipe */
 
-	/* XXX second buffer needed because we can't suspend pipes yet */
+	kmutex_t		sc_lock;
+
 	uint8_t			*sc_statusbuf;
 	uint8_t			*sc_statuspend;
 	uint8_t			*sc_status;
 	size_t			sc_statuslen;
 	int			sc_explorepending;
-	int		sc_isehciroothub; /* see comment in uhub_intr() */
 
 	u_char			sc_running;
 };
@@ -364,8 +364,9 @@ uhub_attach(device_t parent, device_t se
 	sc->sc_status = kmem_alloc(sc->sc_statuslen, KM_SLEEP);
 	if (!sc->sc_status)
 		goto bad;
-	if (device_is_a(device_parent(device_parent(sc->sc_dev)), "ehci"))
-		sc->sc_isehciroothub = 1;
+
+	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
+	memset(sc->sc_statuspend, 0, sc->sc_statuslen);
 
 	/* force initial scan */
 	memset(sc->sc_status, 0xff, sc->sc_statuslen);
@@ -780,9 +781,7 @@ uhub_explore(struct usbd_device *dev)
 				up->up_dev->ud_hub->uh_explore(up->up_dev);
 		}
 	}
-	/* enable status change notifications again */
-	if (!sc->sc_isehciroothub)
-		memset(sc->sc_status, 0, sc->sc_statuslen);
+	mutex_enter(&sc->sc_lock);
 	sc->sc_explorepending = 0;
 	for (int i = 0; i < sc->sc_statuslen; i++) {
 		if (sc->sc_statuspend[i] != 0) {
@@ -793,6 +792,8 @@ uhub_explore(struct usbd_device *dev)
 			break;
 		}
 	}
+	mutex_exit(&sc->sc_lock);
+
 	return USBD_NORMAL_COMPLETION;
 }
 
@@ -930,33 +931,36 @@ uhub_intr(struct usbd_xfer *xfer, void *
 	if (status == USBD_STALLED)
 		usbd_clear_endpoint_stall_async(sc->sc_ipipe);
 	else if (status == USBD_NORMAL_COMPLETION) {
-		int i;
+
+		mutex_enter(&sc->sc_lock);
+
+		DPRINTFN(5, "uhub%d: explore pending %d",
+		    device_unit(sc->sc_dev), sc->sc_explorepending, 0, 0);
 
 		/* merge port bitmap into pending interrupts list */
-		for (i = 0; i < sc->sc_statuslen; i++)
+		for (size_t i = 0; i < sc->sc_statuslen; i++)
 			sc->sc_statuspend[i] |= sc->sc_statusbuf[i];
 
+			DPRINTFN(5, "uhub%d: pending/new ports "
+			    "[%d] %#x/%#x", device_unit(sc->sc_dev),
+			    i, sc->sc_statuspend[i], sc->sc_statusbuf[i]);
+		}
+
 		if (!sc->sc_explorepending) {
-			/*
-			 * Make sure the status is not overwritten in between.
-			 * XXX we should suspend the pipe instead
-			 */
 			sc->sc_explorepending = 1;
+
 			memcpy(sc->sc_status, sc->sc_statuspend,
 			    sc->sc_statuslen);
 			memset(sc->sc_statuspend, 0, sc->sc_statuslen);
-			DPRINTFN(5, "uhub%d: exploring ports %02x",
-			    device_unit(sc->sc_dev), *sc->sc_status, 0, 0);
+
+			for (size_t i = 0; i < sc->sc_statuslen; i++) {
+				DPRINTFN(5, "uhub%d: exploring ports "
+				    "[%d] %#x", device_unit(sc->sc_dev),
+				    i, sc->sc_status[i], 0);
+			}
+
 			usb_needs_explore(sc->sc_hub);
 		}
+		mutex_exit(&sc->sc_lock);
 	}
-	/*
-	 * XXX workaround for broken implementation of the interrupt
-	 * pipe in EHCI root hub emulation which doesn't resend
-	 * status change notifications until handled: force a rescan
-	 * of the ports we touched in the last run
-	 */
-	if (status == USBD_NORMAL_COMPLETION && sc->sc_explorepending &&
-	    sc->sc_isehciroothub)
-		usb_needs_explore(sc->sc_hub);
 }

Reply via email to