summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/uhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/uhci.c')
-rw-r--r--sys/dev/usb/uhci.c24
1 files changed, 23 insertions, 1 deletions
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index 3e5be72..9601da2 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -886,6 +886,22 @@ uhci_intr(arg)
int ack;
uhci_intr_info_t *ii;
+ /*
+ * It can happen that an interrupt will be delivered to
+ * us before the device has been fully attached and the
+ * softc struct has been configured. Usually this happens
+ * when kldloading the USB support as a module after the
+ * system has been booted. If we detect this condition,
+ * we need to squelch the unwanted interrupts until we're
+ * ready for them.
+ */
+ if (sc->sc_bus.bdev == NULL) {
+ UWRITE2(sc, UHCI_STS, 0xFFFF); /* ack pending interrupts */
+ uhci_run(sc, 0); /* stop the controller */
+ UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */
+ return(0);
+ }
+
#ifdef UHCI_DEBUG
if (uhcidebug > 15) {
DPRINTF(("%s: uhci_intr\n", USBDEVNAME(sc->sc_bus.bdev)));
@@ -1210,7 +1226,13 @@ uhci_run(sc, run)
run = run != 0;
s = splusb();
DPRINTF(("uhci_run: setting run=%d\n", run));
- UHCICMD(sc, run ? UHCI_CMD_RS : 0);
+ /*
+ * When activating the controller, set the MAXP bit.
+ * Certain high speed devices such as network adapters
+ * require this in order to avoid babble errors that
+ * can cause an endpoint stall.
+ */
+ UHCICMD(sc, run ? UHCI_CMD_RS|UHCI_CMD_MAXP : 0);
for(n = 0; n < 10; n++) {
running = !(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH);
/* return when we've entered the state we want */
OpenPOWER on IntegriCloud