#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)iprint Usbhost* 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; Usbhost *uh; for(ctlrno = 0; ctlrno < MaxUsb; ctlrno++){ uh = usbhost[ctlrno]; if(uh == nil) continue; if(uh->init != 0) uh->init(uh); /* reserve device for configuration */ d = usbnewdevice(uh); incref(d); d->state = Attached; }} Chan *usbattach(char *spec){ return devattach('U', spec);} static Walkqid*usbwalk(Chan *c, Chan *nc, char **name, int nname)Lines 1–500 of 951. Load more
#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)iprint Usbhost* 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]; void addusbtype(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 void freept(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 void freedev(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 int usbgen(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 void usbreset(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++; } } void usbinit(void) { Udev *d; int ctlrno; Usbhost *uh; for(ctlrno = 0; ctlrno < MaxUsb; ctlrno++){ uh = usbhost[ctlrno]; if(uh == nil) continue; if(uh->init != 0) uh->init(uh); /* reserve device for configuration */ d = usbnewdevice(uh); incref(d); d->state = Attached; } } Chan * usbattach(char *spec) { return devattach('U', spec); } static Walkqid* usbwalk(Chan *c, Chan *nc, char **name, int nname)