📄 devusb.c
字号:
#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h"#include "usb.h"static int debug = 0;#define Chatty 1#define DPRINT if(Chatty)print#define XPRINT if(debug)iprintUsbhost* usbhost[MaxUsb];static char *devstates[] = { [Disabled] "Disabled", [Attached] "Attached", [Enabled] "Enabled", [Assigned] "Assigned", [Configured] "Configured",};static char Ebadusbmsg[] = "invalid parameters to USB ctl message";enum{ Qtopdir = 0, Q2nd, Qnew, Qport, Q3rd, Qctl, Qstatus, Qep0, /* other endpoint files */};/* * Qid path is: * 8 bits of file type (qids above) * 8 bits of slot number; default address 0 used for per-controller files * 4 bits of controller number */enum { TYPEBITS = 8, SLOTBITS = 8, CTLRBITS = 4, SLOTSHIFT = TYPEBITS, CTLRSHIFT = SLOTSHIFT+SLOTBITS, TYPEMASK = (1<<TYPEBITS)-1, SLOTMASK = (1<<SLOTBITS)-1, CTLRMASK = (1<<CTLRBITS)-1,};#define TYPE(q) (((ulong)(q).path)&TYPEMASK)#define SLOT(q) ((((ulong)(q).path)>>SLOTSHIFT)&SLOTMASK)#define CTLR(q) ((((ulong)(q).path)>>CTLRSHIFT)&CTLRMASK)#define PATH(t, s, c) ((t)|((s)<<SLOTSHIFT)|((c)<<CTLRSHIFT))static Dirtab usbdir2[] = { "new", {Qnew}, 0, 0666, "port", {Qport}, 0, 0666,};static Dirtab usbdir3[]={ "ctl", {Qctl}, 0, 0666, "status", {Qstatus}, 0, 0444, "setup", {Qep0}, 0, 0666, /* epNdata names are generated on demand */};enum{ PMdisable, PMenable, PMreset,};enum{ CMclass, CMdata, CMdebug, CMep, CMmaxpkt, CMadjust, CMspeed, CMunstall,};static Cmdtab usbportmsg[] ={ PMdisable, "disable", 2, PMenable, "enable", 2, PMreset, "reset", 2,};static Cmdtab usbctlmsg[] ={ CMclass, "class", 0, CMdata, "data", 3, CMdebug, "debug", 3, CMep, "ep", 6, CMmaxpkt, "maxpkt", 3, CMadjust, "adjust", 3, CMspeed, "speed", 2, CMunstall, "unstall", 2,};static struct{ char* type; int (*reset)(Usbhost*);} usbtypes[MaxUsb+1];voidaddusbtype(char* t, int (*r)(Usbhost*)){ static int ntype; if(ntype == MaxUsb) panic("too many USB host interface types"); usbtypes[ntype].type = t; usbtypes[ntype].reset = r; ntype++;}static Udev*usbdeviceofslot(Usbhost *uh, int s){ if(s < 0 || s > nelem(uh->dev)) return nil; return uh->dev[s];}static Udev*usbdevice(Chan *c){ int bus; Udev *d; Usbhost *uh; bus = CTLR(c->qid); if(bus > nelem(usbhost) || (uh = usbhost[bus]) == nil) { error(Egreg); return nil; /* for compiler */ } d = usbdeviceofslot(uh, SLOT(c->qid)); if(d == nil || d->id != c->qid.vers || d->state == Disabled) error(Ehungup); return d;}static Endpt *devendpt(Udev *d, int id, int add){ Usbhost *uh; Endpt *e, **p; p = &d->ep[id&0xF]; lock(d); e = *p; if(e != nil){ incref(e); XPRINT("incref(0x%p) in devendpt, new value %ld\n", e, e->ref); 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->sched = -1; e->maxpkt = 8; e->nbuf = 1; e->dev = d; e->active = 0; uh = d->uh; uh->epalloc(uh, e); lock(d); if(*p != nil){ incref(*p); XPRINT("incref(0x%p) in devendpt, new value %ld\n", *p, (*p)->ref); unlock(d); uh->epfree(uh, e); 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 voidfreept(Endpt *e){ Usbhost *uh; if(e != nil && decref(e) == 0){ XPRINT("freept(%d,%d)\n", e->dev->x, e->x); uh = e->dev->uh; uh->epclose(uh, e); e->dev->ep[e->x] = nil; uh->epfree(uh, e); free(e); }}static Udev*usbnewdevice(Usbhost *uh){ int i; Udev *d; Endpt *e; d = nil; qlock(uh); if(waserror()){ qunlock(uh); nexterror(); } for(i=0; i<nelem(uh->dev); i++) if(uh->dev[i] == nil){ uh->idgen++; d = mallocz(sizeof(*d), 1); d->uh = uh; d->ref = 1; d->x = i; d->id = (uh->idgen << 8) | i; d->state = Enabled; XPRINT("calling devendpt in usbnewdevice\n"); e = devendpt(d, 0, 1); /* always provide control endpoint 0 */ e->mode = ORDWR; e->iso = 0; e->sched = -1; uh->dev[i] = d; break; } poperror(); qunlock(uh); return d;}static voidfreedev(Udev *d, int ept){ int i; Endpt *e; Usbhost *uh; uh = d->uh; if(decref(d) == 0){ XPRINT("freedev 0x%p, 0\n", d); for(i=0; i<nelem(d->ep); i++) freept(d->ep[i]); if(d->x >= 0) uh->dev[d->x] = nil; free(d); } else { if(ept >= 0 && ept < nelem(d->ep)){ e = d->ep[ept]; XPRINT("freedev, freept 0x%p\n", e); if(e != nil) uh->epclose(uh, e); } } }static intusbgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp){ Qid q; Udev *d; Endpt *e; Dirtab *tab; Usbhost *uh; int t, bus, slot, perm; /* * Top level directory contains the controller names. */ 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 >= nelem(usbhost) || usbhost[s] == nil) return -1; mkqid(&q, PATH(Q2nd, 0, s), 0, QTDIR); snprint(up->genbuf, sizeof up->genbuf, "usb%d", s); devdir(c, q, up->genbuf, 0, eve, 0555, dp); return 1; } bus = CTLR(c->qid); if(bus >= nelem(usbhost) || (uh = usbhost[bus]) == nil) return -1; /* * Second level contains "new", "port", and a numbered * directory for each enumerated device on the bus. */ t = TYPE(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)){ d = uh->dev[0]; if(d == nil) return -1; tab = &usbdir2[s]; mkqid(&q, PATH(tab->qid.path, 0, bus), d->id, QTFILE); devdir(c, q, tab->name, tab->length, eve, tab->perm, dp); return 1; } s -= nelem(usbdir2); if(s >= 0 && s < nelem(uh->dev)) { d = uh->dev[s]; if(d == nil) return 0; sprint(up->genbuf, "%d", s); mkqid(&q, PATH(Q3rd, s, bus), d->id, QTDIR); devdir(c, q, up->genbuf, 0, eve, 0555, dp); return 1; } return -1; } /* * Third level. */ slot = SLOT(c->qid); if(s == DEVDOTDOT) { mkqid(&q, PATH(Q2nd, 0, bus), c->qid.vers, QTDIR); snprint(up->genbuf, sizeof up->genbuf, "usb%d", bus); devdir(c, q, up->genbuf, 0, eve, 0555, dp); return 1; } if(s < nelem(usbdir3)) { tab = &usbdir3[s]; mkqid(&q, PATH(tab->qid.path, slot, bus), c->qid.vers, QTFILE); devdir(c, q, tab->name, tab->length, eve, tab->perm, dp); return 1; } s -= nelem(usbdir3); /* active endpoints */ d = usbdeviceofslot(uh, slot); if(d == nil || 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, slot, bus), c->qid.vers, QTFILE); switch(e->mode) { case OREAD: perm = 0444; break; case OWRITE: perm = 0222; break; default: perm = 0666; break; } devdir(c, q, up->genbuf, e->buffered, eve, perm, dp); return 1;}static Usbhost*usbprobe(int cardno, int ctlrno){ Usbhost *uh; char buf[128], *ebuf, name[64], *p, *type; uh = malloc(sizeof(Usbhost)); memset(uh, 0, sizeof(Usbhost)); uh->tbdf = BUSUNKNOWN; if(cardno < 0){ if(isaconfig("usb", ctlrno, uh) == 0){ free(uh); return nil; } for(cardno = 0; usbtypes[cardno].type; cardno++){ type = uh->type; if(type==nil || *type==0) type = "uhci"; if(cistrcmp(usbtypes[cardno].type, type)) continue; break; } } if(cardno >= MaxUsb || usbtypes[cardno].type == nil){ free(uh); return nil; } if(usbtypes[cardno].reset(uh) < 0){ free(uh); return nil; } /* * IRQ2 doesn't really exist, it's used to gang the interrupt * controllers together. A device set to IRQ2 will appear on * the second interrupt controller as IRQ9. */ if(uh->irq == 2) uh->irq = 9; snprint(name, sizeof(name), "usb%d", ctlrno); intrenable(uh->irq, uh->interrupt, uh, uh->tbdf, name); ebuf = buf + sizeof buf; p = seprint(buf, ebuf, "#U/usb%d: %s: port 0x%luX irq %d", ctlrno, usbtypes[cardno].type, uh->port, uh->irq); if(uh->mem) p = seprint(p, ebuf, " addr 0x%luX", PADDR(uh->mem)); if(uh->size) seprint(p, ebuf, " size 0x%luX", uh->size); print("%s\n", buf); return uh;}static voidusbreset(void){ int cardno, ctlrno; Usbhost *uh; for(ctlrno = 0; ctlrno < MaxUsb; ctlrno++){ if((uh = usbprobe(-1, ctlrno)) == nil) continue; usbhost[ctlrno] = uh; } if(getconf("*nousbprobe")) return; cardno = ctlrno = 0; while(usbtypes[cardno].type != nil && ctlrno < MaxUsb){ if(usbhost[ctlrno] != nil){ ctlrno++; continue; } if((uh = usbprobe(cardno, ctlrno)) == nil){ cardno++; continue; } usbhost[ctlrno] = uh; ctlrno++; }}voidusbinit(void){ Udev *d; int ctlrno;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -