📄 usbuhci.c
字号:
uh = a; ctlr = uh->ctlr; s = IN(Status); ctlr->frameptr = inl(ctlr->io+Flbaseadd); ctlr->framenumber = IN(Frnum) & 0x3ff; OUT(Status, s); if ((s & 0x1f) == 0) return; ctlr->usbints++; frnum = IN(Frnum) & 0x3ff; if (s & 0x1a) { XPRINT("cmd #%x sofmod #%x\n", IN(Cmd), inb(ctlr->io+SOFMod)); XPRINT("sc0 #%x sc1 #%x\n", IN(Portsc0), IN(Portsc1)); } ilock(&ctlr->activends); for(e = ctlr->activends.f; e != nil; e = e->activef) { x = e->private; if(!e->iso && x->epq != nil) { XXPRINT("cleanq(ctlr, x->epq, 0, 0)\n"); cleanq(ctlr, x->epq, 0, 0); } if(e->iso) { XXPRINT("cleaniso(e)\n"); cleaniso(e, frnum); } } iunlock(&ctlr->activends); XXPRINT("cleanq(ctlr, ctlr->ctlq, 0, 0)\n"); cleanq(ctlr, ctlr->ctlq, 0, 0); XXPRINT("cleanq(ctlr, ctlr->bulkq, 0, Vf)\n"); cleanq(ctlr, ctlr->bulkq, 0, Vf); XXPRINT("clean recvq\n"); for (q = ctlr->recvq->next; q; q = q->hlink) { XXPRINT("cleanq(ctlr, q, 0, Vf)\n"); cleanq(ctlr, q, 0, Vf); }}static inteptinput(void *arg){ Endpt *e; e = arg; return e->eof || e->err || qcanread(e->rq);}static intisoready(void *a){ Endptx *x; TD *etd; x = a; return (etd = x->etd) == nil || (etd != x->xtd && (etd->status & Active) == 0);}static longisoio(Ctlr *ctlr, Endpt *e, void *a, long n, ulong offset, int w){ TD *td; Endptx *x; int i, frnum; uchar *p, *q, *bp; volatile int isolock; x = e->private; qlock(&e->rlock); isolock = 0; if(waserror()){ if (isolock){ isolock = 0; iunlock(&ctlr->activends); } qunlock(&e->rlock); eptcancel(ctlr, e); nexterror(); } p = a; if (offset != 0 && offset != e->foffset){ iprint("offset %lud, foffset %lud\n", offset, e->foffset); /* Seek to a specific position */ frnum = (IN(Frnum) + 8) & 0x3ff; td = x->td0 +frnum; if (offset < td->offset) error("ancient history"); while (offset > e->toffset){ tsleep(&e->wr, return0, 0, 500); } while (offset >= td->offset + ((w?(td->dev >> 21):td->status) + 1) & 0x7ff){ td = td->next; if (td == x->xtd) iprint("trouble\n"); } ilock(&ctlr->activends); isolock = 1; e->off = td->offset - offset; if (e->off >= e->maxpkt){ iprint("I can't program: %d\n", e->off); e->off = 0; } x->etd = td; e->foffset = offset; } do { if (isolock == 0){ ilock(&ctlr->activends); isolock = 1; } td = x->etd; if (td == nil || e->off == 0){ if (td == nil){ XPRINT("0"); if (w){ frnum = (IN(Frnum) + 1) & 0x3ff; td = x->td0 + frnum; while(td->status & Active) td = td->next; }else{ frnum = (IN(Frnum) - 4) & 0x3ff; td = x->td0 + frnum; while(td->next != x->xtd) td = td->next; } x->etd = td; e->off = 0; }else{ /* New td, make sure it's ready */ while (isoready(x) == 0){ isolock = 0; iunlock(&ctlr->activends); sleep(&e->wr, isoready, x); ilock(&ctlr->activends); isolock = 1; } if (x->etd == nil){ XPRINT("!"); continue; } } if (w) e->psize = ((td->dev >> 21) + 1) & 0x7ff; else e->psize = (x->etd->status + 1) & 0x7ff; if(e->psize > e->maxpkt) panic("packet size > maximum"); } if((i = n) >= e->psize) i = e->psize; if (w) e->buffered += i; else{ e->buffered -= i; if (e->buffered < 0) e->buffered = 0; } isolock = 0; iunlock(&ctlr->activends); td->flags &= ~IsoClean; bp = x->bp0 + (td - x->td0) * e->maxpkt / e->pollms; q = bp + e->off; if (w){ memmove(q, p, i); }else{ memmove(p, q, i); } p += i; n -= i; e->off += i; e->psize -= i; if (e->psize){ if (n != 0) panic("usb iso: can't happen"); break; } if(w) td->offset = offset + (p-(uchar*)a) - (((td->dev >> 21) + 1) & 0x7ff); td->status = ErrLimit3 | Active | IsoSelect | IOC; x->etd = td->next; e->off = 0; } while(n > 0); n = p-(uchar*)a; e->foffset += n; poperror(); if (isolock) iunlock(&ctlr->activends); qunlock(&e->rlock); return n;}static longread(Usbhost *uh, Endpt *e, void *a, long n, vlong offset){ long l, i; Block *b; Ctlr *ctlr; uchar *p; ctlr = uh->ctlr; if(e->iso) return isoio(ctlr, e, a, n, (ulong)offset, 0); XPRINT("qlock(%p)\n", &e->rlock); qlock(&e->rlock); XPRINT("got qlock(%p)\n", &e->rlock); if(waserror()){ qunlock(&e->rlock); eptcancel(ctlr, e); nexterror(); } p = a; do { if(e->eof) { XPRINT("e->eof\n"); break; } if(e->err) error(e->err); qrcv(ctlr, e); if(!e->iso) e->rdata01 ^= 1; sleep(&e->rr, eptinput, e); if(e->err) error(e->err); b = qget(e->rq); /* TO DO */ if(b == nil) { XPRINT("b == nil\n"); break; } if(waserror()){ freeb(b); nexterror(); } l = BLEN(b); if((i = l) > n) i = n; if(i > 0){ memmove(p, b->rp, i); p += i; } poperror(); freeb(b); n -= i; if (l != e->maxpkt) break; } while (n > 0); poperror(); qunlock(&e->rlock); return p-(uchar*)a;}static intqisempty(void *arg){ return ((QH*)arg)->entries & Terminate;}static longwrite(Usbhost *uh, Endpt *e, void *a, long n, vlong offset, int tok){ int i, j; QH *qh; Block *b; Ctlr *ctlr; uchar *p; ctlr = uh->ctlr; if(e->iso) return isoio(ctlr, e, a, n, (ulong)offset, 1); p = a; qlock(&e->wlock); if(waserror()){ qunlock(&e->wlock); eptcancel(ctlr, e); nexterror(); } do { if(e->err) error(e->err); if((i = n) >= e->maxpkt) i = e->maxpkt; b = allocb(i); if(waserror()){ freeb(b); nexterror(); } XPRINT("out [%d]", i); for (j = 0; j < i; j++) XPRINT(" %.2x", p[j]); XPRINT("\n"); memmove(b->wp, p, i); b->wp += i; p += i; n -= i; poperror(); qh = qxmit(ctlr, e, b, tok); tok = TokOUT; e->wdata01 ^= 1; if(e->ntd >= e->nbuf) {XPRINT("qh %s: q=%p first=%p last=%p entries=%.8lux\n", "writeusb sleep", qh, qh->first, qh->last, qh->entries); XPRINT("write: sleep %lux\n", &e->wr); sleep(&e->wr, qisempty, qh); XPRINT("write: awake\n"); } } while(n > 0); poperror(); qunlock(&e->wlock); return p-(uchar*)a;}static voidinit(Usbhost* uh){ Ctlr *ctlr; ctlr = uh->ctlr; ilock(ctlr); outl(ctlr->io+Flbaseadd, PCIWADDR(ctlr->frames)); OUT(Frnum, 0); OUT(Usbintr, 0xF); /* enable all interrupts */ XPRINT("cmd 0x%x sofmod 0x%x\n", IN(Cmd), inb(ctlr->io+SOFMod)); XPRINT("sc0 0x%x sc1 0x%x\n", IN(Portsc0), IN(Portsc1)); if((IN(Cmd)&1)==0) OUT(Cmd, 1); /* run */// pprint("at: c=%x s=%x c0=%x\n", IN(Cmd), IN(Status), IN(Portsc0)); iunlock(ctlr);}static voidscanpci(void){ int io; Ctlr *ctlr; Pcidev *p; static int already = 0; if(already) return; already = 1; p = nil; while(p = pcimatch(p, 0, 0)) { /* * Find UHCI controllers. Class = 12 (serial controller), * Sub-class = 3 (USB) and Programming Interface = 0. */ if(p->ccrb != 0x0C || p->ccru != 0x03) continue; switch(p->ccrp){ case 0x00: io = p->mem[4].bar & ~0x0F; break; case 0x10: case 0x20: print("usb%chci: %x/%x %sport 0x%lux size 0x%x irq %d (ignored)\n", (p->ccrp == 0x10? 'o': 'e'), p->vid, p->did, (p->ccrp == 0x10? "": "USB 2 "), p->mem[0].bar & ~0x0F, p->mem[0].size, p->intl); /* fallthrough */ default: continue; } if(io == 0) { print("usbuhci: failed to map registers\n"); continue; } if(ioalloc(io, p->mem[4].size, 0, "usbuhci") < 0){ print("usbuhci: port %d in use\n", io); continue; } if(p->intl == 0xFF || p->intl == 0) { print("usbuhci: no irq assigned for port %d\n", io); continue; } XPRINT("usbuhci: %x/%x port 0x%ux size 0x%x irq %d\n", p->vid, p->did, io, p->mem[4].size, p->intl); ctlr = malloc(sizeof(Ctlr)); ctlr->pcidev = p; ctlr->io = io; if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; }}static intreset(Usbhost *uh){ int i; TD *t; ulong io; Ctlr *ctlr; Pcidev *p; scanpci(); /* * Any adapter matches if no uh->port is supplied, * otherwise the ports must match. */ for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){ if(ctlr->active) continue; if(uh->port == 0 || uh->port == ctlr->io){ ctlr->active = 1; break; } } if(ctlr == nil) return -1; io = ctlr->io; p = ctlr->pcidev; uh->ctlr = ctlr; uh->port = io; uh->irq = p->intl; uh->tbdf = p->tbdf; XPRINT("usbcmd\t0x%.4x\nusbsts\t0x%.4x\nusbintr\t0x%.4x\nfrnum\t0x%.2x\n", IN(Cmd), IN(Status), IN(Usbintr), inb(io+Frnum)); XPRINT("frbaseadd\t0x%.4x\nsofmod\t0x%x\nportsc1\t0x%.4x\nportsc2\t0x%.4x\n", IN(Flbaseadd), inb(io+SOFMod), IN(Portsc0), IN(Portsc1)); OUT(Cmd, 0); /* stop */ while((IN(Status) & (1<<5)) == 0) /* wait for halt */ ; OUT(Status, 0xFF); /* clear pending interrupts */ pcicfgw16(p, 0xc0, 0x2000); /* legacy support register: turn off lunacy mode */ if(0){ i = inb(io+SOFMod); OUT(Cmd, 4); /* global reset */ delay(15); OUT(Cmd, 0); /* end reset */ delay(4); outb(io+SOFMod, i); } ctlr->tdpool = xspanalloc(128*sizeof(TD), 16, 0); for(i=128; --i>=0;){ ctlr->tdpool[i].next = ctlr->freetd; ctlr->freetd = &ctlr->tdpool[i]; } ctlr->qhpool = xspanalloc(64*sizeof(QH), 16, 0); for(i=64; --i>=0;){ ctlr->qhpool[i].next = ctlr->freeqh; ctlr->freeqh = &ctlr->qhpool[i]; } /* * the last entries of the periodic (interrupt & isochronous) scheduling TD entries * points to the control queue and the bandwidth sop for bulk traffic. * this is looped following the instructions in PIIX4 errata 29773804.pdf: * a QH links to a looped but inactive TD as its sole entry, * with its head entry leading on to the bulk traffic, the last QH of which * links back to the empty QH. */ ctlr->ctlq = allocqh(ctlr); ctlr->bwsop = allocqh(ctlr); ctlr->bulkq = allocqh(ctlr); ctlr->recvq = allocqh(ctlr); t = alloctd(ctlr); /* inactive TD, looped */ t->link = PCIWADDR(t); ctlr->bwsop->entries = PCIWADDR(t); ctlr->ctlq->head = PCIWADDR(ctlr->bulkq) | IsQH; ctlr->bulkq->head = PCIWADDR(ctlr->recvq) | IsQH; ctlr->recvq->head = PCIWADDR(ctlr->bwsop) | IsQH; if (1) /* don't use loop back */ ctlr->bwsop->head = Terminate; else /* set up loop back */ ctlr->bwsop->head = PCIWADDR(ctlr->bwsop) | IsQH; ctlr->frames = xspanalloc(FRAMESIZE, FRAMESIZE, 0); ctlr->frameld = xallocz(FRAMESIZE, 1); for (i = 0; i < NFRAME; i++) ctlr->frames[i] = PCIWADDR(ctlr->ctlq) | IsQH; /* * Linkage to the generic USB driver. */ uh->init = init; uh->interrupt = interrupt; uh->portinfo = portinfo; uh->portreset = portreset; uh->portenable = portenable; uh->epalloc = epalloc; uh->epfree = epfree; uh->epopen = epopen; uh->epclose = epclose; uh->epmode = epmode; uh->read = read; uh->write = write; return 0;}voidusbuhcilink(void){ addusbtype("uhci", reset);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -