summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorNathan Binkert <nate@cvs.openbsd.org>2003-07-08 13:19:10 +0000
committerNathan Binkert <nate@cvs.openbsd.org>2003-07-08 13:19:10 +0000
commite375f3615c7463097f3e178339aad0f6ec36c197 (patch)
tree5080b79ebe15758c7db466ea511c6083b4d9fad2 /sys/dev/usb
parent18791832a5c844c5d36cd0f7afaf4e92d40bcd09 (diff)
Sync USB code with NetBSD.
This includes numerous fixes and paves the way for usb 2.0 support.
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/ohci.c503
-rw-r--r--sys/dev/usb/ohcivar.h17
-rw-r--r--sys/dev/usb/uhci.c361
-rw-r--r--sys/dev/usb/uhcireg.h5
-rw-r--r--sys/dev/usb/uhcivar.h11
-rw-r--r--sys/dev/usb/uhub.c23
-rw-r--r--sys/dev/usb/usb.c222
-rw-r--r--sys/dev/usb/usb.h141
-rw-r--r--sys/dev/usb/usb_mem.c14
-rw-r--r--sys/dev/usb/usb_mem.h19
-rw-r--r--sys/dev/usb/usb_port.h111
-rw-r--r--sys/dev/usb/usb_subr.c98
-rw-r--r--sys/dev/usb/usbdi.c113
-rw-r--r--sys/dev/usb/usbdi.h67
-rw-r--r--sys/dev/usb/usbdi_util.c79
-rw-r--r--sys/dev/usb/usbdi_util.h8
-rw-r--r--sys/dev/usb/usbdivar.h27
17 files changed, 1248 insertions, 571 deletions
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index af43eb9cb11..26d96ef8793 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ohci.c,v 1.34 2003/05/19 04:17:53 nate Exp $ */
-/* $NetBSD: ohci.c,v 1.104 2001/09/28 23:57:21 augustss Exp $ */
+/* $OpenBSD: ohci.c,v 1.35 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: ohci.c,v 1.139 2003/02/22 05:24:16 tsutsui Exp $ */
/* $FreeBSD: src/sys/dev/usb/ohci.c,v 1.22 1999/11/17 22:33:40 n_hibma Exp $ */
/*
@@ -201,15 +201,15 @@ Static void ohci_device_isoc_done(usbd_xfer_handle);
Static usbd_status ohci_device_setintr(ohci_softc_t *sc,
struct ohci_pipe *pipe, int ival);
-Static int ohci_str(usb_string_descriptor_t *, int, char *);
+Static int ohci_str(usb_string_descriptor_t *, int, const char *);
Static void ohci_timeout(void *);
+Static void ohci_timeout_task(void *);
Static void ohci_rhsc_able(ohci_softc_t *, int);
-Static void ohci_rhsc_enable(void *sc);
+Static void ohci_rhsc_enable(void *);
Static void ohci_close_pipe(usbd_pipe_handle, ohci_soft_ed_t *);
Static void ohci_abort_xfer(usbd_xfer_handle, usbd_status);
-Static void ohci_abort_xfer_end(void *);
Static void ohci_device_clear_toggle(usbd_pipe_handle pipe);
Static void ohci_noop(usbd_pipe_handle pipe);
@@ -372,11 +372,15 @@ ohci_detach(struct ohci_softc *sc, int flags)
if (rv != 0)
return (rv);
+ usb_uncallout(sc->sc_tmo_rhsc, ohci_rhsc_enable, sc);
+
#if defined(__NetBSD__) || defined(__OpenBSD__)
powerhook_disestablish(sc->sc_powerhook);
shutdownhook_disestablish(sc->sc_shutdownhook);
#endif
+ usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */
+
/* free data structures XXX */
return (rv);
@@ -399,8 +403,8 @@ ohci_alloc_sed(ohci_softc_t *sc)
return (0);
for(i = 0; i < OHCI_SED_CHUNK; i++) {
offs = i * OHCI_SED_SIZE;
- sed = (ohci_soft_ed_t *)((char *)KERNADDR(&dma) +offs);
- sed->physaddr = DMAADDR(&dma) + offs;
+ sed = KERNADDR(&dma, offs);
+ sed->physaddr = DMAADDR(&dma, offs);
sed->next = sc->sc_freeeds;
sc->sc_freeeds = sed;
}
@@ -437,8 +441,8 @@ ohci_alloc_std(ohci_softc_t *sc)
s = splusb();
for(i = 0; i < OHCI_STD_CHUNK; i++) {
offs = i * OHCI_STD_SIZE;
- std = (ohci_soft_td_t *)((char *)KERNADDR(&dma) +offs);
- std->physaddr = DMAADDR(&dma) + offs;
+ std = KERNADDR(&dma, offs);
+ std->physaddr = DMAADDR(&dma, offs);
std->nexttd = sc->sc_freetds;
sc->sc_freetds = std;
}
@@ -485,7 +489,7 @@ ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
len = alen;
cur = sp;
- dataphys = DMAADDR(dma);
+ dataphys = DMAADDR(dma, 0);
dataphysend = OHCI_PAGE(dataphys + len - 1);
tdflags = htole32(
(rd ? OHCI_TD_IN : OHCI_TD_OUT) |
@@ -591,13 +595,15 @@ ohci_alloc_sitd(ohci_softc_t *sc)
OHCI_ITD_ALIGN, &dma);
if (err)
return (NULL);
+ s = splusb();
for(i = 0; i < OHCI_SITD_CHUNK; i++) {
offs = i * OHCI_SITD_SIZE;
- sitd = (ohci_soft_itd_t *)((char *)KERNADDR(&dma)+offs);
- sitd->physaddr = DMAADDR(&dma) + offs;
+ sitd = KERNADDR(&dma, offs);
+ sitd->physaddr = DMAADDR(&dma, offs);
sitd->nextitd = sc->sc_freeitds;
sc->sc_freeitds = sitd;
}
+ splx(s);
}
s = splusb();
@@ -628,6 +634,8 @@ ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd)
panic("ohci_free_sitd: sitd=%p not done", sitd);
return;
}
+ /* Warn double free */
+ sitd->isdone = 0;
#endif
s = splusb();
@@ -637,15 +645,6 @@ ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd)
splx(s);
}
-void
-ohci_reset(ohci_softc_t *sc)
-{
- ohci_shutdown(sc);
- /* disable all interrupts and then switch on all desired
- interrupts */
- OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
-}
-
usbd_status
ohci_init(ohci_softc_t *sc)
{
@@ -685,7 +684,7 @@ ohci_init(ohci_softc_t *sc)
OHCI_HCCA_ALIGN, &sc->sc_hccadma);
if (err)
return (err);
- sc->sc_hcca = (struct ohci_hcca *)KERNADDR(&sc->sc_hccadma);
+ sc->sc_hcca = KERNADDR(&sc->sc_hccadma, 0);
memset(sc->sc_hcca, 0, OHCI_HCCA_SIZE);
sc->sc_eintrs = OHCI_NORMAL_INTRS;
@@ -818,7 +817,7 @@ ohci_init(ohci_softc_t *sc)
/* The controller is now in SUSPEND state, we have 2ms to finish. */
/* Set up HC registers. */
- OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma));
+ OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0));
OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr);
OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr);
/* disable all interrupts and then switch on all desired interrupts */
@@ -874,6 +873,7 @@ ohci_init(ohci_softc_t *sc)
sc->sc_powerhook = powerhook_establish(ohci_power, sc);
sc->sc_shutdownhook = shutdownhook_establish(ohci_shutdown, sc);
#endif
+
usb_callout_init(sc->sc_tmo_rhsc);
return (USBD_NORMAL_COMPLETION);
@@ -919,12 +919,23 @@ ohci_allocx(struct usbd_bus *bus)
usbd_xfer_handle xfer;
xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
- if (xfer != NULL)
+ if (xfer != NULL) {
SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, xfer, next);
- else
- xfer = malloc(sizeof(*xfer), M_USB, M_NOWAIT);
- if (xfer != NULL)
- memset(xfer, 0, sizeof *xfer);
+#ifdef DIAGNOSTIC
+ if (xfer->busy_free != XFER_FREE) {
+ printf("ohci_allocx: xfer=%p not free, 0x%08x\n", xfer,
+ xfer->busy_free);
+ }
+#endif
+ } else {
+ xfer = malloc(sizeof(struct ohci_xfer), M_USB, M_NOWAIT);
+ }
+ if (xfer != NULL) {
+ memset(xfer, 0, sizeof (struct ohci_xfer));
+#ifdef DIAGNOSTIC
+ xfer->busy_free = XFER_BUSY;
+#endif
+ }
return (xfer);
}
@@ -933,6 +944,14 @@ ohci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer)
{
struct ohci_softc *sc = (struct ohci_softc *)bus;
+#ifdef DIAGNOSTIC
+ if (xfer->busy_free != XFER_BUSY) {
+ printf("ohci_freex: xfer=%p not busy, 0x%08x\n", xfer,
+ xfer->busy_free);
+ return;
+ }
+ xfer->busy_free = XFER_FREE;
+#endif
SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
}
@@ -989,7 +1008,7 @@ ohci_power(int why, void *v)
case PWR_RESUME:
sc->sc_bus.use_polling++;
/* Some broken BIOSes do not recover these values */
- OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma));
+ OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0));
OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr);
OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr);
if (sc->sc_intre)
@@ -1066,6 +1085,9 @@ ohci_intr(void *p)
{
ohci_softc_t *sc = p;
+ if (sc == NULL || sc->sc_dying)
+ return (0);
+
/* If we get an interrupt while polling, then just ignore it. */
if (sc->sc_bus.use_polling) {
#ifdef DIAGNOSTIC
@@ -1083,6 +1105,8 @@ ohci_intr1(ohci_softc_t *sc)
u_int32_t intrs, eintrs;
ohci_physaddr_t done;
+ DPRINTFN(14,("ohci_intr1: enter\n"));
+
/* In case the interrupt occurs before initialization has completed. */
if (sc == NULL || sc->sc_hcca == NULL) {
#ifdef DIAGNOSTIC
@@ -1098,6 +1122,7 @@ ohci_intr1(ohci_softc_t *sc)
intrs = OHCI_WDH;
if (done & OHCI_DONE_INTRS)
intrs |= OREAD4(sc, OHCI_INTERRUPT_STATUS);
+ sc->sc_hcca->hcca_done_head = 0;
} else
intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS);
@@ -1124,13 +1149,12 @@ ohci_intr1(ohci_softc_t *sc)
sc->sc_overrun_cnt = 0;
}
/* XXX do what */
- intrs &= ~OHCI_SO;
+ eintrs &= ~OHCI_SO;
}
if (eintrs & OHCI_WDH) {
ohci_add_done(sc, done &~ OHCI_DONE_INTRS);
- sc->sc_hcca->hcca_done_head = 0;
usb_schedsoftintr(&sc->sc_bus);
- intrs &= ~OHCI_WDH;
+ eintrs &= ~OHCI_WDH;
}
if (eintrs & OHCI_RD) {
printf("%s: resume detect\n", USBDEVNAME(sc->sc_bus.bdev));
@@ -1144,22 +1168,28 @@ ohci_intr1(ohci_softc_t *sc)
}
if (eintrs & OHCI_RHSC) {
ohci_rhsc(sc, sc->sc_intrxfer);
- intrs &= ~OHCI_RHSC;
-
/*
* Disable RHSC interrupt for now, because it will be
* on until the port has been reset.
*/
ohci_rhsc_able(sc, 0);
+ DPRINTFN(2, ("%s: rhsc interrupt disabled\n",
+ USBDEVNAME(sc->sc_bus.bdev)));
+
/* Do not allow RHSC interrupts > 1 per second */
- usb_callout(sc->sc_tmo_rhsc, hz, ohci_rhsc_enable, sc);
+ usb_callout(sc->sc_tmo_rhsc, hz, ohci_rhsc_enable, sc);
+ eintrs &= ~OHCI_RHSC;
}
sc->sc_bus.intr_context--;
- /* Block unprocessed interrupts. XXX */
- OWRITE4(sc, OHCI_INTERRUPT_DISABLE, intrs);
- sc->sc_eintrs &= ~intrs;
+ if (eintrs != 0) {
+ /* Block unprocessed interrupts. XXX */
+ OWRITE4(sc, OHCI_INTERRUPT_DISABLE, eintrs);
+ sc->sc_eintrs &= ~eintrs;
+ printf("%s: blocking intrs 0x%x\n",
+ USBDEVNAME(sc->sc_bus.bdev), eintrs);
+ }
return (1);
}
@@ -1181,8 +1211,15 @@ void
ohci_rhsc_enable(void *v_sc)
{
ohci_softc_t *sc = v_sc;
+ int s;
+ ohci_rhsc(sc, sc->sc_intrxfer);
+ DPRINTFN(2, ("%s: rhsc interrupt enabled\n",
+ USBDEVNAME(sc->sc_bus.bdev)));
+
+ s = splhardusb();
ohci_rhsc_able(sc, 1);
+ splx(s);
}
#ifdef OHCI_DEBUG
@@ -1250,7 +1287,11 @@ ohci_softintr(void *v)
ohci_soft_itd_t *sitd, *sidone, *sitdnext;
ohci_soft_td_t *std, *sdone, *stdnext;
usbd_xfer_handle xfer;
+ struct ohci_pipe *opipe;
int len, cc, s;
+ int i, j, actlen, iframes, uedir;
+
+ DPRINTFN(10,("ohci_softintr: enter\n"));
sc->sc_bus.intr_context++;
@@ -1261,7 +1302,7 @@ ohci_softintr(void *v)
sc->sc_sidone = NULL;
splx(s);
- DPRINTFN(10,("ohci_process_done: sdone=%p sidone=%p\n", sdone, sidone));
+ DPRINTFN(10,("ohci_softintr: sdone=%p sidone=%p\n", sdone, sidone));
#ifdef OHCI_DEBUG
if (ohcidebug > 10) {
@@ -1276,9 +1317,11 @@ ohci_softintr(void *v)
DPRINTFN(10, ("ohci_process_done: std=%p xfer=%p hcpriv=%p\n",
std, xfer, xfer ? xfer->hcpriv : 0));
if (xfer == NULL) {
- /* xfer == NULL: There seems to be no xfer associated
+ /*
+ * xfer == NULL: There seems to be no xfer associated
* with this TD. It is tailp that happened to end up on
* the done queue.
+ * Shouldn't happen, but some chips are broken(?).
*/
continue;
}
@@ -1302,7 +1345,9 @@ ohci_softintr(void *v)
xfer->actlen += len;
if (std->flags & OHCI_CALL_DONE) {
xfer->status = USBD_NORMAL_COMPLETION;
+ s = splusb();
usb_transfer_complete(xfer);
+ splx(s);
}
ohci_free_std(sc, std);
} else {
@@ -1312,8 +1357,7 @@ ohci_softintr(void *v)
* the endpoint.
*/
ohci_soft_td_t *p, *n;
- struct ohci_pipe *opipe =
- (struct ohci_pipe *)xfer->pipe;
+ opipe = (struct ohci_pipe *)xfer->pipe;
DPRINTFN(15,("ohci_process_done: error cc=%d (%s)\n",
OHCI_TD_GET_CC(le32toh(std->td.td_flags)),
@@ -1333,13 +1377,15 @@ ohci_softintr(void *v)
xfer->status = USBD_STALLED;
else
xfer->status = USBD_IOERROR;
+ s = splusb();
usb_transfer_complete(xfer);
+ splx(s);
}
}
#ifdef OHCI_DEBUG
if (ohcidebug > 10) {
- DPRINTF(("ohci_process_done: ITD done:\n"));
+ DPRINTF(("ohci_softintr: ITD done:\n"));
ohci_dump_itds(sidone);
}
#endif
@@ -1363,26 +1409,62 @@ ohci_softintr(void *v)
printf("ohci_softintr: sitd=%p is done\n", sitd);
sitd->isdone = 1;
#endif
- cc = OHCI_ITD_GET_CC(le32toh(sitd->itd.itd_flags));
- if (cc == OHCI_CC_NO_ERROR) {
- /* XXX compute length for input */
- struct ohci_pipe *opipe =
- (struct ohci_pipe *)xfer->pipe;
- if (sitd->flags & OHCI_CALL_DONE) {
- opipe->u.iso.inuse -= xfer->nframes;
- /* XXX update frlengths with actual length */
- /* XXX xfer->actlen = actlen; */
- xfer->status = USBD_NORMAL_COMPLETION;
- usb_transfer_complete(xfer);
+ if (sitd->flags & OHCI_CALL_DONE) {
+ ohci_soft_itd_t *next;
+
+ opipe = (struct ohci_pipe *)xfer->pipe;
+ opipe->u.iso.inuse -= xfer->nframes;
+ uedir = UE_GET_DIR(xfer->pipe->endpoint->edesc->
+ bEndpointAddress);
+ xfer->status = USBD_NORMAL_COMPLETION;
+ actlen = 0;
+ for (i = 0, sitd = xfer->hcpriv;;
+ sitd = next) {
+ next = sitd->nextitd;
+ if (OHCI_ITD_GET_CC(le32toh(sitd->
+ itd.itd_flags)) != OHCI_CC_NO_ERROR)
+ xfer->status = USBD_IOERROR;
+ /* For input, update frlengths with actual */
+ /* XXX anything necessary for output? */
+ if (uedir == UE_DIR_IN &&
+ xfer->status == USBD_NORMAL_COMPLETION) {
+ iframes = OHCI_ITD_GET_FC(le32toh(
+ sitd->itd.itd_flags));
+ for (j = 0; j < iframes; i++, j++) {
+ len = le16toh(sitd->
+ itd.itd_offset[j]);
+ len =
+ (OHCI_ITD_PSW_GET_CC(len) ==
+ OHCI_CC_NOT_ACCESSED) ? 0 :
+ OHCI_ITD_PSW_LENGTH(len);
+ xfer->frlengths[i] = len;
+ actlen += len;
+ }
+ }
+ if (sitd->flags & OHCI_CALL_DONE)
+ break;
+ ohci_free_sitd(sc, sitd);
}
- } else {
- /* XXX Do more */
- xfer->status = USBD_IOERROR;
+ ohci_free_sitd(sc, sitd);
+ if (uedir == UE_DIR_IN &&
+ xfer->status == USBD_NORMAL_COMPLETION)
+ xfer->actlen = actlen;
+
+ s = splusb();
usb_transfer_complete(xfer);
+ splx(s);
}
}
+#ifdef USB_USE_SOFTINTR
+ if (sc->sc_softwake) {
+ sc->sc_softwake = 0;
+ wakeup(&sc->sc_softwake);
+ }
+#endif /* USB_USE_SOFTINTR */
+
sc->sc_bus.intr_context--;
+ DPRINTFN(10,("ohci_softintr: done:\n"));
}
void
@@ -1426,7 +1508,7 @@ ohci_device_intr_done(usbd_xfer_handle xfer)
OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY);
if (xfer->flags & USBD_SHORT_XFER_OK)
data->td.td_flags |= htole32(OHCI_TD_R);
- data->td.td_cbp = htole32(DMAADDR(&xfer->dmabuf));
+ data->td.td_cbp = htole32(DMAADDR(&xfer->dmabuf, 0));
data->nexttd = tail;
data->td.td_nexttd = htole32(tail->physaddr);
data->td.td_be = htole32(le32toh(data->td.td_cbp) +
@@ -1472,7 +1554,7 @@ ohci_rhsc(ohci_softc_t *sc, usbd_xfer_handle xfer)
pipe = xfer->pipe;
opipe = (struct ohci_pipe *)pipe;
- p = KERNADDR(&xfer->dmabuf);
+ p = KERNADDR(&xfer->dmabuf, 0);
m = min(sc->sc_noport, xfer->length * 8 - 1);
memset(p, 0, xfer->length);
for (i = 1; i <= m; i++) {
@@ -1514,6 +1596,8 @@ ohci_waitintr(ohci_softc_t *sc, usbd_xfer_handle xfer)
xfer->status = USBD_IN_PROGRESS;
for (usecs = timo * 1000000 / hz; usecs > 0; usecs -= 1000) {
usb_delay_ms(&sc->sc_bus, 1);
+ if (sc->sc_dying)
+ break;
intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs;
DPRINTFN(15,("ohci_waitintr: 0x%04x\n", intrs));
#ifdef OHCI_DEBUG
@@ -1538,6 +1622,15 @@ void
ohci_poll(struct usbd_bus *bus)
{
ohci_softc_t *sc = (ohci_softc_t *)bus;
+#ifdef OHCI_DEBUG
+ static int last;
+ int new;
+ new = OREAD4(sc, OHCI_INTERRUPT_STATUS);
+ if (new != last) {
+ DPRINTFN(10,("ohci_poll: intrs=0x%04x\n", new));
+ last = new;
+ }
+#endif
if (OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs)
ohci_intr1(sc);
@@ -1607,11 +1700,11 @@ ohci_device_request(usbd_xfer_handle xfer)
std->td.td_flags |= htole32(OHCI_TD_TOGGLE_1);
}
- memcpy(KERNADDR(&opipe->u.ctl.reqdma), req, sizeof *req);
+ memcpy(KERNADDR(&opipe->u.ctl.reqdma, 0), req, sizeof *req);
setup->td.td_flags = htole32(OHCI_TD_SETUP | OHCI_TD_NOCC |
OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR);
- setup->td.td_cbp = htole32(DMAADDR(&opipe->u.ctl.reqdma));
+ setup->td.td_cbp = htole32(DMAADDR(&opipe->u.ctl.reqdma, 0));
setup->nexttd = next;
setup->td.td_nexttd = htole32(next->physaddr);
setup->td.td_be = htole32(le32toh(setup->td.td_cbp) + sizeof *req - 1);
@@ -1645,16 +1738,20 @@ ohci_device_request(usbd_xfer_handle xfer)
opipe->tail.td = tail;
OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
if (xfer->timeout && !sc->sc_bus.use_polling) {
- usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
+ usb_callout(xfer->timeout_handle, mstohz(xfer->timeout),
ohci_timeout, xfer);
}
splx(s);
-#if 0
- if (ohcidebug > 10) {
+#ifdef OHCI_DEBUG
+ if (ohcidebug > 20) {
delay(10000);
DPRINTF(("ohci_device_request: status=%x\n",
OREAD4(sc, OHCI_COMMAND_STATUS)));
+ ohci_dumpregs(sc);
+ printf("ctrl head:\n");
+ ohci_dump_ed(sc->sc_ctrl_head);
+ printf("sed:\n");
ohci_dump_ed(sed);
ohci_dump_tds(setup);
}
@@ -1676,6 +1773,8 @@ ohci_device_request(usbd_xfer_handle xfer)
void
ohci_add_ed(ohci_soft_ed_t *sed, ohci_soft_ed_t *head)
{
+ DPRINTFN(8,("ohci_add_ed: sed=%p head=%p\n", sed, head));
+
SPLUSBCHECK;
sed->next = head->next;
sed->ed.ed_nexted = head->ed.ed_nexted;
@@ -1694,7 +1793,7 @@ ohci_rem_ed(ohci_soft_ed_t *sed, ohci_soft_ed_t *head)
SPLUSBCHECK;
/* XXX */
- for (p = head; p == NULL && p->next != sed; p = p->next)
+ for (p = head; p != NULL && p->next != sed; p = p->next)
;
if (p == NULL)
panic("ohci_rem_ed: ED not found");
@@ -1790,15 +1889,32 @@ ohci_hash_find_itd(ohci_softc_t *sc, ohci_physaddr_t a)
void
ohci_timeout(void *addr)
{
+ struct ohci_xfer *oxfer = addr;
+ struct ohci_pipe *opipe = (struct ohci_pipe *)oxfer->xfer.pipe;
+ ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus;
+
+ DPRINTF(("ohci_timeout: oxfer=%p\n", oxfer));
+
+ if (sc->sc_dying) {
+ ohci_abort_xfer(&oxfer->xfer, USBD_TIMEOUT);
+ return;
+ }
+
+ /* Execute the abort in a process context. */
+ usb_init_task(&oxfer->abort_task, ohci_timeout_task, addr);
+ usb_add_task(oxfer->xfer.pipe->device, &oxfer->abort_task);
+}
+
+void
+ohci_timeout_task(void *addr)
+{
usbd_xfer_handle xfer = addr;
int s;
- DPRINTF(("ohci_timeout: xfer=%p\n", xfer));
+ DPRINTF(("ohci_timeout_task: xfer=%p\n", xfer));
s = splusb();
- xfer->device->bus->intr_context++;
ohci_abort_xfer(xfer, USBD_TIMEOUT);
- xfer->device->bus->intr_context--;
splx(s);
}
@@ -1815,19 +1931,19 @@ ohci_dump_td(ohci_soft_td_t *std)
{
char sbuf[128];
- bitmask_snprintf((int)le32toh(std->td.td_flags),
+ bitmask_snprintf((u_int32_t)le32toh(std->td.td_flags),
"\20\23R\24OUT\25IN\31TOG1\32SETTOGGLE",
sbuf, sizeof(sbuf));
- DPRINTF(("TD(%p) at %08lx: %s delay=%d ec=%d cc=%d\ncbp=0x%08lx "
- "nexttd=0x%08lx be=0x%08lx\n",
- std, (u_long)std->physaddr, sbuf,
- OHCI_TD_GET_DI(le32toh(std->td.td_flags)),
- OHCI_TD_GET_EC(le32toh(std->td.td_flags)),
- OHCI_TD_GET_CC(le32toh(std->td.td_flags)),
- (u_long)le32toh(std->td.td_cbp),
- (u_long)le32toh(std->td.td_nexttd),
- (u_long)le32toh(std->td.td_be)));
+ printf("TD(%p) at %08lx: %s delay=%d ec=%d cc=%d\ncbp=0x%08lx "
+ "nexttd=0x%08lx be=0x%08lx\n",
+ std, (u_long)std->physaddr, sbuf,
+ OHCI_TD_GET_DI(le32toh(std->td.td_flags)),
+ OHCI_TD_GET_EC(le32toh(std->td.td_flags)),
+ OHCI_TD_GET_CC(le32toh(std->td.td_flags)),
+ (u_long)le32toh(std->td.td_cbp),
+ (u_long)le32toh(std->td.td_nexttd),
+ (u_long)le32toh(std->td.td_be));
}
void
@@ -1835,20 +1951,20 @@ ohci_dump_itd(ohci_soft_itd_t *sitd)
{
int i;
- DPRINTF(("ITD(%p) at %08lx: sf=%d di=%d fc=%d cc=%d\n"
- "bp0=0x%08lx next=0x%08lx be=0x%08lx\n",
- sitd, (u_long)sitd->physaddr,
- OHCI_ITD_GET_SF(le32toh(sitd->itd.itd_flags)),
- OHCI_ITD_GET_DI(le32toh(sitd->itd.itd_flags)),
- OHCI_ITD_GET_FC(le32toh(sitd->itd.itd_flags)),
- OHCI_ITD_GET_CC(le32toh(sitd->itd.itd_flags)),
- (u_long)le32toh(sitd->itd.itd_bp0),
- (u_long)le32toh(sitd->itd.itd_nextitd),
- (u_long)le32toh(sitd->itd.itd_be)));
+ printf("ITD(%p) at %08lx: sf=%d di=%d fc=%d cc=%d\n"
+ "bp0=0x%08lx next=0x%08lx be=0x%08lx\n",
+ sitd, (u_long)sitd->physaddr,
+ OHCI_ITD_GET_SF(le32toh(sitd->itd.itd_flags)),
+ OHCI_ITD_GET_DI(le32toh(sitd->itd.itd_flags)),
+ OHCI_ITD_GET_FC(le32toh(sitd->itd.itd_flags)),
+ OHCI_ITD_GET_CC(le32toh(sitd->itd.itd_flags)),
+ (u_long)le32toh(sitd->itd.itd_bp0),
+ (u_long)le32toh(sitd->itd.itd_nextitd),
+ (u_long)le32toh(sitd->itd.itd_be));
for (i = 0; i < OHCI_ITD_NOFFSET; i++)
- DPRINTF(("offs[%d]=0x%04x ", i,
- (u_int)le16toh(sitd->itd.itd_offset[i])));
- DPRINTF(("\n"));
+ printf("offs[%d]=0x%04x ", i,
+ (u_int)le16toh(sitd->itd.itd_offset[i]));
+ printf("\n");
}
void
@@ -1863,21 +1979,21 @@ ohci_dump_ed(ohci_soft_ed_t *sed)
{
char sbuf[128], sbuf2[128];
- bitmask_snprintf((int)le32toh(sed->ed.ed_flags),
+ bitmask_snprintf((u_int32_t)le32toh(sed->ed.ed_flags),
"\20\14OUT\15IN\16LOWSPEED\17SKIP\20ISO",
sbuf, sizeof(sbuf));
- bitmask_snprintf((u_long)le32toh(sed->ed.ed_headp),
+ bitmask_snprintf((u_int32_t)le32toh(sed->ed.ed_headp),
"\20\1HALT\2CARRY", sbuf2, sizeof(sbuf2));
- DPRINTF(("ED(%p) at 0x%08lx: addr=%d endpt=%d maxp=%d %s\ntailp=0x%08lx "
- "headflags=%s headp=0x%08lx nexted=0x%08lx\n",
- sed, (u_long)sed->physaddr,
- OHCI_ED_GET_FA(le32toh(sed->ed.ed_flags)),
- OHCI_ED_GET_EN(le32toh(sed->ed.ed_flags)),
- OHCI_ED_GET_MAXP(le32toh(sed->ed.ed_flags)), sbuf,
- (u_long)le32toh(sed->ed.ed_tailp), sbuf2,
- (u_long)le32toh(sed->ed.ed_headp),
- (u_long)le32toh(sed->ed.ed_nexted)));
+ printf("ED(%p) at 0x%08lx: addr=%d endpt=%d maxp=%d flags=%s\n"
+ "tailp=0x%08lx headflags=%s headp=0x%08lx nexted=0x%08lx\n",
+ sed, (u_long)sed->physaddr,
+ OHCI_ED_GET_FA(le32toh(sed->ed.ed_flags)),
+ OHCI_ED_GET_EN(le32toh(sed->ed.ed_flags)),
+ OHCI_ED_GET_MAXP(le32toh(sed->ed.ed_flags)), sbuf,
+ (u_long)le32toh(sed->ed.ed_tailp), sbuf2,
+ (u_long)le32toh(sed->ed.ed_headp),
+ (u_long)le32toh(sed->ed.ed_nexted));
}
#endif
@@ -1902,6 +2018,9 @@ ohci_open(usbd_pipe_handle pipe)
DPRINTFN(1, ("ohci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
pipe, addr, ed->bEndpointAddress, sc->sc_addr));
+ if (sc->sc_dying)
+ return (USBD_IOERROR);
+
std = NULL;
sed = NULL;
@@ -1934,10 +2053,8 @@ ohci_open(usbd_pipe_handle pipe)
fmt |= OHCI_ED_DIR_OUT;
} else {
std = ohci_alloc_std(sc);
- if (std == NULL) {
- ohci_free_std(sc, std);
+ if (std == NULL)
goto bad1;
- }
opipe->tail.td = std;
tdphys = std->physaddr;
fmt = OHCI_ED_FORMAT_GEN | OHCI_ED_DIR_TD;
@@ -1945,8 +2062,8 @@ ohci_open(usbd_pipe_handle pipe)
sed->ed.ed_flags = htole32(
OHCI_ED_SET_FA(addr) |
OHCI_ED_SET_EN(ed->bEndpointAddress) |
- (dev->lowspeed ? OHCI_ED_SPEED : 0) | fmt |
- OHCI_ED_SET_MAXP(UGETW(ed->wMaxPacketSize)));
+ (dev->speed == USB_SPEED_LOW ? OHCI_ED_SPEED : 0) |
+ fmt | OHCI_ED_SET_MAXP(UGETW(ed->wMaxPacketSize)));
sed->ed.ed_headp = sed->ed.ed_tailp = htole32(tdphys);
switch (xfertype) {
@@ -2008,18 +2125,21 @@ ohci_close_pipe(usbd_pipe_handle pipe, ohci_soft_ed_t *head)
sed->ed.ed_flags |= htole32(OHCI_ED_SKIP);
if ((le32toh(sed->ed.ed_tailp) & OHCI_HEADMASK) !=
(le32toh(sed->ed.ed_headp) & OHCI_HEADMASK)) {
- ohci_physaddr_t td = le32toh(sed->ed.ed_headp);
ohci_soft_td_t *std;
- for (std = LIST_FIRST(&sc->sc_hash_tds[HASH(td)]);
- std != NULL;
- std = LIST_NEXT(std, hnext))
- if (std->physaddr == td)
- break;
+ std = ohci_hash_find_td(sc, le32toh(sed->ed.ed_headp));
printf("ohci_close_pipe: pipe not empty sed=%p hd=0x%x "
"tl=0x%x pipe=%p, std=%p\n", sed,
(int)le32toh(sed->ed.ed_headp),
(int)le32toh(sed->ed.ed_tailp),
pipe, std);
+#ifdef USB_DEBUG
+ usbd_dump_pipe(&opipe->pipe);
+#endif
+#ifdef OHCI_DEBUG
+ ohci_dump_ed(sed);
+ if (std)
+ ohci_dump_td(std);
+#endif
usb_delay_ms(&sc->sc_bus, 2);
if ((le32toh(sed->ed.ed_tailp) & OHCI_HEADMASK) !=
(le32toh(sed->ed.ed_headp) & OHCI_HEADMASK))
@@ -2027,6 +2147,8 @@ ohci_close_pipe(usbd_pipe_handle pipe, ohci_soft_ed_t *head)
}
#endif
ohci_rem_ed(sed, head);
+ /* Make sure the host controller is not touching this ED */
+ usb_delay_ms(&sc->sc_bus, 1);
splx(s);
ohci_free_sed(sc, opipe->sed);
}
@@ -2045,68 +2167,100 @@ void
ohci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
{
struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
- ohci_soft_ed_t *sed;
+ ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus;
+ ohci_soft_ed_t *sed = opipe->sed;
+ ohci_soft_td_t *p, *n;
+ ohci_physaddr_t headp;
+ int s, hit;
+
+ DPRINTF(("ohci_abort_xfer: xfer=%p pipe=%p sed=%p\n", xfer, opipe,
+ sed));
- DPRINTF(("ohci_abort_xfer: xfer=%p pipe=%p\n", xfer, opipe));
+ if (sc->sc_dying) {
+ /* If we're dying, just do the software part. */
+ s = splusb();
+ xfer->status = status; /* make software ignore it */
+ usb_uncallout(xfer->timeout_handle, ohci_timeout, xfer);
+ usb_transfer_complete(xfer);
+ splx(s);
+ }
- xfer->status = status;
+ if (xfer->device->bus->intr_context || !curproc)
+ panic("ohci_abort_xfer: not in process context");
+ /*
+ * Step 1: Make interrupt routine and hardware ignore xfer.
+ */
+ s = splusb();
+ xfer->status = status; /* make software ignore it */
usb_uncallout(xfer->timeout_handle, ohci_timeout, xfer);
-
- sed = opipe->sed;
+ splx(s);
DPRINTFN(1,("ohci_abort_xfer: stop ed=%p\n", sed));
sed->ed.ed_flags |= htole32(OHCI_ED_SKIP); /* force hardware skip */
-#if 1
- if (xfer->device->bus->intr_context) {
- /* We have no process context, so we can't use tsleep(). */
- usb_callout(xfer->pipe->abort_handle,
- hz / USB_FRAMES_PER_SECOND, ohci_abort_xfer_end, xfer);
- } else {
-#if defined(DIAGNOSTIC) && defined(__i386__) && defined(__FreeBSD__)
- KASSERT(intr_nesting_level == 0,
- ("ohci_abort_req in interrupt context"));
-#endif
- usb_delay_ms(opipe->pipe.device->bus, 1);
- ohci_abort_xfer_end(xfer);
- }
-#else
- delay(1000);
- ohci_abort_xfer_end(xfer);
-#endif
-}
-
-void
-ohci_abort_xfer_end(void *v)
-{
- usbd_xfer_handle xfer = v;
- struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
- ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus;
- ohci_soft_ed_t *sed;
- ohci_soft_td_t *p, *n;
- int s;
-
+ /*
+ * Step 2: Wait until we know hardware has finished any possible
+ * use of the xfer. Also make sure the soft interrupt routine
+ * has run.
+ */
+ usb_delay_ms(opipe->pipe.device->bus, 20); /* Hardware finishes in 1ms */
s = splusb();
+#ifdef USB_USE_SOFTINTR
+ sc->sc_softwake = 1;
+#endif /* USB_USE_SOFTINTR */
+ usb_schedsoftintr(&sc->sc_bus);
+#ifdef USB_USE_SOFTINTR
+ tsleep(&sc->sc_softwake, PZERO, "ohciab", 0);
+#endif /* USB_USE_SOFTINTR */
+ splx(s);
+ /*
+ * Step 3: Remove any vestiges of the xfer from the hardware.
+ * The complication here is that the hardware may have executed
+ * beyond the xfer we're trying to abort. So as we're scanning
+ * the TDs of this xfer we check if the hardware points to
+ * any of them.
+ */
+ s = splusb(); /* XXX why? */
p = xfer->hcpriv;
#ifdef DIAGNOSTIC
if (p == NULL) {
splx(s);
- printf("ohci_abort_xfer: hcpriv==0\n");
+ printf("ohci_abort_xfer: hcpriv is NULL\n");
return;
}
#endif
+#ifdef OHCI_DEBUG
+ if (ohcidebug > 1) {
+ DPRINTF(("ohci_abort_xfer: sed=\n"));
+ ohci_dump_ed(sed);
+ ohci_dump_tds(p);
+ }
+#endif
+ headp = le32toh(sed->ed.ed_headp) & OHCI_HEADMASK;
+ hit = 0;
for (; p->xfer == xfer; p = n) {
+ hit |= headp == p->physaddr;
n = p->nexttd;
ohci_free_std(sc, p);
}
+ /* Zap headp register if hardware pointed inside the xfer. */
+ if (hit) {
+ DPRINTFN(1,("ohci_abort_xfer: set hd=0x08%x, tl=0x%08x\n",
+ (int)p->physaddr, (int)le32toh(sed->ed.ed_tailp)));
+ sed->ed.ed_headp = htole32(p->physaddr); /* unlink TDs */
+ } else {
+ DPRINTFN(1,("ohci_abort_xfer: no hit\n"));
+ }
- sed = opipe->sed;
- DPRINTFN(2,("ohci_abort_xfer: set hd=%x, tl=%x\n",
- (int)p->physaddr, (int)le32toh(sed->ed.ed_tailp)));
- sed->ed.ed_headp = htole32(p->physaddr); /* unlink TDs */
+ /*
+ * Step 4: Turn on hardware again.
+ */
sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP); /* remove hardware skip */
+ /*
+ * Step 5: Execute callback.
+ */
usb_transfer_complete(xfer);
splx(s);
@@ -2121,7 +2275,7 @@ Static usb_device_descriptor_t ohci_devd = {
{0x00, 0x01}, /* USB version */
UDCLASS_HUB, /* class */
UDSUBCLASS_HUB, /* subclass */
- 0, /* protocol */
+ UDPROTO_FSHUB,
64, /* max packet */
{0},{0},{0x00,0x01}, /* device id */
1,2,0, /* string indicies */
@@ -2149,7 +2303,7 @@ Static usb_interface_descriptor_t ohci_ifcd = {
1,
UICLASS_HUB,
UISUBCLASS_HUB,
- 0,
+ UIPROTO_FSHUB,
0
};
@@ -2173,10 +2327,7 @@ Static usb_hub_descriptor_t ohci_hubd = {
};
Static int
-ohci_str(p, l, s)
- usb_string_descriptor_t *p;
- int l;
- char *s;
+ohci_str(usb_string_descriptor_t *p, int l, const char *s)
{
int i;
@@ -2240,7 +2391,7 @@ ohci_root_ctrl_start(usbd_xfer_handle xfer)
index = UGETW(req->wIndex);
if (len != 0)
- buf = KERNADDR(&xfer->dmabuf);
+ buf = KERNADDR(&xfer->dmabuf, 0);
#define C(x,y) ((x) | ((y) << 8))
switch(C(req->bRequest, req->bmRequestType)) {
@@ -2479,8 +2630,13 @@ ohci_root_ctrl_start(usbd_xfer_handle xfer)
DPRINTFN(5,("ohci_root_ctrl_transfer: reset port %d\n",
index));
OWRITE4(sc, port, UPS_RESET);
- for (i = 0; i < 10; i++) {
- usb_delay_ms(&sc->sc_bus, 10); /* XXX */
+ for (i = 0; i < 5; i++) {
+ usb_delay_ms(&sc->sc_bus,
+ USB_PORT_ROOT_RESET_DELAY);
+ if (sc->sc_dying) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
if ((OREAD4(sc, port) & UPS_RESET) == 0)
break;
}
@@ -2751,7 +2907,7 @@ ohci_device_bulk_start(usbd_xfer_handle xfer)
sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP);
OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
if (xfer->timeout && !sc->sc_bus.use_polling) {
- usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
+ usb_callout(xfer->timeout_handle, mstohz(xfer->timeout),
ohci_timeout, xfer);
}
@@ -2844,7 +3000,7 @@ ohci_device_intr_start(usbd_xfer_handle xfer)
OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY);
if (xfer->flags & USBD_SHORT_XFER_OK)
data->td.td_flags |= htole32(OHCI_TD_R);
- data->td.td_cbp = htole32(DMAADDR(&xfer->dmabuf));
+ data->td.td_cbp = htole32(DMAADDR(&xfer->dmabuf, 0));
data->nexttd = tail;
data->td.td_nexttd = htole32(tail->physaddr);
data->td.td_be = htole32(le32toh(data->td.td_cbp) + len - 1);
@@ -3052,7 +3208,7 @@ ohci_device_isoc_enter(usbd_xfer_handle xfer)
}
sitd = opipe->tail.itd;
- buf = DMAADDR(&xfer->dmabuf);
+ buf = DMAADDR(&xfer->dmabuf, 0);
bp0 = OHCI_PAGE(buf);
offs = OHCI_PAGE_OFFSET(buf);
nframes = xfer->nframes;
@@ -3130,6 +3286,7 @@ ohci_device_isoc_enter(usbd_xfer_handle xfer)
s = splusb();
opipe->tail.itd = nsitd;
+ sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP);
sed->ed.ed_tailp = htole32(nsitd->physaddr);
splx(s);
@@ -3157,7 +3314,7 @@ ohci_device_isoc_start(usbd_xfer_handle xfer)
#ifdef DIAGNOSTIC
if (xfer->status != USBD_IN_PROGRESS)
- printf("uhci_device_isoc_start: not in progress %p\n", xfer);
+ printf("ohci_device_isoc_start: not in progress %p\n", xfer);
#endif
/* XXX anything to do? */
@@ -3225,20 +3382,9 @@ ohci_device_isoc_abort(usbd_xfer_handle xfer)
void
ohci_device_isoc_done(usbd_xfer_handle xfer)
{
- struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
- ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus;
- ohci_soft_itd_t *sitd, *nsitd;
DPRINTFN(1,("ohci_device_isoc_done: xfer=%p\n", xfer));
- for (sitd = xfer->hcpriv;
- !(sitd->flags & OHCI_CALL_DONE);
- sitd = nsitd) {
- nsitd = sitd->nextitd;
- DPRINTFN(1,("ohci_device_isoc_done: free sitd=%p\n", sitd));
- ohci_free_sitd(sc, sitd);
- }
- ohci_free_sitd(sc, sitd);
xfer->hcpriv = NULL;
}
@@ -3265,13 +3411,8 @@ ohci_device_isoc_close(usbd_pipe_handle pipe)
{
struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
- int s;
DPRINTF(("ohci_device_isoc_close: pipe=%p\n", pipe));
-
- s = splusb();
- ohci_rem_ed(opipe->sed, sc->sc_isoc_head);
- splx(s);
ohci_close_pipe(pipe, sc->sc_isoc_head);
#ifdef DIAGNOSTIC
opipe->tail.itd->isdone = 1;
diff --git a/sys/dev/usb/ohcivar.h b/sys/dev/usb/ohcivar.h
index 396f9dacf65..96be803111a 100644
--- a/sys/dev/usb/ohcivar.h
+++ b/sys/dev/usb/ohcivar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: ohcivar.h,v 1.17 2002/05/07 18:29:18 nate Exp $ */
-/* $NetBSD: ohcivar.h,v 1.28 2001/09/28 23:57:21 augustss Exp $ */
+/* $OpenBSD: ohcivar.h,v 1.18 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: ohcivar.h,v 1.32 2003/02/22 05:24:17 tsutsui Exp $ */
/* $FreeBSD: src/sys/dev/usb/ohcivar.h,v 1.13 1999/11/17 22:33:41 n_hibma Exp $ */
/*
@@ -107,6 +107,10 @@ typedef struct ohci_softc {
u_int8_t sc_addr; /* device address */
u_int8_t sc_conf; /* device configuration */
+#ifdef USB_USE_SOFTINTR
+ char sc_softwake;
+#endif /* USB_USE_SOFTINTR */
+
ohci_soft_ed_t *sc_freeeds;
ohci_soft_td_t *sc_freetds;
ohci_soft_itd_t *sc_freeitds;
@@ -138,13 +142,14 @@ typedef struct ohci_softc {
char sc_dying;
} ohci_softc_t;
-void ohci_reset(ohci_softc_t *);
+struct ohci_xfer {
+ struct usbd_xfer xfer;
+ struct usb_task abort_task;
+};
+
usbd_status ohci_init(ohci_softc_t *);
int ohci_intr(void *);
#if defined(__NetBSD__) || defined(__OpenBSD__)
int ohci_detach(ohci_softc_t *, int);
int ohci_activate(device_ptr_t, enum devact);
#endif
-Static void ohci_rhsc_enable(void *sc);
-
-#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index 4091fa0527b..a22656d935b 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: uhci.c,v 1.28 2003/05/19 04:17:53 nate Exp $ */
-/* $NetBSD: uhci.c,v 1.142 2001/10/25 02:08:13 augustss Exp $ */
+/* $OpenBSD: uhci.c,v 1.29 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: uhci.c,v 1.172 2003/02/23 04:19:26 simonb Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $ */
/*
@@ -88,8 +88,6 @@
#define delay(d) DELAY(d)
#endif
-#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
-
#if defined(__OpenBSD__)
struct cfdriver uhci_cd = {
NULL, "uhci", DV_DULL
@@ -160,6 +158,7 @@ struct uhci_pipe {
};
Static void uhci_globalreset(uhci_softc_t *);
+Static usbd_status uhci_portreset(uhci_softc_t*, int);
Static void uhci_reset(uhci_softc_t *);
Static void uhci_shutdown(void *v);
Static void uhci_power(int, void *);
@@ -187,6 +186,7 @@ Static void uhci_idone(uhci_intr_info_t *);
Static void uhci_abort_xfer(usbd_xfer_handle, usbd_status status);
Static void uhci_timeout(void *);
+Static void uhci_timeout_task(void *);
Static void uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
Static void uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
Static void uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *);
@@ -249,7 +249,7 @@ Static void uhci_softintr(void *);
Static usbd_status uhci_device_request(usbd_xfer_handle xfer);
Static void uhci_add_intr(uhci_softc_t *, uhci_soft_qh_t *);
-Static void uhci_remove_intr(uhci_softc_t*, uhci_soft_qh_t*);
+Static void uhci_remove_intr(uhci_softc_t *, uhci_soft_qh_t *);
Static usbd_status uhci_device_setintr(uhci_softc_t *sc,
struct uhci_pipe *pipe, int ival);
@@ -273,11 +273,14 @@ void uhci_dump(void);
#define UBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \
BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
#define UWRITE1(sc, r, x) \
- do { UBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); } while (0)
+ do { UBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); \
+ } while (/*CONSTCOND*/0)
#define UWRITE2(sc, r, x) \
- do { UBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); } while (0)
+ do { UBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); \
+ } while (/*CONSTCOND*/0)
#define UWRITE4(sc, r, x) \
- do { UBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); } while (0)
+ do { UBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); \
+ } while (/*CONSTCOND*/0)
#define UREAD1(sc, r) (UBARR(sc), bus_space_read_1((sc)->iot, (sc)->ioh, (r)))
#define UREAD2(sc, r) (UBARR(sc), bus_space_read_2((sc)->iot, (sc)->ioh, (r)))
#define UREAD4(sc, r) (UBARR(sc), bus_space_read_4((sc)->iot, (sc)->ioh, (r)))
@@ -356,9 +359,13 @@ struct usbd_pipe_methods uhci_device_isoc_methods = {
};
#define uhci_add_intr_info(sc, ii) \
- LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ii), list);
+ LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ii), list)
#define uhci_del_intr_info(ii) \
- LIST_REMOVE((ii), list)
+ do { \
+ LIST_REMOVE((ii), list); \
+ (ii)->list.le_prev = NULL; \
+ } while (0)
+#define uhci_active_intr_info(ii) ((ii)->list.le_prev != NULL)
Static __inline__ uhci_soft_qh_t *
uhci_find_prev_qh(uhci_soft_qh_t *pqh, uhci_soft_qh_t *sqh)
@@ -401,7 +408,6 @@ uhci_init(uhci_softc_t *sc)
uhci_dumpregs(sc);
#endif
- uhci_run(sc, 0); /* stop the controller */
UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */
uhci_globalreset(sc); /* reset the controller */
uhci_reset(sc);
@@ -412,9 +418,9 @@ uhci_init(uhci_softc_t *sc)
UHCI_FRAMELIST_ALIGN, &sc->sc_dma);
if (err)
return (err);
- sc->sc_pframes = KERNADDR(&sc->sc_dma);
+ sc->sc_pframes = KERNADDR(&sc->sc_dma, 0);
UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */
- UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma)); /* set frame list*/
+ UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); /* set frame list*/
/*
* Allocate a TD, inactive, that hangs from the last QH.
@@ -534,7 +540,6 @@ uhci_activate(device_ptr_t self, enum devact act)
switch (act) {
case DVACT_ACTIVATE:
return (EOPNOTSUPP);
- break;
case DVACT_DEACTIVATE:
if (sc->sc_child != NULL)
@@ -585,7 +590,7 @@ uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)
/*
* XXX
* Since we are allocating a buffer we can assume that we will
- * need TDs for it. Since we don't want to alolocate those from
+ * need TDs for it. Since we don't want to allocate those from
* an interrupt context, we allocate them here and free them again.
* This is no guarantee that we'll get the TDs next time...
*/
@@ -594,7 +599,8 @@ uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)
u_int32_t i;
uhci_soft_td_t **stds;
DPRINTF(("uhci_allocm: get %d TDs\n", n));
- stds = malloc(sizeof(uhci_soft_td_t *) * n, M_TEMP, M_NOWAIT);
+ stds = malloc(sizeof(uhci_soft_td_t *) * n, M_TEMP,
+ M_NOWAIT);
if (stds == NULL)
panic("uhci_allocm");
memset(stds, 0, sizeof(uhci_soft_td_t *) * n);
@@ -732,13 +738,14 @@ uhci_power(int why, void *v)
uhci_run(sc, 0); /* in case BIOS has started it */
/* restore saved state */
- UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma));
+ 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);
UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force global resume */
usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */
+ UHCICMD(sc, UHCI_CMD_MAXP);
UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* re-enable intrs */
uhci_run(sc, 1); /* and start traffic again */
@@ -792,9 +799,9 @@ uhci_dump_td(uhci_soft_td_t *p)
(long)le32toh(p->td.td_token),
(long)le32toh(p->td.td_buffer)));
- bitmask_snprintf((int)le32toh(p->td.td_link), "\20\1T\2Q\3VF",
+ bitmask_snprintf((u_int32_t)le32toh(p->td.td_link), "\20\1T\2Q\3VF",
sbuf, sizeof(sbuf));
- bitmask_snprintf((int)le32toh(p->td.td_status),
+ bitmask_snprintf((u_int32_t)le32toh(p->td.td_status),
"\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27"
"STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD",
sbuf2, sizeof(sbuf2));
@@ -966,7 +973,7 @@ uhci_poll_hub(void *addr)
usb_callout(sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, xfer);
- p = KERNADDR(&xfer->dmabuf);
+ p = KERNADDR(&xfer->dmabuf, 0);
p[0] = 0;
if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
p[0] |= 1<<1;
@@ -1073,7 +1080,7 @@ uhci_remove_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
}
pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh);
- pqh->hlink = sqh->hlink;
+ pqh->hlink = sqh->hlink;
pqh->qh.qh_hlink = sqh->qh.qh_hlink;
delay(UHCI_QH_REMOVE_DELAY);
if (sc->sc_hctl_end == sqh)
@@ -1090,9 +1097,9 @@ uhci_add_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
DPRINTFN(10, ("uhci_add_ls_ctrl: sqh=%p\n", sqh));
eqh = sc->sc_lctl_end;
- sqh->hlink = eqh->hlink;
+ sqh->hlink = eqh->hlink;
sqh->qh.qh_hlink = eqh->qh.qh_hlink;
- eqh->hlink = sqh;
+ eqh->hlink = sqh;
eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
sc->sc_lctl_end = sqh;
}
@@ -1112,7 +1119,7 @@ uhci_remove_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
delay(UHCI_QH_REMOVE_DELAY);
}
pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh);
- pqh->hlink = sqh->hlink;
+ pqh->hlink = sqh->hlink;
pqh->qh.qh_hlink = sqh->qh.qh_hlink;
delay(UHCI_QH_REMOVE_DELAY);
if (sc->sc_lctl_end == sqh)
@@ -1129,9 +1136,9 @@ uhci_add_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
DPRINTFN(10, ("uhci_add_bulk: sqh=%p\n", sqh));
eqh = sc->sc_bulk_end;
- sqh->hlink = eqh->hlink;
+ sqh->hlink = eqh->hlink;
sqh->qh.qh_hlink = eqh->qh.qh_hlink;
- eqh->hlink = sqh;
+ eqh->hlink = sqh;
eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
sc->sc_bulk_end = sqh;
uhci_add_loop(sc);
@@ -1167,6 +1174,9 @@ uhci_intr(void *arg)
{
uhci_softc_t *sc = arg;
+ if (sc->sc_dying)
+ return (0);
+
DPRINTFN(15,("uhci_intr: real interrupt\n"));
if (sc->sc_bus.use_polling) {
#ifdef DIAGNOSTIC
@@ -1190,15 +1200,10 @@ uhci_intr1(uhci_softc_t *sc)
}
#endif
- status = UREAD2(sc, UHCI_STS);
+ status = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS;
if (status == 0) /* The interrupt was not for us. */
return (0);
-#if defined(DIAGNOSTIC) && defined(__NetBSD__)
- if (sc->sc_suspend != PWR_RESUME)
- printf("uhci_intr: suspended sts=0x%x\n", status);
-#endif
-
if (sc->sc_suspend != PWR_RESUME) {
printf("%s: interrupt while not operating ignored\n",
USBDEVNAME(sc->sc_bus.bdev));
@@ -1275,6 +1280,13 @@ uhci_softintr(void *v)
for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list))
uhci_check_intr(sc, ii);
+#ifdef USB_USE_SOFTINTR
+ if (sc->sc_softwake) {
+ sc->sc_softwake = 0;
+ wakeup(&sc->sc_softwake);
+ }
+#endif /* USB_USE_SOFTINTR */
+
sc->sc_bus.intr_context--;
}
@@ -1292,6 +1304,12 @@ uhci_check_intr(uhci_softc_t *sc, uhci_intr_info_t *ii)
return;
}
#endif
+ if (ii->xfer->status == USBD_CANCELLED ||
+ ii->xfer->status == USBD_TIMEOUT) {
+ DPRINTF(("uhci_check_intr: aborted xfer=%p\n", ii->xfer));
+ return;
+ }
+
if (ii->stdstart == NULL)
return;
lstd = ii->stdend;
@@ -1361,12 +1379,6 @@ uhci_idone(uhci_intr_info_t *ii)
}
#endif
- if (xfer->status == USBD_CANCELLED ||
- xfer->status == USBD_TIMEOUT) {
- DPRINTF(("uhci_idone: aborted xfer=%p\n", xfer));
- return;
- }
-
if (xfer->nframes != 0) {
/* Isoc transfer, do things differently. */
uhci_soft_td_t **stds = upipe->u.iso.stds;
@@ -1429,7 +1441,8 @@ uhci_idone(uhci_intr_info_t *ii)
#ifdef UHCI_DEBUG
char sbuf[128];
- bitmask_snprintf((int)status, "\20\22BITSTUFF\23CRCTO\24NAK\25"
+ bitmask_snprintf((u_int32_t)status,
+ "\20\22BITSTUFF\23CRCTO\24NAK\25"
"BABBLE\26DBUFFER\27STALLED\30ACTIVE",
sbuf, sizeof(sbuf));
@@ -1461,17 +1474,33 @@ void
uhci_timeout(void *addr)
{
uhci_intr_info_t *ii = addr;
+ struct uhci_xfer *uxfer = UXFER(ii->xfer);
+ struct uhci_pipe *upipe = (struct uhci_pipe *)uxfer->xfer.pipe;
+ uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
- DPRINTF(("uhci_timeout: ii=%p\n", ii));
+ DPRINTF(("uhci_timeout: uxfer=%p\n", uxfer));
-#ifdef UHCI_DEBUG
- if (uhcidebug > 10)
- uhci_dump_tds(ii->stdstart);
-#endif
+ if (sc->sc_dying) {
+ uhci_abort_xfer(&uxfer->xfer, USBD_TIMEOUT);
+ return;
+ }
+
+ /* Execute the abort in a process context. */
+ usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer);
+ usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task);
+}
+
+void
+uhci_timeout_task(void *addr)
+{
+ usbd_xfer_handle xfer = addr;
+ int s;
+
+ DPRINTF(("uhci_timeout_task: xfer=%p\n", xfer));
- ii->xfer->device->bus->intr_context++;
- uhci_abort_xfer(ii->xfer, USBD_TIMEOUT);
- ii->xfer->device->bus->intr_context--;
+ s = splusb();
+ uhci_abort_xfer(xfer, USBD_TIMEOUT);
+ splx(s);
}
/*
@@ -1594,8 +1623,8 @@ uhci_alloc_std(uhci_softc_t *sc)
return (0);
for(i = 0; i < UHCI_STD_CHUNK; i++) {
offs = i * UHCI_STD_SIZE;
- std = (uhci_soft_td_t *)((char *)KERNADDR(&dma) +offs);
- std->physaddr = DMAADDR(&dma) + offs;
+ std = KERNADDR(&dma, offs);
+ std->physaddr = DMAADDR(&dma, offs);
std->link.std = sc->sc_freetds;
sc->sc_freetds = std;
}
@@ -1637,8 +1666,8 @@ uhci_alloc_sqh(uhci_softc_t *sc)
return (0);
for(i = 0; i < UHCI_SQH_CHUNK; i++) {
offs = i * UHCI_SQH_SIZE;
- sqh = (uhci_soft_qh_t *)((char *)KERNADDR(&dma) +offs);
- sqh->physaddr = DMAADDR(&dma) + offs;
+ sqh = KERNADDR(&dma, offs);
+ sqh->physaddr = DMAADDR(&dma, offs);
sqh->hlink = sc->sc_freeqhs;
sc->sc_freeqhs = sqh;
}
@@ -1680,9 +1709,9 @@ uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len,
int addr = upipe->pipe.device->address;
int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
- DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d ls=%d "
+ DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d speed=%d "
"flags=0x%x\n", addr, UE_GET_ADDR(endpt), len,
- upipe->pipe.device->lowspeed, flags));
+ upipe->pipe.device->speed, flags));
maxp = UGETW(upipe->pipe.endpoint->edesc->wMaxPacketSize);
if (maxp == 0) {
printf("uhci_alloc_std_chain: maxp=0\n");
@@ -1705,14 +1734,14 @@ uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len,
lastlink = UHCI_PTR_T;
ntd--;
status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);
- if (upipe->pipe.device->lowspeed)
+ if (upipe->pipe.device->speed == USB_SPEED_LOW)
status |= UHCI_TD_LS;
if (flags & USBD_SHORT_XFER_OK)
status |= UHCI_TD_SPD;
for (i = ntd; i >= 0; i--) {
p = uhci_alloc_std(sc);
if (p == NULL) {
- uhci_free_std_chain(sc, lastp, 0);
+ uhci_free_std_chain(sc, lastp, NULL);
return (USBD_NOMEM);
}
p->link.std = lastp;
@@ -1731,7 +1760,7 @@ uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len,
p->td.td_token =
htole32(rd ? UHCI_TD_IN (l, endpt, addr, tog) :
UHCI_TD_OUT(l, endpt, addr, tog));
- p->td.td_buffer = htole32(DMAADDR(dma) + i * maxp);
+ p->td.td_buffer = htole32(DMAADDR(dma, i * maxp));
tog ^= 1;
}
*sp = lastp;
@@ -1782,8 +1811,8 @@ uhci_device_bulk_start(usbd_xfer_handle xfer)
int len, isread, endpt;
int s;
- DPRINTFN(3, ("uhci_device_bulk_transfer: xfer=%p len=%d flags=%d\n",
- xfer, xfer->length, xfer->flags));
+ DPRINTFN(3, ("uhci_device_bulk_start: xfer=%p len=%d flags=%d ii=%p\n",
+ xfer, xfer->length, xfer->flags, ii));
if (sc->sc_dying)
return (USBD_IOERROR);
@@ -1833,7 +1862,7 @@ uhci_device_bulk_start(usbd_xfer_handle xfer)
uhci_add_intr_info(sc, ii);
if (xfer->timeout && !sc->sc_bus.use_polling) {
- usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
+ usb_callout(xfer->timeout_handle, mstohz(xfer->timeout),
uhci_timeout, ii);
}
xfer->status = USBD_IN_PROGRESS;
@@ -1861,44 +1890,72 @@ uhci_device_bulk_abort(usbd_xfer_handle xfer)
}
/*
- * XXX This way of aborting is neither safe, nor good.
- * But it will have to do until I figure out what to do.
- * I apologize for the delay().
+ * Abort a device request.
+ * If this routine is called at splusb() it guarantees that the request
+ * will be removed from the hardware scheduling and that the callback
+ * for it will be called with USBD_CANCELLED status.
+ * It's impossible to guarantee that the requested transfer will not
+ * have happened since the hardware runs concurrently.
+ * If the transaction has already happened we rely on the ordinary
+ * interrupt processing to process it.
*/
void
uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
{
uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
+ struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
+ uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
uhci_soft_td_t *std;
int s;
DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status));
- s = splusb();
-
- /* Transfer is already done. */
- if (xfer->status != USBD_NOT_STARTED &&
- xfer->status != USBD_IN_PROGRESS) {
+ if (sc->sc_dying) {
+ /* If we're dying, just do the software part. */
+ s = splusb();
+ xfer->status = status; /* make software ignore it */
+ usb_uncallout(xfer->timeout_handle, uhci_timeout, xfer);
+ usb_transfer_complete(xfer);
splx(s);
- return;
}
- /* Make interrupt routine ignore it, */
- xfer->status = status;
+ if (xfer->device->bus->intr_context || !curproc)
+ panic("uhci_abort_xfer: not in process context");
- /* don't timeout, */
+ /*
+ * Step 1: Make interrupt routine and hardware ignore xfer.
+ */
+ s = splusb();
+ xfer->status = status; /* make software ignore it */
usb_uncallout(xfer->timeout_handle, uhci_timeout, ii);
-
- /* make hardware ignore it, */
+ DPRINTFN(1,("uhci_abort_xfer: stop ii=%p\n", ii));
for (std = ii->stdstart; std != NULL; std = std->link.std)
std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
+ splx(s);
- xfer->hcpriv = ii;
-
+ /*
+ * Step 2: Wait until we know hardware has finished any possible
+ * use of the xfer. Also make sure the soft interrupt routine
+ * has run.
+ */
+ usb_delay_ms(upipe->pipe.device->bus, 2); /* Hardware finishes in 1ms */
+ s = splusb();
+#ifdef USB_USE_SOFTINTR
+ sc->sc_softwake = 1;
+#endif /* USB_USE_SOFTINTR */
+ usb_schedsoftintr(&sc->sc_bus);
+#ifdef USB_USE_SOFTINTR
+ DPRINTFN(1,("uhci_abort_xfer: tsleep\n"));
+ tsleep(&sc->sc_softwake, PZERO, "uhciab", 0);
+#endif /* USB_USE_SOFTINTR */
splx(s);
- delay(1000);
+ /*
+ * Step 3: Execute callback.
+ */
+ xfer->hcpriv = ii;
+ DPRINTFN(1,("uhci_abort_xfer: callback\n"));
s = splusb();
#ifdef DIAGNOSTIC
ii->isdone = 1;
@@ -2067,7 +2124,7 @@ uhci_device_intr_abort(usbd_xfer_handle xfer)
DPRINTFN(1,("uhci_device_intr_abort: xfer=%p\n", xfer));
if (xfer->pipe->intrxfer == xfer) {
DPRINTFN(1,("uhci_device_intr_abort: remove\n"));
- xfer->pipe->intrxfer = 0;
+ xfer->pipe->intrxfer = NULL;
}
uhci_abort_xfer(xfer, USBD_CANCELLED);
}
@@ -2125,7 +2182,7 @@ uhci_device_request(usbd_xfer_handle xfer)
UGETW(req->wIndex), UGETW(req->wLength),
addr, endpt));
- ls = dev->lowspeed ? UHCI_TD_LS : 0;
+ ls = dev->speed == USB_SPEED_LOW ? UHCI_TD_LS : 0;
isread = req->bmRequestType & UT_READ;
len = UGETW(req->wLength);
@@ -2148,14 +2205,14 @@ uhci_device_request(usbd_xfer_handle xfer)
}
upipe->u.ctl.length = len;
- memcpy(KERNADDR(&upipe->u.ctl.reqdma), req, sizeof *req);
+ memcpy(KERNADDR(&upipe->u.ctl.reqdma, 0), req, sizeof *req);
setup->link.std = next;
setup->td.td_link = htole32(next->physaddr | UHCI_PTR_VF | UHCI_PTR_TD);
setup->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
UHCI_TD_ACTIVE);
setup->td.td_token = htole32(UHCI_TD_SETUP(sizeof *req, endpt, addr));
- setup->td.td_buffer = htole32(DMAADDR(&upipe->u.ctl.reqdma));
+ setup->td.td_buffer = htole32(DMAADDR(&upipe->u.ctl.reqdma, 0));
stat->link.std = NULL;
stat->td.td_link = htole32(UHCI_PTR_T);
@@ -2188,7 +2245,7 @@ uhci_device_request(usbd_xfer_handle xfer)
sqh->qh.qh_elink = htole32(setup->physaddr | UHCI_PTR_TD);
s = splusb();
- if (dev->lowspeed)
+ if (dev->speed == USB_SPEED_LOW)
uhci_add_ls_ctrl(sc, sqh);
else
uhci_add_hs_ctrl(sc, sqh);
@@ -2221,7 +2278,7 @@ uhci_device_request(usbd_xfer_handle xfer)
}
#endif
if (xfer->timeout && !sc->sc_bus.use_polling) {
- usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
+ usb_callout(xfer->timeout_handle, mstohz(xfer->timeout),
uhci_timeout, ii);
}
xfer->status = USBD_IN_PROGRESS;
@@ -2295,7 +2352,7 @@ uhci_device_isoc_enter(usbd_xfer_handle xfer)
xfer->status = USBD_IN_PROGRESS;
UXFER(xfer)->curframe = next;
- buf = DMAADDR(&xfer->dmabuf);
+ buf = DMAADDR(&xfer->dmabuf, 0);
status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(0) |
UHCI_TD_ACTIVE |
UHCI_TD_IOS);
@@ -2532,6 +2589,9 @@ uhci_device_isoc_done(usbd_xfer_handle xfer)
/* Not on interrupt list, ignore it. */
return;
+ if (!uhci_active_intr_info(ii))
+ return;
+
#ifdef DIAGNOSTIC
if (xfer->busy_free != XFER_BUSY) {
printf("uhci_device_isoc_done: xfer=%p not busy 0x%08x\n",
@@ -2571,7 +2631,7 @@ uhci_device_intr_done(usbd_xfer_handle xfer)
sqh->elink = NULL;
sqh->qh.qh_elink = htole32(UHCI_PTR_T);
}
- uhci_free_std_chain(sc, ii->stdstart, 0);
+ uhci_free_std_chain(sc, ii->stdstart, NULL);
/* XXX Wasteful. */
if (xfer->pipe->repeat) {
@@ -2609,7 +2669,8 @@ uhci_device_intr_done(usbd_xfer_handle xfer)
/* The ii is already on the examined list, just leave it. */
} else {
DPRINTFN(5,("uhci_device_intr_done: removing\n"));
- uhci_del_intr_info(ii);
+ if (uhci_active_intr_info(ii))
+ uhci_del_intr_info(ii);
}
}
@@ -2626,9 +2687,12 @@ uhci_device_ctrl_done(usbd_xfer_handle xfer)
panic("uhci_ctrl_done: not a request");
#endif
+ if (!uhci_active_intr_info(ii))
+ return;
+
uhci_del_intr_info(ii); /* remove from active list */
- if (upipe->pipe.device->lowspeed)
+ if (upipe->pipe.device->speed == USB_SPEED_LOW)
uhci_remove_ls_ctrl(sc, upipe->u.ctl.sqh);
else
uhci_remove_hs_ctrl(sc, upipe->u.ctl.sqh);
@@ -2647,11 +2711,17 @@ uhci_device_bulk_done(usbd_xfer_handle xfer)
uhci_softc_t *sc = ii->sc;
struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
+ DPRINTFN(5,("uhci_device_ctrl_done: xfer=%p ii=%p sc=%p upipe=%p\n",
+ xfer, ii, sc, upipe));
+
+ if (!uhci_active_intr_info(ii))
+ return;
+
uhci_del_intr_info(ii); /* remove from active list */
uhci_remove_bulk(sc, upipe->u.bulk.sqh);
- uhci_free_std_chain(sc, ii->stdstart, 0);
+ uhci_free_std_chain(sc, ii->stdstart, NULL);
DPRINTFN(5, ("uhci_bulk_done: length=%d\n", xfer->actlen));
}
@@ -2841,7 +2911,7 @@ usb_device_descriptor_t uhci_devd = {
{0x00, 0x01}, /* USB version */
UDCLASS_HUB, /* class */
UDSUBCLASS_HUB, /* subclass */
- 0, /* protocol */
+ UDPROTO_FSHUB, /* protocol */
64, /* max packet */
{0},{0},{0x00,0x01}, /* device id */
1,2,0, /* string indicies */
@@ -2869,7 +2939,7 @@ usb_interface_descriptor_t uhci_ifcd = {
1,
UICLASS_HUB,
UISUBCLASS_HUB,
- 0,
+ UIPROTO_FSHUB,
0
};
@@ -2910,6 +2980,101 @@ uhci_str(usb_string_descriptor_t *p, int l, char *s)
}
/*
+ * The USB hub protocol requires that SET_FEATURE(PORT_RESET) also
+ * enables the port, and also states that SET_FEATURE(PORT_ENABLE)
+ * should not be used by the USB subsystem. As we cannot issue a
+ * SET_FEATURE(PORT_ENABLE) externally, we must ensure that the port
+ * will be enabled as part of the reset.
+ *
+ * On the VT83C572, the port cannot be successfully enabled until the
+ * outstanding "port enable change" and "connection status change"
+ * events have been reset.
+ */
+Static usbd_status
+uhci_portreset(uhci_softc_t *sc, int index)
+{
+ int lim, port, x;
+
+ if (index == 1)
+ port = UHCI_PORTSC1;
+ else if (index == 2)
+ port = UHCI_PORTSC2;
+ else
+ return (USBD_IOERROR);
+
+ x = URWMASK(UREAD2(sc, port));
+ UWRITE2(sc, port, x | UHCI_PORTSC_PR);
+
+ usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
+
+ DPRINTFN(3,("uhci port %d reset, status0 = 0x%04x\n",
+ index, UREAD2(sc, port)));
+
+ x = URWMASK(UREAD2(sc, port));
+ UWRITE2(sc, port, x & ~UHCI_PORTSC_PR);
+
+ delay(100);
+
+ DPRINTFN(3,("uhci port %d reset, status1 = 0x%04x\n",
+ index, UREAD2(sc, port)));
+
+ x = URWMASK(UREAD2(sc, port));
+ UWRITE2(sc, port, x | UHCI_PORTSC_PE);
+
+ for (lim = 10; --lim > 0;) {
+ usb_delay_ms(&sc->sc_bus, USB_PORT_RESET_DELAY);
+
+ x = UREAD2(sc, port);
+
+ DPRINTFN(3,("uhci port %d iteration %u, status = 0x%04x\n",
+ index, lim, x));
+
+ if (!(x & UHCI_PORTSC_CCS)) {
+ /*
+ * No device is connected (or was disconnected
+ * during reset). Consider the port reset.
+ * The delay must be long enough to ensure on
+ * the initial iteration that the device
+ * connection will have been registered. 50ms
+ * appears to be sufficient, but 20ms is not.
+ */
+ DPRINTFN(3,("uhci port %d loop %u, device detached\n",
+ index, lim));
+ break;
+ }
+
+ if (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)) {
+ /*
+ * Port enabled changed and/or connection
+ * status changed were set. Reset either or
+ * both raised flags (by writing a 1 to that
+ * bit), and wait again for state to settle.
+ */
+ UWRITE2(sc, port, URWMASK(x) |
+ (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)));
+ continue;
+ }
+
+ if (x & UHCI_PORTSC_PE)
+ /* Port is enabled */
+ break;
+
+ UWRITE2(sc, port, URWMASK(x) | UHCI_PORTSC_PE);
+ }
+
+ DPRINTFN(3,("uhci port %d reset, status2 = 0x%04x\n",
+ index, UREAD2(sc, port)));
+
+ if (lim <= 0) {
+ DPRINTFN(1,("uhci port %d reset timed out\n", index));
+ return (USBD_TIMEOUT);
+ }
+
+ sc->sc_isreset = 1;
+ return (USBD_NORMAL_COMPLETION);
+}
+
+/*
* Simulate a hardware hub by handling all the necessary requests.
*/
usbd_status
@@ -2957,7 +3122,7 @@ uhci_root_ctrl_start(usbd_xfer_handle xfer)
index = UGETW(req->wIndex);
if (len != 0)
- buf = KERNADDR(&xfer->dmabuf);
+ buf = KERNADDR(&xfer->dmabuf, 0);
#define C(x,y) ((x) | ((y) << 8))
switch(C(req->bRequest, req->bmRequestType)) {
@@ -3219,18 +3384,8 @@ uhci_root_ctrl_start(usbd_xfer_handle xfer)
UWRITE2(sc, port, x | UHCI_PORTSC_SUSP);
break;
case UHF_PORT_RESET:
- x = URWMASK(UREAD2(sc, port));
- UWRITE2(sc, port, x | UHCI_PORTSC_PR);
- usb_delay_ms(&sc->sc_bus, 50); /*XXX USB v1.1 7.1.7.3 */
- UWRITE2(sc, port, x & ~UHCI_PORTSC_PR);
- delay(100);
- x = UREAD2(sc, port);
- UWRITE2(sc, port, x | UHCI_PORTSC_PE);
- usb_delay_ms(&sc->sc_bus, 10); /* XXX */
- DPRINTFN(3,("uhci port %d reset, status = 0x%04x\n",
- index, UREAD2(sc, port)));
- sc->sc_isreset = 1;
- break;
+ err = uhci_portreset(sc, index);
+ goto ret;
case UHF_PORT_POWER:
/* Pretend we turned on power */
err = USBD_NORMAL_COMPLETION;
@@ -3325,7 +3480,7 @@ uhci_root_intr_start(usbd_xfer_handle xfer)
if (sc->sc_dying)
return (USBD_IOERROR);
- sc->sc_ival = MS_TO_TICKS(xfer->pipe->endpoint->edesc->bInterval);
+ sc->sc_ival = mstohz(xfer->pipe->endpoint->edesc->bInterval);
usb_callout(sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, xfer);
sc->sc_intr_xfer = xfer;
return (USBD_IN_PROGRESS);
diff --git a/sys/dev/usb/uhcireg.h b/sys/dev/usb/uhcireg.h
index fa47455002d..57bec42650a 100644
--- a/sys/dev/usb/uhcireg.h
+++ b/sys/dev/usb/uhcireg.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: uhcireg.h,v 1.12 2002/07/25 02:18:10 nate Exp $ */
-/* $NetBSD: uhcireg.h,v 1.14 2001/08/06 15:15:08 augustss Exp $ */
+/* $OpenBSD: uhcireg.h,v 1.13 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: uhcireg.h,v 1.16 2002/07/11 21:14:29 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhcireg.h,v 1.12 1999/11/17 22:33:42 n_hibma Exp $ */
/*
@@ -76,6 +76,7 @@
#define UHCI_STS_HSE 0x0008
#define UHCI_STS_HCPE 0x0010
#define UHCI_STS_HCH 0x0020
+#define UHCI_STS_ALLINTRS 0x003f
#define UHCI_INTR 0x04
#define UHCI_INTR_TOCRCIE 0x0001
diff --git a/sys/dev/usb/uhcivar.h b/sys/dev/usb/uhcivar.h
index 6ec5b6fd01b..403362b55fd 100644
--- a/sys/dev/usb/uhcivar.h
+++ b/sys/dev/usb/uhcivar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: uhcivar.h,v 1.14 2002/07/25 02:18:10 nate Exp $ */
-/* $NetBSD: uhcivar.h,v 1.32 2000/08/13 16:18:09 augustss Exp $ */
+/* $OpenBSD: uhcivar.h,v 1.15 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: uhcivar.h,v 1.36 2002/12/31 00:39:11 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhcivar.h,v 1.14 1999/11/17 22:33:42 n_hibma Exp $ */
/*
@@ -84,6 +84,7 @@ typedef struct uhci_intr_info {
struct uhci_xfer {
struct usbd_xfer xfer;
uhci_intr_info_t iinfo;
+ struct usb_task abort_task;
int curframe;
};
@@ -161,6 +162,10 @@ typedef struct uhci_softc {
u_int8_t sc_saved_sof;
u_int16_t sc_saved_frnum;
+#ifdef USB_USE_SOFTINTR
+ char sc_softwake;
+#endif /* USB_USE_SOFTINTR */
+
char sc_isreset;
char sc_suspend;
char sc_dying;
@@ -172,7 +177,7 @@ typedef struct uhci_softc {
usbd_xfer_handle sc_intr_xfer; /* root hub interrupt transfer */
usb_callout_t sc_poll_handle;
- char sc_vendor[16]; /* vendor string for root hub */
+ char sc_vendor[32]; /* vendor string for root hub */
int sc_id_vendor; /* vendor ID for root hub */
void *sc_powerhook; /* cookie from power hook */
diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c
index 293831e59a1..626bd0d62f7 100644
--- a/sys/dev/usb/uhub.c
+++ b/sys/dev/usb/uhub.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: uhub.c,v 1.20 2003/05/19 04:17:53 nate Exp $ */
-/* $NetBSD: uhub.c,v 1.52 2001/10/26 17:53:59 augustss Exp $ */
+/* $OpenBSD: uhub.c,v 1.21 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: uhub.c,v 1.64 2003/02/08 03:32:51 ichiro Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $ */
/*
@@ -68,7 +68,7 @@
#ifdef UHUB_DEBUG
#define DPRINTF(x) if (uhubdebug) logprintf x
#define DPRINTFN(n,x) if (uhubdebug>(n)) logprintf x
-int uhubdebug;
+int uhubdebug = 0;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
@@ -99,11 +99,16 @@ Static bus_child_detached_t uhub_child_detached;
#if defined(__NetBSD__) || defined(__OpenBSD__)
USB_DECLARE_DRIVER(uhub);
+#if defined(__NetBSD__)
/* Create the driver instance for the hub connected to hub case */
+CFATTACH_DECL(uhub_uhub, sizeof(struct uhub_softc),
+ uhub_match, uhub_attach, uhub_detach, uhub_activate);
+#else
struct cfattach uhub_uhub_ca = {
sizeof(struct uhub_softc), uhub_match, uhub_attach,
uhub_detach, uhub_activate
};
+#endif
#elif defined(__FreeBSD__)
USB_DECLARE_DRIVER_INIT(uhub,
DEVMETHOD(bus_child_detached, uhub_child_detached));
@@ -324,6 +329,7 @@ uhub_explore(usbd_device_handle dev)
struct uhub_softc *sc = dev->hub->hubsoftc;
struct usbd_port *up;
usbd_status err;
+ int speed;
int port;
int change, status;
@@ -446,10 +452,16 @@ uhub_explore(usbd_device_handle dev)
continue;
}
+ /* Figure out device speed */
+ if (status & UPS_HIGH_SPEED)
+ speed = USB_SPEED_HIGH;
+ else if (status & UPS_LOW_SPEED)
+ speed = USB_SPEED_LOW;
+ else
+ speed = USB_SPEED_FULL;
/* Get device info and set its address. */
err = usbd_new_device(USBDEV(sc->sc_dev), dev->bus,
- dev->depth + 1, status & UPS_LOW_SPEED,
- port, up);
+ dev->depth + 1, speed, port, up);
/* XXX retry a few times? */
if (err) {
DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
@@ -488,7 +500,6 @@ uhub_activate(device_ptr_t self, enum devact act)
switch (act) {
case DVACT_ACTIVATE:
return (EOPNOTSUPP);
- break;
case DVACT_DEACTIVATE:
if (hub == NULL) /* malfunctioning hub */
diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c
index 1d6d14fa377..bbb858bb29e 100644
--- a/sys/dev/usb/usb.c
+++ b/sys/dev/usb/usb.c
@@ -1,9 +1,8 @@
-/* $OpenBSD: usb.c,v 1.24 2003/06/27 16:57:14 nate Exp $ */
-/* $NetBSD: usb.c,v 1.53 2001/01/23 17:04:30 augustss Exp $ */
-/* $FreeBSD: src/sys/dev/usb/usb.c,v 1.20 1999/11/17 22:33:46 n_hibma Exp $ */
+/* $OpenBSD: usb.c,v 1.25 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: usb.c,v 1.77 2003/01/01 00:10:26 thorpej Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -45,6 +44,9 @@
* http://www.usb.org/developers/index.html .
*/
+#include "ohci.h"
+#include "uhci.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -53,6 +55,7 @@
#include <sys/kthread.h>
#include <sys/proc.h>
#include <sys/conf.h>
+#include <sys/fcntl.h>
#include <sys/poll.h>
#include <sys/select.h>
#include <sys/vnode.h>
@@ -73,11 +76,11 @@
#define DPRINTF(x) if (usbdebug) logprintf x
#define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
int usbdebug = 0;
-#ifdef UHCI_DEBUG
-int uhcidebug;
+#if defined(UHCI_DEBUG) && NUHCI > 0
+extern int uhcidebug;
#endif
-#ifdef OHCI_DEBUG
-int ohcidebug;
+#if defined(OHCI_DEBUG) && NOHCI > 0
+extern int ohcidebug;
#endif
/*
* 0 - do usual exploration
@@ -95,21 +98,32 @@ struct usb_softc {
usbd_bus_handle sc_bus; /* USB controller */
struct usbd_port sc_port; /* dummy port for root hub */
- TAILQ_HEAD(, usb_task) sc_tasks;
- struct proc *sc_event_thread;
-
- struct usb_task sc_exp_task;
+ usb_proc_ptr sc_event_thread;
char sc_dying;
};
+TAILQ_HEAD(, usb_task) usb_all_tasks;
+
#if defined(__NetBSD__)
-cdev_decl(usb);
+dev_type_open(usbopen);
+dev_type_close(usbclose);
+dev_type_read(usbread);
+dev_type_ioctl(usbioctl);
+dev_type_poll(usbpoll);
+dev_type_kqfilter(usbkqfilter);
+
+const struct cdevsw usb_cdevsw = {
+ usbopen, usbclose, usbread, nowrite, usbioctl,
+ nostop, notty, usbpoll, nommap, usbkqfilter,
+};
#endif
Static void usb_discover(void *);
Static void usb_create_event_thread(void *);
Static void usb_event_thread(void *);
+Static void usb_task_thread(void *);
+Static usb_proc_ptr usb_task_thread_proc = NULL;
#define USB_MAX_EVENTS 100
struct usb_event_q {
@@ -120,7 +134,7 @@ Static SIMPLEQ_HEAD(, usb_event_q) usb_events =
SIMPLEQ_HEAD_INITIALIZER(usb_events);
Static int usb_nevents = 0;
Static struct selinfo usb_selevent;
-Static struct proc *usb_async_proc; /* process that wants USB SIGIO */
+Static usb_proc_ptr usb_async_proc; /* process that wants USB SIGIO */
Static int usb_dev_open = 0;
Static void usb_add_event(int, struct usb_event *);
@@ -142,6 +156,7 @@ USB_ATTACH(usb)
usbd_device_handle dev;
usbd_status err;
int usbrev;
+ int speed;
struct usb_event ue;
DPRINTF(("usbd_attach\n"));
@@ -150,14 +165,20 @@ USB_ATTACH(usb)
sc->sc_bus = aux;
sc->sc_bus->usbctl = sc;
sc->sc_port.power = USB_MAX_POWER;
- TAILQ_INIT(&sc->sc_tasks);
-
- usb_init_task(&sc->sc_exp_task, usb_discover, sc);
usbrev = sc->sc_bus->usbrev;
printf(": USB revision %s", usbrev_str[usbrev]);
- if (usbrev != USBREV_1_0 && usbrev != USBREV_1_1) {
+ switch (usbrev) {
+ case USBREV_1_0:
+ case USBREV_1_1:
+ speed = USB_SPEED_FULL;
+ break;
+ case USBREV_2_0:
+ speed = USB_SPEED_HIGH;
+ break;
+ default:
printf(", not supported\n");
+ sc->sc_dying = 1;
USB_ATTACH_ERROR_RETURN;
}
printf("\n");
@@ -169,7 +190,22 @@ USB_ATTACH(usb)
ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev);
usb_add_event(USB_EVENT_CTRLR_ATTACH, &ue);
- err = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0, 0, 0,
+#ifdef USB_USE_SOFTINTR
+#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
+ /* XXX we should have our own level */
+ sc->sc_bus->soft = softintr_establish(IPL_SOFTNET,
+ sc->sc_bus->methods->soft_intr, sc->sc_bus);
+ if (sc->sc_bus->soft == NULL) {
+ printf("%s: can't register softintr\n", USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+ }
+#else
+ usb_callout_init(sc->sc_bus->softi);
+#endif
+#endif
+
+ err = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0, speed, 0,
&sc->sc_port);
if (!err) {
dev = sc->sc_port.device;
@@ -208,6 +244,7 @@ void
usb_create_event_thread(void *arg)
{
struct usb_softc *sc = arg;
+ static int created = 0;
if (usb_kthread_create1(usb_event_thread, sc, &sc->sc_event_thread,
"%s", sc->sc_dev.dv_xname)) {
@@ -215,39 +252,47 @@ usb_create_event_thread(void *arg)
sc->sc_dev.dv_xname);
panic("usb_create_event_thread");
}
+ if (!created) {
+ created = 1;
+ TAILQ_INIT(&usb_all_tasks);
+ if (usb_kthread_create1(usb_task_thread, NULL,
+ &usb_task_thread_proc, "usbtask")) {
+ printf("unable to create task thread\n");
+ panic("usb_create_event_thread task");
+ }
+ }
}
/*
- * Add a task to be performed by the event thread. This function can be
+ * Add a task to be performed by the task thread. This function can be
* called from any context and the task will be executed in a process
* context ASAP.
*/
void
usb_add_task(usbd_device_handle dev, struct usb_task *task)
{
- struct usb_softc *sc = dev->bus->usbctl;
int s;
s = splusb();
if (!task->onqueue) {
- DPRINTFN(2,("usb_add_task: sc=%p task=%p\n", sc, task));
- TAILQ_INSERT_TAIL(&sc->sc_tasks, task, next);
+ DPRINTFN(2,("usb_add_task: task=%p\n", task));
+ TAILQ_INSERT_TAIL(&usb_all_tasks, task, next);
task->onqueue = 1;
- } else
- DPRINTFN(3,("usb_add_task: sc=%p task=%p on q\n", sc, task));
- wakeup(&sc->sc_tasks);
+ } else {
+ DPRINTFN(3,("usb_add_task: task=%p on q\n", task));
+ }
+ wakeup(&usb_all_tasks);
splx(s);
}
void
usb_rem_task(usbd_device_handle dev, struct usb_task *task)
{
- struct usb_softc *sc = dev->bus->usbctl;
int s;
s = splusb();
if (task->onqueue) {
- TAILQ_REMOVE(&sc->sc_tasks, task, next);
+ TAILQ_REMOVE(&usb_all_tasks, task, next);
task->onqueue = 0;
}
splx(s);
@@ -257,8 +302,6 @@ void
usb_event_thread(void *arg)
{
struct usb_softc *sc = arg;
- struct usb_task *task;
- int s;
DPRINTF(("usb_event_thread: start\n"));
@@ -268,20 +311,18 @@ usb_event_thread(void *arg)
config_pending_decr();
while (!sc->sc_dying) {
- s = splusb();
- task = TAILQ_FIRST(&sc->sc_tasks);
- if (task == NULL) {
- tsleep(&sc->sc_tasks, PWAIT, "usbevt", 0);
- task = TAILQ_FIRST(&sc->sc_tasks);
- }
- DPRINTFN(2,("usb_event_thread: woke up task=%p\n", task));
- if (task != NULL && !sc->sc_dying) {
- TAILQ_REMOVE(&sc->sc_tasks, task, next);
- task->onqueue = 0;
- splx(s);
- task->fun(task->arg);
- } else
- splx(s);
+#ifdef USB_DEBUG
+ if (usb_noexplore < 2)
+#endif
+ usb_discover(sc);
+#ifdef USB_DEBUG
+ (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
+ usb_noexplore ? 0 : hz * 60);
+#else
+ (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
+ hz * 60);
+#endif
+ DPRINTFN(2,("usb_event_thread: woke up\n"));
}
sc->sc_event_thread = NULL;
@@ -292,6 +333,32 @@ usb_event_thread(void *arg)
kthread_exit(0);
}
+void
+usb_task_thread(void *arg)
+{
+ struct usb_task *task;
+ int s;
+
+ DPRINTF(("usb_task_thread: start\n"));
+
+ s = splusb();
+ for (;;) {
+ task = TAILQ_FIRST(&usb_all_tasks);
+ if (task == NULL) {
+ tsleep(&usb_all_tasks, PWAIT, "usbtsk", 0);
+ task = TAILQ_FIRST(&usb_all_tasks);
+ }
+ DPRINTFN(2,("usb_task_thread: woke up task=%p\n", task));
+ if (task != NULL) {
+ TAILQ_REMOVE(&usb_all_tasks, task, next);
+ task->onqueue = 0;
+ splx(s);
+ task->fun(task->arg);
+ s = splusb();
+ }
+ }
+}
+
int
usbctlprint(void *aux, const char *pnp)
{
@@ -304,7 +371,7 @@ usbctlprint(void *aux, const char *pnp)
#endif /* defined(__NetBSD__) || defined(__OpenBSD__) */
int
-usbopen(dev_t dev, int flag, int mode, struct proc *p)
+usbopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
int unit = minor(dev);
struct usb_softc *sc;
@@ -359,7 +426,7 @@ usbread(dev_t dev, struct uio *uio, int flag)
}
int
-usbclose(dev_t dev, int flag, int mode, struct proc *p)
+usbclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
int unit = minor(dev);
@@ -372,7 +439,7 @@ usbclose(dev_t dev, int flag, int mode, struct proc *p)
}
int
-usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
+usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
{
struct usb_softc *sc;
int unit = minor(devt);
@@ -403,15 +470,17 @@ usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
switch (cmd) {
#ifdef USB_DEBUG
case USB_SETDEBUG:
+ if (!(flag & FWRITE))
+ return (EBADF);
usbdebug = ((*(int *)data) & 0x000000ff);
-#ifdef UHCI_DEBUG
+#if defined(UHCI_DEBUG) && NUHCI > 0
uhcidebug = ((*(int *)data) & 0x0000ff00) >> 8;
#endif
-#ifdef OHCI_DEBUG
+#if defined(OHCI_DEBUG) && NOHCI > 0
ohcidebug = ((*(int *)data) & 0x00ff0000) >> 16;
#endif
break;
-#endif
+#endif /* USB_DEBUG */
case USB_REQUEST:
{
struct usb_ctl_request *ur = (void *)data;
@@ -423,6 +492,9 @@ usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
usbd_status err;
int error = 0;
+ if (!(flag & FWRITE))
+ return (EBADF);
+
DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len));
if (len < 0 || len > 32768)
return (EINVAL);
@@ -494,7 +566,7 @@ usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
}
int
-usbpoll(dev_t dev, int events, struct proc *p)
+usbpoll(dev_t dev, int events, usb_proc_ptr p)
{
int revents, mask, s;
@@ -597,7 +669,7 @@ usb_needs_explore(usbd_device_handle dev)
{
DPRINTFN(2,("usb_needs_explore\n"));
dev->bus->needs_explore = 1;
- usb_add_task(dev, &dev->bus->usbctl->sc_exp_task);
+ wakeup(&dev->bus->needs_explore);
}
/* Called at splusb() */
@@ -609,6 +681,13 @@ usb_get_next_event(struct usb_event *ue)
if (usb_nevents <= 0)
return (0);
ueq = SIMPLEQ_FIRST(&usb_events);
+#ifdef DIAGNOSTIC
+ if (ueq == NULL) {
+ printf("usb: usb_nevents got out of sync! %d\n", usb_nevents);
+ usb_nevents = 0;
+ return (0);
+ }
+#endif
*ue = ueq->ue;
SIMPLEQ_REMOVE_HEAD(&usb_events, ueq, next);
free(ueq, M_USBDEV);
@@ -664,10 +743,26 @@ usb_add_event(int type, struct usb_event *uep)
psignal(usb_async_proc, SIGIO);
splx(s);
}
+
void
-usb_schedsoftintr(struct usbd_bus *bus)
+usb_schedsoftintr(usbd_bus_handle bus)
{
+ DPRINTFN(10,("usb_schedsoftintr: polling=%d\n", bus->use_polling));
+#ifdef USB_USE_SOFTINTR
+ if (bus->use_polling) {
+ bus->methods->soft_intr(bus);
+ } else {
+#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
+ softintr_schedule(bus->soft);
+#else
+ if (!usb_callout_pending(bus->softi))
+ usb_callout(bus->softi, 0, bus->methods->soft_intr,
+ bus);
+#endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
+ }
+#else
bus->methods->soft_intr(bus);
+#endif /* USB_USE_SOFTINTR */
}
int
@@ -680,11 +775,11 @@ usb_activate(device_ptr_t self, enum devact act)
switch (act) {
case DVACT_ACTIVATE:
return (EOPNOTSUPP);
- break;
case DVACT_DEACTIVATE:
sc->sc_dying = 1;
- if (dev && dev->cdesc && dev->subdevs) {
+ if (dev != NULL && dev->cdesc != NULL &&
+ dev->subdevs != NULL) {
for (i = 0; dev->subdevs[i]; i++)
rv |= config_deactivate(dev->subdevs[i]);
}
@@ -704,12 +799,12 @@ usb_detach(device_ptr_t self, int flags)
sc->sc_dying = 1;
/* Make all devices disconnect. */
- if (sc->sc_port.device)
+ if (sc->sc_port.device != NULL)
usb_disconnect_port(&sc->sc_port, self);
/* Kill off event thread. */
- if (sc->sc_event_thread) {
- wakeup(&sc->sc_tasks);
+ if (sc->sc_event_thread != NULL) {
+ wakeup(&sc->sc_bus->needs_explore);
if (tsleep(sc, PWAIT, "usbdet", hz * 60))
printf("%s: event thread didn't die\n",
USBDEVNAME(sc->sc_dev));
@@ -718,6 +813,17 @@ usb_detach(device_ptr_t self, int flags)
usbd_finish();
+#ifdef USB_USE_SOFTINTR
+#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
+ if (sc->sc_bus->soft != NULL) {
+ softintr_disestablish(sc->sc_bus->soft);
+ sc->sc_bus->soft = NULL;
+ }
+#else
+ usb_uncallout(sc->sc_bus->softi, bus->methods->soft_intr, bus);
+#endif
+#endif
+
ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev);
usb_add_event(USB_EVENT_CTRLR_DETACH, &ue);
diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h
index 79786cc37a1..a4780f9773a 100644
--- a/sys/dev/usb/usb.h
+++ b/sys/dev/usb/usb.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: usb.h,v 1.21 2003/05/17 06:07:57 nate Exp $ */
-/* $NetBSD: usb.h,v 1.52 2001/07/23 15:17:50 nathanw Exp $ */
+/* $OpenBSD: usb.h,v 1.22 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: usb.h,v 1.69 2002/09/22 23:20:50 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb.h,v 1.14 1999/11/17 22:33:46 n_hibma Exp $ */
/*
@@ -48,24 +48,17 @@
#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/ioctl.h>
+#endif
+#if defined(__FreeBSD__)
+/* These two defines are used by usbd to autoload the usb kld */
+#define USB_KLD "usb" /* name of usb module */
+#define USB_UHUB "usb/uhub" /* root hub */
+#endif
#if defined(_KERNEL)
#include <dev/usb/usb_port.h>
#endif /* _KERNEL */
-#elif defined(__FreeBSD__)
-#if defined(KERNEL)
-#include <sys/malloc.h>
-
-MALLOC_DECLARE(M_USB);
-MALLOC_DECLARE(M_USBDEV);
-MALLOC_DECLARE(M_USBHC);
-
-#include <dev/usb/usb_port.h>
-#endif /* KERNEL */
-#endif /* __FreeBSD__ */
-
-
#define USB_STACK_VERSION 2
#define USB_MAX_DEVICES 128
@@ -161,6 +154,10 @@ typedef struct {
#define UDESC_STRING 0x03
#define UDESC_INTERFACE 0x04
#define UDESC_ENDPOINT 0x05
+#define UDESC_DEVICE_QUALIFIER 0x06
+#define UDESC_OTHER_SPEED_CONFIGURATION 0x07
+#define UDESC_INTERFACE_POWER 0x08
+#define UDESC_OTG 0x09
#define UDESC_CS_DEVICE 0x21 /* class specific */
#define UDESC_CS_CONFIG 0x22
#define UDESC_CS_STRING 0x23
@@ -177,9 +174,13 @@ typedef struct {
/* Feature numbers */
#define UF_ENDPOINT_HALT 0
#define UF_DEVICE_REMOTE_WAKEUP 1
+#define UF_TEST_MODE 2
#define USB_MAX_IPACKET 8 /* maximum size of the initial packet */
+#define USB_2_MAX_CTRL_PACKET 64
+#define USB_2_MAX_BULK_PACKET 512
+
typedef struct {
uByte bLength;
uByte bDescriptorType;
@@ -190,6 +191,8 @@ typedef struct {
uByte bLength;
uByte bDescriptorType;
uWord bcdUSB;
+#define UD_USB_2_0 0x0200
+#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
uByte bDeviceClass;
uByte bDeviceSubClass;
uByte bDeviceProtocol;
@@ -271,6 +274,10 @@ typedef struct {
/* Hub specific request */
#define UR_GET_BUS_STATE 0x02
+#define UR_CLEAR_TT_BUFFER 0x08
+#define UR_RESET_TT 0x09
+#define UR_GET_TT_STATE 0x0a
+#define UR_STOP_TT 0x0b
/* Hub features */
#define UHF_C_HUB_LOCAL_POWER 0
@@ -287,21 +294,29 @@ typedef struct {
#define UHF_C_PORT_SUSPEND 18
#define UHF_C_PORT_OVER_CURRENT 19
#define UHF_C_PORT_RESET 20
+#define UHF_PORT_TEST 21
+#define UHF_PORT_INDICATOR 22
typedef struct {
uByte bDescLength;
uByte bDescriptorType;
uByte bNbrPorts;
uWord wHubCharacteristics;
-#define UHD_PWR 0x03
-#define UHD_PWR_GANGED 0x00
-#define UHD_PWR_INDIVIDUAL 0x01
-#define UHD_PWR_NO_SWITCH 0x02
-#define UHD_COMPOUND 0x04
-#define UHD_OC 0x18
-#define UHD_OC_GLOBAL 0x00
-#define UHD_OC_INDIVIDUAL 0x08
-#define UHD_OC_NONE 0x10
+#define UHD_PWR 0x0003
+#define UHD_PWR_GANGED 0x0000
+#define UHD_PWR_INDIVIDUAL 0x0001
+#define UHD_PWR_NO_SWITCH 0x0002
+#define UHD_COMPOUND 0x0004
+#define UHD_OC 0x0018
+#define UHD_OC_GLOBAL 0x0000
+#define UHD_OC_INDIVIDUAL 0x0008
+#define UHD_OC_NONE 0x0010
+#define UHD_TT_THINK 0x0060
+#define UHD_TT_THINK_8 0x0000
+#define UHD_TT_THINK_16 0x0020
+#define UHD_TT_THINK_24 0x0040
+#define UHD_TT_THINK_32 0x0060
+#define UHD_PORT_IND 0x0080
uByte bPwrOn2PwrGood; /* delay in 2 ms units */
#define UHD_PWRON_FACTOR 2
uByte bHubContrCurrent;
@@ -313,6 +328,32 @@ typedef struct {
#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
typedef struct {
+ uByte bLength;
+ uByte bDescriptorType;
+ uWord bcdUSB;
+ uByte bDeviceClass;
+ uByte bDeviceSubClass;
+ uByte bDeviceProtocol;
+ uByte bMaxPacketSize0;
+ uByte bNumConfigurations;
+ uByte bReserved;
+} UPACKED usb_device_qualifier_t;
+#define USB_DEVICE_QUALIFIER_SIZE 10
+
+typedef struct {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bmAttributes;
+#define UOTG_SRP 0x01
+#define UOTG_HNP 0x02
+} UPACKED usb_otg_descriptor_t;
+
+/* OTG feature selectors */
+#define UOTG_B_HNP_ENABLE 3
+#define UOTG_A_HNP_SUPPORT 4
+#define UOTG_A_ALT_HNP_SUPPORT 5
+
+typedef struct {
uWord wStatus;
/* Device status flags */
#define UDS_SELF_POWERED 0x0001
@@ -337,6 +378,9 @@ typedef struct {
#define UPS_RESET 0x0010
#define UPS_PORT_POWER 0x0100
#define UPS_LOW_SPEED 0x0200
+#define UPS_HIGH_SPEED 0x0400
+#define UPS_PORT_TEST 0x0800
+#define UPS_PORT_INDICATOR 0x1000
uWord wPortChange;
#define UPS_C_CONNECT_STATUS 0x0001
#define UPS_C_PORT_ENABLED 0x0002
@@ -346,12 +390,18 @@ typedef struct {
} UPACKED usb_port_status_t;
/* Device class codes */
-#define UDCLASS_AUDIO 0x00
+#define UDCLASS_IN_INTERFACE 0x00
#define UDCLASS_COMM 0x02
-#define UDCLASS_HID 0x00
#define UDCLASS_HUB 0x09
-#define UDSUBCLASS_HUB 0
-#define UDCLASS_MASS 0x00
+#define UDSUBCLASS_HUB 0x00
+#define UDPROTO_FSHUB 0x00
+#define UDPROTO_HSHUBSTT 0x01
+#define UDPROTO_HSHUBMTT 0x02
+#define UDCLASS_DIAGNOSTIC 0xdc
+#define UDCLASS_WIRELESS 0xe0
+#define UDSUBCLASS_RF 0x01
+#define UDPROTO_BLUETOOTH 0x01
+#define UDCLASS_VENDOR 0xff
/* Interface class codes */
#define UICLASS_UNSPEC 0x00
@@ -377,6 +427,8 @@ typedef struct {
#define UICLASS_PHYSICAL 0x05
+#define UICLASS_IMAGE 0x06
+
#define UICLASS_PRINTER 0x07
#define UISUBCLASS_PRINTER 1
#define UIPROTO_PRINTER_UNI 1
@@ -397,6 +449,9 @@ typedef struct {
#define UICLASS_HUB 0x09
#define UISUBCLASS_HUB 0
+#define UIPROTO_FSHUB 0
+#define UIPROTO_HSHUBSTT 0 /* Yes, same as previous */
+#define UIPROTO_HSHUBMTT 1
#define UICLASS_CDC_DATA 0x0a
#define UISUBCLASS_DATA 0
@@ -414,9 +469,23 @@ typedef struct {
#define UIPROTO_DATA_PUF 0xfe /* see Prot. Unit Func. Desc.*/
#define UIPROTO_DATA_VENDOR 0xff /* Vendor specific */
-#define UICLASS_FIRM_UPD 0x0c
+#define UICLASS_SMARTCARD 0x0b
+
+/*#define UICLASS_FIRM_UPD 0x0c*/
+
+#define UICLASS_SECURITY 0x0d
+
+#define UICLASS_DIAGNOSTIC 0xdc
+
+#define UICLASS_WIRELESS 0xe0
+#define UISUBCLASS_RF 0x01
+#define UIPROTO_BLUETOOTH 0x01
#define UICLASS_APPL_SPEC 0xfe
+#define UISUBCLASS_FIRMWARE_DOWNLOAD 1
+#define UISUBCLASS_IRDA 2
+#define UIPROTO_IRDA 0
+
#define UICLASS_VENDOR 0xff
@@ -432,7 +501,8 @@ typedef struct {
#if 0
/* These are the values from the spec. */
#define USB_PORT_RESET_DELAY 10 /* ms */
-#define USB_PORT_RESET_SETTLE 10 /* ms */
+#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */
+#define USB_PORT_RESET_RECOVERY 10 /* ms */
#define USB_PORT_POWERUP_DELAY 100 /* ms */
#define USB_SET_ADDRESS_SETTLE 2 /* ms */
#define USB_RESUME_DELAY (20*5) /* ms */
@@ -442,8 +512,9 @@ typedef struct {
#else
/* Allow for marginal (i.e. non-conforming) devices. */
#define USB_PORT_RESET_DELAY 50 /* ms */
-#define USB_PORT_RESET_RECOVERY 50 /* ms */
-#define USB_PORT_POWERUP_DELAY 200 /* ms */
+#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
+#define USB_PORT_RESET_RECOVERY 250 /* ms */
+#define USB_PORT_POWERUP_DELAY 300 /* ms */
#define USB_SET_ADDRESS_SETTLE 10 /* ms */
#define USB_RESUME_DELAY (50*5) /* ms */
#define USB_RESUME_WAIT 50 /* ms */
@@ -535,7 +606,10 @@ struct usb_device_info {
u_int8_t udi_subclass;
u_int8_t udi_protocol;
u_int8_t udi_config;
- u_int8_t udi_lowspeed;
+ u_int8_t udi_speed;
+#define USB_SPEED_LOW 1
+#define USB_SPEED_FULL 2
+#define USB_SPEED_HIGH 3
int udi_power; /* power consumption in mA, 0 if selfpowered */
int udi_nports;
char udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
@@ -565,6 +639,7 @@ struct usb_event {
#define USB_EVENT_DRIVER_ATTACH 5
#define USB_EVENT_DRIVER_DETACH 6
#define USB_EVENT_IS_ATTACH(n) ((n) == USB_EVENT_CTRLR_ATTACH || (n) == USB_EVENT_DEVICE_ATTACH || (n) == USB_EVENT_DRIVER_ATTACH)
+#define USB_EVENT_IS_DETACH(n) ((n) == USB_EVENT_CTRLR_DETACH || (n) == USB_EVENT_DEVICE_DETACH || (n) == USB_EVENT_DRIVER_DETACH)
struct timespec ue_time;
union {
struct {
diff --git a/sys/dev/usb/usb_mem.c b/sys/dev/usb/usb_mem.c
index bd917fd6486..311c37c949c 100644
--- a/sys/dev/usb/usb_mem.c
+++ b/sys/dev/usb/usb_mem.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: usb_mem.c,v 1.13 2002/07/25 02:18:11 nate Exp $ */
-/* $NetBSD: usb_mem.c,v 1.22 2001/11/13 06:24:56 lukem Exp $ */
+/* $OpenBSD: usb_mem.c,v 1.14 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: usb_mem.c,v 1.26 2003/02/01 06:23:40 thorpej Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -65,12 +65,18 @@
#ifdef USB_DEBUG
#define DPRINTF(x) if (usbdebug) logprintf x
#define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
-int usbdebug;
+extern int usbdebug;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
#endif
+#if defined(__NetBSD__)
+MALLOC_DEFINE(M_USB, "USB", "USB misc. memory");
+MALLOC_DEFINE(M_USBDEV, "USB device", "USB device driver");
+MALLOC_DEFINE(M_USBHC, "USB HC", "USB host controller");
+#endif
+
#define USB_MEM_SMALL 64
#define USB_MEM_CHUNKS 64
#define USB_MEM_BLOCK (USB_MEM_SMALL * USB_MEM_CHUNKS)
@@ -270,7 +276,7 @@ usb_freemem(usbd_bus_handle bus, usb_dma_t *p)
usb_block_freemem(p->block);
return;
}
- f = KERNADDR(p);
+ f = KERNADDR(p, 0);
f->block = p->block;
f->offs = p->offs;
s = splusb();
diff --git a/sys/dev/usb/usb_mem.h b/sys/dev/usb/usb_mem.h
index 9c7d91b3ae2..28b3d45cb6f 100644
--- a/sys/dev/usb/usb_mem.h
+++ b/sys/dev/usb/usb_mem.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: usb_mem.h,v 1.9 2002/07/25 02:18:11 nate Exp $ */
-/* $NetBSD: usb_mem.h,v 1.15 2000/06/28 16:39:27 mrg Exp $ */
+/* $OpenBSD: usb_mem.h,v 1.10 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: usb_mem.h,v 1.20 2003/05/03 18:11:42 wiz Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_mem.h,v 1.9 1999/11/17 22:33:47 n_hibma Exp $ */
/*
@@ -52,8 +52,9 @@ typedef struct usb_dma_block {
LIST_ENTRY(usb_dma_block) next;
} usb_dma_block_t;
-#define DMAADDR(dma) ((dma)->block->map->dm_segs[0].ds_addr + (dma)->offs)
-#define KERNADDR(dma) ((void *)((dma)->block->kaddr + (dma)->offs))
+#define DMAADDR(dma, o) ((dma)->block->map->dm_segs[0].ds_addr + (dma)->offs + (o))
+#define KERNADDR(dma, o) \
+ ((void *)((char *)((dma)->block->kaddr + (dma)->offs) + (o)))
usbd_status usb_allocmem(usbd_bus_handle,size_t,size_t, usb_dma_t *);
void usb_freemem(usbd_bus_handle, usb_dma_t *);
@@ -61,7 +62,7 @@ void usb_freemem(usbd_bus_handle, usb_dma_t *);
#elif defined(__FreeBSD__)
/*
- * FreeBSD does not have special functions for dma memory, so let's keep it
+ * FreeBSD does not have special functions for DMA memory, so let's keep it
* simple for now.
*/
@@ -78,10 +79,10 @@ void usb_freemem(usbd_bus_handle, usb_dma_t *);
#define usb_freemem(t,p) (free(*(p), M_USB))
#ifdef __alpha__
-#define DMAADDR(dma) (alpha_XXX_dmamap((vm_offset_t) *(dma)))
+#define DMAADDR(dma, o) (alpha_XXX_dmamap((vm_offset_t) *(dma) + (o)))
#else
-#define DMAADDR(dma) (vtophys(*(dma)))
-#endif
-#define KERNADDR(dma) ((void *) *(dma))
+#define DMAADDR(dma, o) (vtophys(*(dma) + (o)))
#endif
+#define KERNADDR(dma, o) ((void *) ((char *)*(dma) + (o)))
+#endif /* __FreeBSD__ */
diff --git a/sys/dev/usb/usb_port.h b/sys/dev/usb/usb_port.h
index 2cccb2f543d..a668052db5f 100644
--- a/sys/dev/usb/usb_port.h
+++ b/sys/dev/usb/usb_port.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: usb_port.h,v 1.42 2003/06/27 16:57:14 nate Exp $ */
-/* $NetBSD: usb_port.h,v 1.44 2001/05/14 20:35:29 bouyer Exp $ */
+/* $OpenBSD: usb_port.h,v 1.43 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: usb_port.h,v 1.62 2003/02/15 18:33:30 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_port.h,v 1.21 1999/11/17 22:33:47 n_hibma Exp $ */
/*
@@ -53,10 +53,20 @@
#include "opt_usbverbose.h"
+#if defined(_KERNEL)
+#include <sys/mallocvar.h>
+
+MALLOC_DECLARE(M_USB);
+MALLOC_DECLARE(M_USBDEV);
+MALLOC_DECLARE(M_USBHC);
+
+#endif
+
#define USB_USE_SOFTINTR
#ifdef USB_DEBUG
#define UKBD_DEBUG 1
+#define UHIDEV_DEBUG 1
#define UHID_DEBUG 1
#define OHCI_DEBUG 1
#define UGEN_DEBUG 1
@@ -65,26 +75,37 @@
#define ULPT_DEBUG 1
#define UCOM_DEBUG 1
#define UPLCOM_DEBUG 1
+#define UMCT_DEBUG 1
#define UMODEM_DEBUG 1
#define UAUDIO_DEBUG 1
#define AUE_DEBUG 1
#define CUE_DEBUG 1
#define KUE_DEBUG 1
+#define URL_DEBUG 1
#define UMASS_DEBUG 1
#define UVISOR_DEBUG 1
#define UPL_DEBUG 1
#define UZCOM_DEBUG 1
#define URIO_DEBUG 1
#define UFTDI_DEBUG 1
-#define UMCT_DEBUG 1
#define USCANNER_DEBUG 1
#define USSCANNER_DEBUG 1
+#define UIRDA_DEBUG 1
+#define USTIR_DEBUG 1
+#define UISDATA_DEBUG 1
+#define UDSBR_DEBUG 1
+#define UBT_DEBUG 1
+#define UAX_DEBUG 1
#define Static
#else
#define Static static
#endif
-#define SCSI_MODE_SENSE MODE_SENSE
+#define SCSI_MODE_SENSE MODE_SENSE
+
+#define UMASS_ATAPISTR "atapibus"
+
+typedef struct proc *usb_proc_ptr;
typedef struct device *device_ptr_t;
#define USBBASEDEVICE struct device
@@ -104,18 +125,22 @@ typedef struct device *device_ptr_t;
typedef struct callout usb_callout_t;
#define usb_callout_init(h) callout_init(&(h))
#define usb_callout(h, t, f, d) callout_reset(&(h), (t), (f), (d))
+#define usb_callout_pending(h) callout_pending(&(h))
#define usb_uncallout(h, f, d) callout_stop(&(h))
+#define usb_lockmgr(l, f, sl, p) lockmgr((l), (f), (sl))
+
#define usb_kthread_create1 kthread_create1
#define usb_kthread_create kthread_create
-typedef int usb_malloc_type;
+typedef struct malloc_type *usb_malloc_type;
#define Ether_ifattach ether_ifattach
#define IF_INPUT(ifp, m) (*(ifp)->if_input)((ifp), (m))
#define logprintf printf
+#define USB_DNAME(dname) dname
#define USB_DECLARE_DRIVER(dname) \
int __CONCAT(dname,_match)(struct device *, struct cfdata *, void *); \
void __CONCAT(dname,_attach)(struct device *, struct device *, void *); \
@@ -124,30 +149,21 @@ int __CONCAT(dname,_activate)(struct device *, enum devact); \
\
extern struct cfdriver __CONCAT(dname,_cd); \
\
-struct cfattach __CONCAT(dname,_ca) = { \
- sizeof(struct __CONCAT(dname,_softc)), \
- __CONCAT(dname,_match), \
- __CONCAT(dname,_attach), \
- __CONCAT(dname,_detach), \
- __CONCAT(dname,_activate), \
-}
+CFATTACH_DECL(USB_DNAME(dname), \
+ sizeof(struct ___CONCAT(dname,_softc)), \
+ ___CONCAT(dname,_match), \
+ ___CONCAT(dname,_attach), \
+ ___CONCAT(dname,_detach), \
+ ___CONCAT(dname,_activate))
#define USB_MATCH(dname) \
-int \
-__CONCAT(dname,_match)(parent, match, aux) \
- struct device *parent; \
- struct cfdata *match; \
- void *aux;
+int __CONCAT(dname,_match)(struct device *parent, struct cfdata *match, void *aux)
#define USB_MATCH_START(dname, uaa) \
struct usb_attach_arg *uaa = aux
#define USB_ATTACH(dname) \
-void \
-__CONCAT(dname,_attach)(parent, self, aux) \
- struct device *parent; \
- struct device *self; \
- void *aux;
+void __CONCAT(dname,_attach)(struct device *parent, struct device *self, void *aux)
#define USB_ATTACH_START(dname, sc, uaa) \
struct __CONCAT(dname,_softc) *sc = \
@@ -161,10 +177,7 @@ __CONCAT(dname,_attach)(parent, self, aux) \
#define USB_ATTACH_SETUP printf("\n")
#define USB_DETACH(dname) \
-int \
-__CONCAT(dname,_detach)(self, flags) \
- struct device *self; \
- int flags;
+int __CONCAT(dname,_detach)(struct device *self, int flags)
#define USB_DETACH_START(dname, sc) \
struct __CONCAT(dname,_softc) *sc = \
@@ -184,10 +197,13 @@ __CONCAT(dname,_detach)(self, flags) \
(config_found_sm(parent, args, print, sub))
#elif defined(__OpenBSD__)
-#include <sys/timeout.h>
/*
* OpenBSD
*/
+#include <sys/timeout.h>
+
+#define USB_USE_SOFTINTR
+
#ifdef USB_DEBUG
#define UKBD_DEBUG 1
#define UHIDEV_DEBUG 1
@@ -198,6 +214,8 @@ __CONCAT(dname,_detach)(self, flags) \
#define UHUB_DEBUG 1
#define ULPT_DEBUG 1
#define UCOM_DEBUG 1
+#define UPLCOM_DEBUG 1
+#define UMCT_DEBUG 1
#define UMODEM_DEBUG 1
#define UAUDIO_DEBUG 1
#define AUE_DEBUG 1
@@ -209,9 +227,10 @@ __CONCAT(dname,_detach)(self, flags) \
#define UZCOM_DEBUG 1
#define URIO_DEBUG 1
#define UFTDI_DEBUG 1
-#define UMCT_DEBUG 1
#define USCANNER_DEBUG 1
#define USSCANNER_DEBUG 1
+#define UISDATA_DEBUG 1
+#define UDSBR_DEBUG 1
#endif
#define Static
@@ -229,6 +248,10 @@ __CONCAT(dname,_detach)(self, flags) \
#define PQUIRK_ONLYBIG SDEV_ONLYBIG
#define PQUIRK_NOBIGMODESENSE 0
+#define sel_klist si_note
+
+typedef struct proc *usb_proc_ptr;
+
#define UCOMBUSCF_PORTNO -1
#define UCOMBUSCF_PORTNO_DEFAULT -1
#define UHIDBUSCF_REPORTID -1
@@ -237,6 +260,8 @@ __CONCAT(dname,_detach)(self, flags) \
#define bswap32(x) swap32(x)
#define bswap16(x) swap16(x)
+#define mstohz(ms) ((ms) * hz / 1000)
+
/*
* The UHCI/OHCI controllers are little endian, so on big endian machines
* the data strored in memory needs to be swapped.
@@ -281,7 +306,6 @@ typedef int usb_malloc_type;
#define realloc usb_realloc
void *usb_realloc(void *, u_int, int, int);
-typedef struct proc *usb_proc_ptr;
typedef struct device *device_ptr_t;
#define USBBASEDEVICE struct device
#define USBDEV(bdev) (&(bdev))
@@ -305,6 +329,7 @@ typedef struct timeout usb_callout_t;
timeout_set(&(h), (f), (d)); \
timeout_add(&(h), (t)); \
} while (0)
+#define usb_callout_pending(h) timeout_pending(&(h))
#define usb_uncallout(h, f, d) timeout_del(&(h))
#define usb_lockmgr(l, f, sl, p) lockmgr((l), (f), (sl), (p))
@@ -319,7 +344,7 @@ struct cfdriver __CONCAT(dname,_cd) = { \
NULL, #dname, DV_DULL \
}; \
\
-struct cfattach __CONCAT(dname,_ca) = { \
+const struct cfattach __CONCAT(dname,_ca) = { \
sizeof(struct __CONCAT(dname,_softc)), \
__CONCAT(dname,_match), \
__CONCAT(dname,_attach), \
@@ -385,6 +410,15 @@ __CONCAT(dname,_detach)(self, flags) \
#include "opt_usb.h"
+#if defined(_KERNEL)
+#include <sys/malloc.h>
+
+MALLOC_DECLARE(M_USB);
+MALLOC_DECLARE(M_USBDEV);
+MALLOC_DECLARE(M_USBHC);
+
+#endif
+
#define Static
#define USBVERBOSE
@@ -399,14 +433,15 @@ __CONCAT(dname,_detach)(self, flags) \
#define DECLARE_USB_DMA_T typedef void * usb_dma_t
+typedef struct proc *usb_proc_ptr;
+
/* XXX Change this when FreeBSD has memset
*/
#define memcpy(d, s, l) bcopy((s),(d),(l))
#define memset(d, v, l) bzero((d),(l))
#define bswap32(x) swap32(x)
-#define usb_kthread_create1(function, sc, priv, string, name)
-#define usb_kthread_create(create_function, sc)
-#define usb_kthread_exit(err)
+#define kthread_create1(f, s, p, a0, a1) \
+ kthread_create((f), (s), (p), RFHIGHPID, (a0), (a1))
typedef struct callout_handle usb_callout_t;
#define usb_callout_init(h) callout_handle_init(&(h))
@@ -420,6 +455,8 @@ typedef struct callout_handle usb_callout_t;
#define powerhook_disestablish(hdl)
#define PWR_RESUME 0
+#define config_detach(dev, flag) device_delete_child(device_get_parent(dev), dev)
+
typedef struct malloc_type *usb_malloc_type;
#define USB_DECLARE_DRIVER_INIT(dname, init) \
@@ -488,13 +525,7 @@ __CONCAT(dname,_detach)(device_t self)
(device_probe_and_attach((bdev)) == 0 ? (bdev) : 0)
/* conversion from one type of queue to the other */
-/* XXX In FreeBSD SIMPLEQ_REMOVE_HEAD only removes the head element.
- */
-#define SIMPLEQ_REMOVE_HEAD(h, e, f) do { \
- if ( (e) != SIMPLEQ_FIRST((h)) ) \
- panic("Removing other than first element"); \
- STAILQ_REMOVE_HEAD(h, f); \
-} while (0)
+#define SIMPLEQ_REMOVE_HEAD STAILQ_REMOVE_HEAD
#define SIMPLEQ_INSERT_HEAD STAILQ_INSERT_HEAD
#define SIMPLEQ_INSERT_TAIL STAILQ_INSERT_TAIL
#define SIMPLEQ_NEXT STAILQ_NEXT
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index 79a189f14e1..8d9f40db20b 100644
--- a/sys/dev/usb/usb_subr.c
+++ b/sys/dev/usb/usb_subr.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: usb_subr.c,v 1.25 2003/05/18 18:13:22 nate Exp $ */
-/* $NetBSD: usb_subr.c,v 1.87 2001/08/15 00:04:59 augustss Exp $ */
+/* $OpenBSD: usb_subr.c,v 1.26 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: usb_subr.c,v 1.103 2003/01/10 11:19:13 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */
/*
@@ -154,15 +154,21 @@ usbd_get_string_desc(usbd_device_handle dev, int sindex, int langid,
{
usb_device_request_t req;
usbd_status err;
+ int actlen;
req.bmRequestType = UT_READ_DEVICE;
req.bRequest = UR_GET_DESCRIPTOR;
USETW2(req.wValue, UDESC_STRING, sindex);
USETW(req.wIndex, langid);
USETW(req.wLength, 1); /* only size byte first */
- err = usbd_do_request(dev, &req, sdesc);
+ err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK,
+ &actlen, USBD_DEFAULT_TIMEOUT);
if (err)
return (err);
+
+ if (actlen < 1)
+ return (USBD_SHORT_XFER);
+
USETW(req.wLength, sdesc->bLength); /* the whole string */
return (usbd_do_request(dev, &req, sdesc));
}
@@ -362,6 +368,9 @@ usbd_reset_port(usbd_device_handle dev, int port, usb_port_status_t *ps)
err));
return (err);
}
+ /* If the device disappeared, just give up. */
+ if (!(UGETW(ps->wPortStatus) & UPS_CURRENT_CONNECT_STATUS))
+ return (USBD_NORMAL_COMPLETION);
} while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0);
if (n == 0)
return (USBD_TIMEOUT);
@@ -485,13 +494,36 @@ usbd_fill_iface_data(usbd_device_handle dev, int ifaceidx, int altidx)
break;
}
/* passed end, or bad desc */
- DPRINTF(("usbd_fill_iface_data: bad descriptor(s): %s\n",
- ed->bLength == 0 ? "0 length" :
- ed->bDescriptorType == UDESC_INTERFACE ? "iface desc":
- "out of data"));
+ printf("usbd_fill_iface_data: bad descriptor(s): %s\n",
+ ed->bLength == 0 ? "0 length" :
+ ed->bDescriptorType == UDESC_INTERFACE ? "iface desc":
+ "out of data");
goto bad;
found:
ifc->endpoints[endpt].edesc = ed;
+ if (dev->speed == USB_SPEED_HIGH) {
+ u_int mps;
+ /* Control and bulk endpoints have max packet
+ limits. */
+ switch (UE_GET_XFERTYPE(ed->bmAttributes)) {
+ case UE_CONTROL:
+ mps = USB_2_MAX_CTRL_PACKET;
+ goto check;
+ case UE_BULK:
+ mps = USB_2_MAX_BULK_PACKET;
+ check:
+ if (UGETW(ed->wMaxPacketSize) != mps) {
+ USETW(ed->wMaxPacketSize, mps);
+#ifdef DIAGNOSTIC
+ printf("usbd_fill_iface_data: bad max "
+ "packet size\n");
+#endif
+ }
+ break;
+ default:
+ break;
+ }
+ }
ifc->endpoints[endpt].refcnt = 0;
p += ed->bLength;
}
@@ -556,7 +588,7 @@ usbd_set_config_index(usbd_device_handle dev, int index, int msg)
usb_status_t ds;
usb_config_descriptor_t cd, *cdp;
usbd_status err;
- int ifcidx, nifc, len, selfpowered, power;
+ int i, ifcidx, nifc, len, selfpowered, power;
DPRINTFN(5,("usbd_set_config_index: dev=%p index=%d\n", dev, index));
@@ -593,9 +625,15 @@ usbd_set_config_index(usbd_device_handle dev, int index, int msg)
if (cdp == NULL)
return (USBD_NOMEM);
/* Get the full descriptor. */
- err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp);
+ for (i = 0; i < 3; i++) {
+ err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp);
+ if (!err)
+ break;
+ usbd_delay_ms(dev, 200);
+ }
if (err)
goto bad;
+
if (cdp->bDescriptorType != UDESC_CONFIG) {
DPRINTFN(-1,("usbd_set_config_index: bad desc %d\n",
cdp->bDescriptorType));
@@ -735,7 +773,6 @@ usbd_setup_pipe(usbd_device_handle dev, usbd_interface_handle iface,
p->repeat = 0;
p->interval = ival;
SIMPLEQ_INIT(&p->queue);
- usb_callout_init(p->abort_handle);
err = dev->bus->methods->open_pipe(p);
if (err) {
DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, error="
@@ -755,6 +792,7 @@ usbd_setup_pipe(usbd_device_handle dev, usbd_interface_handle iface,
void
usbd_kill_pipe(usbd_pipe_handle pipe)
{
+ usbd_abort_pipe(pipe);
pipe->methods->close(pipe);
pipe->endpoint->refcnt--;
free(pipe, M_USB);
@@ -937,16 +975,17 @@ usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev,
*/
usbd_status
usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
- int lowspeed, int port, struct usbd_port *up)
+ int speed, int port, struct usbd_port *up)
{
usbd_device_handle dev;
+ struct usbd_device *hub;
usb_device_descriptor_t *dd;
usbd_status err;
int addr;
int i;
- DPRINTF(("usbd_new_device bus=%p port=%d depth=%d lowspeed=%d\n",
- bus, port, depth, lowspeed));
+ DPRINTF(("usbd_new_device bus=%p port=%d depth=%d speed=%d\n",
+ bus, port, depth, speed));
addr = usbd_getnewaddr(bus);
if (addr < 0) {
printf("%s: No free USB addresses, new device ignored.\n",
@@ -957,7 +996,7 @@ usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
dev = malloc(sizeof *dev, M_USB, M_NOWAIT);
if (dev == NULL)
return (USBD_NOMEM);
- memset(dev, 0, sizeof(*dev));
+ memset(dev, 0, sizeof *dev);
dev->bus = bus;
@@ -975,9 +1014,15 @@ usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
dev->quirks = &usbd_no_quirk;
dev->address = USB_START_ADDR;
dev->ddesc.bMaxPacketSize = 0;
- dev->lowspeed = lowspeed != 0;
dev->depth = depth;
dev->powersrc = up;
+ dev->myhub = up->parent;
+ for (hub = up->parent;
+ hub != NULL && hub->speed != USB_SPEED_HIGH;
+ hub = hub->myhub)
+ ;
+ dev->myhighhub = hub;
+ dev->speed = speed;
dev->langid = USBD_NOLANG;
dev->cookie.cookie = ++usb_cookie_no;
@@ -1007,11 +1052,22 @@ usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
return (err);
}
+ if (speed == USB_SPEED_HIGH) {
+ /* Max packet size must be 64 (sec 5.5.3). */
+ if (dd->bMaxPacketSize != USB_2_MAX_CTRL_PACKET) {
+#ifdef DIAGNOSTIC
+ printf("usbd_new_device: addr=%d bad max packet size\n",
+ addr);
+#endif
+ dd->bMaxPacketSize = USB_2_MAX_CTRL_PACKET;
+ }
+ }
+
DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, "
- "subclass=%d, protocol=%d, maxpacket=%d, len=%d, ls=%d\n",
+ "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n",
addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass,
dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength,
- dev->lowspeed));
+ dev->speed));
if (dd->bDescriptorType != UDESC_DEVICE) {
/* Illegal device descriptor */
@@ -1215,7 +1271,7 @@ usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di,
di->udi_protocol = dev->ddesc.bDeviceProtocol;
di->udi_config = dev->config;
di->udi_power = dev->self_powered ? 0 : dev->power;
- di->udi_lowspeed = dev->lowspeed;
+ di->udi_speed = dev->speed;
if (dev->subdevs != NULL) {
for (i = 0; dev->subdevs[i] &&
@@ -1318,13 +1374,7 @@ usb_disconnect_port(struct usbd_port *up, device_ptr_t parent)
if (up->portno != 0)
printf(" port %d", up->portno);
printf(" (addr %d) disconnected\n", dev->address);
-#if defined(__NetBSD__) || defined(__OpenBSD__)
config_detach(dev->subdevs[i], DETACH_FORCE);
-#elif defined(__FreeBSD__)
- device_delete_child(device_get_parent(dev->subdevs[i]),
- dev->subdevs[i]);
-#endif
-
}
}
diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index dd075a22acb..44c247998bf 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: usbdi.c,v 1.22 2003/05/17 05:33:45 nate Exp $ */
-/* $NetBSD: usbdi.c,v 1.81 2001/04/17 00:05:33 augustss Exp $ */
+/* $OpenBSD: usbdi.c,v 1.23 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: usbdi.c,v 1.103 2002/09/27 15:37:38 provos Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdi.c,v 1.28 1999/11/17 22:33:49 n_hibma Exp $ */
/*
@@ -79,10 +79,10 @@ extern int usbdebug;
Static usbd_status usbd_ar_pipe(usbd_pipe_handle pipe);
Static void usbd_do_request_async_cb
-(usbd_xfer_handle, usbd_private_handle, usbd_status);
+ (usbd_xfer_handle, usbd_private_handle, usbd_status);
Static void usbd_start_next(usbd_pipe_handle pipe);
Static usbd_status usbd_open_pipe_ival
-(usbd_interface_handle, u_int8_t, u_int8_t, usbd_pipe_handle *, int);
+ (usbd_interface_handle, u_int8_t, u_int8_t, usbd_pipe_handle *, int);
Static int usbd_nbuses = 0;
@@ -109,19 +109,67 @@ usbd_xfer_isread(usbd_xfer_handle xfer)
}
#ifdef USB_DEBUG
-void usbd_dump_queue(usbd_pipe_handle pipe);
+void
+usbd_dump_iface(struct usbd_interface *iface)
+{
+ printf("usbd_dump_iface: iface=%p\n", iface);
+ if (iface == NULL)
+ return;
+ printf(" device=%p idesc=%p index=%d altindex=%d priv=%p\n",
+ iface->device, iface->idesc, iface->index, iface->altindex,
+ iface->priv);
+}
+
+void
+usbd_dump_device(struct usbd_device *dev)
+{
+ printf("usbd_dump_device: dev=%p\n", dev);
+ if (dev == NULL)
+ return;
+ printf(" bus=%p default_pipe=%p\n", dev->bus, dev->default_pipe);
+ printf(" address=%d config=%d depth=%d speed=%d self_powered=%d "
+ "power=%d langid=%d\n",
+ dev->address, dev->config, dev->depth, dev->speed,
+ dev->self_powered, dev->power, dev->langid);
+}
+
+void
+usbd_dump_endpoint(struct usbd_endpoint *endp)
+{
+ printf("usbd_dump_endpoint: endp=%p\n", endp);
+ if (endp == NULL)
+ return;
+ printf(" edesc=%p refcnt=%d\n", endp->edesc, endp->refcnt);
+ if (endp->edesc)
+ printf(" bEndpointAddress=0x%02x\n",
+ endp->edesc->bEndpointAddress);
+}
+
void
usbd_dump_queue(usbd_pipe_handle pipe)
{
usbd_xfer_handle xfer;
printf("usbd_dump_queue: pipe=%p\n", pipe);
- for (xfer = SIMPLEQ_FIRST(&pipe->queue);
- xfer;
- xfer = SIMPLEQ_NEXT(xfer, next)) {
+ SIMPLEQ_FOREACH(xfer, &pipe->queue, next) {
printf(" xfer=%p\n", xfer);
}
}
+
+void
+usbd_dump_pipe(usbd_pipe_handle pipe)
+{
+ printf("usbd_dump_pipe: pipe=%p\n", pipe);
+ if (pipe == NULL)
+ return;
+ usbd_dump_iface(pipe->iface);
+ usbd_dump_device(pipe->device);
+ usbd_dump_endpoint(pipe->endpoint);
+ printf(" (usbd_dump_pipe:)\n refcnt=%d running=%d aborting=%d\n",
+ pipe->refcnt, pipe->running, pipe->aborting);
+ printf(" intrxfer=%p, repeat=%d, interval=%d\n",
+ pipe->intrxfer, pipe->repeat, pipe->interval);
+}
#endif
usbd_status
@@ -216,17 +264,11 @@ usbd_close_pipe(usbd_pipe_handle pipe)
if (--pipe->refcnt != 0)
return (USBD_NORMAL_COMPLETION);
- if (SIMPLEQ_FIRST(&pipe->queue) != 0)
+ if (! SIMPLEQ_EMPTY(&pipe->queue))
return (USBD_PENDING_REQUESTS);
LIST_REMOVE(pipe, next);
pipe->endpoint->refcnt--;
pipe->methods->close(pipe);
-#if defined(__NetBSD__) && defined(DIAGNOSTIC)
- if (callout_pending(&pipe->abort_handle)) {
- callout_stop(&pipe->abort_handle);
- printf("usbd_close_pipe: abort_handle pending");
- }
-#endif
if (pipe->intrxfer != NULL)
usbd_free_xfer(pipe->intrxfer);
free(pipe, M_USB);
@@ -271,7 +313,7 @@ usbd_transfer(usbd_xfer_handle xfer)
/* Copy data if going out. */
if (!(xfer->flags & USBD_NO_COPY) && size != 0 &&
!usbd_xfer_isread(xfer))
- memcpy(KERNADDR(dmap), xfer->buffer, size);
+ memcpy(KERNADDR(dmap, 0), xfer->buffer, size);
err = pipe->methods->transfer(xfer);
@@ -315,11 +357,15 @@ usbd_alloc_buffer(usbd_xfer_handle xfer, u_int32_t size)
struct usbd_bus *bus = xfer->device->bus;
usbd_status err;
+#ifdef DIAGNOSTIC
+ if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))
+ printf("usbd_alloc_buffer: xfer already has a buffer\n");
+#endif
err = bus->methods->allocm(bus, &xfer->dmabuf, size);
if (err)
- return (0);
+ return (NULL);
xfer->rqflags |= URQ_DEV_DMABUF;
- return (KERNADDR(&xfer->dmabuf));
+ return (KERNADDR(&xfer->dmabuf, 0));
}
void
@@ -340,7 +386,7 @@ usbd_get_buffer(usbd_xfer_handle xfer)
{
if (!(xfer->rqflags & URQ_DEV_DMABUF))
return (0);
- return (KERNADDR(&xfer->dmabuf));
+ return (KERNADDR(&xfer->dmabuf, 0));
}
usbd_xfer_handle
@@ -512,7 +558,7 @@ usbd_clear_endpoint_stall(usbd_pipe_handle pipe)
DPRINTFN(8, ("usbd_clear_endpoint_stall\n"));
/*
- * Clearing en endpoint stall resets the enpoint toggle, so
+ * Clearing en endpoint stall resets the endpoint toggle, so
* do the same to the HC toggle.
*/
pipe->methods->cleartoggle(pipe);
@@ -579,12 +625,11 @@ usbd_interface_count(usbd_device_handle dev, u_int8_t *count)
return (USBD_NORMAL_COMPLETION);
}
-usbd_status
+void
usbd_interface2device_handle(usbd_interface_handle iface,
usbd_device_handle *dev)
{
*dev = iface->device;
- return (USBD_NORMAL_COMPLETION);
}
usbd_status
@@ -718,6 +763,13 @@ usb_transfer_complete(usbd_xfer_handle xfer)
DPRINTFN(5, ("usb_transfer_complete: pipe=%p xfer=%p status=%d "
"actlen=%d\n", pipe, xfer, xfer->status, xfer->actlen));
+#ifdef DIAGNOSTIC
+ if (xfer->busy_free != XFER_ONQU) {
+ printf("usb_transfer_complete: xfer=%p not busy 0x%08x\n",
+ xfer, xfer->busy_free);
+ return;
+ }
+#endif
#ifdef DIAGNOSTIC
if (pipe == NULL) {
@@ -739,7 +791,7 @@ usb_transfer_complete(usbd_xfer_handle xfer)
xfer->actlen = xfer->length;
}
#endif
- memcpy(xfer->buffer, KERNADDR(dmap), xfer->actlen);
+ memcpy(xfer->buffer, KERNADDR(dmap, 0), xfer->actlen);
}
/* if we allocated the buffer in usbd_transfer() we free it here. */
@@ -757,6 +809,7 @@ usb_transfer_complete(usbd_xfer_handle xfer)
if (xfer != SIMPLEQ_FIRST(&pipe->queue))
printf("usb_transfer_complete: bad dequeue %p != %p\n",
xfer, SIMPLEQ_FIRST(&pipe->queue));
+ xfer->busy_free = XFER_BUSY;
#endif
SIMPLEQ_REMOVE_HEAD(&pipe->queue, xfer, next);
}
@@ -810,6 +863,14 @@ usb_insert_transfer(usbd_xfer_handle xfer)
DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d timeout=%d\n",
pipe, pipe->running, xfer->timeout));
+#ifdef DIAGNOSTIC
+ if (xfer->busy_free != XFER_BUSY) {
+ printf("usb_insert_transfer: xfer=%p not busy 0x%08x\n",
+ xfer, xfer->busy_free);
+ return (USBD_INVAL);
+ }
+ xfer->busy_free = XFER_ONQU;
+#endif
s = splusb();
SIMPLEQ_INSERT_TAIL(&pipe->queue, xfer, next);
if (pipe->running)
@@ -1025,9 +1086,11 @@ usbd_set_polling(usbd_device_handle dev, int on)
dev->bus->use_polling++;
else
dev->bus->use_polling--;
+ /* When polling we need to make sure there is nothing pending to do. */
+ if (dev->bus->use_polling)
+ dev->bus->methods->soft_intr(dev->bus);
}
-
usb_endpoint_descriptor_t *
usbd_get_endpoint_descriptor(usbd_interface_handle iface, u_int8_t address)
{
@@ -1069,7 +1132,7 @@ usb_match_device(const struct usb_devno *tbl, u_int nentries, u_int sz,
if (tbl->ud_vendor == vendor &&
(tproduct == product || tproduct == USB_PRODUCT_ANY))
return (tbl);
- tbl = (struct usb_devno *)((char *)tbl + sz);
+ tbl = (const struct usb_devno *)((const char *)tbl + sz);
}
return (NULL);
}
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 360bdd6241a..2df02e6e854 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: usbdi.h,v 1.20 2003/05/17 05:33:45 nate Exp $ */
-/* $NetBSD: usbdi.h,v 1.53 2001/08/15 00:04:59 augustss Exp $ */
+/* $OpenBSD: usbdi.h,v 1.21 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: usbdi.h,v 1.62 2002/07/11 21:14:35 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdi.h,v 1.18 1999/11/17 22:33:49 n_hibma Exp $ */
/*
@@ -48,25 +48,25 @@ typedef void *usbd_private_handle;
typedef enum { /* keep in sync with usbd_status_msgs */
USBD_NORMAL_COMPLETION = 0, /* must be 0 */
- USBD_IN_PROGRESS,
+ USBD_IN_PROGRESS, /* 1 */
/* errors */
- USBD_PENDING_REQUESTS,
- USBD_NOT_STARTED,
- USBD_INVAL,
- USBD_NOMEM,
- USBD_CANCELLED,
- USBD_BAD_ADDRESS,
- USBD_IN_USE,
- USBD_NO_ADDR,
- USBD_SET_ADDR_FAILED,
- USBD_NO_POWER,
- USBD_TOO_DEEP,
- USBD_IOERROR,
- USBD_NOT_CONFIGURED,
- USBD_TIMEOUT,
- USBD_SHORT_XFER,
- USBD_STALLED,
- USBD_INTERRUPTED,
+ USBD_PENDING_REQUESTS, /* 2 */
+ USBD_NOT_STARTED, /* 3 */
+ USBD_INVAL, /* 4 */
+ USBD_NOMEM, /* 5 */
+ USBD_CANCELLED, /* 6 */
+ USBD_BAD_ADDRESS, /* 7 */
+ USBD_IN_USE, /* 8 */
+ USBD_NO_ADDR, /* 9 */
+ USBD_SET_ADDR_FAILED, /* 10 */
+ USBD_NO_POWER, /* 11 */
+ USBD_TOO_DEEP, /* 12 */
+ USBD_IOERROR, /* 13 */
+ USBD_NOT_CONFIGURED, /* 14 */
+ USBD_TIMEOUT, /* 15 */
+ USBD_SHORT_XFER, /* 16 */
+ USBD_STALLED, /* 17 */
+ USBD_INTERRUPTED, /* 18 */
USBD_ERROR_MAX /* must be last */
} usbd_status;
@@ -120,14 +120,14 @@ usbd_status usbd_clear_endpoint_stall_async(usbd_pipe_handle pipe);
void usbd_clear_endpoint_toggle(usbd_pipe_handle pipe);
usbd_status usbd_endpoint_count(usbd_interface_handle dev, u_int8_t *count);
usbd_status usbd_interface_count(usbd_device_handle dev, u_int8_t *count);
-usbd_status usbd_interface2device_handle(usbd_interface_handle iface,
- usbd_device_handle *dev);
+void usbd_interface2device_handle(usbd_interface_handle iface,
+ usbd_device_handle *dev);
usbd_status usbd_device2interface_handle(usbd_device_handle dev,
u_int8_t ifaceno, usbd_interface_handle *iface);
usbd_device_handle usbd_pipe2device_handle(usbd_pipe_handle);
-void *usbd_alloc_buffer(usbd_xfer_handle req, u_int32_t size);
-void usbd_free_buffer(usbd_xfer_handle req);
+void *usbd_alloc_buffer(usbd_xfer_handle xfer, u_int32_t size);
+void usbd_free_buffer(usbd_xfer_handle xfer);
void *usbd_get_buffer(usbd_xfer_handle xfer);
usbd_status usbd_sync_transfer(usbd_xfer_handle req);
usbd_status usbd_open_pipe_intr(usbd_interface_handle iface, u_int8_t address,
@@ -152,7 +152,7 @@ usb_device_descriptor_t *usbd_get_device_descriptor(usbd_device_handle dev);
usbd_status usbd_set_interface(usbd_interface_handle, int);
int usbd_get_no_alts(usb_config_descriptor_t *, int);
usbd_status usbd_get_interface(usbd_interface_handle iface, u_int8_t *aiface);
-void usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di, int);
+void usbd_fill_deviceinfo(usbd_device_handle, struct usb_device_info *, int);
int usbd_get_interface_altindex(usbd_interface_handle iface);
usb_interface_descriptor_t *usbd_find_idesc(usb_config_descriptor_t *cd,
@@ -269,14 +269,15 @@ struct usb_attach_arg {
int usbd_driver_load(module_t mod, int what, void *arg);
#endif
-/*
- * XXX
- * splusb MUST be the lowest level interrupt so that within USB callbacks
- * the level can be raised the appropriate level.
- * XXX Should probably use a softsplusb.
- */
-/* XXX */
+/* XXX Perhaps USB should have its own levels? */
+#ifdef USB_USE_SOFTINTR
+#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
+#define splusb splsoftnet
+#else
+#define splusb splsoftclock
+#endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
+#else
#define splusb splbio
+#endif /* USB_USE_SOFTINTR */
#define splhardusb splbio
#define IPL_USB IPL_BIO
-/* XXX */
diff --git a/sys/dev/usb/usbdi_util.c b/sys/dev/usb/usbdi_util.c
index 196e0a3cb6e..66d05ba40a6 100644
--- a/sys/dev/usb/usbdi_util.c
+++ b/sys/dev/usb/usbdi_util.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: usbdi_util.c,v 1.14 2002/07/25 02:18:11 nate Exp $ */
-/* $NetBSD: usbdi_util.c,v 1.35 2001/10/26 17:58:21 augustss Exp $ */
+/* $OpenBSD: usbdi_util.c,v 1.15 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: usbdi_util.c,v 1.40 2002/07/11 21:14:36 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdi_util.c,v 1.14 1999/11/17 22:33:50 n_hibma Exp $ */
/*
@@ -220,6 +220,25 @@ usbd_set_port_feature(usbd_device_handle dev, int port, int sel)
return (usbd_do_request(dev, &req, 0));
}
+usbd_status
+usbd_get_protocol(usbd_interface_handle iface, u_int8_t *report)
+{
+ usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
+ usbd_device_handle dev;
+ usb_device_request_t req;
+
+ DPRINTFN(4, ("usbd_get_protocol: iface=%p, endpt=%d\n",
+ iface, id->bInterfaceNumber));
+ if (id == NULL)
+ return (USBD_IOERROR);
+ usbd_interface2device_handle(iface, &dev);
+ req.bmRequestType = UT_READ_CLASS_INTERFACE;
+ req.bRequest = UR_GET_PROTOCOL;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, id->bInterfaceNumber);
+ USETW(req.wLength, 1);
+ return (usbd_do_request(dev, &req, report));
+}
usbd_status
usbd_set_protocol(usbd_interface_handle iface, int report)
@@ -227,15 +246,12 @@ usbd_set_protocol(usbd_interface_handle iface, int report)
usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
usbd_device_handle dev;
usb_device_request_t req;
- usbd_status err;
DPRINTFN(4, ("usbd_set_protocol: iface=%p, report=%d, endpt=%d\n",
iface, report, id->bInterfaceNumber));
if (id == NULL)
return (USBD_IOERROR);
- err = usbd_interface2device_handle(iface, &dev);
- if (err)
- return (err);
+ usbd_interface2device_handle(iface, &dev);
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
req.bRequest = UR_SET_PROTOCOL;
USETW(req.wValue, report);
@@ -251,14 +267,11 @@ usbd_set_report(usbd_interface_handle iface, int type, int id, void *data,
usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
usbd_device_handle dev;
usb_device_request_t req;
- usbd_status err;
DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
if (ifd == NULL)
return (USBD_IOERROR);
- err = usbd_interface2device_handle(iface, &dev);
- if (err)
- return (err);
+ usbd_interface2device_handle(iface, &dev);
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
req.bRequest = UR_SET_REPORT;
USETW2(req.wValue, type, id);
@@ -268,20 +281,17 @@ usbd_set_report(usbd_interface_handle iface, int type, int id, void *data,
}
usbd_status
-usbd_set_report_async(usbd_interface_handle iface, int type, int id, void *data,
- int len)
+usbd_set_report_async(usbd_interface_handle iface, int type, int id,
+ void *data, int len)
{
usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
usbd_device_handle dev;
usb_device_request_t req;
- usbd_status err;
DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len));
if (ifd == NULL)
return (USBD_IOERROR);
- err = usbd_interface2device_handle(iface, &dev);
- if (err)
- return (err);
+ usbd_interface2device_handle(iface, &dev);
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
req.bRequest = UR_SET_REPORT;
USETW2(req.wValue, type, id);
@@ -297,14 +307,11 @@ usbd_get_report(usbd_interface_handle iface, int type, int id, void *data,
usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
usbd_device_handle dev;
usb_device_request_t req;
- usbd_status err;
DPRINTFN(4, ("usbd_get_report: len=%d\n", len));
if (ifd == NULL)
return (USBD_IOERROR);
- err = usbd_interface2device_handle(iface, &dev);
- if (err)
- return (err);
+ usbd_interface2device_handle(iface, &dev);
req.bmRequestType = UT_READ_CLASS_INTERFACE;
req.bRequest = UR_GET_REPORT;
USETW2(req.wValue, type, id);
@@ -319,14 +326,11 @@ usbd_set_idle(usbd_interface_handle iface, int duration, int id)
usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
usbd_device_handle dev;
usb_device_request_t req;
- usbd_status err;
DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration, id));
if (ifd == NULL)
return (USBD_IOERROR);
- err = usbd_interface2device_handle(iface, &dev);
- if (err)
- return (err);
+ usbd_interface2device_handle(iface, &dev);
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
req.bRequest = UR_SET_IDLE;
USETW2(req.wValue, duration, id);
@@ -357,13 +361,10 @@ usbd_get_hid_descriptor(usbd_interface_handle ifc)
usb_config_descriptor_t *cdesc;
usb_hid_descriptor_t *hd;
char *p, *end;
- usbd_status err;
if (idesc == NULL)
return (0);
- err = usbd_interface2device_handle(ifc, &dev);
- if (err)
- return (0);
+ usbd_interface2device_handle(ifc, &dev);
cdesc = usbd_get_config_descriptor(dev);
p = (char *)idesc + idesc->bLength;
@@ -388,9 +389,7 @@ usbd_read_report_desc(usbd_interface_handle ifc, void **descp, int *sizep,
usbd_device_handle dev;
usbd_status err;
- err = usbd_interface2device_handle(ifc, &dev);
- if (err)
- return (err);
+ usbd_interface2device_handle(ifc, &dev);
id = usbd_get_interface_descriptor(ifc);
if (id == NULL)
return (USBD_INVAL);
@@ -482,3 +481,21 @@ usb_detach_wakeup(device_ptr_t dv)
DPRINTF(("usb_detach_wakeup: for %s\n", USBDEVPTRNAME(dv)));
wakeup(dv);
}
+
+usb_descriptor_t *
+usb_find_desc(usbd_device_handle dev, int type)
+{
+ usb_descriptor_t *desc;
+ usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
+ uByte *p = (uByte *)cd;
+ uByte *end = p + UGETW(cd->wTotalLength);
+
+ while (p < end) {
+ desc = (usb_descriptor_t *)p;
+ if (desc->bDescriptorType == type)
+ return (desc);
+ p += desc->bLength;
+ }
+
+ return (NULL);
+}
diff --git a/sys/dev/usb/usbdi_util.h b/sys/dev/usb/usbdi_util.h
index 0e707710a4d..1d435df6ee5 100644
--- a/sys/dev/usb/usbdi_util.h
+++ b/sys/dev/usb/usbdi_util.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: usbdi_util.h,v 1.11 2002/07/25 02:18:11 nate Exp $ */
-/* $NetBSD: usbdi_util.h,v 1.23 2001/10/26 17:58:22 augustss Exp $ */
+/* $OpenBSD: usbdi_util.h,v 1.12 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: usbdi_util.h,v 1.28 2002/07/11 21:14:36 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdi_util.h,v 1.9 1999/11/17 22:33:50 n_hibma Exp $ */
/*
@@ -53,8 +53,9 @@ usbd_status usbd_set_hub_feature(usbd_device_handle dev, int);
usbd_status usbd_clear_hub_feature(usbd_device_handle, int);
usbd_status usbd_set_port_feature(usbd_device_handle dev, int, int);
usbd_status usbd_clear_port_feature(usbd_device_handle, int, int);
-usbd_status usbd_get_device_status(usbd_device_handle,usb_status_t*);
+usbd_status usbd_get_device_status(usbd_device_handle, usb_status_t *);
usbd_status usbd_get_hub_status(usbd_device_handle, usb_hub_status_t *);
+usbd_status usbd_get_protocol(usbd_interface_handle dev, u_int8_t *report);
usbd_status usbd_set_protocol(usbd_interface_handle dev, int report);
usbd_status usbd_get_report_descriptor(usbd_device_handle dev, int ifcno,
int size, void *d);
@@ -84,3 +85,4 @@ usbd_status usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
void usb_detach_wait(device_ptr_t);
void usb_detach_wakeup(device_ptr_t);
+usb_descriptor_t *usb_find_desc(usbd_device_handle dev, int type);
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index 8b815ad5540..fa323578859 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: usbdivar.h,v 1.18 2003/05/07 04:33:33 deraadt Exp $ */
-/* $NetBSD: usbdivar.h,v 1.63 2001/01/21 19:00:06 augustss Exp $ */
+/* $OpenBSD: usbdivar.h,v 1.19 2003/07/08 13:19:09 nate Exp $ */
+/* $NetBSD: usbdivar.h,v 1.70 2002/07/11 21:14:36 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $ */
/*
@@ -80,7 +80,7 @@ struct usbd_port {
u_int8_t portno;
u_int8_t restartcnt;
#define USBD_RESTART_MAX 5
- struct usbd_device *device;
+ struct usbd_device *device; /* Connected device */
struct usbd_device *parent; /* The ports hub */
};
@@ -117,13 +117,11 @@ struct usbd_bus {
#define USBREV_2_0 4
#define USBREV_STR { "unknown", "pre 1.0", "1.0", "1.1", "2.0" }
-#if 0
#ifdef USB_USE_SOFTINTR
#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
void *soft; /* soft interrupt cookie */
#else
- struct callout softi;
-#endif
+ usb_callout_t softi;
#endif
#endif
@@ -138,13 +136,15 @@ struct usbd_device {
u_int8_t address; /* device addess */
u_int8_t config; /* current configuration # */
u_int8_t depth; /* distance from root hub */
- u_int8_t lowspeed; /* lowspeed flag */
+ u_int8_t speed; /* low/full/high speed */
u_int8_t self_powered; /* flag for self powered */
u_int16_t power; /* mA the device uses */
int16_t langid; /* language for strings */
#define USBD_NOLANG (-1)
usb_event_cookie_t cookie; /* unique connection id */
struct usbd_port *powersrc; /* upstream hub port, or 0 */
+ struct usbd_device *myhub; /* upstream hub */
+ struct usbd_device *myhighhub; /* closest high speed hub */
struct usbd_endpoint def_ep; /* for pipe 0 */
usb_endpoint_descriptor_t def_ep_desc; /* for pipe 0 */
struct usbd_interface *ifaces; /* array of all interfaces */
@@ -179,8 +179,6 @@ struct usbd_pipe {
char repeat;
int interval;
- usb_callout_t abort_handle;
-
/* Filled by HC driver. */
struct usbd_pipe_methods *methods;
};
@@ -199,7 +197,8 @@ struct usbd_xfer {
#ifdef DIAGNOSTIC
u_int32_t busy_free;
#define XFER_FREE 0x46524545
-#define XFER_BUSY 0x42555357
+#define XFER_BUSY 0x42555359
+#define XFER_ONQU 0x4f4e5155
#endif
/* For control pipe */
@@ -228,6 +227,14 @@ struct usbd_xfer {
void usbd_init(void);
void usbd_finish(void);
+#ifdef USB_DEBUG
+void usbd_dump_iface(struct usbd_interface *iface);
+void usbd_dump_device(struct usbd_device *dev);
+void usbd_dump_endpoint(struct usbd_endpoint *endp);
+void usbd_dump_queue(usbd_pipe_handle pipe);
+void usbd_dump_pipe(usbd_pipe_handle pipe);
+#endif
+
/* Routines from usb_subr.c */
int usbctlprint(void *, const char *);
void usb_delay_ms(usbd_bus_handle, u_int);