svn commit: r196167 - stable/7/sys/dev/usb

Nick Hibma n_hibma at FreeBSD.org
Thu Aug 13 07:21:25 UTC 2009


Author: n_hibma
Date: Thu Aug 13 07:21:24 2009
New Revision: 196167
URL: http://svn.freebsd.org/changeset/base/196167

Log:
  Restart the controller if it has halted. Restarting it makes the USB
  tree functional again (without reconnecting the devices, mind you).
  
  On my laptop there is probably a short somewhere on the motherboard and
  once in a while the host controller halts.

Modified:
  stable/7/sys/dev/usb/uhci.c

Modified: stable/7/sys/dev/usb/uhci.c
==============================================================================
--- stable/7/sys/dev/usb/uhci.c	Thu Aug 13 07:19:43 2009	(r196166)
+++ stable/7/sys/dev/usb/uhci.c	Thu Aug 13 07:21:24 2009	(r196167)
@@ -1205,20 +1205,55 @@ uhci_intr1(uhci_softc_t *sc)
 		       device_get_nameunit(sc->sc_bus.bdev));
 	}
 	if (status & UHCI_STS_HCH) {
-		/* no acknowledge needed */
 		if (!sc->sc_dying) {
+			ack |= UHCI_STS_HCH;
 			printf("%s: host controller halted\n",
-			    device_get_nameunit(sc->sc_bus.bdev));
-#ifdef USB_DEBUG
-			uhci_dump_all(sc);
-#endif
+			       device_get_nameunit(sc->sc_bus.bdev));
 		}
-		sc->sc_dying = 1;
 	}
 
 	if (!ack)
 		return (0);	/* nothing to acknowledge */
-	UWRITE2(sc, UHCI_STS, ack); /* acknowledge the ints */
+
+	UWRITE2(sc, UHCI_STS, ack & ~UHCI_STS_HCH); /* acknowledge the ints */
+
+	if (ack & UHCI_STS_HCH) {
+		/* Restart the controller, by Manuel Bouyer */
+		sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM);
+		sc->sc_saved_sof = UREAD1(sc, UHCI_SOF);
+
+		sc->sc_bus.use_polling++;
+		uhci_run(sc, 0); /* stop the controller */
+		UWRITE2(sc, UHCI_INTR, 0); /* disable intrs */
+
+		uhci_globalreset(sc);
+		uhci_reset(sc);
+
+		/* restore saved state */
+		UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0));
+		UWRITE2(sc, UHCI_FRNUM, sc->sc_saved_frnum);
+		UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof);
+
+		UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
+			UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* re-enable intrs */
+		UHCICMD(sc, UHCI_CMD_MAXP);
+
+		uhci_run(sc, 1); /* and start traffic again */
+		sc->sc_bus.use_polling--;
+
+		if (UREAD2(sc, UHCI_STS) & UHCI_STS_HCH) {
+			printf("%s: host controller couldn't be restarted\n",
+			       device_get_nameunit(sc->sc_bus.bdev));
+#ifdef USB_DEBUG
+			uhci_dump_all(sc);
+#endif
+			sc->sc_dying = 1;
+			return (0);
+		}
+
+		printf("%s: host controller restarted\n",
+		       device_get_nameunit(sc->sc_bus.bdev));
+	}
 
 	sc->sc_bus.no_intrs++;
 	usb_schedsoftintr(&sc->sc_bus);


More information about the svn-src-stable mailing list