From e375f3615c7463097f3e178339aad0f6ec36c197 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Tue, 8 Jul 2003 13:19:10 +0000 Subject: Sync USB code with NetBSD. This includes numerous fixes and paves the way for usb 2.0 support. --- sys/dev/usb/ohci.c | 503 ++++++++++++++++++++++++++++++----------------- sys/dev/usb/ohcivar.h | 17 +- sys/dev/usb/uhci.c | 361 ++++++++++++++++++++++++---------- sys/dev/usb/uhcireg.h | 5 +- sys/dev/usb/uhcivar.h | 11 +- sys/dev/usb/uhub.c | 23 ++- sys/dev/usb/usb.c | 222 +++++++++++++++------ sys/dev/usb/usb.h | 141 +++++++++---- sys/dev/usb/usb_mem.c | 14 +- sys/dev/usb/usb_mem.h | 19 +- sys/dev/usb/usb_port.h | 111 +++++++---- sys/dev/usb/usb_subr.c | 98 ++++++--- sys/dev/usb/usbdi.c | 113 ++++++++--- sys/dev/usb/usbdi.h | 67 +++---- sys/dev/usb/usbdi_util.c | 79 +++++--- sys/dev/usb/usbdi_util.h | 8 +- sys/dev/usb/usbdivar.h | 27 ++- 17 files changed, 1248 insertions(+), 571 deletions(-) (limited to 'sys/dev/usb') 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"); @@ -1789,16 +1888,33 @@ 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 }; @@ -2909,6 +2979,101 @@ uhci_str(usb_string_descriptor_t *p, int l, char *s) return (2*i+2); } +/* + * 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. */ @@ -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 #include #include @@ -53,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -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 +#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 #endif /* _KERNEL */ -#elif defined(__FreeBSD__) -#if defined(KERNEL) -#include - -MALLOC_DECLARE(M_USB); -MALLOC_DECLARE(M_USBDEV); -MALLOC_DECLARE(M_USBHC); - -#include -#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; @@ -312,6 +327,32 @@ typedef struct { } UPACKED usb_hub_descriptor_t; #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 */ @@ -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 + +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 /* * OpenBSD */ +#include + +#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 + +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); -- cgit v1.2.3