ohci.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,245 行 · 第 1/4 页
C
2,245 行
printf(" port1=0x%08x port2=0x%08x\n", OREAD4(sc, OHCI_RH_PORT_STATUS(1)), OREAD4(sc, OHCI_RH_PORT_STATUS(2))); printf(" HCCA: frame_number=0x%04x done_head=0x%08x\n", LE(sc->sc_hcca->hcca_frame_number), LE(sc->sc_hcca->hcca_done_head));}#endifintohci_intr(p) void *p;{ ohci_softc_t *sc = p; u_int32_t intrs, eintrs; ohci_physaddr_t done; /* In case the interrupt occurs before initialization has completed. */ if (sc == NULL || sc->sc_hcca == NULL) { /* NWH added sc==0 */#ifdef DIAGNOSTIC printf("ohci_intr: sc->sc_hcca == NULL\n");#endif return (0); } intrs = 0; done = LE(sc->sc_hcca->hcca_done_head); if (done != 0) { sc->sc_hcca->hcca_done_head = 0; if (done & ~OHCI_DONE_INTRS) intrs = OHCI_WDH; if (done & OHCI_DONE_INTRS) intrs |= OREAD4(sc, OHCI_INTERRUPT_STATUS); } else intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS); if (!intrs) return (0); intrs &= ~OHCI_MIE; OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs); /* Acknowledge */ eintrs = intrs & sc->sc_eintrs; if (!eintrs) return (0); sc->sc_intrs++; DPRINTFN(7, ("ohci_intr: sc=%p intrs=%x(%x) eintr=%x\n", sc, (u_int)intrs, OREAD4(sc, OHCI_INTERRUPT_STATUS), (u_int)eintrs)); if (eintrs & OHCI_SO) { printf("%s: scheduling overrun\n",USBDEVNAME(sc->sc_bus.bdev)); /* XXX do what */ intrs &= ~OHCI_SO; } if (eintrs & OHCI_WDH) { ohci_process_done(sc, done &~ OHCI_DONE_INTRS); intrs &= ~OHCI_WDH; } if (eintrs & OHCI_RD) { /* XXX process resume detect */ } if (eintrs & OHCI_UE) { printf("%s: unrecoverable error, controller halted\n", USBDEVNAME(sc->sc_bus.bdev)); OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); /* XXX what else */ } if (eintrs & OHCI_RHSC) { ohci_rhsc(sc, sc->sc_intrreqh); intrs &= ~OHCI_RHSC; /* * Disable RHSC interrupt for now, because it will be * on until the port has been reset. */ ohci_rhsc_able(sc, 0); } /* Block unprocessed interrupts. XXX */ OWRITE4(sc, OHCI_INTERRUPT_DISABLE, intrs); sc->sc_eintrs &= ~intrs; return (1);}voidohci_rhsc_able(sc, on) ohci_softc_t *sc; int on;{ DPRINTFN(4, ("ohci_rhsc_able: on=%d\n", on)); if (on) { sc->sc_eintrs |= OHCI_RHSC; OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC); } else { sc->sc_eintrs &= ~OHCI_RHSC; OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_RHSC); }}#ifdef OHCI_DEBUGchar *ohci_cc_strs[] = { "NO_ERROR", "CRC", "BIT_STUFFING", "DATA_TOGGLE_MISMATCH", "STALL", "DEVICE_NOT_RESPONDING", "PID_CHECK_FAILURE", "UNEXPECTED_PID", "DATA_OVERRUN", "DATA_UNDERRUN", "BUFFER_OVERRUN", "BUFFER_UNDERRUN", "NOT_ACCESSED",};#endifvoidohci_process_done(sc, done) ohci_softc_t *sc; ohci_physaddr_t done;{ ohci_soft_td_t *std, *sdone; usbd_request_handle reqh; int len, cc; DPRINTFN(10,("ohci_process_done: done=0x%08lx\n", (u_long)done)); /* Reverse the done list. */ for (sdone = 0; done; done = LE(std->td->td_nexttd)) { std = ohci_hash_find_td(sc, done); std->dnext = sdone; sdone = std; }#ifdef OHCI_DEBUG if (ohcidebug > 11) { printf("ohci_process_done: TD done:\n"); ohci_dump_tds(sdone); }#endif for (std = sdone; std; std = std->dnext) { reqh = std->reqh; DPRINTFN(10, ("ohci_process_done: std=%p reqh=%p hcpriv=%p\n", std, reqh, reqh->hcpriv)); cc = OHCI_TD_GET_CC(LE(std->td->td_flags)); if (cc == OHCI_CC_NO_ERROR) { if (std->td->td_cbp == 0) len = std->len; else len = LE(std->td->td_be) - LE(std->td->td_cbp) + 1; /* * Only do a callback on the last stage of a transfer. * Others have hcpriv = 0. */ if ((reqh->pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL) { /* For a control transfer the length is in * the xfer stage */ if (reqh->hcpriv == std) { reqh->status = USBD_NORMAL_COMPLETION; ohci_ii_done(sc, reqh); } else reqh->actlen = len; } else { if (reqh->hcpriv == std) { reqh->actlen = len; reqh->status = USBD_NORMAL_COMPLETION; ohci_ii_done(sc, reqh); } } } else { ohci_soft_td_t *p, *n; struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe; DPRINTFN(-1,("ohci_process_done: error cc=%d (%s)\n", OHCI_TD_GET_CC(LE(std->td->td_flags)), ohci_cc_strs[OHCI_TD_GET_CC(LE(std->td->td_flags))])); /* * Endpoint is halted. First unlink all the TDs * belonging to the failed transfer, and then restart * the endpoint. */ for (p = std->nexttd; p->reqh == reqh; p = n) { n = p->nexttd; ohci_hash_rem_td(sc, p); ohci_free_std(sc, p); } /* clear halt */ opipe->sed->ed->ed_headp = LE(p->physaddr); OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); if (cc == OHCI_CC_STALL) reqh->status = USBD_STALLED; else reqh->status = USBD_IOERROR; ohci_ii_done(sc, reqh); } ohci_hash_rem_td(sc, std); ohci_free_std(sc, std); }}voidohci_ii_done(sc, reqh) ohci_softc_t *sc; usbd_request_handle reqh;{ switch (reqh->pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE) { case UE_CONTROL: ohci_ctrl_done(sc, reqh); usb_start_next(reqh->pipe); break; case UE_INTERRUPT: ohci_intr_done(sc, reqh); break; case UE_BULK: ohci_bulk_done(sc, reqh); usb_start_next(reqh->pipe); break; case UE_ISOCHRONOUS: printf("ohci_process_done: ISO done?\n"); usb_start_next(reqh->pipe); break; } /* And finally execute callback. */ reqh->xfercb(reqh);}voidohci_ctrl_done(sc, reqh) ohci_softc_t *sc; usbd_request_handle reqh;{ struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe; u_int len = opipe->u.ctl.length; usb_dma_t *dma; DPRINTFN(10,("ohci_ctrl_done: reqh=%p\n", reqh)); if (!reqh->isreq) { panic("ohci_ctrl_done: not a request\n"); return; } if (len != 0) { dma = &opipe->u.ctl.datadma; if (reqh->request.bmRequestType & UT_READ) memcpy(reqh->buffer, KERNADDR(dma), len); usb_freemem(sc->sc_dmatag, dma); } usb_untimeout(ohci_timeout, reqh, reqh->timo_handle);}voidohci_intr_done(sc, reqh) ohci_softc_t *sc; usbd_request_handle reqh;{ struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe; usb_dma_t *dma; ohci_soft_ed_t *sed = opipe->sed; ohci_soft_td_t *xfer, *tail; DPRINTFN(10,("ohci_intr_done: reqh=%p, actlen=%d\n", reqh, reqh->actlen)); dma = &opipe->u.intr.datadma; memcpy(reqh->buffer, KERNADDR(dma), reqh->actlen); if (reqh->pipe->intrreqh == reqh) { xfer = opipe->tail; tail = ohci_alloc_std(sc); /* XXX should reuse TD */ if (!tail) { reqh->status = USBD_NOMEM; return; } tail->reqh = 0; xfer->td->td_flags = LE( OHCI_TD_IN | OHCI_TD_NOCC | OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY); if (reqh->flags & USBD_SHORT_XFER_OK) xfer->td->td_flags |= LE(OHCI_TD_R); xfer->td->td_cbp = LE(DMAADDR(dma)); xfer->nexttd = tail; xfer->td->td_nexttd = LE(tail->physaddr); xfer->td->td_be = LE(LE(xfer->td->td_cbp) + reqh->length - 1); xfer->len = reqh->length; xfer->reqh = reqh; reqh->hcpriv = xfer; ohci_hash_add_td(sc, xfer); sed->ed->ed_tailp = LE(tail->physaddr); opipe->tail = tail; } else { usb_freemem(sc->sc_dmatag, dma); usb_start_next(reqh->pipe); }}voidohci_bulk_done(sc, reqh) ohci_softc_t *sc; usbd_request_handle reqh;{ struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe; usb_dma_t *dma; DPRINTFN(10,("ohci_bulk_done: reqh=%p, actlen=%d\n", reqh, reqh->actlen)); dma = &opipe->u.bulk.datadma; if (reqh->request.bmRequestType & UT_READ) memcpy(reqh->buffer, KERNADDR(dma), reqh->actlen); usb_freemem(sc->sc_dmatag, dma); usb_untimeout(ohci_timeout, reqh, reqh->timo_handle);}voidohci_rhsc(sc, reqh) ohci_softc_t *sc; usbd_request_handle reqh;{ usbd_pipe_handle pipe; struct ohci_pipe *opipe; u_char *p; int i, m; int hstatus; hstatus = OREAD4(sc, OHCI_RH_STATUS); DPRINTF(("ohci_rhsc: sc=%p reqh=%p hstatus=0x%08x\n", sc, reqh, hstatus)); if (reqh == 0) { /* Just ignore the change. */ return; } pipe = reqh->pipe; opipe = (struct ohci_pipe *)pipe; p = KERNADDR(&opipe->u.intr.datadma); m = min(sc->sc_noport, reqh->length * 8 - 1); memset(p, 0, reqh->length); for (i = 1; i <= m; i++) { if (OREAD4(sc, OHCI_RH_PORT_STATUS(i)) >> 16) p[i/8] |= 1 << (i%8); } DPRINTF(("ohci_rhsc: change=0x%02x\n", *p)); reqh->actlen = reqh->length; reqh->status = USBD_NORMAL_COMPLETION; reqh->xfercb(reqh); if (reqh->pipe->intrreqh != reqh) { sc->sc_intrreqh = 0; usb_freemem(sc->sc_dmatag, &opipe->u.intr.datadma); usb_start_next(reqh->pipe); }}/* * Wait here until controller claims to have an interrupt. * Then call ohci_intr and return. Use timeout to avoid waiting * too long. */voidohci_waitintr(sc, reqh) ohci_softc_t *sc; usbd_request_handle reqh;{ int timo = reqh->timeout; int usecs; u_int32_t intrs; reqh->status = USBD_IN_PROGRESS; for (usecs = timo * 1000000 / hz; usecs > 0; usecs -= 1000) { usb_delay_ms(&sc->sc_bus, 1); intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs; DPRINTFN(15,("ohci_waitintr: 0x%04x\n", intrs));#ifdef OHCI_DEBUG if (ohcidebug > 15) ohci_dumpregs(sc);#endif if (intrs) { ohci_intr(sc); if (reqh->status != USBD_IN_PROGRESS) return; } } /* Timeout */ DPRINTF(("ohci_waitintr: timeout\n")); reqh->status = USBD_TIMEOUT; ohci_ii_done(sc, reqh); /* XXX should free TD */}voidohci_poll(bus) struct usbd_bus *bus;{ ohci_softc_t *sc = (ohci_softc_t *)bus; if (OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs) ohci_intr(sc);}usbd_statusohci_device_request(reqh) usbd_request_handle reqh;{ struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe; usb_device_request_t *req = &reqh->request; usbd_device_handle dev = opipe->pipe.device; ohci_softc_t *sc = (ohci_softc_t *)dev->bus; int addr = dev->address; ohci_soft_td_t *setup, *xfer = 0, *stat, *next, *tail; ohci_soft_ed_t *sed; usb_dma_t *dmap; int isread; int len; usbd_status r; int s; isread = req->bmRequestType & UT_READ; len = UGETW(req->wLength); DPRINTFN(3,("ohci_device_control type=0x%02x, request=0x%02x, " "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n", req->bmRequestType, req->bRequest, UGETW(req->wValue), UGETW(req->wIndex), len, addr, opipe->pipe.endpoint->edesc->bEndpointAddress)); setup = opipe->tail; stat = ohci_alloc_std(sc); if (!stat) { r = USBD_NOMEM; goto bad1; } tail = ohci_alloc_std(sc); if (!tail) { r = USBD_NOMEM; goto bad2; } tail->reqh = 0; sed = opipe->sed; dmap = &opipe->u.ctl.datadma; opipe->u.ctl.length = len; /* Update device address and length since they may have changed. */ /* XXX This only needs to be done once, but it's too early in open. */ sed->ed->ed_flags = LE( (LE(sed->ed->ed_flags) & ~(OHCI_ED_ADDRMASK | OHCI_ED_MAXPMASK)) | OHCI_ED_SET_FA(addr) | OHCI_ED_SET_MAXP(UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize))); /* Set up data transaction */ if (len != 0) { xfer = ohci_alloc_std(sc); if (!xfer) { r = USBD_NOMEM; goto bad3; } r = usb_allocmem(sc->sc_dmatag, len, 0, dmap); if (r != USBD_NORMAL_COMPLETION) goto bad4; xfer->td->td_flags = LE( (isread ? OHCI_TD_IN : OHCI_TD_OUT) | OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_NOINTR | (reqh->flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0)); xfer->td->td_cbp = LE(DMAADDR(dmap)); xfer->nexttd = stat; xfer->td->td_nexttd = LE(stat->physaddr); xfer->td->td_be = LE(LE(xfer->td->td_cbp) + len - 1); xfer->len = len; xfer->reqh = reqh; next = xfer; } else next = stat; memcpy(KERNADDR(&opipe->u.ctl.reqdma), req, sizeof *req); if (!isread && len != 0) memcpy(KERNADDR(dmap), reqh->buffer, len); setup->td->td_flags = LE(OHCI_TD_SETUP | OHCI_TD_NOCC | OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR); setup->td->td_cbp = LE(DMAADDR(&opipe->u.ctl.reqdma)); setup->nexttd = next; setup->td->td_nexttd = LE(next->physaddr); setup->td->td_be = LE(LE(setup->td->td_cbp) + sizeof *req - 1); setup->len = 0; /* XXX The number of byte we count */ setup->reqh = reqh; stat->td->td_flags = LE( (isread ? OHCI_TD_OUT : OHCI_TD_IN) | OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); stat->td->td_cbp = 0; stat->nexttd = tail; stat->td->td_nexttd = LE(tail->physaddr); stat->td->td_be = 0; stat->len = 0; stat->reqh = reqh; reqh->hcpriv = stat;#ifdef OHCI_DEBUG if (ohcidebug > 5) { printf("ohci_device_request:\n"); ohci_dump_ed(sed); ohci_dump_tds(setup); }#endif /* Insert ED in schedule */ s = splusb(); ohci_hash_add_td(sc, setup); if (len != 0) ohci_hash_add_td(sc, xfer); ohci_hash_add_td(sc, stat); sed->ed->ed_tailp = LE(tail->physaddr); opipe->tail = tail; OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); if (reqh->timeout && !sc->sc_bus.use_polling) { usb_timeout(ohci_timeout, reqh, MS_TO_TICKS(reqh->timeout), reqh->timo_handle); } splx(s);#if 0#ifdef OHCI_DEBUG if (ohcidebug > 15) { delay(5000); printf("ohci_device_request: status=%x\n", OREAD4(sc, OHCI_COMMAND_STATUS)); ohci_dump_ed(sed); ohci_dump_tds(setup); }#endif#endif return (USBD_NORMAL_COMPLETION); bad4: ohci_free_std(sc, xfer); bad3: ohci_free_std(sc, tail); bad2: ohci_free_std(sc, stat); bad1: return (r);}/*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?