summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/usb/ohci.c57
-rw-r--r--sys/dev/usb/ohcivar.h3
2 files changed, 44 insertions, 16 deletions
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index c1449fc..5b57ead 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -91,7 +91,7 @@ struct cfdriver ohci_cd = {
#ifdef OHCI_DEBUG
#define DPRINTF(x) if (ohcidebug) logprintf x
#define DPRINTFN(n,x) if (ohcidebug>(n)) logprintf x
-int ohcidebug = 0;
+int ohcidebug = 1;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
@@ -360,8 +360,8 @@ ohci_detach(sc, flags)
if (rv != 0)
return (rv);
- powerhook_disestablish(sc->sc_powerhook);
#if defined(__NetBSD__) || defined(__OpenBSD__)
+ powerhook_disestablish(sc->sc_powerhook);
shutdownhook_disestablish(sc->sc_shutdownhook);
#endif
/* free data structures XXX */
@@ -417,6 +417,7 @@ ohci_alloc_std(sc)
usbd_status err;
int i, offs;
usb_dma_t dma;
+ int s;
if (sc->sc_freetds == NULL) {
DPRINTFN(2, ("ohci_alloc_std: allocating chunk\n"));
@@ -436,6 +437,11 @@ ohci_alloc_std(sc)
sc->sc_freetds = std->nexttd;
memset(&std->td, 0, sizeof(ohci_td_t));
std->nexttd = NULL;
+
+ s = splusb();
+ ohci_hash_add_td(sc, std);
+ splx(s);
+
return (std);
}
@@ -444,6 +450,12 @@ ohci_free_std(sc, std)
ohci_softc_t *sc;
ohci_soft_td_t *std;
{
+ int s;
+
+ s = splusb();
+ ohci_hash_rem_td(sc, std);
+ splx(s);
+
std->nexttd = sc->sc_freetds;
sc->sc_freetds = std;
}
@@ -812,8 +824,8 @@ ohci_init(sc)
sc->sc_bus.methods = &ohci_bus_methods;
sc->sc_bus.pipe_size = sizeof(struct ohci_pipe);
- sc->sc_powerhook = powerhook_establish(ohci_power, sc);
#if defined(__NetBSD__) || defined(__OpenBSD__)
+ sc->sc_powerhook = powerhook_establish(ohci_power, sc);
sc->sc_shutdownhook = shutdownhook_establish(ohci_shutdown, sc);
#endif
@@ -1156,7 +1168,7 @@ ohci_process_done(sc, done)
if (ohcidebug > 10) {
DPRINTF(("ohci_process_done: TD done:\n"));
for (std = sdone; std; std = std->dnext)
- ohci_dump_td(std);
+ ohci_dump_td(sdone);
}
#endif
@@ -1164,7 +1176,16 @@ ohci_process_done(sc, done)
xfer = std->xfer;
stdnext = std->dnext;
DPRINTFN(5, ("ohci_process_done: std=%p xfer=%p hcpriv=%p\n",
- std, xfer, xfer->hcpriv));
+ std, xfer, (xfer? xfer->hcpriv:NULL)));
+ if (xfer == NULL || (std->flags & OHCI_TD_HANDLED)) {
+ /* xfer == NULL: There seems to be no xfer associated
+ * with this TD. It is tailp that happened to end up on
+ * the done queue.
+ * flags & OHCI_TD_HANDLED: The TD has already been
+ * handled by process_done and should not be done again.
+ */
+ continue;
+ }
cc = OHCI_TD_GET_CC(LE(std->td.td_flags));
usb_untimeout(ohci_timeout, xfer, xfer->timo_handle);
if (xfer->status == USBD_CANCELLED ||
@@ -1173,7 +1194,7 @@ ohci_process_done(sc, done)
xfer));
/* Handled by abort routine. */
} else if (cc == OHCI_CC_NO_ERROR) {
- DPRINTF(("ohci_process_done: no error, xfer=%p\n",
+ DPRINTFN(15, ("ohci_process_done: no error, xfer=%p\n",
xfer));
len = std->len;
if (std->td.td_cbp != 0)
@@ -1185,7 +1206,6 @@ ohci_process_done(sc, done)
xfer->status = USBD_NORMAL_COMPLETION;
usb_transfer_complete(xfer);
}
- ohci_hash_rem_td(sc, std);
ohci_free_std(sc, std);
} else {
/*
@@ -1202,15 +1222,22 @@ ohci_process_done(sc, done)
ohci_cc_strs[OHCI_TD_GET_CC(LE(std->td.td_flags))],
xfer));
- /* remove TDs */
+ /* Mark all the TDs in the done queue for the current
+ * xfer as handled
+ */
+ for (p = stdnext; p; p = p->dnext) {
+ if (p->xfer == xfer)
+ p->flags |= OHCI_TD_HANDLED;
+ }
+
+ /* remove TDs for the current xfer from the ED */
for (p = std; p->xfer == xfer; p = n) {
n = p->nexttd;
- ohci_hash_rem_td(sc, p);
ohci_free_std(sc, p);
}
-
- /* clear halt */
opipe->sed->ed.ed_headp = LE(p->physaddr);
+
+ /* XXX why is this being done? Why not OHCI_BLF too */
OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
if (cc == OHCI_CC_STALL)
@@ -1368,6 +1395,9 @@ ohci_waitintr(sc, xfer)
/* Timeout */
DPRINTF(("ohci_waitintr: timeout\n"));
+#ifdef OHCI_DEBUG
+ ohci_dumpregs(sc);
+#endif
xfer->status = USBD_TIMEOUT;
usb_transfer_complete(xfer);
/* XXX should free TD */
@@ -1491,10 +1521,6 @@ ohci_device_request(xfer)
/* Insert ED in schedule */
s = splusb();
- ohci_hash_add_td(sc, setup);
- if (len != 0)
- ohci_hash_add_td(sc, data);
- ohci_hash_add_td(sc, stat);
sed->ed.ed_tailp = LE(tail->physaddr);
opipe->tail.td = tail;
OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
@@ -1899,7 +1925,6 @@ ohci_abort_xfer_end(v)
#endif
for (; p->xfer == xfer; p = n) {
n = p->nexttd;
- ohci_hash_rem_td(sc, p);
ohci_free_std(sc, p);
}
diff --git a/sys/dev/usb/ohcivar.h b/sys/dev/usb/ohcivar.h
index 9d8005c..bd7000b 100644
--- a/sys/dev/usb/ohcivar.h
+++ b/sys/dev/usb/ohcivar.h
@@ -57,6 +57,7 @@ typedef struct ohci_soft_td {
u_int16_t flags;
#define OHCI_CALL_DONE 0x0001
#define OHCI_ADD_LEN 0x0002
+#define OHCI_TD_HANDLED 0x0004 /* signal process_done has seen it */
} ohci_soft_td_t;
#define OHCI_STD_SIZE ((sizeof (struct ohci_soft_td) + OHCI_TD_ALIGN - 1) / OHCI_TD_ALIGN * OHCI_TD_ALIGN)
#define OHCI_STD_CHUNK 128
@@ -106,8 +107,10 @@ typedef struct ohci_softc {
char sc_vendor[16];
int sc_id_vendor;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
void *sc_powerhook;
void *sc_shutdownhook; /* cookie from shutdown hook */
+#endif
device_ptr_t sc_child;
} ohci_softc_t;
OpenPOWER on IntegriCloud