--- src/sys/bus/usb/ehci.c 2005/08/27 19:00:49 1.12 +++ src/sys/bus/usb/ehci.c 2005/09/04 04:27:57 1.13 @@ -1,5 +1,5 @@ /* - * $NetBSD: ehci.c,v 1.79 2004/10/23 13:36:43 augustss Exp $ + * $NetBSD: ehci.c,v 1.67 2004/07/06 04:18:05 mycroft Exp $ * $FreeBSD: src/sys/dev/usb/ehci.c,v 1.5 2003/11/10 00:20:52 joe Exp $ * $DragonFly$ */ @@ -59,7 +59,7 @@ * Interrupt transfers are not difficult, it's just not done. * * 3) The meaty part to implement is the support for USB 2.0 hubs. - * They are quite complicated since the need to be able to do + * They are quite compolicated since the need to be able to do * "transaction translation", i.e., converting to/from USB 2 and USB 1. * So the hub driver needs to handle and schedule these things, to * assign place in frame where different devices get to go. See chapter @@ -141,9 +141,7 @@ struct ehci_pipe { /*ehci_soft_qtd_t *setup, *data, *stat;*/ } ctl; /* Interrupt pipe */ - struct { - u_int length; - } intr; + /* XXX */ /* Bulk pipe */ struct { u_int length; @@ -232,9 +230,6 @@ Static void ehci_free_sqtd_chain(ehci_s Static usbd_status ehci_device_request(usbd_xfer_handle xfer); -Static usbd_status ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *, - int ival); - Static void ehci_add_qh(ehci_soft_qh_t *, ehci_soft_qh_t *); Static void ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *, ehci_soft_qh_t *); @@ -401,23 +396,18 @@ ehci_init(ehci_softc_t *sc) return (USBD_IOERROR); } - /* XXX need proper intr scheduling */ - sc->sc_rand = 96; - /* frame list size at default, read back what we got and use that */ switch (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD))) { - case 0: sc->sc_flsize = 1024; break; - case 1: sc->sc_flsize = 512; break; - case 2: sc->sc_flsize = 256; break; + case 0: sc->sc_flsize = 1024*4; break; + case 1: sc->sc_flsize = 512*4; break; + case 2: sc->sc_flsize = 256*4; break; case 3: return (USBD_IOERROR); } - err = usb_allocmem(&sc->sc_bus, sc->sc_flsize * sizeof(ehci_link_t), + err = usb_allocmem(&sc->sc_bus, sc->sc_flsize, EHCI_FLALIGN_ALIGN, &sc->sc_fldma); if (err) return (err); DPRINTF(("%s: flsize=%d\n", USBDEVNAME(sc->sc_bus.bdev),sc->sc_flsize)); - sc->sc_flist = KERNADDR(&sc->sc_fldma, 0); - EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0)); /* Set up the bus struct. */ sc->sc_bus.methods = &ehci_bus_methods; @@ -430,46 +420,6 @@ ehci_init(ehci_softc_t *sc) sc->sc_eintrs = EHCI_NORMAL_INTRS; - /* - * Allocate the interrupt dummy QHs. These are arranged to give poll - * intervals that are powers of 2 times 1ms. - */ - for (i = 0; i < EHCI_INTRQHS; i++) { - sqh = ehci_alloc_sqh(sc); - if (sqh == NULL) { - err = USBD_NOMEM; - goto bad1; - } - sc->sc_islots[i].sqh = sqh; - } - for (i = 0; i < EHCI_INTRQHS; i++) { - sqh = sc->sc_islots[i].sqh; - if (i == 0) { - /* The last (1ms) QH terminates. */ - sqh->qh.qh_link = EHCI_NULL; - sqh->next = NULL; - } else { - /* Otherwise the next QH has half the poll interval */ - sqh->next = sc->sc_islots[(i + 1) / 2 - 1].sqh; - sqh->qh.qh_link = htole32(sqh->next->physaddr | - EHCI_LINK_QH); - } - sqh->qh.qh_endp = htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH)); - sqh->qh.qh_link = EHCI_NULL; - sqh->qh.qh_curqtd = EHCI_NULL; - sqh->next = NULL; - sqh->qh.qh_qtd.qtd_next = EHCI_NULL; - sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; - sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED); - sqh->sqtd = NULL; - } - /* Point the frame list at the last level (128ms). */ - for (i = 0; i < sc->sc_flsize; i++) { - sc->sc_flist[i] = htole32(EHCI_LINK_QH | - sc->sc_islots[EHCI_IQHIDX(EHCI_IPOLLRATES - 1, - i)].sqh->physaddr); - } - /* Allocate dummy QH that starts the async list. */ sqh = ehci_alloc_sqh(sc); if (sqh == NULL) { @@ -507,7 +457,7 @@ ehci_init(ehci_softc_t *sc) EHCI_CMD_ITC_8 | /* 8 microframes */ (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) | EHCI_CMD_ASE | - EHCI_CMD_PSE | + /* EHCI_CMD_PSE | */ EHCI_CMD_RS); /* Take over port ownership */ @@ -552,10 +502,6 @@ ehci_intr(void *v) /* If we get an interrupt while polling, then just ignore it. */ if (sc->sc_bus.use_polling) { - u_int32_t intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); - - if (intrs) - EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */ #ifdef DIAGNOSTIC DPRINTFN(16, ("ehci_intr: ignored interrupt while polling\n")); #endif @@ -823,7 +769,7 @@ ehci_idone(struct ehci_xfer *ex) /* If there are left over TDs we need to update the toggle. */ if (sqtd != NULL) { - DPRINTF(("ehci_idone: need toggle update status=%08x nstatus=%08x\n", status, nstatus)); + printf("ehci_idone: need toggle update status=%08x nstatus=%08x\n", status, nstatus); #if 0 ehci_dump_sqh(epipe->sqh); ehci_dump_sqtds(ex->sqtdstart); @@ -843,7 +789,7 @@ ehci_idone(struct ehci_xfer *ex) "\20\7HALTED\6BUFERR\5BABBLE\4XACTERR" "\3MISSED", sbuf, sizeof(sbuf)); - DPRINTFN((status & EHCI_QTD_HALTED) ? 2 : 0, + DPRINTFN((status == EHCI_QTD_HALTED)*/*10*/2, ("ehci_idone: error, addr=%d, endpt=0x%02x, " "status 0x%s\n", xfer->pipe->device->address, @@ -982,13 +928,11 @@ void ehci_power(int why, void *v) { ehci_softc_t *sc = v; - u_int32_t cmd, hcr; - int s, i; + //u_int32_t ctl; #ifdef USB_DEBUG DPRINTF(("ehci_power: sc=%p, why=%d\n", sc, why)); - if (ehcidebug > 0) - ehci_dump_regs(sc); + ehci_dump_regs(sc); #endif crit_enter(); @@ -997,69 +941,46 @@ ehci_power(int why, void *v) case PWR_SUSPEND: case PWR_STANDBY: sc->sc_bus.use_polling++; - - sc->sc_cmd = EOREAD4(sc, EHCI_USBCMD); - - cmd = sc->sc_cmd & ~(EHCI_CMD_ASE | EHCI_CMD_PSE); - EOWRITE4(sc, EHCI_USBCMD, cmd); - - for (i = 0; i < 100; i++) { - hcr = EOREAD4(sc, EHCI_USBSTS) & - (EHCI_STS_ASS | EHCI_STS_PSS); - if (hcr == 0) - break; - - usb_delay_ms(&sc->sc_bus, 1); - } - if (hcr != 0) { - printf("%s: reset timeout\n", - USBDEVNAME(sc->sc_bus.bdev)); - } - - cmd &= ~EHCI_CMD_RS; - EOWRITE4(sc, EHCI_USBCMD, cmd); - - for (i = 0; i < 100; i++) { - hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; - if (hcr == EHCI_STS_HCH) - break; - - usb_delay_ms(&sc->sc_bus, 1); - } - if (hcr != EHCI_STS_HCH) { - printf("%s: config timeout\n", - USBDEVNAME(sc->sc_bus.bdev)); +#if 0 +OOO + ctl = OREAD4(sc, EHCI_CONTROL) & ~EHCI_HCFS_MASK; + if (sc->sc_control == 0) { + /* + * Preserve register values, in case that APM BIOS + * does not recover them. + */ + sc->sc_control = ctl; + sc->sc_intre = OREAD4(sc, EHCI_INTERRUPT_ENABLE); } - + ctl |= EHCI_HCFS_SUSPEND; + OWRITE4(sc, EHCI_CONTROL, ctl); +#endif + usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); sc->sc_bus.use_polling--; break; - case PWR_RESUME: sc->sc_bus.use_polling++; - - /* restore things in case the bios sucks */ - EOWRITE4(sc, EHCI_CTRLDSSEGMENT, 0); - EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0)); - EOWRITE4(sc, EHCI_ASYNCLISTADDR, - sc->sc_async_head->physaddr | EHCI_LINK_QH); - EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); - - EOWRITE4(sc, EHCI_USBCMD, sc->sc_cmd); - - for (i = 0; i < 100; i++) { - hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; - if (hcr != EHCI_STS_HCH) - break; - - usb_delay_ms(&sc->sc_bus, 1); - } - if (hcr == EHCI_STS_HCH) { - printf("%s: config timeout\n", - USBDEVNAME(sc->sc_bus.bdev)); - } - - usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); - +#if 0 +OOO + /* Some broken BIOSes do not recover these values */ + OWRITE4(sc, EHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); + OWRITE4(sc, EHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr); + OWRITE4(sc, EHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr); + if (sc->sc_intre) + OWRITE4(sc, EHCI_INTERRUPT_ENABLE, + sc->sc_intre & (EHCI_ALL_INTRS | EHCI_MIE)); + if (sc->sc_control) + ctl = sc->sc_control; + else + ctl = OREAD4(sc, EHCI_CONTROL); + ctl |= EHCI_HCFS_RESUME; + OWRITE4(sc, EHCI_CONTROL, ctl); + usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); + ctl = (ctl & ~EHCI_HCFS_MASK) | EHCI_HCFS_OPERATIONAL; + OWRITE4(sc, EHCI_CONTROL, ctl); + usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); + sc->sc_control = sc->sc_intre = 0; +#endif sc->sc_bus.use_polling--; break; case PWR_SOFTSUSPEND: @@ -1068,12 +989,6 @@ ehci_power(int why, void *v) break; } crit_exit(); - -#ifdef USB_DEBUG - DPRINTF(("ehci_power: sc=%p\n", sc)); - if (ehcidebug > 0) - ehci_dump_regs(sc); -#endif } #endif @@ -1320,7 +1235,7 @@ ehci_open(usbd_pipe_handle pipe) struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; ehci_soft_qh_t *sqh; usbd_status err; - int ival, speed, naks; + int speed, naks; DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d (%d)\n", pipe, addr, ed->bEndpointAddress, sc->sc_addr)); @@ -1367,9 +1282,9 @@ ehci_open(usbd_pipe_handle pipe) EHCI_QH_SET_NRL(naks) ); sqh->qh.qh_endphub = htole32( - EHCI_QH_SET_MULT(1) | + EHCI_QH_SET_MULT(1) /* XXX TT stuff */ - EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0) + /* XXX interrupt mask */ ); sqh->qh.qh_curqtd = EHCI_NULL; /* Fill the overlay qTD */ @@ -1402,10 +1317,7 @@ ehci_open(usbd_pipe_handle pipe) break; case UE_INTERRUPT: pipe->methods = &ehci_device_intr_methods; - ival = pipe->interval; - if (ival == USBD_DEFAULT_INTERVAL) - ival = ed->bInterval; - return (ehci_device_setintr(sc, sqh, ival)); + return (USBD_INVAL); case UE_ISOCHRONOUS: pipe->methods = &ehci_device_isoc_methods; return (USBD_INVAL); @@ -1487,7 +1399,7 @@ ehci_sync_hc(ehci_softc_t *sc) } DPRINTFN(2,("ehci_sync_hc: enter\n")); /* get doorbell */ - usb_lockmgr(&sc->sc_doorbell_lock, LK_EXCLUSIVE, NULL, NULL); + lockmgr(&sc->sc_doorbell_lock, LK_EXCLUSIVE, NULL, NULL); crit_enter(); /* ask for doorbell */ EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD); @@ -1498,7 +1410,7 @@ ehci_sync_hc(ehci_softc_t *sc) EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS))); crit_exit(); /* release doorbell */ - usb_lockmgr(&sc->sc_doorbell_lock, LK_RELEASE, NULL, NULL); + lockmgr(&sc->sc_doorbell_lock, LK_RELEASE, NULL, NULL); #ifdef DIAGNOSTIC if (error) printf("ehci_sync_hc: tsleep() = %d\n", error); @@ -2045,7 +1957,6 @@ ehci_root_ctrl_close(usbd_pipe_handle pi void ehci_root_intr_done(usbd_xfer_handle xfer) { - xfer->hcpriv = NULL; } Static usbd_status @@ -2104,7 +2015,6 @@ ehci_root_intr_close(usbd_pipe_handle pi void ehci_root_ctrl_done(usbd_xfer_handle xfer) { - xfer->hcpriv = NULL; } /************************/ @@ -2903,213 +2813,11 @@ ehci_device_bulk_done(usbd_xfer_handle x /************************/ -Static usbd_status -ehci_device_setintr(ehci_softc_t *sc, ehci_soft_qh_t *sqh, int ival) -{ - struct ehci_soft_islot *isp; - int islot, lev; - - /* Find a poll rate that is large enough. */ - for (lev = EHCI_IPOLLRATES - 1; lev > 0; lev--) - if (EHCI_ILEV_IVAL(lev) <= ival) - break; - - /* Pick an interrupt slot at the right level. */ - /* XXX could do better than picking at random */ - sc->sc_rand = (sc->sc_rand + 191) % sc->sc_flsize; - islot = EHCI_IQHIDX(lev, sc->sc_rand); - - sqh->islot = islot; - isp = &sc->sc_islots[islot]; - ehci_add_qh(sqh, isp->sqh); - - return (USBD_NORMAL_COMPLETION); -} - -Static usbd_status -ehci_device_intr_transfer(usbd_xfer_handle xfer) -{ - usbd_status err; - - /* Insert last in queue. */ - err = usb_insert_transfer(xfer); - if (err) - return (err); - - /* - * Pipe isn't running (otherwise err would be USBD_INPROG), - * so start it first. - */ - return (ehci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); -} - -Static usbd_status -ehci_device_intr_start(usbd_xfer_handle xfer) -{ -#define exfer EXFER(xfer) - struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; - usbd_device_handle dev = xfer->pipe->device; - ehci_softc_t *sc = (ehci_softc_t *)dev->bus; - ehci_soft_qtd_t *data, *dataend; - ehci_soft_qh_t *sqh; - usbd_status err; - int len, isread, endpt; - int s; - - DPRINTFN(2, ("ehci_device_intr_start: xfer=%p len=%d flags=%d\n", - xfer, xfer->length, xfer->flags)); - - if (sc->sc_dying) - return (USBD_IOERROR); - -#ifdef DIAGNOSTIC - if (xfer->rqflags & URQ_REQUEST) - panic("ehci_device_intr_start: a request"); -#endif - - len = xfer->length; - endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; - isread = UE_GET_DIR(endpt) == UE_DIR_IN; - sqh = epipe->sqh; - - epipe->u.intr.length = len; - - err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &data, - &dataend); - if (err) { - DPRINTFN(-1, ("ehci_device_intr_start: no memory\n")); - xfer->status = err; - usb_transfer_complete(xfer); - return (err); - } - -#ifdef USB_DEBUG - if (ehcidebug > 5) { - DPRINTF(("ehci_device_intr_start: data(1)\n")); - ehci_dump_sqh(sqh); - ehci_dump_sqtds(data); - } -#endif - - /* Set up interrupt info. */ - exfer->sqtdstart = data; - exfer->sqtdend = dataend; -#ifdef DIAGNOSTIC - if (!exfer->isdone) { - printf("ehci_device_intr_start: not done, ex=%p\n", exfer); - } - exfer->isdone = 0; -#endif - - crit_enter(); - ehci_set_qh_qtd(sqh, data); - if (xfer->timeout && !sc->sc_bus.use_polling) { - usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout), - ehci_timeout, xfer); - } - ehci_add_intr_list(sc, exfer); - xfer->status = USBD_IN_PROGRESS; - crit_exit(); - -#ifdef USB_DEBUG - if (ehcidebug > 10) { - DPRINTF(("ehci_device_intr_start: data(2)\n")); - delay(10000); - DPRINTF(("ehci_device_intr_start: data(3)\n")); - ehci_dump_regs(sc); - printf("sqh:\n"); - ehci_dump_sqh(sqh); - ehci_dump_sqtds(data); - } -#endif - - if (sc->sc_bus.use_polling) - ehci_waitintr(sc, xfer); - return (USBD_IN_PROGRESS); -#undef exfer -} - -Static void -ehci_device_intr_abort(usbd_xfer_handle xfer) -{ - DPRINTFN(1, ("ehci_device_intr_abort: xfer=%p\n", xfer)); - if (xfer->pipe->intrxfer == xfer) { - DPRINTFN(1, ("echi_device_intr_abort: remove\n")); - xfer->pipe->intrxfer = NULL; - } - ehci_abort_xfer(xfer, USBD_CANCELLED); -} - -Static void -ehci_device_intr_close(usbd_pipe_handle pipe) -{ - ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus; - struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; - struct ehci_soft_islot *isp; - - isp = &sc->sc_islots[epipe->sqh->islot]; - ehci_close_pipe(pipe, isp->sqh); -} - -Static void -ehci_device_intr_done(usbd_xfer_handle xfer) -{ -#define exfer EXFER(xfer) - struct ehci_xfer *ex = EXFER(xfer); - ehci_softc_t *sc = (ehci_softc_t *)xfer->pipe->device->bus; - struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; - ehci_soft_qtd_t *data, *dataend; - ehci_soft_qh_t *sqh; - usbd_status err; - int len, isread, endpt, s; - - DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n", - xfer, xfer->actlen)); - - if (xfer->pipe->repeat) { - ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); - - len = epipe->u.intr.length; - xfer->length = len; - endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; - isread = UE_GET_DIR(endpt) == UE_DIR_IN; - sqh = epipe->sqh; - - err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, - &data, &dataend); - if (err) { - DPRINTFN(-1, ("ehci_device_intr_done: no memory\n")); - xfer->status = err; - return; - } - - /* Set up interrupt info. */ - exfer->sqtdstart = data; - exfer->sqtdend = dataend; -#ifdef DIAGNOSTIC - if (!exfer->isdone) { - printf("ehci_device_intr_done: not done, ex=%p\n", - exfer); - } - exfer->isdone = 0; -#endif - - crit_enter(); - ehci_set_qh_qtd(sqh, data); - if (xfer->timeout && !sc->sc_bus.use_polling) { - usb_callout(xfer->timeout_handle, - MS_TO_TICKS(xfer->timeout), ehci_timeout, - xfer); - } - crit_exit(); - - xfer->status = USBD_IN_PROGRESS; - } else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { - ehci_del_intr_list(ex); /* remove from active list */ - ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); - } -#undef exfer -} +Static usbd_status ehci_device_intr_transfer(usbd_xfer_handle xfer) { return USBD_IOERROR; } +Static usbd_status ehci_device_intr_start(usbd_xfer_handle xfer) { return USBD_IOERROR; } +Static void ehci_device_intr_abort(usbd_xfer_handle xfer) { } +Static void ehci_device_intr_close(usbd_pipe_handle pipe) { } +Static void ehci_device_intr_done(usbd_xfer_handle xfer) { } /************************/