| plan 9 kernel history: overview | file list | diff list |
1999/1006/pc/devusb.c (diff list | history)
| 1999/1005/sys/src/9/pc/devusb.c:1123,1223 – 1999/1006/sys/src/9/pc/devusb.c:1123,1128 (short | long) | ||
| 1999/1005 | iunlock(&activends); } | |
| 1999/1005/sys/src/9/pc/devusb.c:1317,1323 – 1999/1006/sys/src/9/pc/devusb.c:1222,1317 | ||
| 1999/1005 | static void usbreset(void) { | |
| 1999/1006 | Ctlr *ub; Pcidev *cfg; int i; ulong port; QTree *qt; TD *t; ub = &ubus; memset(&cfg, 0, sizeof(cfg)); cfg = pcimatch(0, 0x8086, 0x7112); /* Intel chipset PIIX 4*/ if(cfg == nil) { // cfg = pcimatch(0, 0x8086, 0x7112); /* Intel chipset PIIX 3*/ // if(cfg == nil) { cfg = pcimatch(0, 0x1106, 0x0586); /* Via chipset */ if(cfg == nil) { DPRINT("No USB device found\n"); return; } // } } port = cfg->mem[4].bar & ~0x0F; if (port == 0) { print("usb: failed to map registers\n"); return; } print("USB: %x/%x port 0x%lux size 0x%x irq %d\n", cfg->vid, cfg->did, port, cfg->mem[4].size, cfg->intl); i = inb(port+SOFMod); if(0){ OUT(Cmd, 4); /* global reset */ delay(15); OUT(Cmd, 0); /* end reset */ delay(4); } outb(port+SOFMod, i); // Interrupt handler intrenable(cfg->intl, interrupt, ub, cfg->tbdf, "usb"); ub->io = port; ub->tdpool = xspanalloc(128*sizeof(TD), 16, 0); for(i=128; --i>=0;){ ub->tdpool[i].next = ub->freetd; ub->freetd = &ub->tdpool[i]; } ub->qhpool = xspanalloc(32*sizeof(QH), 16, 0); for(i=32; --i>=0;){ ub->qhpool[i].next = ub->freeqh; ub->freeqh = &ub->qhpool[i]; } /* * the root of the periodic (interrupt & isochronous) scheduling tree * 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. */ ub->bulkq = allocqh(ub); t = alloctd(ub); /* inactive TD, looped */ t->link = PADDR(t); ub->bwsop = allocqh(ub); ub->bwsop->head = PADDR(ub->bulkq) | IsQH; ub->bwsop->entries = PADDR(t); ub->ctlq = allocqh(ub); ub->ctlq->head = PADDR(ub->bwsop) | IsQH; // ub->bulkq->head = PADDR(ub->bwsop) | IsQH; /* loop back */ print("usbcmd\t0x%.4x\nusbsts\t0x%.4x\nusbintr\t0x%.4x\nfrnum\t0x%.2x\n", IN(Cmd), IN(Status), IN(Usbintr), inb(port+Frnum)); print("frbaseadd\t0x%.4x\nsofmod\t0x%x\nportsc1\t0x%.4x\nportsc2\t0x%.4x\n", IN(Flbaseadd), inb(port+SOFMod), IN(Portsc0), IN(Portsc1)); OUT(Cmd, 0); /* stop */ ub->frames = xspanalloc(FRAMESIZE, FRAMESIZE, 0); qt = mkqhtree(ub->frames, NFRAME, 32); if(qt == nil){ print("usb: can't allocate scheduling tree\n"); ub->io = 0; return; } qt->root->head = PADDR(ub->ctlq) | IsQH; ub->tree = qt; print("usb tree: nel=%d depth=%d\n", qt->nel, qt->depth); outl(port+Flbaseadd, PADDR(ub->frames)); OUT(Frnum, 0); OUT(Usbintr, 0xF); /* enable all interrupts */ print("cmd 0x%x sofmod 0x%x\n", IN(Cmd), inb(port+SOFMod)); print("sc0 0x%x sc1 0x%x\n", IN(Portsc0), IN(Portsc1)); | |
| 1999/1005 | } void | |
| 1999/1005/sys/src/9/pc/devusb.c:1851,1858 – 1999/1006/sys/src/9/pc/devusb.c:1845,1854 | ||
| 1999/1005 | }else if(nf == 6 && strcmp(fields[0], "ep") == 0){ /* ep n maxpkt mode poll nbuf */ i = strtoul(fields[1], nil, 0); | |
| 1999/1006 | if(i < 0 || i >= nelem(d->ep)) { pprint("field 1: 0 <= %d < %d\n", i, nelem(d->ep)); | |
| 1999/1005 | error(Ebadarg); | |
| 1999/1006 | } | |
| 1999/1005 | if(d->ep[i] != nil) error(Einuse); e = devendpt(d, i, 1); | |
| 1999/1005/sys/src/9/pc/devusb.c:1872,1886 – 1999/1006/sys/src/9/pc/devusb.c:1868,1886 | ||
| 1999/1005 | i = strtoul(fields[4], nil, 0); if(i > 0 && i <= 1000) e->pollms = i; | |
| 1999/1006 | else { pprint("field 4: 0 <= %d <= 1000\n", i); | |
| 1999/1005 | error(Ebadarg); | |
| 1999/1006 | } | |
| 1999/1005 | } i = strtoul(fields[5], nil, 0); if(i >= 1 && i <= 32) e->nbuf = i; poperror(); | |
| 1999/1006 | }else { pprint("command %s, fields %d\n", fields[0], nf); | |
| 1999/1005 | error(Ebadarg); | |
| 1999/1006 | } | |
| 1999/1005 | return n; case Qsetup: /* SETUP endpoint 0 */ | |
| 1999/1006/sys/src/9/pc/devusb.c:369,377 – 1999/1007/sys/src/9/pc/devusb.c:369,377 (short | long) | ||
| 1999/1005 | if(t->status & LowSpeed) *s++ = 'L'; *s = 0; | |
| 1999/1007 | XPRINT("td %8.8lux: l=%8.8lux s=%8.8lux d=%8.8lux b=%8.8lux %8.8lux f=%8.8lux\n", | |
| 1999/1005 | t, t->link, t->status, t->dev, t->buffer, t->bp?(ulong)t->bp->rp:0, t->flags); | |
| 1999/1007 | XPRINT("\ts=%s,ep=%ld,d=%ld,D=%ld\n", buf, (t->dev>>15)&0xF, (t->dev>>8)&0xFF, (t->dev>>19)&1); | |
| 1999/1005 | if(t->bp) dumpdata(t->bp, n); if(!follow || t->link & Terminate || t->link & IsQH) | |
| 1999/1006/sys/src/9/pc/devusb.c:401,444 – 1999/1007/sys/src/9/pc/devusb.c:401,406 | ||
| 1999/1005 | return t; } | |
| 1999/1006/sys/src/9/pc/devusb.c:475,487 – 1999/1007/sys/src/9/pc/devusb.c:437,449 | ||
| 1999/1005 | q0 = q; for(i = 0; q != nil && i < 10; i++){ | |
| 1999/1007 | XPRINT("qh %8.8lux: %8.8lux %8.8lux\n", q, q->head, q->entries); | |
| 1999/1005 | if((q->entries & Terminate) == 0) dumptd(TFOL(q->entries), 1); if(q->head & Terminate) break; if((q->head & IsQH) == 0){ | |
| 1999/1007 | XPRINT("head:"); | |
| 1999/1005 | dumptd(TFOL(q->head), 1); break; } | |
| 1999/1006/sys/src/9/pc/devusb.c:525,531 – 1999/1007/sys/src/9/pc/devusb.c:487,493 | ||
| 1999/1005 | err = t->status & (AnyError&~NAKed); /* TO DO: on t->status&AnyError, q->entries will not have advanced */ if (err) | |
| 1999/1007 | XPRINT("cleanTD: Error %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer); | |
| 1999/1005 | switch(t->dev&0xFF){ case TokIN: if(discard || (t->flags & CancelTD) || t->ep == nil || t->ep->x!=0&&err){ | |
| 1999/1006/sys/src/9/pc/devusb.c:624,630 – 1999/1007/sys/src/9/pc/devusb.c:586,592 | ||
| 1999/1005 | if(t->ep == e) t->flags |= CancelTD; iunlock(ub); | |
| 1999/1007 | XPRINT("cancel:\n"); | |
| 1999/1005 | dumpqh(q); } } | |
| 1999/1006/sys/src/9/pc/devusb.c:805,811 – 1999/1007/sys/src/9/pc/devusb.c:767,773 | ||
| 1999/1005 | o |= 1; } if(leaf0+o >= n){ | |
| 1999/1007 | XPRINT("leaf0=%d o=%d i=%d n=%d\n", leaf0, o, i, n); | |
| 1999/1005 | break; } frame[i] = PADDR(&tree[leaf0+o]) | IsQH; | |
| 1999/1006/sys/src/9/pc/devusb.c:828,841 – 1999/1007/sys/src/9/pc/devusb.c:790,803 | ||
| 1999/1005 | if(t < 0) t = 32; for(i=f; i<t; i++){ | |
| 1999/1007 | XPRINT("F%.2d %8.8lux %8.8lux\n", i, frame[i], QFOL(frame[i])->head); | |
| 1999/1005 | for(p=frame[i]; (p & IsQH) && (p &Terminate) == 0; p = q->head){ q = QFOL(p); if(!(q >= tree && q < &tree[n])){ | |
| 1999/1007 | XPRINT("Q: p=%8.8lux out of range\n", p); | |
| 1999/1005 | break; } | |
| 1999/1007 | XPRINT(" -> %8.8lux h=%8.8lux e=%8.8lux\n", p, q->head, q->entries); | |
| 1999/1005 | } } } | |
| 1999/1006/sys/src/9/pc/devusb.c:1104,1112 – 1999/1007/sys/src/9/pc/devusb.c:1066,1074 | ||
| 1999/1005 | ub = a; s = IN(Status); if (s & 0x1a) { | |
| 1999/1007 | XPRINT("usbint: #%x f%d\n", s, IN(Frnum)); XPRINT("cmd #%x sofmod #%x\n", IN(Cmd), inb(ub->io+SOFMod)); XPRINT("sc0 #%x sc1 #%x\n", IN(Portsc0), IN(Portsc1)); | |
| 1999/1005 | } OUT(Status, s); | |
| 1999/1006/sys/src/9/pc/devusb.c:1570,1576 – 1999/1007/sys/src/9/pc/devusb.c:1532,1538 | ||
| 1999/1005 | p = a; do { if(e->eof) { | |
| 1999/1007 | XPRINT("e->eof\n"); | |
| 1999/1005 | break; } if(e->err) | |
| 1999/1006/sys/src/9/pc/devusb.c:1583,1589 – 1999/1007/sys/src/9/pc/devusb.c:1545,1551 | ||
| 1999/1005 | error(e->err); b = qget(e->rq); /* TO DO */ if(b == nil) { | |
| 1999/1007 | XPRINT("b == nil\n"); | |
| 1999/1005 | break; } if(waserror()){ | |
| 1999/1006/sys/src/9/pc/devusb.c:1846,1852 – 1999/1007/sys/src/9/pc/devusb.c:1808,1814 | ||
| 1999/1005 | /* ep n maxpkt mode poll nbuf */ i = strtoul(fields[1], nil, 0); | |
| 1999/1006 | if(i < 0 || i >= nelem(d->ep)) { | |
| 1999/1007 | XPRINT("field 1: 0 <= %d < %d\n", i, nelem(d->ep)); | |
| 1999/1005 | error(Ebadarg); | |
| 1999/1006 | } | |
| 1999/1005 | if(d->ep[i] != nil) | |
| 1999/1006/sys/src/9/pc/devusb.c:1869,1875 – 1999/1007/sys/src/9/pc/devusb.c:1831,1837 | ||
| 1999/1005 | if(i > 0 && i <= 1000) e->pollms = i; | |
| 1999/1006 | else { | |
| 1999/1007 | XPRINT("field 4: 0 <= %d <= 1000\n", i); | |
| 1999/1005 | error(Ebadarg); | |
| 1999/1006 | } | |
| 1999/1005 | } | |
| 1999/1006/sys/src/9/pc/devusb.c:1878,1884 – 1999/1007/sys/src/9/pc/devusb.c:1840,1846 | ||
| 1999/1005 | e->nbuf = i; poperror(); | |
| 1999/1006 | }else { | |
| 1999/1007 | XPRINT("command %s, fields %d\n", fields[0], nf); | |
| 1999/1005 | error(Ebadarg); | |
| 1999/1006 | } | |
| 1999/1005 | return n; | |
| 1999/1007/sys/src/9/pc/devusb.c:30,37 – 1999/1116/sys/src/9/pc/devusb.c:30,39 (short | long) | ||
| 1999/1005 | #define Pprint #define Chatty 1 #define DPRINT if(Chatty)print | |
| 1999/1116 | #define XPRINT if(debug)print | |
| 1999/1005 | ||
| 1999/1116 | static int debug = 1; | |
| 1999/1005 | /* * USB packet definitions */ | |
| 1999/1007/sys/src/9/pc/devusb.c:211,220 – 1999/1116/sys/src/9/pc/devusb.c:213,222 | ||
| 1999/1005 | struct Endpt { Ref; Lock; | |
| 1999/1116 | int x; /* index in Udev.ep */ int id; /* hardware endpoint address */ int maxpkt; /* maximum packet size (from endpoint descriptor) */ int data01; /* 0=DATA0, 1=DATA1 */ | |
| 1999/1005 | byte eof; byte class; byte subclass; | |
| 1999/1007/sys/src/9/pc/devusb.c:225,235 – 1999/1116/sys/src/9/pc/devusb.c:227,237 | ||
| 1999/1005 | byte iso; byte debug; byte active; /* listed for examination by interrupts */ | |
| 1999/1116 | int sched; /* schedule index; -1 if undefined or aperiodic */ int setin; | |
| 1999/1005 | ulong bw; /* bandwidth requirement */ | |
| 1999/1116 | int pollms; /* polling interval in msec */ QH* epq; /* queue of TDs for this endpoint */ | |
| 1999/1005 | QLock rlock; Rendez rr; | |
| 1999/1007/sys/src/9/pc/devusb.c:238,244 – 1999/1116/sys/src/9/pc/devusb.c:240,246 | ||
| 1999/1005 | Rendez wr; Queue* wq; | |
| 1999/1116 | int ntd; | |
| 1999/1005 | char* err; Udev* dev; /* owning device */ | |
| 1999/1007/sys/src/9/pc/devusb.c:470,475 – 1999/1116/sys/src/9/pc/devusb.c:472,478 | ||
| 1999/1005 | q->entries = PADDR(t); } q->last = lt; | |
| 1999/1116 | dumpqh(q); | |
| 1999/1005 | iunlock(ub); } | |
| 1999/1007/sys/src/9/pc/devusb.c:541,576 – 1999/1116/sys/src/9/pc/devusb.c:544,603 | ||
| 1999/1005 | } static void | |
| 1999/1116 | cleanq(QH *q, int discard, int vf) | |
| 1999/1005 | { | |
| 1999/1116 | TD *t, *tp; | |
| 1999/1005 | Ctlr *ub; ub = &ubus; ilock(ub); | |
| 1999/1116 | tp = nil; | |
| 1999/1005 | for(t = q->first; t != nil;){ | |
| 1999/1116 | XPRINT("cleanq: %8.8lux %8.8lux %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer, t->flags, t->next); | |
| 1999/1005 | if(t->status & Active){ | |
| 1999/1116 | if(t->status & NAKed){ t->status = (t->status & ~NAKed) | IOC; /* ensure interrupt next frame */ tp = t; t = t->next; continue; } | |
| 1999/1005 | if(t->flags & CancelTD){ XPRINT("cancelTD: %8.8lux\n", (ulong)t); t->status = (t->status & ~Active) | IOC; /* ensure interrupt next frame */ | |
| 1999/1116 | tp = t; | |
| 1999/1005 | t = t->next; continue; } | |
| 1999/1116 | tp = t; t = t->next; continue; | |
| 1999/1005 | break; } t->status &= ~IOC; | |
| 1999/1116 | if (tp == nil) { q->first = t->next; if(q->first != nil) q->entries = PADDR(q->first); else q->entries = Terminate; } else { tp->next = t->next; if (t->next != nil) tp->link = PADDR(t->next) | vf; else tp->link = Terminate; } if (q->last == t) q->last = tp; | |
| 1999/1005 | iunlock(ub); cleantd(t, discard); ilock(ub); | |
| 1999/1116 | if (tp) t = tp->next; else t = q->first; XPRINT("t = %8.8lux\n", t); dumpqh(q); | |
| 1999/1005 | } iunlock(ub); } | |
| 1999/1007/sys/src/9/pc/devusb.c:676,681 – 1999/1116/sys/src/9/pc/devusb.c:703,709 | ||
| 1999/1005 | QH *qh; int vf; | |
| 1999/1116 | XPRINT("qrcv\n"); | |
| 1999/1005 | t = alloctde(e, TokIN, e->maxpkt); b = allocb(e->maxpkt); t->bp = b; | |
| 1999/1007/sys/src/9/pc/devusb.c:683,691 – 1999/1116/sys/src/9/pc/devusb.c:711,720 | ||
| 1999/1005 | ub = &ubus; vf = 0; if(e->x == 0){ | |
| 1999/1116 | XPRINT("enq\n"); | |
| 1999/1005 | qh = ub->ctlq; | |
| 1999/1116 | XPRINT("bulkenq\n"); | |
| 1999/1005 | qh = ub->bulkq; vf = Vf; } | |
| 1999/1007/sys/src/9/pc/devusb.c:912,917 – 1999/1116/sys/src/9/pc/devusb.c:941,950 | ||
| 1999/1005 | e->nbuf = 1; e->dev = d; e->active = 0; | |
| 1999/1116 | e->epq = allocqh(ub); if(e->epq == nil) panic("devendpt"); | |
| 1999/1005 | lock(d); if(*p != nil){ incref(*p); | |
| 1999/1007/sys/src/9/pc/devusb.c:1065,1086 – 1999/1116/sys/src/9/pc/devusb.c:1098,1119 | ||
| 1999/1005 | ub = a; s = IN(Status); | |
| 1999/1116 | XPRINT("usbint: #%x f%d\n", s, IN(Frnum)); | |
| 1999/1005 | if (s & 0x1a) { | |
| 1999/1007 |
| |
| 1999/1005 | } OUT(Status, s); | |
| 1999/1116 | XPRINT("cleanq(ub->ctlq, 0, 0)\n"); cleanq(ub->ctlq, 0, 0); XPRINT("cleanq(ub->bulkq, 0, Vf)\n"); cleanq(ub->bulkq, 0, Vf); | |
| 1999/1005 | ilock(&activends); for(e = activends.f; e != nil; e = e->activef) if(e->epq != nil) { | |
| 1999/1116 | XPRINT("cleanq(e->epq, 0, 0)\n"); cleanq(e->epq, 0, 0); | |
| 1999/1005 | } iunlock(&activends); } | |
| 1999/1007/sys/src/9/pc/devusb.c:1252,1258 – 1999/1116/sys/src/9/pc/devusb.c:1285,1291 | ||
| 1999/1006 | ub->bwsop->entries = PADDR(t); ub->ctlq = allocqh(ub); ub->ctlq->head = PADDR(ub->bwsop) | IsQH; | |
| 1999/1116 | ub->bulkq->head = PADDR(ub->bwsop) | IsQH; /* loop back */ | |
| 1999/1006 | print("usbcmd\t0x%.4x\nusbsts\t0x%.4x\nusbintr\t0x%.4x\nfrnum\t0x%.2x\n", IN(Cmd), IN(Status), IN(Usbintr), inb(port+Frnum)); print("frbaseadd\t0x%.4x\nsofmod\t0x%x\nportsc1\t0x%.4x\nportsc2\t0x%.4x\n", | |
| 1999/1007/sys/src/9/pc/devusb.c:1523,1529 – 1999/1116/sys/src/9/pc/devusb.c:1556,1564 | ||
| 1999/1005 | uchar *p; long l, i; | |
| 1999/1116 | XPRINT("qlock(%p)\n", &e->rlock); | |
| 1999/1005 | qlock(&e->rlock); | |
| 1999/1116 | XPRINT("got qlock(%p)\n", &e->rlock); | |
| 1999/1005 | if(waserror()){ qunlock(&e->rlock); eptcancel(e); | |
| 1999/1007/sys/src/9/pc/devusb.c:1794,1803 – 1999/1116/sys/src/9/pc/devusb.c:1829,1843 | ||
| 1999/1005 | e->maxpkt = 1500; }else if(nf > 2 && strcmp(fields[0], "debug") == 0){ i = strtoul(fields[1], nil, 0); | |
| 1999/1116 | if(i < -1 || i >= nelem(d->ep) || d->ep[i] == nil) | |
| 1999/1005 | error(Ebadarg); | |
| 1999/1116 | if (i == -1) debug = 0; else { debug = 1; e = d->ep[i]; e->debug = strtoul(fields[2], nil, 0); } | |
| 1999/1005 | }else if(nf > 1 && strcmp(fields[0], "unstall") == 0){ i = strtoul(fields[1], nil, 0); if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) | |
| 1999/1116/sys/src/9/pc/devusb.c:32,38 – 1999/1117/sys/src/9/pc/devusb.c:32,38 (short | long) | ||
| 1999/1005 | #define DPRINT if(Chatty)print | |
| 1999/1116 | #define XPRINT if(debug)print | |
| 1999/1005 | ||
| 1999/1116 |
| |
| 1999/1117 | static int debug = 0; | |
| 1999/1116 | ||
| 1999/1005 | /* * USB packet definitions | |
| 1999/1116/sys/src/9/pc/devusb.c:86,96 – 1999/1117/sys/src/9/pc/devusb.c:86,97 | ||
| 1999/1005 | ulong entries; /* address of next TD or QH to process (updated by controller) */ /* software */ | |
| 1999/1117 | QH* hlink; TD* first; QH* next; /* free list */ TD* last; ulong _d1; /* fillers */ ulong _d2; | |
| 1999/1005 | }; #define QFOL(p) ((QH*)KADDR((ulong)(p) & ~0xF)) | |
| 1999/1116/sys/src/9/pc/devusb.c:267,272 – 1999/1117/sys/src/9/pc/devusb.c:268,274 | ||
| 1999/1005 | QH* ctlq; /* queue for control i/o */ QH* bwsop; /* empty bandwidth sop (to PIIX4 errata specifications) */ QH* bulkq; /* queue for bulk i/o (points back to bandwidth sop) */ | |
| 1999/1117 | QH* recvq; /* receive queues for bulk i/o */ | |
| 1999/1005 | Udev* ports[2]; }; | |
| 1999/1116/sys/src/9/pc/devusb.c:371,381 – 1999/1117/sys/src/9/pc/devusb.c:373,384 | ||
| 1999/1005 | if(t->status & LowSpeed) *s++ = 'L'; *s = 0; | |
| 1999/1007 |
| |
| 1999/1005 |
| |
| 1999/1117 | XPRINT("td %8.8lux: ", t); XPRINT("l=%8.8lux s=%8.8lux d=%8.8lux b=%8.8lux %8.8lux f=%8.8lux\n", t->link, t->status, t->dev, t->buffer, t->bp?(ulong)t->bp->rp:0, t->flags); | |
| 1999/1007 | XPRINT("\ts=%s,ep=%ld,d=%ld,D=%ld\n", buf, (t->dev>>15)&0xF, (t->dev>>8)&0xFF, (t->dev>>19)&1); | |
| 1999/1005 |
| |
| 1999/1117 | // if(t->bp && (t->flags & CancelTD) == 0 && (t->status & Active) == 0) // dumpdata(t->bp, n); | |
| 1999/1005 | if(!follow || t->link & Terminate || t->link & IsQH) break; t = TFOL(t->link); | |
| 1999/1116/sys/src/9/pc/devusb.c:417,422 – 1999/1117/sys/src/9/pc/devusb.c:420,426 | ||
| 1999/1005 | iunlock(ub); qh->head = Terminate; qh->entries = Terminate; | |
| 1999/1117 | qh->hlink = nil; | |
| 1999/1005 | qh->first = nil; qh->last = nil; return qh; | |
| 1999/1116/sys/src/9/pc/devusb.c:662,667 – 1999/1117/sys/src/9/pc/devusb.c:666,689 | ||
| 1999/1005 | iunlock(&activends); } | |
| 1999/1117 | static void queueqh(QH *qh) { QH *q; Ctlr *ub; ub = &ubus; // See if it's already queued for (q = ub->recvq->next; q; q = q->hlink) if (q == qh) return; if ((qh->hlink = ub->recvq->next) == nil) qh->head = Terminate; else qh->head = PADDR(ub->recvq->next) | IsQH; ub->recvq->next = qh; ub->recvq->entries = PADDR(qh) | IsQH; } | |
| 1999/1005 | static QH* qxmit(Endpt *e, Block *b, int pid) { | |
| 1999/1116/sys/src/9/pc/devusb.c:670,675 – 1999/1117/sys/src/9/pc/devusb.c:692,698 | ||
| 1999/1005 | Ctlr *ub; QH *qh; | |
| 1999/1117 | XPRINT("qxmit\n"); | |
| 1999/1005 | if(b != nil){ n = BLEN(b); t = alloctde(e, pid, n); | |
| 1999/1116/sys/src/9/pc/devusb.c:684,692 – 1999/1117/sys/src/9/pc/devusb.c:707,717 | ||
| 1999/1005 | if(e->debug)pprint("QTD: %8.8lux n=%ld\n", t, b?BLEN(b): 0); vf = 0; if(e->x == 0){ | |
| 1999/1117 | XPRINT("enq\n"); | |
| 1999/1005 | qh = ub->ctlq; vf = 0; }else if((qh = e->epq) == nil || e->mode != OWRITE){ | |
| 1999/1117 | XPRINT("bulkenq\n"); | |
| 1999/1005 | qh = ub->bulkq; vf = Vf; } | |
| 1999/1116/sys/src/9/pc/devusb.c:898,904 – 1999/1117/sys/src/9/pc/devusb.c:923,929 | ||
| 1999/1005 | int q; ub = &ubus; | |
| 1999/1117 | if(!e->periodic || (q = e->sched) < 0) | |
| 1999/1005 | return; p = PADDR(e->epq) | IsQH; qlock(ub->tree); | |
| 1999/1116/sys/src/9/pc/devusb.c:918,924 – 1999/1117/sys/src/9/pc/devusb.c:943,951 | ||
| 1999/1005 | devendpt(Udev *d, int id, int add) { Endpt *e, **p; | |
| 1999/1117 | Ctlr *ub; | |
| 1999/1005 | ||
| 1999/1117 | ub = &ubus; | |
| 1999/1005 | p = &d->ep[id&0xF]; lock(d); if((e = *p) != nil){ | |
| 1999/1116/sys/src/9/pc/devusb.c:1095,1100 – 1999/1117/sys/src/9/pc/devusb.c:1122,1128 | ||
| 1999/1005 | Ctlr *ub; Endpt *e; int s; | |
| 1999/1117 | QH *q; | |
| 1999/1005 | ub = a; s = IN(Status); | |
| 1999/1116/sys/src/9/pc/devusb.c:1109,1114 – 1999/1117/sys/src/9/pc/devusb.c:1137,1147 | ||
| 1999/1116 | cleanq(ub->ctlq, 0, 0); XPRINT("cleanq(ub->bulkq, 0, Vf)\n"); cleanq(ub->bulkq, 0, Vf); | |
| 1999/1117 | XPRINT("clean recvq\n"); for (q = ub->recvq->next; q; q = q->hlink) { XPRINT("cleanq(q, 0, Vf)\n"); cleanq(q, 0, Vf); } | |
| 1999/1005 | ilock(&activends); for(e = activends.f; e != nil; e = e->activef) if(e->epq != nil) { | |
| 1999/1116/sys/src/9/pc/devusb.c:1217,1228 – 1999/1117/sys/src/9/pc/devusb.c:1250,1261 | ||
| 1999/1005 | static void usbreset(void) { | |
| 1999/1006 |
| |
| 1999/1117 | Ctlr *ub; | |
| 1999/1006 | ub = &ubus; memset(&cfg, 0, sizeof(cfg)); | |
| 1999/1116/sys/src/9/pc/devusb.c:1277,1291 – 1999/1117/sys/src/9/pc/devusb.c:1310,1330 | ||
| 1999/1006 | * with its head entry leading on to the bulk traffic, the last QH of which * links back to the empty QH. */ | |
| 1999/1117 | ub->ctlq = allocqh(ub); ub->bwsop = allocqh(ub); | |
| 1999/1006 | ub->bulkq = allocqh(ub); | |
| 1999/1117 | ub->recvq = allocqh(ub); XPRINT("bulkq: 0x%8.8lux\n", ub->bulkq); XPRINT("recvq: 0x%8.8lux\n", ub->recvq); XPRINT("bwsop: 0x%8.8lux\n", ub->bwsop); XPRINT("ctlq: 0x%8.8lux\n", ub->ctlq); | |
| 1999/1006 | t = alloctd(ub); /* inactive TD, looped */ t->link = PADDR(t); | |
| 1999/1116 |
| |
| 1999/1117 | ub->bwsop->head = PADDR(ub->bulkq) | IsQH; ub->bulkq->head = PADDR(ub->recvq) | IsQH; ub->recvq->head = PADDR(ub->bwsop) | IsQH; /* loop back */ | |
| 1999/1006 | print("usbcmd\t0x%.4x\nusbsts\t0x%.4x\nusbintr\t0x%.4x\nfrnum\t0x%.2x\n", IN(Cmd), IN(Status), IN(Usbintr), inb(port+Frnum)); print("frbaseadd\t0x%.4x\nsofmod\t0x%x\nportsc1\t0x%.4x\nportsc2\t0x%.4x\n", | |
| 1999/1116/sys/src/9/pc/devusb.c:1865,1871 – 1999/1117/sys/src/9/pc/devusb.c:1904,1923 | ||
| 1999/1005 | e->mode = strcmp(fields[3],"r")==0? OREAD: strcmp(fields[3],"w") == 0? OWRITE: ORDWR; e->periodic = 0; e->sched = -1; | |
| 1999/1117 | if(strcmp(fields[4], "bulk") == 0){ Ctlr *ub; ub = &ubus; /* Each bulk device gets a queue head hanging off the * bulk queue head */ if (e->epq == nil) { e->epq = allocqh(ub); if(e->epq == nil) panic("usbwrite: allocqh"); } queueqh(e->epq); } else { | |
| 1999/1005 | e->periodic = 1; i = strtoul(fields[4], nil, 0); if(i > 0 && i <= 1000) | |
| 1999/1117/sys/src/9/pc/devusb.c:27,33 – 1999/1118/sys/src/9/pc/devusb.c:27,32 (short | long) | ||
| 1999/1005 | #endif */ | |
| 1999/1116 | #define XPRINT if(debug)print | |
| 1999/1117/sys/src/9/pc/devusb.c:377,384 – 1999/1118/sys/src/9/pc/devusb.c:376,383 | ||
| 1999/1117 | XPRINT("l=%8.8lux s=%8.8lux d=%8.8lux b=%8.8lux %8.8lux f=%8.8lux\n", t->link, t->status, t->dev, t->buffer, t->bp?(ulong)t->bp->rp:0, t->flags); | |
| 1999/1007 | XPRINT("\ts=%s,ep=%ld,d=%ld,D=%ld\n", buf, (t->dev>>15)&0xF, (t->dev>>8)&0xFF, (t->dev>>19)&1); | |
| 1999/1117 |
| |
| 1999/1118 | if(debug && t->bp && (t->flags & CancelTD) == 0) dumpdata(t->bp, n); | |
| 1999/1005 | if(!follow || t->link & Terminate || t->link & IsQH) break; t = TFOL(t->link); | |
| 1999/1117/sys/src/9/pc/devusb.c:692,698 – 1999/1118/sys/src/9/pc/devusb.c:691,696 | ||
| 1999/1005 | Ctlr *ub; QH *qh; | |
| 1999/1117 |
| |
| 1999/1005 | if(b != nil){ n = BLEN(b); t = alloctde(e, pid, n); | |
| 1999/1117/sys/src/9/pc/devusb.c:704,717 – 1999/1118/sys/src/9/pc/devusb.c:702,713 | ||
| 1999/1005 | ilock(ub); e->ntd++; iunlock(ub); | |
| 1999/1118 | if(e->debug) pprint("QTD: %8.8lux n=%ld\n", t, b?BLEN(b): 0); | |
| 1999/1005 | vf = 0; if(e->x == 0){ | |
| 1999/1117 |
| |
| 1999/1005 | qh = ub->ctlq; vf = 0; }else if((qh = e->epq) == nil || e->mode != OWRITE){ | |
| 1999/1117 |
| |
| 1999/1005 | qh = ub->bulkq; vf = Vf; } | |
| 1999/1117/sys/src/9/pc/devusb.c:728,734 – 1999/1118/sys/src/9/pc/devusb.c:724,729 | ||
| 1999/1005 | QH *qh; int vf; | |
| 1999/1116 |
| |
| 1999/1005 | t = alloctde(e, TokIN, e->maxpkt); b = allocb(e->maxpkt); t->bp = b; | |
| 1999/1117/sys/src/9/pc/devusb.c:736,745 – 1999/1118/sys/src/9/pc/devusb.c:731,738 | ||
| 1999/1005 | ub = &ubus; vf = 0; if(e->x == 0){ | |
| 1999/1116 |
| |
| 1999/1005 | qh = ub->ctlq; }else if((qh = e->epq) == nil || e->mode != OREAD){ | |
| 1999/1116 |
| |
| 1999/1005 | qh = ub->bulkq; vf = Vf; } | |
| 1999/1117/sys/src/9/pc/devusb.c:1179,1191 – 1999/1118/sys/src/9/pc/devusb.c:1172,1184 | ||
| 1999/1005 | #define DEVPATH(q) (((q)&~CHDIR)>>QSHIFT) static Dirtab usbdir2[] = { | |
| 1999/1118 | "new", {Qnew}, 0, 0666, | |
| 1999/1005 | "ctl", {Qbusctl}, 0, 0666, | |
| 1999/1118 | "port", {Qport}, 0, 0444, | |
| 1999/1005 | }; static Dirtab usbdir3[]={ | |
| 1999/1118 | "ctl", {Qctl}, 0, 0666, | |
| 1999/1005 | "setup", {Qsetup}, 0, 0666, "status", {Qstatus}, 0, 0444, "debug", {Qdebug}, 1, 0666, | |
| 1999/1117/sys/src/9/pc/devusb.c:1276,1282 – 1999/1118/sys/src/9/pc/devusb.c:1269,1275 | ||
| 1999/1006 | return; } | |
| 1999/1118 | DPRINT("USB: %x/%x port 0x%lux size 0x%x irq %d\n", | |
| 1999/1006 | cfg->vid, cfg->did, port, cfg->mem[4].size, cfg->intl); i = inb(port+SOFMod); | |
| 1999/1117/sys/src/9/pc/devusb.c:1314,1323 – 1999/1118/sys/src/9/pc/devusb.c:1307,1312 | ||
| 1999/1117 | ub->bwsop = allocqh(ub); | |
| 1999/1006 | ub->bulkq = allocqh(ub); | |
| 1999/1117 | ub->recvq = allocqh(ub); | |
| 1999/1006 | t = alloctd(ub); /* inactive TD, looped */ t->link = PADDR(t); ub->bwsop->entries = PADDR(t); | |
| 1999/1117/sys/src/9/pc/devusb.c:1325,1333 – 1999/1118/sys/src/9/pc/devusb.c:1314,1322 | ||
| 1999/1117 | ub->bwsop->head = PADDR(ub->bulkq) | IsQH; ub->bulkq->head = PADDR(ub->recvq) | IsQH; ub->recvq->head = PADDR(ub->bwsop) | IsQH; /* loop back */ | |
| 1999/1006 |
| |
| 1999/1118 | XPRINT("usbcmd\t0x%.4x\nusbsts\t0x%.4x\nusbintr\t0x%.4x\nfrnum\t0x%.2x\n", | |
| 1999/1006 | IN(Cmd), IN(Status), IN(Usbintr), inb(port+Frnum)); | |
| 1999/1118 | XPRINT("frbaseadd\t0x%.4x\nsofmod\t0x%x\nportsc1\t0x%.4x\nportsc2\t0x%.4x\n", | |
| 1999/1006 | IN(Flbaseadd), inb(port+SOFMod), IN(Portsc0), IN(Portsc1)); OUT(Cmd, 0); /* stop */ ub->frames = xspanalloc(FRAMESIZE, FRAMESIZE, 0); | |
| 1999/1117/sys/src/9/pc/devusb.c:1339,1351 – 1999/1118/sys/src/9/pc/devusb.c:1328,1340 | ||
| 1999/1006 | } qt->root->head = PADDR(ub->ctlq) | IsQH; ub->tree = qt; | |
| 1999/1118 | XPRINT("usb tree: nel=%d depth=%d\n", qt->nel, qt->depth); | |
| 1999/1006 | outl(port+Flbaseadd, PADDR(ub->frames)); OUT(Frnum, 0); OUT(Usbintr, 0xF); /* enable all interrupts */ | |
| 1999/1118 | XPRINT("cmd 0x%x sofmod 0x%x\n", IN(Cmd), inb(port+SOFMod)); XPRINT("sc0 0x%x sc1 0x%x\n", IN(Portsc0), IN(Portsc1)); | |
| 1999/1005 | } void | |
| 1999/1118/sys/src/9/pc/devusb.c:1836,1846 – 1999/1119/sys/src/9/pc/devusb.c:1836,1846 (short | long) | ||
| 1999/1005 | nf = getfields(cmd, fields, nelem(fields)); if(nf > 1 && strcmp(fields[0], "speed") == 0){ d->ls = strtoul(fields[1], nil, 0) == 0; | |
| 1999/1119 | } else if(nf > 3 && strcmp(fields[0], "class") == 0){ | |
| 1999/1005 | /* class class subclass proto */ | |
| 1999/1119 | d->class = strtoul(fields[1], nil, 0); d->subclass = strtoul(fields[2], nil, 0); d->proto = strtoul(fields[3], nil, 0); | |
| 1999/1005 | }else if(nf > 2 && strcmp(fields[0], "data") == 0){ i = strtoul(fields[1], nil, 0); if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) | |
| 1999/1119/sys/src/9/pc/devusb.c:170,187 – 1999/1120/sys/src/9/pc/devusb.c:170,187 (short | long) | ||
| 1999/1005 | struct Udev { Ref; Lock; | |
| 1999/1120 | int x; /* index in usbdev[] */ int busy; int state; int id; | |
| 1999/1005 | byte port; /* port number on connecting hub */ byte class; byte subclass; byte proto; | |
| 1999/1120 | int ls; int npt; | |
| 1999/1005 | Endpt* ep[16]; /* active end points */ | |
| 1999/1120 | Udev* ports; /* active ports, if hub */ | |
| 1999/1005 | Udev* next; /* next device on this hub */ }; | |
| 1999/1119/sys/src/9/pc/devusb.c:200,210 – 1999/1120/sys/src/9/pc/devusb.c:200,210 | ||
| 1999/1005 | }; static char *devstates[] = { | |
| 1999/1120 | [Disabled] "Disabled", [Attached] "Attached", [Enabled] "Enabled", [Assigned] "Assigned", [Configured] "Configured", | |
| 1999/1005 | }; /* | |
| 1999/1119/sys/src/9/pc/devusb.c:1685,1691 – 1999/1120/sys/src/9/pc/devusb.c:1685,1691 | ||
| 1999/1005 | l = snprint(s, READSTR, "%s %d %d %d\n", devstates[d->state], d->class, d->subclass, d->proto); for(i=0; i<nelem(d->ep); i++) if((e = d->ep[i]) != nil) /* TO DO: freeze e */ | |
| 1999/1120 | l += snprint(s+l, READSTR-l, "%2d class 0x%2.2ux subclass 0x%2.2ux proto 0x%2.2ux bytes %10lud blocks %10lud\n", i, e->class, e->subclass, e->proto, e->nbytes, e->nblocks); | |
| 1999/1005 | n = readstr(offset, a, n, s); poperror(); free(s); | |
| 1999/1119/sys/src/9/pc/devusb.c:1836,1846 – 1999/1120/sys/src/9/pc/devusb.c:1836,1858 | ||
| 1999/1005 | nf = getfields(cmd, fields, nelem(fields)); if(nf > 1 && strcmp(fields[0], "speed") == 0){ d->ls = strtoul(fields[1], nil, 0) == 0; | |
| 1999/1119 |
| |
| 1999/1005 |
| |
| 1999/1119 |
| |
| 1999/1120 | } else if(nf > 5 && strcmp(fields[0], "class") == 0){ i = strtoul(fields[2], nil, 0); d->npt = strtoul(fields[1], nil, 0); /* class config# class subclass proto */ if (i < 0 || i >= nelem(d->ep) || d->npt > nelem(d->ep) || i >= d->npt) error(Ebadarg); if (i == 0) { d->class = strtoul(fields[3], nil, 0); d->subclass = strtoul(fields[4], nil, 0); d->proto = strtoul(fields[5], nil, 0); } if(d->ep[i] == nil) d->ep[i] = devendpt(d, i, 1); d->ep[i]->class = strtoul(fields[3], nil, 0); d->ep[i]->subclass = strtoul(fields[4], nil, 0); d->ep[i]->proto = strtoul(fields[5], nil, 0); | |
| 1999/1005 | }else if(nf > 2 && strcmp(fields[0], "data") == 0){ i = strtoul(fields[1], nil, 0); if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) | |
| 1999/1119/sys/src/9/pc/devusb.c:1879,1887 – 1999/1120/sys/src/9/pc/devusb.c:1891,1898 | ||
| 1999/1007 | XPRINT("field 1: 0 <= %d < %d\n", i, nelem(d->ep)); | |
| 1999/1005 | error(Ebadarg); | |
| 1999/1006 | } | |
| 1999/1005 |
| |
| 1999/1120 | if((e = d->ep[i]) == nil) e = devendpt(d, i, 1); | |
| 1999/1005 | if(waserror()){ freept(e); nexterror(); | |
| 1999/1120/sys/src/9/pc/devusb.c:1280,1286 – 1999/1209/sys/src/9/pc/devusb.c:1280,1291 (short | long) | ||
| 1999/1006 | delay(4); } outb(port+SOFMod, i); | |
| 1999/1209 | /* * Interrupt handler. * Bail out if no IRQ assigned by the BIOS. */ if(cfg->intl == 0xFF) return; | |
| 1999/1006 | intrenable(cfg->intl, interrupt, ub, cfg->tbdf, "usb"); ub->io = port; | |
| 1999/1209/sys/src/9/pc/devusb.c:1389,1394 – 1999/1230/sys/src/9/pc/devusb.c:1389,1398 (short | long) | ||
| 1999/1005 | * Top level directory contains the name of the device. */ if(c->qid.path == CHDIR){ | |
| 1999/1230 | if(s == DEVDOTDOT){ devdir(c, (Qid){CHDIR, 0}, "#U", 0, eve, 0555, dp); return 1; } | |
| 1999/1005 | if(s == 0){ devdir(c, (Qid){CHDIR|Q2nd, 0}, "usb", 0, eve, 0555, dp); return 1; | |
| 1999/1209/sys/src/9/pc/devusb.c:1401,1406 – 1999/1230/sys/src/9/pc/devusb.c:1405,1414 | ||
| 1999/1005 | */ t = QID(c->qid); if(t < Q3rd){ | |
| 1999/1230 | if(s == DEVDOTDOT){ devdir(c, (Qid){CHDIR, 0}, "#U", 0, eve, 0555, dp); return 1; } | |
| 1999/1005 | if(s < nelem(usbdir2)){ tab = &usbdir2[s]; devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp); | |
| 1999/1209/sys/src/9/pc/devusb.c:1423,1428 – 1999/1230/sys/src/9/pc/devusb.c:1431,1440 | ||
| 1999/1005 | */ path = c->qid.path&~(CHDIR|QMASK); /* slot component */ q.vers = c->qid.vers; | |
| 1999/1230 | if(s == DEVDOTDOT){ devdir(c, (Qid){CHDIR|Q2nd, 0}, "usb", 0, eve, 0555, dp); return 1; } | |
| 1999/1005 | if(s < nelem(usbdir3)){ Dirtab *tab = &usbdir3[s]; q.path = path | tab->qid.path; | |
| 1999/1230/sys/src/9/pc/devusb.c:1776,1811 – 2000/0308/sys/src/9/pc/devusb.c:1776,1781 (short | long) | ||
| 1999/1005 | return p-(uchar*)a; } | |
| 1999/1230/sys/src/9/pc/devusb.c:1822,1828 – 2000/0308/sys/src/9/pc/devusb.c:1792,1798 | ||
| 1999/1005 | n = sizeof(cmd)-1; memmove(cmd, a, n); cmd[n] = 0; | |
| 2000/0308 | nf = getfields(cmd, fields, nelem(fields), 0, " \t\n"); | |
| 1999/1005 | if(nf==1 && strcmp(fields[0], "dump")==0){ dumpframe(-1, -1); return n; | |
| 1999/1230/sys/src/9/pc/devusb.c:1850,1856 – 2000/0308/sys/src/9/pc/devusb.c:1820,1826 | ||
| 1999/1005 | n = sizeof(cmd)-1; memmove(cmd, a, n); cmd[n] = 0; | |
| 2000/0308 | nf = getfields(cmd, fields, nelem(fields), 0, " \t\n"); | |
| 1999/1005 | if(nf > 1 && strcmp(fields[0], "speed") == 0){ d->ls = strtoul(fields[1], nil, 0) == 0; | |
| 1999/1120 | } else if(nf > 5 && strcmp(fields[0], "class") == 0){ | |
| 2000/0308/sys/src/9/pc/devusb.c:1284,1290 – 2000/0517/sys/src/9/pc/devusb.c:1284,1290 (short | long) | ||
| 1999/1209 | * Interrupt handler. * Bail out if no IRQ assigned by the BIOS. */ | |
| 2000/0517 | if(cfg->intl == 0xFF || cfg->intl == 0) | |
| 1999/1209 | return; | |
| 1999/1006 | intrenable(cfg->intl, interrupt, ub, cfg->tbdf, "usb"); | |
| 2000/0517/sys/src/9/pc/devusb.c:20,32 – 2000/0719/sys/src/9/pc/devusb.c:20,25 (short | long) | ||
| 1999/1005 | #include "io.h" #include "../port/error.h" | |
| 1999/1116 | #define XPRINT if(debug)print | |
| 2000/0719/sys/src/9/pc/devusb.c:1247,1260 – 2000/0720/sys/src/9/pc/devusb.c:1247,1257 (short | long) | ||
| 1999/1006 | memset(&cfg, 0, sizeof(cfg)); cfg = pcimatch(0, 0x8086, 0x7112); /* Intel chipset PIIX 4*/ if(cfg == nil) { | |
| 2000/0720 | cfg = pcimatch(0, 0x1106, 0x0586); /* Via chipset */ if(cfg == nil) { DPRINT("No USB device found\n"); return; } | |
| 1999/1006 | } port = cfg->mem[4].bar & ~0x0F; if (port == 0) { | |
| 2000/0720/sys/src/9/pc/devusb.c:1689,1698 – 2000/0722/sys/src/9/pc/devusb.c:1689,1698 (short | long) | ||
| 1999/1005 | free(s); nexterror(); } | |
| 2000/0722 | l = snprint(s, READSTR, "%s %d.%d.%d\n", devstates[d->state], d->class, d->subclass, d->proto); | |
| 1999/1005 | for(i=0; i<nelem(d->ep); i++) if((e = d->ep[i]) != nil) /* TO DO: freeze e */ | |
| 1999/1120 |
| |
| 2000/0722 | l += snprint(s+l, READSTR-l, "%2d %ud.%ud.%ud bytes %10lud blocks %10lud\n", i, e->class, e->subclass, e->proto, e->nbytes, e->nblocks); | |
| 1999/1005 | n = readstr(offset, a, n, s); poperror(); free(s); | |
| 2000/0722/sys/src/9/pc/devusb.c:59,64 – 2000/0724/sys/src/9/pc/devusb.c:59,69 (short | long) | ||
| 1999/1005 | typedef struct QH QH; typedef struct TD TD; | |
| 2000/0724 | #define Class(csp) ((csp)&0xff) #define Subclass(csp) (((csp)>>8)&0xff) #define Proto(csp) (((csp)>>16)&0xff) #define CSP(c, s, p) ((c) | ((s)<<8) | ((p)<<16)) | |
| 1999/1005 | struct TD { ulong link; ulong status; /* controller r/w */ | |
| 2000/0722/sys/src/9/pc/devusb.c:168,176 – 2000/0724/sys/src/9/pc/devusb.c:173,179 | ||
| 1999/1120 | int state; int id; | |
| 1999/1005 | byte port; /* port number on connecting hub */ | |
| 2000/0724 | ulong csp; | |
| 1999/1120 | int ls; int npt; | |
| 1999/1005 | Endpt* ep[16]; /* active end points */ | |
| 2000/0722/sys/src/9/pc/devusb.c:211,219 – 2000/0724/sys/src/9/pc/devusb.c:214,220 | ||
| 1999/1116 | int maxpkt; /* maximum packet size (from endpoint descriptor) */ int data01; /* 0=DATA0, 1=DATA1 */ | |
| 1999/1005 | byte eof; | |
| 2000/0724 | ulong csp; | |
| 1999/1005 | byte mode; /* OREAD, OWRITE, ORDWR */ byte nbuf; /* number of buffers allowed */ byte periodic; | |
| 2000/0722/sys/src/9/pc/devusb.c:990,996 – 2000/0724/sys/src/9/pc/devusb.c:991,997 | ||
| 1999/1005 | usbdevreset(Udev *d) { d->state = Disabled; | |
| 2000/0724 | if(Class(d->csp) == Hubclass) | |
| 1999/1005 | for(d = d->ports; d != nil; d = d->next) usbdevreset(d); } | |
| 2000/0722/sys/src/9/pc/devusb.c:1689,1698 – 2000/0724/sys/src/9/pc/devusb.c:1690,1699 | ||
| 1999/1005 | free(s); nexterror(); } | |
| 2000/0722 |
| |
| 2000/0724 | l = snprint(s, READSTR, "%s %#6.6x\n", devstates[d->state], d->csp); | |
| 1999/1005 | for(i=0; i<nelem(d->ep); i++) if((e = d->ep[i]) != nil) /* TO DO: freeze e */ | |
| 2000/0722 |
| |
| 2000/0724 | l += snprint(s+l, READSTR-l, "%2d %#6.6x %10lud bytes %10lud blocks\n", i, e->csp, e->nbytes, e->nblocks); | |
| 1999/1005 | n = readstr(offset, a, n, s); poperror(); free(s); | |
| 2000/0722/sys/src/9/pc/devusb.c:1813,1835 – 2000/0724/sys/src/9/pc/devusb.c:1814,1832 | ||
| 2000/0308 | nf = getfields(cmd, fields, nelem(fields), 0, " \t\n"); | |
| 1999/1005 | if(nf > 1 && strcmp(fields[0], "speed") == 0){ d->ls = strtoul(fields[1], nil, 0) == 0; | |
| 1999/1120 |
| |
| 2000/0724 | } else if(nf > 3 && strcmp(fields[0], "class") == 0){ | |
| 1999/1120 | i = strtoul(fields[2], nil, 0); d->npt = strtoul(fields[1], nil, 0); | |
| 2000/0724 | /* class config# csp ( == class subclass proto) */ | |
| 1999/1120 | if (i < 0 || i >= nelem(d->ep) || d->npt > nelem(d->ep) || i >= d->npt) error(Ebadarg); if (i == 0) { | |
| 2000/0724 | d->csp = strtoul(fields[3], nil, 0); | |
| 1999/1120 | } if(d->ep[i] == nil) d->ep[i] = devendpt(d, i, 1); | |
| 2000/0724 | d->ep[i]->csp = strtoul(fields[3], nil, 0); | |
| 1999/1005 | }else if(nf > 2 && strcmp(fields[0], "data") == 0){ i = strtoul(fields[1], nil, 0); if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) | |
| 2000/0724/sys/src/9/pc/devusb.c:1690,1699 – 2000/0725/sys/src/9/pc/devusb.c:1690,1699 (short | long) | ||
| 1999/1005 | free(s); nexterror(); } | |
| 2000/0724 |
| |
| 2000/0725 | l = snprint(s, READSTR, "%s %#6.6lux\n", devstates[d->state], d->csp); | |
| 1999/1005 | for(i=0; i<nelem(d->ep); i++) if((e = d->ep[i]) != nil) /* TO DO: freeze e */ | |
| 2000/0724 |
| |
| 2000/0725 | l += snprint(s+l, READSTR-l, "%2d %#6.6lux %10lud bytes %10lud blocks\n", i, e->csp, e->nbytes, e->nblocks); | |
| 1999/1005 | n = readstr(offset, a, n, s); poperror(); free(s); | |
| 2000/0724/sys/src/9/pc/devusb.c:1875,1881 – 2000/0725/sys/src/9/pc/devusb.c:1875,1882 | ||
| 1999/1005 | if(i < 8 || i > 1023) i = 8; e->maxpkt = i; | |
| 2000/0725 | e->mode = strcmp(fields[3],"r") == 0? OREAD : strcmp(fields[3],"w") == 0? OWRITE : ORDWR; | |
| 1999/1005 | e->periodic = 0; e->sched = -1; | |
| 1999/1117 | if(strcmp(fields[4], "bulk") == 0){ | |
| 2000/0724/sys/src/9/pc/devusb.c:1930,1939 – 2000/0725/sys/src/9/pc/devusb.c:1931,1943 | ||
| 1999/1005 | break; default: /* sends DATA[01] */ | |
| 2000/0725 | if((t -= Qep0) < 0 || t >= nelem(d->ep)) { print("t = %d\n", t); | |
| 1999/1005 | error(Eio); | |
| 2000/0725 | } if((e = d->ep[t]) == nil || e->mode == OREAD) { | |
| 1999/1005 | error(Eio); /* can't happen */ | |
| 2000/0725 | } | |
| 1999/1005 | n = writeusb(e, a, n, TokOUT); break; } | |
| 2000/0725/sys/src/9/pc/devusb.c:1238,1266 – 2001/0126/sys/src/9/pc/devusb.c:1238,1273 (short | long) | ||
| 1999/1005 | usbreset(void) { | |
| 1999/1006 | Pcidev *cfg; | |
| 2001/0126 | int i, port; | |
| 1999/1006 | QTree *qt; TD *t; | |
| 1999/1117 | Ctlr *ub; | |
| 1999/1006 | ub = &ubus; | |
| 2000/0720 |
| |
| 2001/0126 | for(cfg = pcimatch(nil, 0, 0); cfg != nil; cfg = pcimatch(cfg, 0, 0)){ /* * Look for devices with the correct class and * sub-class code and known device and vendor ID. */ if(cfg->ccrb != 0x0C || cfg->ccru != 0x03) continue; switch((cfg->did<<16)|cfg->vid){ default: continue; case (0x7112<<16)|0x8086: /* 82371[AE]B (PIIX4[E]) */ case (0x719A<<16)|0x8086: /* 82443MX */ case (0x1106<<16)|0x0586: /* VIA 82C586 */ break; | |
| 2000/0720 | } | |
| 2001/0126 | if((cfg->mem[4].bar & ~0x0F) != 0) break; | |
| 1999/1006 | } | |
| 2001/0126 | if(cfg == nil) | |
| 1999/1006 | return; | |
| 1999/1118 |
| |
| 2001/0126 | port = cfg->mem[4].bar & ~0x0F; DPRINT("USB: %x/%x port 0x%ux size 0x%x irq %d\n", | |
| 1999/1006 | cfg->vid, cfg->did, port, cfg->mem[4].size, cfg->intl); i = inb(port+SOFMod); | |
| 2001/0126/sys/src/9/pc/devusb.c:791,796 – 2001/0131/sys/src/9/pc/devusb.c:791,797 (short | long) | ||
| 1999/1005 | return nil; } qt->root = tree; | |
| 2001/0131 | print("tree root %8.8lux\n", tree); | |
| 1999/1005 | tree->head = Terminate; /* root */ tree->entries = Terminate; for(i=1; i<n; i++){ | |
| 2001/0126/sys/src/9/pc/devusb.c:798,803 – 2001/0131/sys/src/9/pc/devusb.c:799,805 | ||
| 1999/1005 | qh->head = PADDR(&tree[(i-1)/2]) | IsQH; qh->entries = Terminate; } | |
| 2001/0131 | print("after loop tree root %8.8lux head %8.8lux entries %8.8lux\n", tree, tree->head, tree->entries); | |
| 1999/1005 | /* distribute leaves evenly round the frame list */ leaf0 = n/2; for(i=0; i<framesize; i++){ | |
| 2001/0126/sys/src/9/pc/devusb.c:831,844 – 2001/0131/sys/src/9/pc/devusb.c:833,846 | ||
| 1999/1005 | if(t < 0) t = 32; for(i=f; i<t; i++){ | |
| 1999/1007 |
| |
| 2001/0131 | pprint("F%.2d %8.8lux %8.8lux\n", i, frame[i], QFOL(frame[i])->head); | |
| 1999/1005 | for(p=frame[i]; (p & IsQH) && (p &Terminate) == 0; p = q->head){ q = QFOL(p); if(!(q >= tree && q < &tree[n])){ | |
| 1999/1007 |
| |
| 2001/0131 | pprint("Q: p=%8.8lux out of range\n", p); | |
| 1999/1005 | break; } | |
| 1999/1007 |
| |
| 2001/0131 | pprint(" -> %8.8lux h=%8.8lux e=%8.8lux\n", p, q->head, q->entries); | |
| 1999/1005 | } } } | |
| 2001/0126/sys/src/9/pc/devusb.c:1310,1315 – 2001/0131/sys/src/9/pc/devusb.c:1312,1318 | ||
| 1999/1117 | ub->bwsop = allocqh(ub); | |
| 1999/1006 | ub->bulkq = allocqh(ub); | |
| 1999/1117 | ub->recvq = allocqh(ub); | |
| 2001/0131 | if(0){ /* DISABLE ERRATA FOR NOW */ | |
| 1999/1006 | t = alloctd(ub); /* inactive TD, looped */ t->link = PADDR(t); ub->bwsop->entries = PADDR(t); | |
| 2001/0126/sys/src/9/pc/devusb.c:1317,1322 – 2001/0131/sys/src/9/pc/devusb.c:1320,1326 | ||
| 1999/1117 | ub->bwsop->head = PADDR(ub->bulkq) | IsQH; ub->bulkq->head = PADDR(ub->recvq) | IsQH; ub->recvq->head = PADDR(ub->bwsop) | IsQH; /* loop back */ | |
| 2001/0131 | } | |
| 1999/1118 | XPRINT("usbcmd\t0x%.4x\nusbsts\t0x%.4x\nusbintr\t0x%.4x\nfrnum\t0x%.2x\n", | |
| 1999/1006 | IN(Cmd), IN(Status), IN(Usbintr), inb(port+Frnum)); | |
| 1999/1118 | XPRINT("frbaseadd\t0x%.4x\nsofmod\t0x%x\nportsc1\t0x%.4x\nportsc2\t0x%.4x\n", | |
| 2001/0131/sys/src/9/pc/devusb.c:1312,1318 – 2001/0201/sys/src/9/pc/devusb.c:1312,1318 (short | long) | ||
| 1999/1117 | ub->bwsop = allocqh(ub); | |
| 1999/1006 | ub->bulkq = allocqh(ub); | |
| 1999/1117 | ub->recvq = allocqh(ub); | |
| 2001/0131 |
| |
| 2001/0201 | if(0){ | |
| 1999/1006 | t = alloctd(ub); /* inactive TD, looped */ t->link = PADDR(t); ub->bwsop->entries = PADDR(t); | |
| 2001/0201/sys/src/9/pc/devusb.c:791,797 – 2001/0216/sys/src/9/pc/devusb.c:791,796 (short | long) | ||
| 1999/1005 | return nil; } qt->root = tree; | |
| 2001/0131 |
| |
| 1999/1005 | tree->head = Terminate; /* root */ tree->entries = Terminate; for(i=1; i<n; i++){ | |
| 2001/0201/sys/src/9/pc/devusb.c:799,805 – 2001/0216/sys/src/9/pc/devusb.c:798,803 | ||
| 1999/1005 | qh->head = PADDR(&tree[(i-1)/2]) | IsQH; qh->entries = Terminate; } | |
| 2001/0131 |
| |
| 1999/1005 | /* distribute leaves evenly round the frame list */ leaf0 = n/2; for(i=0; i<framesize; i++){ | |
| 2001/0216/sys/src/9/pc/devusb.c:1197,1203 – 2001/0503/sys/src/9/pc/devusb.c:1197,1203 (short | long) | ||
| 1999/1005 | d = usbdeviceofpath(c->qid.path); if(d == nil || d->id != c->qid.vers || d->state == Disabled) | |
| 2001/0503 | return nil; | |
| 1999/1005 | return d; } | |
| 2001/0216/sys/src/9/pc/devusb.c:1515,1520 – 2001/0503/sys/src/9/pc/devusb.c:1515,1522 | ||
| 1999/1005 | switch(QID(c->qid)){ case Qctl: d = usbdevice(c); | |
| 2001/0503 | if (d == nil) error(Ehungup); | |
| 1999/1005 | if(0&&d->busy) error(Einuse); d->busy = 1; | |
| 2001/0216/sys/src/9/pc/devusb.c:1524,1529 – 2001/0503/sys/src/9/pc/devusb.c:1526,1533 | ||
| 1999/1005 | default: d = usbdevice(c); | |
| 2001/0503 | if (d == nil) error(Ehungup); | |
| 1999/1005 | s = QID(c->qid) - Qep0; if(s >= 0 && s < nelem(d->ep)){ Endpt *e; | |
| 2001/0216/sys/src/9/pc/devusb.c:1572,1587 – 2001/0503/sys/src/9/pc/devusb.c:1576,1588 | ||
| 1999/1005 | if(c->qid.path & CHDIR || c->qid.path < Q3rd) return; qlock(&usbstate); | |
| 2001/0503 | d = usbdeviceofpath(c->qid.path); if (d && d->id == c->qid.vers) { if(QID(c->qid) == Qctl) d->busy = 0; if(c->flag & COPEN) freedev(d); | |
| 1999/1005 | } | |
| 2001/0216/sys/src/9/pc/devusb.c:1672,1682 – 2001/0503/sys/src/9/pc/devusb.c:1673,1687 | ||
| 1999/1005 | case Qctl: d = usbdevice(c); | |
| 2001/0503 | if (d == nil) error(Ehungup); | |
| 1999/1005 | sprint(buf, "%11d %11d ", d->x, d->id); return readstr(offset, a, n, buf); case Qsetup: /* endpoint 0 */ d = usbdevice(c); | |
| 2001/0503 | if (d == nil) error(Ehungup); | |
| 1999/1005 | if((e = d->ep[0]) == nil) error(Eio); /* can't happen */ e->data01 = 1; | |
| 2001/0216/sys/src/9/pc/devusb.c:1694,1699 – 2001/0503/sys/src/9/pc/devusb.c:1699,1706 | ||
| 1999/1005 | case Qstatus: d = usbdevice(c); | |
| 2001/0503 | if (d == nil) error(Ehungup); | |
| 1999/1005 | s = smalloc(READSTR); if(waserror()){ free(s); | |
| 2001/0216/sys/src/9/pc/devusb.c:1710,1715 – 2001/0503/sys/src/9/pc/devusb.c:1717,1724 | ||
| 1999/1005 | default: d = usbdevice(c); | |
| 2001/0503 | if (d == nil) error(Ehungup); | |
| 1999/1005 | if((t -= Qep0) < 0 || t >= nelem(d->ep)) error(Eio); if((e = d->ep[t]) == nil || e->mode == OWRITE) | |
| 2001/0216/sys/src/9/pc/devusb.c:1813,1818 – 2001/0503/sys/src/9/pc/devusb.c:1822,1829 | ||
| 1999/1005 | return n; } d = usbdevice(c); | |
| 2001/0503 | if (d == nil) error(Ehungup); | |
| 1999/1005 | t = QID(c->qid); switch(t){ case Qctl: | |
| 2001/0503/sys/src/9/pc/devusb.c:718,725 – 2001/0504/sys/src/9/pc/devusb.c:718,725 (short | long) | ||
| 1999/1005 | QH *qh; int vf; | |
| 2001/0504 | t = alloctde(e, TokIN, e->maxpkt); | |
| 1999/1005 | t->bp = b; t->buffer = PADDR(b->wp); ub = &ubus; | |
| 2001/0503/sys/src/9/pc/devusb.c:732,752 – 2001/0504/sys/src/9/pc/devusb.c:732,737 | ||
| 1999/1005 | } queuetd(ub, qh, t, vf); return qh; | |
| 2001/0504/sys/src/9/pc/devusb.c:718,725 – 2001/0527/sys/src/9/pc/devusb.c:718,725 (short | long) | ||
| 1999/1005 | QH *qh; int vf; | |
| 2001/0504 | t = alloctde(e, TokIN, e->maxpkt); | |
| 2001/0527 | b = allocb(e->maxpkt); | |
| 1999/1005 | t->bp = b; t->buffer = PADDR(b->wp); ub = &ubus; | |
| 2001/0504/sys/src/9/pc/devusb.c:734,739 – 2001/0527/sys/src/9/pc/devusb.c:734,754 | ||
| 1999/1005 | return qh; } | |
| 2001/0527 | static Block * usbreq(int type, int req, int value, int offset, int count) { Block *b; b = allocb(8); b->wp[0] = type; b->wp[1] = req; PUT2(b->wp+2, value); PUT2(b->wp+4, offset); PUT2(b->wp+6, count); b->wp += 8; return b; } | |
| 1999/1005 | /* * return smallest power of 2 >= n */ | |
| 2001/0504/sys/src/9/pc/devusb.c:816,829 – 2001/0527/sys/src/9/pc/devusb.c:831,844 | ||
| 1999/1005 | if(t < 0) t = 32; for(i=f; i<t; i++){ | |
| 2001/0131 |
| |
| 2001/0527 | XPRINT("F%.2d %8.8lux %8.8lux\n", i, frame[i], QFOL(frame[i])->head); | |
| 1999/1005 | for(p=frame[i]; (p & IsQH) && (p &Terminate) == 0; p = q->head){ q = QFOL(p); if(!(q >= tree && q < &tree[n])){ | |
| 2001/0131 |
| |
| 2001/0527 | XPRINT("Q: p=%8.8lux out of range\n", p); | |
| 1999/1005 | break; } | |
| 2001/0131 |
| |
| 2001/0527 | XPRINT(" -> %8.8lux h=%8.8lux e=%8.8lux\n", p, q->head, q->entries); | |
| 1999/1005 | } } } | |
| 2001/0504/sys/src/9/pc/devusb.c:1182,1188 – 2001/0527/sys/src/9/pc/devusb.c:1197,1203 | ||
| 1999/1005 | d = usbdeviceofpath(c->qid.path); if(d == nil || d->id != c->qid.vers || d->state == Disabled) | |
| 2001/0503 |
| |
| 2001/0527 | error(Ehungup); | |
| 1999/1005 | return d; } | |
| 2001/0504/sys/src/9/pc/devusb.c:1223,1258 – 2001/0527/sys/src/9/pc/devusb.c:1238,1266 | ||
| 1999/1005 | usbreset(void) { | |
| 1999/1006 | Pcidev *cfg; | |
| 2001/0126 |
| |
| 2001/0527 | int i; ulong port; | |
| 1999/1006 | QTree *qt; TD *t; | |
| 1999/1117 | Ctlr *ub; | |
| 1999/1006 | ub = &ubus; | |
| 2001/0126 |
| |
| 2001/0527 | memset(&cfg, 0, sizeof(cfg)); cfg = pcimatch(0, 0x8086, 0x7112); /* Intel chipset PIIX 4*/ if(cfg == nil) { cfg = pcimatch(0, 0x1106, 0x0586); /* Via chipset */ if(cfg == nil) { DPRINT("No USB device found\n"); return; | |
| 2000/0720 | } | |
| 2001/0126 |
| |
| 1999/1006 | } | |
| 2001/0126 |
| |
| 2001/0527 | port = cfg->mem[4].bar & ~0x0F; if (port == 0) { print("usb: failed to map registers\n"); | |
| 1999/1006 | return; | |
| 2001/0527 | } | |
| 1999/1006 | ||
| 2001/0126 |
| |
| 2001/0527 | DPRINT("USB: %x/%x port 0x%lux size 0x%x irq %d\n", | |
| 1999/1006 | cfg->vid, cfg->did, port, cfg->mem[4].size, cfg->intl); i = inb(port+SOFMod); | |
| 2001/0504/sys/src/9/pc/devusb.c:1295,1301 – 2001/0527/sys/src/9/pc/devusb.c:1303,1308 | ||
| 1999/1117 | ub->bwsop = allocqh(ub); | |
| 1999/1006 | ub->bulkq = allocqh(ub); | |
| 1999/1117 | ub->recvq = allocqh(ub); | |
| 2001/0201 |
| |
| 1999/1006 | t = alloctd(ub); /* inactive TD, looped */ t->link = PADDR(t); ub->bwsop->entries = PADDR(t); | |
| 2001/0504/sys/src/9/pc/devusb.c:1303,1309 – 2001/0527/sys/src/9/pc/devusb.c:1310,1315 | ||
| 1999/1117 | ub->bwsop->head = PADDR(ub->bulkq) | IsQH; ub->bulkq->head = PADDR(ub->recvq) | IsQH; ub->recvq->head = PADDR(ub->bwsop) | IsQH; /* loop back */ | |
| 2001/0131 |
| |
| 1999/1118 | XPRINT("usbcmd\t0x%.4x\nusbsts\t0x%.4x\nusbintr\t0x%.4x\nfrnum\t0x%.2x\n", | |
| 1999/1006 | IN(Cmd), IN(Status), IN(Usbintr), inb(port+Frnum)); | |
| 1999/1118 | XPRINT("frbaseadd\t0x%.4x\nsofmod\t0x%x\nportsc1\t0x%.4x\nportsc2\t0x%.4x\n", | |
| 2001/0504/sys/src/9/pc/devusb.c:1500,1507 – 2001/0527/sys/src/9/pc/devusb.c:1506,1511 | ||
| 1999/1005 | switch(QID(c->qid)){ case Qctl: d = usbdevice(c); | |
| 2001/0503 |
| |
| 1999/1005 | if(0&&d->busy) error(Einuse); d->busy = 1; | |
| 2001/0504/sys/src/9/pc/devusb.c:1511,1518 – 2001/0527/sys/src/9/pc/devusb.c:1515,1520 | ||
| 1999/1005 | default: d = usbdevice(c); | |
| 2001/0503 |
| |
| 1999/1005 | s = QID(c->qid) - Qep0; if(s >= 0 && s < nelem(d->ep)){ Endpt *e; | |
| 2001/0504/sys/src/9/pc/devusb.c:1561,1573 – 2001/0527/sys/src/9/pc/devusb.c:1563,1578 | ||
| 1999/1005 | if(c->qid.path & CHDIR || c->qid.path < Q3rd) return; qlock(&usbstate); | |
| 2001/0503 |
| |
| 2001/0527 | if(waserror()){ qunlock(&usbstate); nexterror(); | |
| 1999/1005 | } | |
| 2001/0527 | d = usbdevice(c); if(QID(c->qid) == Qctl) d->busy = 0; if(c->flag & COPEN) freedev(d); poperror(); | |
| 1999/1005 | qunlock(&usbstate); } | |
| 2001/0504/sys/src/9/pc/devusb.c:1658,1672 – 2001/0527/sys/src/9/pc/devusb.c:1663,1673 | ||
| 1999/1005 | case Qctl: d = usbdevice(c); | |
| 2001/0503 |
| |
| 1999/1005 | sprint(buf, "%11d %11d ", d->x, d->id); return readstr(offset, a, n, buf); case Qsetup: /* endpoint 0 */ d = usbdevice(c); | |
| 2001/0503 |
| |
| 1999/1005 | if((e = d->ep[0]) == nil) error(Eio); /* can't happen */ e->data01 = 1; | |
| 2001/0504/sys/src/9/pc/devusb.c:1684,1691 – 2001/0527/sys/src/9/pc/devusb.c:1685,1690 | ||
| 1999/1005 | case Qstatus: d = usbdevice(c); | |
| 2001/0503 |
| |
| 1999/1005 | s = smalloc(READSTR); if(waserror()){ free(s); | |
| 2001/0504/sys/src/9/pc/devusb.c:1702,1709 – 2001/0527/sys/src/9/pc/devusb.c:1701,1706 | ||
| 1999/1005 | default: d = usbdevice(c); | |
| 2001/0503 |
| |
| 1999/1005 | if((t -= Qep0) < 0 || t >= nelem(d->ep)) error(Eio); if((e = d->ep[t]) == nil || e->mode == OWRITE) | |
| 2001/0504/sys/src/9/pc/devusb.c:1807,1814 – 2001/0527/sys/src/9/pc/devusb.c:1804,1809 | ||
| 1999/1005 | return n; } d = usbdevice(c); | |
| 2001/0503 |
| |
| 1999/1005 | t = QID(c->qid); switch(t){ case Qctl: | |
| 2001/0527/sys/src/9/pc/devusb.c:879,1966 – 2001/0624/sys/src/9/pc/devusb.c:879,882 (short | long) | ||
| 1999/1005 | QH *qh; int q; | |
| 1999/1117 |
| |
| 1999/1005 |
| |
| 1999/1117 |
| |
| 1999/1005 | ||
| 1999/1117 |
| |
| 1999/1005 |
| |
| 1999/1116 |
| |
| 1999/1005 |
| |
| 2000/0724 |
| |
| 1999/1005 |
| |
| 1999/1117 |
| |
| 1999/1005 |
| |
| 1999/1116 |
| |
| 1999/1005 |
| |
| 1999/1007 |
| |
| 1999/1005 |
| |
| 1999/1116 |
| |
| 1999/1117 |
| |
| 1999/1005 |
| |
| 1999/1116 |
| |
| 1999/1005 |
| |
| 1999/1118 |
| |
| 1999/1005 |
| |
| 1999/1118 |
| |
| 1999/1005 |
| |
| 1999/1118 |
| |
| 1999/1005 |
| |
| 2001/0527 |
| |
| 1999/1005 |
| |
| 1999/1006 |
| |
| 2001/0527 |
| |
| 1999/1006 |
| |
| 1999/1117 |
| |
| 1999/1006 |
| |
| 2001/0527 |
| |
| 2000/0720 |
| |
| 1999/1006 |
| |
| 2001/0527 |
| |
| 1999/1006 |
| |
| 2001/0527 |
| |
| 1999/1006 | ||
| 2001/0527 |
| |
| 1999/1006 |
| |
| 1999/1209 |
| |
| 2000/0517 |
| |
| 1999/1209 |
| |
| 1999/1006 |
| |
| 1999/1117 |
| |
| 1999/1006 |
| |
| 1999/1117 |
| |
| 1999/1006 |
| |
| 1999/1117 |
| |
| 1999/1118 |
| |
| 1999/1006 |
| |
| 1999/1118 |
| |
| 1999/1006 |
| |
| 1999/1118 |
| |
| 1999/1006 |
| |
| 1999/1118 |
| |
| 1999/1005 |
| |
| 1999/1230 |
| |
| 1999/1005 |
| |
| 1999/1230 |
| |
| 1999/1005 |
| |
| 1999/1230 |
| |
| 1999/1005 |
| |
| 2001/0527 |
| |
| 1999/1005 |
| |
| 2001/0527 |
| |
| 1999/1005 |
| |
| 1999/1116 |
| |
| 1999/1005 |
| |
| 1999/1116 |
| |
| 1999/1005 |
| |
| 1999/1007 |
| |
| 1999/1005 |
| |
| 1999/1007 |
| |
| 1999/1005 |
| |
| 2000/0725 |
| |
| 1999/1005 |
| |
| 2000/0725 |
| |
| 1999/1005 |
| |
| 2000/0308 |
| |
| 1999/1005 |
| |
| 2000/0308 |
| |
| 1999/1005 |
| |
| 2000/0724 |
| |
| 1999/1120 |
| |
| 2000/0724 |
| |
| 1999/1120 |
| |
| 2000/0724 |
| |
| 1999/1120 |
| |
| 2000/0724 |
| |
| 1999/1005 |
| |
| 1999/1116 |
| |
| 1999/1005 |
| |
| 1999/1116 |
| |
| 1999/1005 |
| |
| 1999/1006 |
| |
| 1999/1007 |
| |
| 1999/1005 |
| |
| 1999/1006 |
| |
| 1999/1120 |
| |
| 1999/1005 |
| |
| 2000/0725 |
| |
| 1999/1005 |
| |
| 1999/1117 |
| |
| 1999/1005 |
| |
| 1999/1006 |
| |
| 1999/1007 |
| |
| 1999/1005 |
| |
| 1999/1006 |
| |
| 1999/1005 |
| |
| 1999/1006 |
| |
| 1999/1007 |
| |
| 1999/1005 |
| |
| 1999/1006 |
| |
| 1999/1005 |
| |
| 2000/0725 |
| |
| 1999/1005 |
| |
| 2000/0725 |
| |
| 1999/1005 |
| |
| 2000/0725 |
| |
| 1999/1005 |
| |
| 2001/0624 | if(!e->periodic || e->sched | |
| 2001/0624/sys/src/9/pc/devusb.c:197,205 – 2001/0626/sys/src/9/pc/devusb.c:197,205 (short | long) | ||
| 1999/1005 | static char *devstates[] = { | |
| 1999/1120 | [Disabled] "Disabled", | |
| 2001/0626 | [Attached] "Attached", | |
| 1999/1120 | [Enabled] "Enabled", | |
| 2001/0626 | [Assigned] "Assigned", | |
| 1999/1120 | [Configured] "Configured", | |
| 1999/1005 | }; | |
| 2001/0624/sys/src/9/pc/devusb.c:213,226 – 2001/0626/sys/src/9/pc/devusb.c:213,226 | ||
| 1999/1116 | int id; /* hardware endpoint address */ int maxpkt; /* maximum packet size (from endpoint descriptor) */ int data01; /* 0=DATA0, 1=DATA1 */ | |
| 1999/1005 |
| |
| 2001/0626 | byte eof; | |
| 2000/0724 | ulong csp; | |
| 1999/1005 |
| |
| 2001/0626 | byte mode; /* OREAD, OWRITE, ORDWR */ byte nbuf; /* number of buffers allowed */ byte periodic; byte iso; byte debug; byte active; /* listed for examination by interrupts */ | |
| 1999/1116 | int sched; /* schedule index; -1 if undefined or aperiodic */ int setin; | |
| 1999/1005 | ulong bw; /* bandwidth requirement */ | |
| 2001/0624/sys/src/9/pc/devusb.c:369,375 – 2001/0626/sys/src/9/pc/devusb.c:369,376 | ||
| 1999/1117 | XPRINT("td %8.8lux: ", t); XPRINT("l=%8.8lux s=%8.8lux d=%8.8lux b=%8.8lux %8.8lux f=%8.8lux\n", t->link, t->status, t->dev, t->buffer, t->bp?(ulong)t->bp->rp:0, t->flags); | |
| 1999/1007 |
| |
| 2001/0626 | XPRINT("\ts=%s,ep=%ld,d=%ld,D=%ld\n", buf, (t->dev>>15)&0xF, (t->dev>>8)&0xFF, (t->dev>>19)&1); | |
| 1999/1118 | if(debug && t->bp && (t->flags & CancelTD) == 0) dumpdata(t->bp, n); | |
| 1999/1005 | if(!follow || t->link & Terminate || t->link & IsQH) | |
| 2001/0624/sys/src/9/pc/devusb.c:479,485 – 2001/0626/sys/src/9/pc/devusb.c:480,487 | ||
| 1999/1005 | Block *b; int n, err; | |
| 2001/0626 | XPRINT("cleanTD: %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer); | |
| 1999/1005 | if(t->ep != nil && t->ep->debug) dumptd(t, 0); if(t->status & Active) | |
| 2001/0624/sys/src/9/pc/devusb.c:487,493 – 2001/0626/sys/src/9/pc/devusb.c:489,496 | ||
| 1999/1005 | err = t->status & (AnyError&~NAKed); /* TO DO: on t->status&AnyError, q->entries will not have advanced */ if (err) | |
| 1999/1007 |
| |
| 2001/0626 | XPRINT("cleanTD: Error %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer); | |
| 1999/1005 | switch(t->dev&0xFF){ case TokIN: if(discard || (t->flags & CancelTD) || t->ep == nil || t->ep->x!=0&&err){ | |
| 2001/0624/sys/src/9/pc/devusb.c:550,556 – 2001/0626/sys/src/9/pc/devusb.c:553,560 | ||
| 1999/1005 | ilock(ub); | |
| 1999/1116 | tp = nil; | |
| 1999/1005 | for(t = q->first; t != nil;){ | |
| 1999/1116 |
| |
| 2001/0626 | XPRINT("cleanq: %8.8lux %8.8lux %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer, t->flags, t->next); | |
| 1999/1005 | if(t->status & Active){ | |
| 1999/1116 | if(t->status & NAKed){ t->status = (t->status & ~NAKed) | IOC; /* ensure interrupt next frame */ | |
| 2001/0624/sys/src/9/pc/devusb.c:565,573 – 2001/0626/sys/src/9/pc/devusb.c:569,577 | ||
| 1999/1005 | t = t->next; continue; } | |
| 1999/1116 |
| |
| 2001/0626 | tp = t; t = t->next; continue; | |
| 1999/1005 | break; } t->status &= ~IOC; | |
| 2001/0624/sys/src/9/pc/devusb.c:879,882 – 2001/0626/sys/src/9/pc/devusb.c:883,1964 | ||
| 1999/1005 | QH *qh; int q; | |
| 2001/0624 |
| |
| 2001/0626 | if(!e->periodic || e->sched >= 0) return 0; ub = &ubus; if(e->epq == nil){ e->epq = allocqh(ub); if(e->epq == nil) return -1; } qlock(ub->tree); q = pickschedq(ub->tree, e->pollms, e->bw, ~0); /* TO DO: bus bandwidth limit */ if(q < 0) return -1; ub->tree->bw[q] += e->bw; qh = &ub->tree->root[q]; e->sched = q; e->epq->head = qh->entries; e->epq->entries = Terminate; qh->entries = PADDR(e->epq) | IsQH; qunlock(ub->tree); return 0; } static void unschedendpt(Endpt *e) { Ctlr *ub; ulong p; QH *qh; int q; ub = &ubus; if(!e->periodic || (q = e->sched) < 0) return; p = PADDR(e->epq) | IsQH; qlock(ub->tree); ub->tree->bw[q] -= e->bw; qh = &ub->tree->root[q]; for(; qh->entries != p; qh = QFOL(qh->entries)) if(qh->entries & Terminate || (qh->entries & IsQH) == 0){ qunlock(ub->tree); panic("usb: unschedendpt"); } qh->entries = e->epq->head; qunlock(ub->tree); e->epq->head = Terminate; } static Endpt * devendpt(Udev *d, int id, int add) { Endpt *e, **p; Ctlr *ub; ub = &ubus; p = &d->ep[id&0xF]; lock(d); if((e = *p) != nil){ incref(e); unlock(d); return e; } unlock(d); if(!add) return nil; e = mallocz(sizeof(*e), 1); e->ref = 1; e->x = id&0xF; e->id = id; e->periodic = 0; e->sched = -1; e->maxpkt = 8; e->pollms = 0; e->bw = 0; e->nbuf = 1; e->dev = d; e->active = 0; e->epq = allocqh(ub); if(e->epq == nil) panic("devendpt"); lock(d); if(*p != nil){ incref(*p); unlock(d); free(e); return *p; } *p = e; unlock(d); e->rq = qopen(8*1024, 0, nil, e); e->wq = qopen(8*1024, 0, nil, e); return e; } static void freept(Endpt *e) { if(e != nil && decref(e) == 0){ XPRINT("freept(%d,%d)\n", e->dev->x, e->x); unschedendpt(e); e->dev->ep[e->x] = nil; eptdeactivate(e); if(e->epq != nil) freeqh(&ubus, e->epq); free(e); } } static void usbdevreset(Udev *d) { d->state = Disabled; if(Class(d->csp) == Hubclass) for(d = d->ports; d != nil; d = d->next) usbdevreset(d); } static void freedev(Udev *d) { int i; if(d != nil && decref(d) == 0){ for(i=0; i<nelem(d->ep); i++) freept(d->ep[i]); if(d->x >= 0) usbdev[d->x] = nil; free(d); } } static void hubportreset(Udev *h, int p) { USED(h, p); /* reset state of each attached device? */ } static int ioports[] = {-1, Portsc0, Portsc1}; static void portreset(int port) { Ctlr *ub; int i, p; /* should check that device not being configured on other port? */ p = ioports[port]; ub = &ubus; qlock(&ub->resetl); if(waserror()){ qunlock(&ub->resetl); nexterror(); } XPRINT("r: %x\n", IN(p)); ilock(ub); 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(ub); hubportreset(nil, port); poperror(); qunlock(&ub->resetl); } static void portenable(int port, int on) { Ctlr *ub; int w, p; /* should check that device not being configured on other port? */ p = ioports[port]; ub = &ubus; qlock(&ub->resetl); if(waserror()){ qunlock(&ub->resetl); nexterror(); } ilock(ub); w = IN(p); if(on) w |= PortEnable; else w &= ~PortEnable; OUT(p, w); microdelay(64); iunlock(ub); XPRINT("e: %x\n", IN(p)); if(!on) hubportreset(nil, port); poperror(); qunlock(&ub->resetl); } static int portinfo(Ctlr *ub, int *p0, int *p1) { int m, v; ilock(ub); m = 0; if((v = IN(Portsc0)) & PortChange){ OUT(Portsc0, v); m |= 1<<0; } *p0 = v; if((v = IN(Portsc1)) & PortChange){ OUT(Portsc1, v); m |= 1<<1; } *p1 = v; iunlock(ub); return m; } static void interrupt(Ureg*, void *a) { Ctlr *ub; Endpt *e; int s; QH *q; ub = a; s = IN(Status); OUT(Status, s); if ((s & 0x1f) == 0) return; XPRINT("usbint: #%x f%d\n", s, IN(Frnum)); if (s & 0x1a) { XPRINT("cmd #%x sofmod #%x\n", IN(Cmd), inb(ub->io+SOFMod)); XPRINT("sc0 #%x sc1 #%x\n", IN(Portsc0), IN(Portsc1)); } XPRINT("cleanq(ub->ctlq, 0, 0)\n"); cleanq(ub->ctlq, 0, 0); XPRINT("cleanq(ub->bulkq, 0, Vf)\n"); cleanq(ub->bulkq, 0, Vf); XPRINT("clean recvq\n"); for (q = ub->recvq->next; q; q = q->hlink) { XPRINT("cleanq(q, 0, Vf)\n"); cleanq(q, 0, Vf); } ilock(&activends); for(e = activends.f; e != nil; e = e->activef) if(e->epq != nil) { XPRINT("cleanq(e->epq, 0, 0)\n"); cleanq(e->epq, 0, 0); } iunlock(&activends); } enum { Qtopdir = 0, Q2nd, Qbusctl, Qnew, Qport, Q3rd, Qctl, Qsetup, Qdebug, Qstatus, Qep0, /* other endpoint files */ }; /* * Qid path is: * 8 bits of file type (qids above) * 10 bits of slot number +1; 0 means not attached to device */ #define QSHIFT 8 /* location in qid of device # */ #define QMASK ((1<<QSHIFT)-1) #define QID(q) ((ulong)(q).path&QMASK) #define DEVPATH(p) ((p)>>QSHIFT) static Dirtab usbdir2[] = { "new", {Qnew}, 0, 0666, "ctl", {Qbusctl}, 0, 0666, "port", {Qport}, 0, 0444, }; static Dirtab usbdir3[]={ "ctl", {Qctl}, 0, 0666, "setup", {Qsetup}, 0, 0666, "status", {Qstatus}, 0, 0444, "debug", {Qdebug}, 0, 0666, /* epNdata names are generated on demand */ }; static Udev * usbdeviceofpath(ulong path) { int s; s = DEVPATH(path); if(s == 0) return nil; return usbdev[s-1]; } static Udev * usbdevice(Chan *c) { Udev *d; d = usbdeviceofpath(c->qid.path); if(d == nil || d->id != c->qid.vers || d->state == Disabled) error(Ehungup); return d; } static Udev * usbnewdevice(void) { Udev *d; Endpt *e; int i; d = nil; qlock(&usbstate); if(waserror()){ qunlock(&usbstate); nexterror(); } for(i=0; i<nelem(usbdev); i++) if(usbdev[i] == nil){ ubus.idgen++; d = mallocz(sizeof(*d), 1); d->ref = 1; d->x = i; d->id = (ubus.idgen << 8) | i; d->state = Enabled; e = devendpt(d, 0, 1); /* always provide control endpoint 0 */ e->mode = ORDWR; e->periodic = 0; e->sched = -1; usbdev[i] = d; break; } poperror(); qunlock(&usbstate); return d; } static void usbreset(void) { Pcidev *cfg; int i; ulong port; QTree *qt; TD *t; Ctlr *ub; ISAConf isa; if(isaconfig("usb", 0, &isa) == 0) { XPRINT("usb not in plan9.ini\n"); // return; } ub = &ubus; memset(&cfg, 0, sizeof(cfg)); cfg = pcimatch(0, 0x8086, 0x7112); /* Intel chipset PIIX 4*/ if(cfg == nil) { cfg = pcimatch(0, 0x1106, 0x0586); /* Via chipset */ if(cfg == nil) { DPRINT("No USB device found\n"); return; } } port = cfg->mem[4].bar & ~0x0F; if (port == 0) { print("usb: failed to map registers\n"); return; } DPRINT("USB: %x/%x port 0x%lux size 0x%x irq %d\n", cfg->vid, cfg->did, port, cfg->mem[4].size, cfg->intl); i = inb(port+SOFMod); if(1){ OUT(Cmd, 4); /* global reset */ delay(15); OUT(Cmd, 0); /* end reset */ delay(4); } outb(port+SOFMod, i); /* * Interrupt handler. * Bail out if no IRQ assigned by the BIOS. */ if(cfg->intl == 0xFF || cfg->intl == 0) return; intrenable(cfg->intl, interrupt, ub, cfg->tbdf, "usb"); ub->io = port; ub->tdpool = xspanalloc(128*sizeof(TD), 16, 0); for(i=128; --i>=0;){ ub->tdpool[i].next = ub->freetd; ub->freetd = &ub->tdpool[i]; } ub->qhpool = xspanalloc(32*sizeof(QH), 16, 0); for(i=32; --i>=0;){ ub->qhpool[i].next = ub->freeqh; ub->freeqh = &ub->qhpool[i]; } /* * the root of the periodic (interrupt & isochronous) scheduling tree * 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. */ ub->ctlq = allocqh(ub); ub->bwsop = allocqh(ub); ub->bulkq = allocqh(ub); ub->recvq = allocqh(ub); t = alloctd(ub); /* inactive TD, looped */ t->link = PADDR(t); ub->bwsop->entries = PADDR(t); ub->ctlq->head = PADDR(ub->bwsop) | IsQH; ub->bwsop->head = PADDR(ub->bulkq) | IsQH; ub->bulkq->head = PADDR(ub->recvq) | IsQH; ub->recvq->head = PADDR(ub->bwsop) | IsQH; /* loop back */ XPRINT("usbcmd\t0x%.4x\nusbsts\t0x%.4x\nusbintr\t0x%.4x\nfrnum\t0x%.2x\n", IN(Cmd), IN(Status), IN(Usbintr), inb(port+Frnum)); XPRINT("frbaseadd\t0x%.4x\nsofmod\t0x%x\nportsc1\t0x%.4x\nportsc2\t0x%.4x\n", IN(Flbaseadd), inb(port+SOFMod), IN(Portsc0), IN(Portsc1)); OUT(Cmd, 0); /* stop */ ub->frames = xspanalloc(FRAMESIZE, FRAMESIZE, 0); qt = mkqhtree(ub->frames, NFRAME, 32); if(qt == nil){ print("usb: can't allocate scheduling tree\n"); ub->io = 0; return; } qt->root->head = PADDR(ub->ctlq) | IsQH; ub->tree = qt; XPRINT("usb tree: nel=%d depth=%d\n", qt->nel, qt->depth); outl(port+Flbaseadd, PADDR(ub->frames)); OUT(Frnum, 0); OUT(Usbintr, 0xF); /* enable all interrupts */ XPRINT("cmd 0x%x sofmod 0x%x\n", IN(Cmd), inb(port+SOFMod)); XPRINT("sc0 0x%x sc1 0x%x\n", IN(Portsc0), IN(Portsc1)); } void usbinit(void) { Udev *d; if(ubus.io != 0 && usbdev[0] == nil){ d = usbnewdevice(); /* reserve device 0 for configuration */ incref(d); d->state = Attached; } } Chan * usbattach(char *spec) { Ctlr *ub; ub = &ubus; if(ub->io == 0) { XPRINT("usbattach failed\n"); error(Enodev); } if((IN(Cmd)&1)==0 || *spec) OUT(Cmd, 1); /* run */ // pprint("at: c=%x s=%x c0=%x\n", IN(Cmd), IN(Status), IN(Portsc0)); return devattach('U', spec); } static int usbgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp) { int t; Qid q; ulong path; Udev *d; Dirtab *tab; Endpt *e; /* * Top level directory contains the name of the device. */ if(c->qid.path == Qtopdir){ if(s == DEVDOTDOT){ mkqid(&q, Qtopdir, 0, QTDIR); devdir(c, q, "#U", 0, eve, 0555, dp); return 1; } if(s == 0){ mkqid(&q, Q2nd, 0, QTDIR); devdir(c, q, "usb", 0, eve, 0555, dp); return 1; } return -1; } /* * Second level contains "new" plus all the clients. */ t = QID(c->qid); if(t < Q3rd){ if(s == DEVDOTDOT){ mkqid(&q, Qtopdir, 0, QTDIR); devdir(c, q, "#U", 0, eve, 0555, dp); return 1; } if(s < nelem(usbdir2)){ tab = &usbdir2[s]; devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp); return 1; } s -= nelem(usbdir2); if(s >= 0 && s < nelem(usbdev)){ d = usbdev[s]; if(d == nil) return -1; sprint(up->genbuf, "%d", s); mkqid(&q, ((s+1)<<QSHIFT)|Q3rd, d->id, QTDIR); devdir(c, q, up->genbuf, 0, eve, 0555, dp); return 1; } return -1; } /* * Third level. */ path = c->qid.path & ~QMASK; /* slot component */ if(s == DEVDOTDOT){ mkqid(&q, Q2nd, c->qid.vers, QTDIR); devdir(c, q, "usb", 0, eve, 0555, dp); return 1; } if(s < nelem(usbdir3)){ Dirtab *tab = &usbdir3[s]; mkqid(&q, path | tab->qid.path, c->qid.vers, QTFILE); devdir(c, q, tab->name, tab->length, eve, tab->perm, dp); return 1; } /* active endpoints */ d = usbdeviceofpath(path); if(d == nil) return -1; s -= nelem(usbdir3); if(s < 0 || s >= nelem(d->ep)) return -1; if(s == 0 || (e = d->ep[s]) == nil) /* ep0data is called "setup" */ return 0; sprint(up->genbuf, "ep%ddata", s); mkqid(&q, path | (Qep0+s), c->qid.vers, QTFILE); devdir(c, q, up->genbuf, 0, eve, e->mode==OREAD? 0444: e->mode==OWRITE? 0222: 0666, dp); return 1; } static Walkqid* usbwalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, nil, 0, usbgen); } static int usbstat(Chan *c, uchar *db, int n) { return devstat(c, db, n, nil, 0, usbgen); } Chan * usbopen(Chan *c, int omode) { Udev *d; int f, s; if(c->qid.type == QTDIR) return devopen(c, omode, nil, 0, usbgen); f = 0; if(QID(c->qid) == Qnew){ d = usbnewdevice(); if(d == nil) { XPRINT("usbopen failed (usbnewdevice)\n"); error(Enodev); } c->qid.path = Qctl|((d->x+1)<<QSHIFT); c->qid.vers = d->id; f = 1; } if(c->qid.path < Q3rd) return devopen(c, omode, nil, 0, usbgen); qlock(&usbstate); if(waserror()){ qunlock(&usbstate); nexterror(); } switch(QID(c->qid)){ case Qctl: d = usbdevice(c); if(0&&d->busy) error(Einuse); d->busy = 1; if(!f) incref(d); break; default: d = usbdevice(c); s = QID(c->qid) - Qep0; if(s >= 0 && s < nelem(d->ep)){ Endpt *e; if((e = d->ep[s]) == nil) { XPRINT("usbopen failed (endpoint)\n"); error(Enodev); } if(schedendpt(e) < 0) error("can't schedule USB endpoint"); eptactivate(e); } incref(d); break; } poperror(); qunlock(&usbstate); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } void usbcreate(Chan *c, char *name, int omode, ulong perm) { USED(c, name, omode, perm); error(Eperm); } void usbremove(Chan*) { error(Eperm); } void usbwstat(Chan *c, char *dp) { USED(c, dp); error(Eperm); } void usbclose(Chan *c) { Udev *d; if(c->qid.type == QTDIR || c->qid.path < Q3rd) return; qlock(&usbstate); if(waserror()){ qunlock(&usbstate); nexterror(); } d = usbdevice(c); if(QID(c->qid) == Qctl) d->busy = 0; if(c->flag & COPEN) freedev(d); poperror(); qunlock(&usbstate); } static int eptinput(void *arg) { Endpt *e; e = arg; return e->eof || e->err || qcanread(e->rq); } static long readusb(Endpt *e, void *a, long n) { Block *b; uchar *p; long l, i; XPRINT("qlock(%p)\n", &e->rlock); qlock(&e->rlock); XPRINT("got qlock(%p)\n", &e->rlock); if(waserror()){ qunlock(&e->rlock); eptcancel(e); nexterror(); } p = a; do { if(e->eof) { XPRINT("e->eof\n"); break; } if(e->err) error(e->err); qrcv(e); if(!e->iso) e->data01 ^= 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; } while (l == e->maxpkt && n > 0); poperror(); qunlock(&e->rlock); return p-(uchar*)a; } long usbread(Chan *c, void *a, long n, vlong offset) { Endpt *e; Udev *d; char buf[48], *s; int t, w0, w1, ps, l, i; if(c->qid.type == QTDIR) return devdirread(c, a, n, nil, 0, usbgen); t = QID(c->qid); switch(t){ case Qbusctl: snprint(buf, sizeof(buf), "%11d %11d ", 0, 0); return readstr(offset, a, n, buf); case Qport: ps = portinfo(&ubus, &w0, &w1); snprint(buf, sizeof(buf), "0x%ux 0x%ux 0x%ux ", ps, w0, w1); return readstr(offset, a, n, buf); case Qctl: d = usbdevice(c); sprint(buf, "%11d %11d ", d->x, d->id); return readstr(offset, a, n, buf); case Qsetup: /* endpoint 0 */ d = usbdevice(c); if((e = d->ep[0]) == nil) error(Eio); /* can't happen */ e->data01 = 1; n = readusb(e, a, n); if(e->setin){ e->setin = 0; e->data01 = 1; writeusb(e, "", 0, TokOUT); } break; case Qdebug: n=0; break; case Qstatus: d = usbdevice(c); s = smalloc(READSTR); if(waserror()){ free(s); nexterror(); } l = snprint(s, READSTR, "%s %#6.6lux\n", devstates[d->state], d->csp); for(i=0; i<nelem(d->ep); i++) if((e = d->ep[i]) != nil) /* TO DO: freeze e */ l += snprint(s+l, READSTR-l, "%2d %#6.6lux %10lud bytes %10lud blocks\n", i, e->csp, e->nbytes, e->nblocks); n = readstr(offset, a, n, s); poperror(); free(s); break; default: d = usbdevice(c); if((t -= Qep0) < 0 || t >= nelem(d->ep)) error(Eio); if((e = d->ep[t]) == nil || e->mode == OWRITE) error(Eio); /* can't happen */ n=readusb(e, a, n); break; } return n; } static int qisempty(void *arg) { return ((QH*)arg)->entries & Terminate; } static long writeusb(Endpt *e, void *a, long n, int tok) { long i; Block *b; uchar *p; QH *qh; p = a; qlock(&e->wlock); if(waserror()){ qunlock(&e->wlock); eptcancel(e); nexterror(); } do { int j; if(e->err) error(e->err); if((i = n) >= e->maxpkt) i = e->maxpkt; b = allocb(i); if(waserror()){ freeb(b); nexterror(); } XPRINT("out [%ld]", 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(e, b, tok); tok = TokOUT; if(!e->iso) e->data01 ^= 1; if(e->ntd >= e->nbuf) { XPRINT("writeusb: sleep %lux\n", &e->wr); sleep(&e->wr, qisempty, qh); XPRINT("writeusb: awake\n"); } } while(n > 0); poperror(); qunlock(&e->wlock); return p-(uchar*)a; } long usbwrite(Chan *c, void *a, long n, vlong) { Udev *d; Endpt *e; int id, nw, nf, t, i; char cmd[50], *fields[10]; if(c->qid.type == QTDIR) error(Egreg); t = QID(c->qid); if(t == Qbusctl){ if(n >= sizeof(cmd)-1) n = sizeof(cmd)-1; memmove(cmd, a, n); cmd[n] = 0; nf = getfields(cmd, fields, nelem(fields), 0, " \t\n"); if(nf==1 && strcmp(fields[0], "dump")==0){ dumpframe(-1, -1); return n; } if(nf < 2) error(Ebadarg); id = strtol(fields[1], nil, 0); if(id != 1 && id != 2) error(Ebadarg); /* there are two ports on the root hub */ if(strcmp(fields[0], "reset") == 0) portreset(id); else if(strcmp(fields[0], "enable") == 0) portenable(id, 1); else if(strcmp(fields[0], "disable") == 0) portenable(id, 0); else error(Ebadarg); return n; } d = usbdevice(c); t = QID(c->qid); switch(t){ case Qctl: if(n >= sizeof(cmd)-1) n = sizeof(cmd)-1; memmove(cmd, a, n); cmd[n] = 0; nf = getfields(cmd, fields, nelem(fields), 0, " \t\n"); if(nf > 1 && strcmp(fields[0], "speed") == 0){ d->ls = strtoul(fields[1], nil, 0) == 0; } else if(nf > 3 && strcmp(fields[0], "class") == 0){ i = strtoul(fields[2], nil, 0); d->npt = strtoul(fields[1], nil, 0); /* class config# csp ( == class subclass proto) */ if (i < 0 || i >= nelem(d->ep) || d->npt > nelem(d->ep) || i >= d->npt) error(Ebadarg); if (i == 0) { d->csp = strtoul(fields[3], nil, 0); } if(d->ep[i] == nil) d->ep[i] = devendpt(d, i, 1); d->ep[i]->csp = strtoul(fields[3], nil, 0); }else if(nf > 2 && strcmp(fields[0], "data") == 0){ i = strtoul(fields[1], nil, 0); if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) error(Ebadarg); e = d->ep[i]; e->data01 = strtoul(fields[2], nil, 0) != 0; }else if(nf > 2 && strcmp(fields[0], "maxpkt") == 0){ i = strtoul(fields[1], nil, 0); if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) error(Ebadarg); e = d->ep[i]; e->maxpkt = strtoul(fields[2], nil, 0); if(e->maxpkt > 1500) e->maxpkt = 1500; }else if(nf > 2 && strcmp(fields[0], "debug") == 0){ i = strtoul(fields[1], nil, 0); if(i < -1 || i >= nelem(d->ep) || d->ep[i] == nil) error(Ebadarg); if (i == -1) debug = 0; else { debug = 1; e = d->ep[i]; e->debug = strtoul(fields[2], nil, 0); } }else if(nf > 1 && strcmp(fields[0], "unstall") == 0){ i = strtoul(fields[1], nil, 0); if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) error(Ebadarg); e = d->ep[i]; e->err = nil; }else if(nf == 6 && strcmp(fields[0], "ep") == 0){ /* ep n maxpkt mode poll nbuf */ i = strtoul(fields[1], nil, 0); if(i < 0 || i >= nelem(d->ep)) { XPRINT("field 1: 0 <= %d < %d\n", i, nelem(d->ep)); error(Ebadarg); } if((e = d->ep[i]) == nil) e = devendpt(d, i, 1); if(waserror()){ freept(e); nexterror(); } i = strtoul(fields[2], nil, 0); if(i < 8 || i > 1023) i = 8; e->maxpkt = i; e->mode = strcmp(fields[3],"r") == 0? OREAD : strcmp(fields[3],"w") == 0? OWRITE : ORDWR; e->periodic = 0; e->sched = -1; if(strcmp(fields[4], "bulk") == 0){ Ctlr *ub; ub = &ubus; /* Each bulk device gets a queue head hanging off the * bulk queue head */ if (e->epq == nil) { e->epq = allocqh(ub); if(e->epq == nil) panic("usbwrite: allocqh"); } queueqh(e->epq); } else { e->periodic = 1; i = strtoul(fields[4], nil, 0); if(i > 0 && i <= 1000) e->pollms = i; else { XPRINT("field 4: 0 <= %d <= 1000\n", i); error(Ebadarg); } } i = strtoul(fields[5], nil, 0); if(i >= 1 && i <= 32) e->nbuf = i; poperror(); }else { XPRINT("command %s, fields %d\n", fields[0], nf); error(Ebadarg); } return n; case Qsetup: /* SETUP endpoint 0 */ /* should canqlock etc */ if((e = d->ep[0]) == nil) error(Eio); /* can't happen */ if(n < 8 || n > 1023) error(Eio); nw = *(uchar*)a & RD2H; e->data01 = 0; n = writeusb(e, a, n, TokSETUP); if(nw == 0){ /* host to device: use IN[DATA1] to ack */ e->data01 = 1; nw = readusb(e, cmd, 8); if(nw != 0) error(Eio); /* could provide more status */ }else e->setin = 1; /* two-phase */ break; default: /* sends DATA[01] */ if((t -= Qep0) < 0 || t >= nelem(d->ep)) { print("t = %d\n", t); error(Eio); } if((e = d->ep[t]) == nil || e->mode == OREAD) { error(Eio); /* can't happen */ } n = writeusb(e, a, n, TokOUT); break; } return n; } Dev usbdevtab = { 'U', "usb", usbreset, usbinit, usbattach, usbwalk, usbstat, usbopen, devcreate, usbclose, usbread, devbread, usbwrite, devbwrite, devremove, devwstat, }; | |
| Too many diffs (26 > 25). Stopping. | ||