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);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to