@@ 879,1088 879,4 @@ schedendpt(Endpt *e)
QH *qh;
int q;
- 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);
- 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));
- }
- OUT(Status, s);
-
- 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) ((q).path&QMASK)
-#define DEVPATH(q) (((q)&~CHDIR)>>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}, 1, 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;
-
- 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(0){
- 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)
- 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);
-}
-
-Chan *
-usbclone(Chan *c, Chan *nc)
-{
- return devclone(c, nc);
-}
-
-static int
-usbgen(Chan *c, Dirtab*, int, int s, Dir *dp)
-{
- int t;
- Qid q;
- ulong path;
- Udev *d;
- Dirtab *tab;
- Endpt *e;
- char buf[NAMELEN];
-
- /*
- * Top level directory contains the name of the device.
- */
- if(c->qid.path == CHDIR){
- if(s == DEVDOTDOT){
- devdir(c, (Qid){CHDIR, 0}, "#U", 0, eve, 0555, dp);
- return 1;
- }
- if(s == 0){
- devdir(c, (Qid){CHDIR|Q2nd, 0}, "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){
- devdir(c, (Qid){CHDIR, 0}, "#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;
- }
- if((s -= nelem(usbdir2)) >= 0 && s < nelem(usbdev)){
- d = usbdev[s];
- if(d == nil)
- return 0;
- sprint(buf, "%d", s);
- q = (Qid){CHDIR|((s+1)<<QSHIFT)|Q3rd, d->id};
- devdir(c, q, buf, 0, eve, 0555, dp);
- return 1;
- }
- return -1;
- }
-
- /*
- * Third level.
- */
- path = c->qid.path&~(CHDIR|QMASK); /* slot component */
- q.vers = c->qid.vers;
- if(s == DEVDOTDOT){
- devdir(c, (Qid){CHDIR|Q2nd, 0}, "usb", 0, eve, 0555, dp);
- return 1;
- }
- if(s < nelem(usbdir3)){
- Dirtab *tab = &usbdir3[s];
- q.path = path | tab->qid.path;
- 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(buf, "ep%ddata", s);
- q.path = path | (Qep0+s);
- devdir(c, q, buf, 0, eve, e->mode==OREAD? 0444: e->mode==OWRITE? 0222: 0666, dp);
- return 1;
-}
-
-int
-usbwalk(Chan *c, char *name)
-{
- if(strcmp(name, "..") == 0){
- switch(QID(c->qid)){
- case Qtopdir:
- return 1;
- case Q2nd:
- c->qid = (Qid){CHDIR|Qtopdir, 0};
- break;
- case Q3rd:
- c->qid = (Qid){CHDIR|Q2nd, 0};
- break;
- default:
- panic("usbwalk %lux", c->qid.path);
- }
- return 1;
- }
- return devwalk(c, name, nil, 0, usbgen);
-}
-
-void
-usbstat(Chan *c, char *db)
-{
- devstat(c, db, nil, 0, usbgen);
-}
-
-Chan *
-usbopen(Chan *c, int omode)
-{
- Udev *d;
- int f, s;
-
- if(c->qid.path & CHDIR)
- return devopen(c, omode, nil, 0, usbgen);
-
- f = 0;
- if(QID(c->qid) == Qnew){
- d = usbnewdevice();
- if(d == nil)
- 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)
- 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.path & CHDIR || 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.path & CHDIR)
- 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.path & CHDIR)
- 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,
- usbclone,
- usbwalk,
- usbstat,
- usbopen,
- devcreate,
- usbclose,
- usbread,
- devbread,
- usbwrite,
- devbwrite,
- devremove,
- devwstat,
-};
+ if(!e->periodic || e->sched