📄 usbuhci.c
字号:
static voidcanceltds(Ctlr *ctlr, QH *q, Endpt *e){ TD *t; if(q != nil){ ilock(ctlr); for(t = q->first; t != nil; t = t->next) if(t->ep == e) t->flags |= CancelTD; iunlock(ctlr); XPRINT("cancel:\n"); dumpqh(q); }}static voideptcancel(Ctlr *ctlr, Endpt *e){ Endptx *x; if(e == nil) return; x = e->private; canceltds(ctlr, x->epq, e); canceltds(ctlr, ctlr->ctlq, e); canceltds(ctlr, ctlr->bulkq, e);}static voideptactivate(Ctlr *ctlr, Endpt *e){ ilock(&ctlr->activends); if(e->active == 0){ XPRINT("activate 0x%p\n", e); e->active = 1; e->activef = ctlr->activends.f; ctlr->activends.f = e; } iunlock(&ctlr->activends);}static voideptdeactivate(Ctlr *ctlr, Endpt *e){ Endpt **l; /* could be O(1) but not worth it yet */ ilock(&ctlr->activends); if(e->active){ e->active = 0; XPRINT("deactivate 0x%p\n", e); for(l = &ctlr->activends.f; *l != e; l = &(*l)->activef) if(*l == nil){ iunlock(&ctlr->activends); panic("usb eptdeactivate"); } *l = e->activef; } iunlock(&ctlr->activends);}static voidqueueqh(Ctlr *ctlr, QH *qh){ QH *q; // See if it's already queued for (q = ctlr->recvq->next; q; q = q->hlink) if (q == qh) return; if ((qh->hlink = ctlr->recvq->next) == nil) qh->head = Terminate; else qh->head = PCIWADDR(ctlr->recvq->next) | IsQH; ctlr->recvq->next = qh; ctlr->recvq->entries = PCIWADDR(qh) | IsQH;}static QH*qxmit(Ctlr *ctlr, Endpt *e, Block *b, int pid){ TD *t; int n, vf; QH *qh; Endptx *x; x = e->private; if(b != nil){ n = BLEN(b); t = alloctde(ctlr, e, pid, n); t->bp = b; t->buffer = PCIWADDR(b->rp); }else t = alloctde(ctlr, e, pid, 0); ilock(ctlr); e->ntd++; iunlock(ctlr); if(e->debug) pprint("QTD: %8.8lux n=%ld\n", t, b?BLEN(b): 0); vf = 0; if(e->x == 0){ qh = ctlr->ctlq; vf = 0; }else if((qh = x->epq) == nil || e->mode != OWRITE){ qh = ctlr->bulkq; vf = Vf; } queuetd(ctlr, qh, t, vf, "qxmit"); return qh;}static QH*qrcv(Ctlr *ctlr, Endpt *e){ TD *t; Block *b; QH *qh; int vf; Endptx *x; x = e->private; t = alloctde(ctlr, e, TokIN, e->maxpkt); b = allocb(e->maxpkt); t->bp = b; t->buffer = PCIWADDR(b->wp); vf = 0; if(e->x == 0){ qh = ctlr->ctlq; }else if((qh = x->epq) == nil || e->mode != OREAD){ qh = ctlr->bulkq; vf = Vf; } queuetd(ctlr, qh, t, vf, "qrcv"); return qh;}static intusbsched(Ctlr *ctlr, int pollms, ulong load){ int i, d, q; ulong best, worst; best = 1000000; q = -1; for (d = 0; d < pollms; d++){ worst = 0; for (i = d; i < NFRAME; i++){ if (ctlr->frameld[i] + load > worst) worst = ctlr->frameld[i] + load; } if (worst < best){ best = worst; q = d; } } return q;}static intschedendpt(Ctlr *ctlr, Endpt *e){ TD *td; Endptx *x; uchar *bp; int i, id, ix, size, frnum; if(!e->iso || e->sched >= 0) return 0; if (e->active){ return -1; } e->off = 0; e->sched = usbsched(ctlr, e->pollms, e->maxpkt); if(e->sched < 0) return -1; x = e->private; if (x->tdalloc || x->bpalloc) panic("usb: tdalloc/bpalloc"); x->tdalloc = mallocz(0x10 + NFRAME*sizeof(TD), 1); x->bpalloc = mallocz(0x10 + e->maxpkt*NFRAME/e->pollms, 1); x->td0 = (TD*)(((ulong)x->tdalloc + 0xf) & ~0xf); x->bp0 = (uchar *)(((ulong)x->bpalloc + 0xf) & ~0xf); frnum = (IN(Frnum) + 1) & 0x3ff; frnum = (frnum & ~(e->pollms - 1)) + e->sched; x->xtd = &x->td0[(frnum+8)&0x3ff]; /* Next td to finish */ x->etd = nil; e->remain = 0; e->nbytes = 0; td = x->td0; for(i = e->sched; i < NFRAME; i += e->pollms){ bp = x->bp0 + e->maxpkt*i/e->pollms; td->buffer = PCIWADDR(bp); td->ep = e; td->next = &td[1]; ctlr->frameld[i] += e->maxpkt; td++; } td[-1].next = x->td0; for(i = e->sched; i < NFRAME; i += e->pollms){ ix = (frnum+i) & 0x3ff; td = &x->td0[ix]; id = (e->x<<7)|(e->dev->x&0x7F); if (e->mode == OREAD) /* enable receive on this entry */ td->dev = ((e->maxpkt-1)<<21) | ((id&0x7FF)<<8) | TokIN; else{ size = (e->hz + e->remain)*e->pollms/1000; e->remain = (e->hz + e->remain)*e->pollms%1000; size *= e->samplesz; td->dev = ((size-1)<<21) | ((id&0x7FF)<<8) | TokOUT; } td->status = ErrLimit1 | Active | IsoSelect | IOC; td->link = ctlr->frames[ix]; td->flags |= IsoClean; ctlr->frames[ix] = PCIWADDR(td); } return 0;}static voidunschedendpt(Ctlr *ctlr, Endpt *e){ int q; TD *td; Endptx *x; ulong *addr; if(!e->iso || e->sched < 0) return; x = e->private; if (x->tdalloc == nil) panic("tdalloc"); for (q = e->sched; q < NFRAME; q += e->pollms){ td = x->td0++; addr = &ctlr->frames[q]; while(*addr != PADDR(td)) { if(*addr & IsQH) panic("usb: TD expected"); addr = &TFOL(*addr)->link; } *addr = td->link; ctlr->frameld[q] -= e->maxpkt; } free(x->tdalloc); free(x->bpalloc); x->tdalloc = nil; x->bpalloc = nil; x->etd = nil; x->td0 = nil; e->sched = -1;}static voidepalloc(Usbhost *uh, Endpt *e){ Endptx *x; x = malloc(sizeof(Endptx)); e->private = x; x->epq = allocqh(uh->ctlr); if(x->epq == nil) panic("devendptx");}static voidepfree(Usbhost *uh, Endpt *e){ Ctlr *ctlr; Endptx *x; ctlr = uh->ctlr; x = e->private; if(x->epq != nil) freeqh(ctlr, x->epq);}static voidepopen(Usbhost *uh, Endpt *e){ Ctlr *ctlr; ctlr = uh->ctlr; if(e->iso && e->active) error("already open"); if(schedendpt(ctlr, e) < 0){ if(e->active) error("cannot schedule USB endpoint, active"); else error("cannot schedule USB endpoint"); } eptactivate(ctlr, e);}static voidepclose(Usbhost *uh, Endpt *e){ Ctlr *ctlr; ctlr = uh->ctlr; eptdeactivate(ctlr, e); unschedendpt(ctlr, e);}static voidepmode(Usbhost *uh, Endpt *e){ Ctlr *ctlr; Endptx *x; ctlr = uh->ctlr; x = e->private; if(e->iso) { if(x->epq != nil) { freeqh(ctlr, x->epq); x->epq = nil; } } else { /* Each bulk device gets a queue head hanging off the * bulk queue head */ if(x->epq == nil) { x->epq = allocqh(ctlr); if(x->epq == nil) panic("epbulk: allocqh"); } queueqh(ctlr, x->epq); }}static int ioport[] = {-1, Portsc0, Portsc1};static voidportreset(Usbhost *uh, int port){ int i, p; Ctlr *ctlr; ctlr = uh->ctlr; if(port != 1 && port != 2) error(Ebadarg); /* should check that device not being configured on other port? */ p = ioport[port]; qlock(&ctlr->resetl); if(waserror()){ qunlock(&ctlr->resetl); nexterror(); } XPRINT("r: %x\n", IN(p)); ilock(ctlr); OUT(p, PortReset); delay(12); /* BUG */ XPRINT("r2: %x\n", IN(p)); OUT(p, IN(p) & ~PortReset); XPRINT("r3: %x\n", IN(p)); OUT(p, IN(p) | PortEnable); microdelay(64); for(i=0; i<1000 && (IN(p) & PortEnable) == 0; i++) ; XPRINT("r': %x %d\n", IN(p), i); OUT(p, (IN(p) & ~PortReset)|PortEnable); iunlock(ctlr); poperror(); qunlock(&ctlr->resetl);}static voidportenable(Usbhost *uh, int port, int on){ int w, p; Ctlr *ctlr; ctlr = uh->ctlr; if(port != 1 && port != 2) error(Ebadarg); /* should check that device not being configured on other port? */ p = ioport[port]; qlock(&ctlr->resetl); if(waserror()){ qunlock(&ctlr->resetl); nexterror(); } ilock(ctlr); w = IN(p); if(on) w |= PortEnable; else w &= ~PortEnable; OUT(p, w); microdelay(64); iunlock(ctlr); XPRINT("e: %x\n", IN(p)); poperror(); qunlock(&ctlr->resetl);}static voidportinfo(Usbhost *uh, char *s, char *se){ int x, i, j; Ctlr *ctlr; ctlr = uh->ctlr; for(i = 1; i <= 2; i++) { ilock(ctlr); x = IN(ioport[i]); if((x & (PortChange|StatusChange)) != 0) OUT(ioport[i], x); iunlock(ctlr); s = seprint(s, se, "%d %ux", i, x); for(j = 0; j < nelem(portstatus); j++) { if((x & portstatus[j].bit) != 0) s = seprint(s, se, " %s", portstatus[j].name); } s = seprint(s, se, "\n"); }}static voidcleaniso(Endpt *e, int frnum){ TD *td; int id, n, i; Endptx *x; uchar *bp; x = e->private; td = x->xtd; if (td->status & Active) return; id = (e->x<<7)|(e->dev->x&0x7F); do { if (td->status & AnyError) XPRINT("usbisoerror 0x%lux\n", td->status); n = (td->status + 1) & 0x3ff; e->nbytes += n; if ((td->flags & IsoClean) == 0) e->nblocks++; if (e->mode == OREAD){ e->buffered += n; e->poffset += (td->status + 1) & 0x3ff; td->offset = e->poffset; td->dev = ((e->maxpkt -1)<<21) | ((id&0x7FF)<<8) | TokIN; e->toffset = td->offset; }else{ if ((td->flags & IsoClean) == 0){ e->buffered -= n; if (e->buffered < 0){// print("e->buffered %d?\n", e->buffered); e->buffered = 0; } } e->toffset = td->offset; n = (e->hz + e->remain)*e->pollms/1000; e->remain = (e->hz + e->remain)*e->pollms%1000; n *= e->samplesz; td->dev = ((n -1)<<21) | ((id&0x7FF)<<8) | TokOUT; td->offset = e->poffset; e->poffset += n; } td = td->next; if (x->xtd == td){ XPRINT("@"); break; } } while ((td->status & Active) == 0); e->time = todget(nil); x->xtd = td; for (n = 2; n < 4; n++){ i = ((frnum + n)&0x3ff); td = x->td0 + i; bp = x->bp0 + e->maxpkt*i/e->pollms; if (td->status & Active) continue; if (e->mode == OWRITE){ if (td == x->etd) { XPRINT("*"); memset(bp+e->off, 0, e->maxpkt-e->off); if (e->off == 0) td->flags |= IsoClean; else e->buffered += (((td->dev>>21) +1) & 0x3ff) - e->off; x->etd = nil; }else if ((td->flags & IsoClean) == 0){ XPRINT("-"); memset(bp, 0, e->maxpkt); td->flags |= IsoClean; } } else { /* Unread bytes are now lost */ e->buffered -= (td->status + 1) & 0x3ff; } td->status = ErrLimit1 | Active | IsoSelect | IOC; } wakeup(&e->wr);}static voidinterrupt(Ureg*, void *a){ QH *q; Ctlr *ctlr; Endpt *e; Endptx *x; int s, frnum; Usbhost *uh;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -