📄 devusb.c
字号:
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){ return devwalk(c, nc, name, nname, nil, 0, usbgen);}static intusbstat(Chan *c, uchar *db, int n){ return devstat(c, db, n, nil, 0, usbgen);}Chan*usbopen(Chan *c, int omode){ Udev *d; Endpt *e; int f, s, type; Usbhost *uh; if(c->qid.type == QTDIR) return devopen(c, omode, nil, 0, usbgen); f = 0; type = TYPE(c->qid); if(type == Qnew){ d = usbdevice(c); d = usbnewdevice(d->uh); XPRINT("usbopen, new dev 0x%p\n", d); if(d == nil) { XPRINT("usbopen failed (usbnewdevice)\n"); error(Enodev); } type = Qctl; mkqid(&c->qid, PATH(type, d->x, CTLR(c->qid)), d->id, QTFILE); f = 1; } if(type < Q3rd){ XPRINT("usbopen, devopen < Q3rd\n"); return devopen(c, omode, nil, 0, usbgen); } d = usbdevice(c); uh = d->uh; qlock(uh); if(waserror()){ qunlock(uh); nexterror(); } switch(type){ case Qctl: if(0&&d->busy) error(Einuse); d->busy = 1; if(!f) incref(d); XPRINT("usbopen, Qctl 0x%p\n", d); break; default: s = type - Qep0; XPRINT("usbopen, default 0x%p, %d\n", d, s); if(s >= 0 && s < nelem(d->ep)){ if((e = d->ep[s]) == nil) { XPRINT("usbopen failed (endpoint)\n"); error(Enodev); } XPRINT("usbopen: dev 0x%p, ept 0x%p\n", d, e); uh->epopen(uh, e); e->foffset = 0; e->toffset = 0; e->poffset = 0; e->buffered = 0; } incref(d); break; } poperror(); qunlock(uh); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c;}voidusbclose(Chan *c){ Udev *d; int ept, type; Usbhost *uh; type = TYPE(c->qid); if(c->qid.type == QTDIR || type < Q3rd) return; d = usbdevice(c); uh = d->uh; qlock(uh); if(waserror()){ qunlock(uh); nexterror(); } if(type == Qctl) d->busy = 0; XPRINT("usbclose: dev 0x%p\n", d); if(c->flag & COPEN){ ept = (type != Qctl) ? type - Qep0 : -1; XPRINT("usbclose: freedev 0x%p\n", d); freedev(d, ept); } poperror(); qunlock(uh);}static char *epstatus(char *s, char *se, Endpt *e, int i){ char *p; p = seprint(s, se, "%2d %#6.6lux %10lud bytes %10lud blocks\n", i, e->csp, e->nbytes, e->nblocks); if(e->iso){ p = seprint(p, se, "bufsize %6d buffered %6d", e->maxpkt, e->buffered); if(e->toffset) p = seprint(p, se, " offset %10lud time %19lld\n", e->toffset, e->time); p = seprint(p, se, "\n"); } return p;}longusbread(Chan *c, void *a, long n, vlong offset){ int t, i; Udev *d; Endpt *e; Usbhost *uh; char *s, *se, *p; if(c->qid.type == QTDIR) return devdirread(c, a, n, nil, 0, usbgen); d = usbdevice(c); uh = d->uh; t = TYPE(c->qid); if(t >= Qep0) { t -= Qep0; if(t >= nelem(d->ep)) error(Eio); e = d->ep[t]; if(e == nil || e->mode == OWRITE) error(Egreg); if(t == 0) { if(e->iso) error(Egreg); e->rdata01 = 1; n = uh->read(uh, e, a, n, 0LL); if(e->setin){ e->setin = 0; e->wdata01 = 1; uh->write(uh, e, "", 0, 0LL, TokOUT); } return n; } return uh->read(uh, e, a, n, offset); } s = smalloc(READSTR); se = s+READSTR; if(waserror()){ free(s); nexterror(); } switch(t){ case Qport: uh->portinfo(uh, s, se); break; case Qctl: seprint(s, se, "%11d %11d\n", d->x, d->id); break; case Qstatus: if (d->did || d->vid) p = seprint(s, se, "%s %#6.6lux %#4.4ux %#4.4ux\n", devstates[d->state], d->csp, d->vid, d->did); else p = seprint(s, se, "%s %#6.6lux\n", devstates[d->state], d->csp); for(i=0; i<nelem(d->ep); i++) { e = d->ep[i]; if(e == nil) continue; /* TO DO: freeze e */ p = epstatus(p, se, e, i); } } n = readstr(offset, a, n, s); poperror(); free(s); return n;}longusbwrite(Chan *c, void *a, long n, vlong offset){ Udev *d; Endpt *e; Cmdtab *ct; Cmdbuf *cb; Usbhost *uh; int id, nw, t, i; char cmd[50]; if(c->qid.type == QTDIR) error(Egreg); d = usbdevice(c); uh = d->uh; t = TYPE(c->qid); switch(t){ case Qport: cb = parsecmd(a, n); if(waserror()){ free(cb); nexterror(); } ct = lookupcmd(cb, usbportmsg, nelem(usbportmsg)); id = strtol(cb->f[1], nil, 0); switch(ct->index){ case PMdisable: uh->portenable(uh, id, 0); break; case PMenable: uh->portenable(uh, id, 1); break; case PMreset: uh->portreset(uh, id); break; } poperror(); free(cb); return n; case Qctl: cb = parsecmd(a, n); if(waserror()){ free(cb); nexterror(); } ct = lookupcmd(cb, usbctlmsg, nelem(usbctlmsg)); switch(ct->index){ case CMspeed: d->ls = strtoul(cb->f[1], nil, 0) == 0; break; case CMclass: if (cb->nf != 4 && cb->nf != 6) cmderror(cb, Ebadusbmsg); /* class #ifc ept csp ( == class subclass proto) [vendor product] */ d->npt = strtoul(cb->f[1], nil, 0); /* # of interfaces */ i = strtoul(cb->f[2], nil, 0); /* endpoint */ if (i < 0 || i >= nelem(d->ep) || d->npt > nelem(d->ep) || i >= d->npt) cmderror(cb, Ebadusbmsg); if (cb->nf == 6) { d->vid = strtoul(cb->f[4], nil, 0); d->did = strtoul(cb->f[5], nil, 0); } if (i == 0) d->csp = strtoul(cb->f[3], nil, 0); if(d->ep[i] == nil){ XPRINT("calling devendpt in usbwrite (CMclass)\n"); d->ep[i] = devendpt(d, i, 1); } d->ep[i]->csp = strtoul(cb->f[3], nil, 0); break; case CMdata: i = strtoul(cb->f[1], nil, 0); if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) error(Ebadusbmsg); e = d->ep[i]; e->wdata01 = e->rdata01 = strtoul(cb->f[2], nil, 0) != 0; break; case CMmaxpkt: i = strtoul(cb->f[1], nil, 0); if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) error(Ebadusbmsg); e = d->ep[i]; e->maxpkt = strtoul(cb->f[2], nil, 0); if(e->maxpkt > 1500) e->maxpkt = 1500; break; case CMadjust: i = strtoul(cb->f[1], nil, 0); if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) error(Ebadusbmsg); e = d->ep[i]; if (e->iso == 0) error(Eperm); i = strtoul(cb->f[2], nil, 0); /* speed may not result in change of maxpkt */ if (i < (e->maxpkt-1)/e->samplesz * 1000/e->pollms || i > e->maxpkt/e->samplesz * 1000/e->pollms){ snprint(cmd, sizeof(cmd), "%d < %d < %d?", (e->maxpkt-1)/e->samplesz * 1000/e->pollms, i, e->maxpkt/e->samplesz * 1000/e->pollms); error(cmd); } e->hz = i; break; case CMdebug: i = strtoul(cb->f[1], nil, 0); if(i < -1 || i >= nelem(d->ep) || d->ep[i] == nil) error(Ebadusbmsg); if (i == -1) debug = 0; else { debug = 1; e = d->ep[i]; e->debug = strtoul(cb->f[2], nil, 0); } break; case CMunstall: i = strtoul(cb->f[1], nil, 0); if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) error(Ebadusbmsg); e = d->ep[i]; e->err = nil; break; case CMep: /* ep n `bulk' mode maxpkt nbuf OR * ep n period mode samplesize Hz */ i = strtoul(cb->f[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){ XPRINT("calling devendpt in usbwrite (CMep)\n"); e = devendpt(d, i, 1); } qlock(uh); if(waserror()){ freept(e); qunlock(uh); nexterror(); } if(e->active) error(Eperm); if(strcmp(cb->f[2], "bulk") == 0){ /* ep n `bulk' mode maxpkt nbuf */ e->iso = 0; i = strtoul(cb->f[4], nil, 0); if(i < 8 || i > 1023) i = 8; e->maxpkt = i; i = strtoul(cb->f[5], nil, 0); if(i >= 1 && i <= 32) e->nbuf = i; } else { /* ep n period mode samplesize Hz */ i = strtoul(cb->f[2], nil, 0); if(i > 0 && i <= 1000){ e->pollms = i; }else { XPRINT("field 4: 0 <= %d <= 1000\n", i); error(Ebadarg); } i = strtoul(cb->f[4], nil, 0); if(i >= 1 && i <= 8){ e->samplesz = i; }else { XPRINT("field 4: 0 < %d <= 8\n", i); error(Ebadarg); } i = strtoul(cb->f[5], nil, 0); if(i >= 1 && i*e->samplesz <= 12*1000*1000){ /* Hz */ e->hz = i; e->remain = 0; }else { XPRINT("field 5: 1 < %d <= 100000 Hz\n", i); error(Ebadarg); } e->maxpkt = (e->hz * e->pollms + 999)/1000 * e->samplesz; e->iso = 1; } e->mode = strcmp(cb->f[3],"r") == 0? OREAD : strcmp(cb->f[3],"w") == 0? OWRITE : ORDWR; uh->epmode(uh, e); poperror(); qunlock(uh); } poperror(); free(cb); return n; case Qep0: /* SETUP endpoint 0 */ /* should canqlock etc */ e = d->ep[0]; if(e == nil || e->iso) error(Egreg); if(n < 8) error(Eio); nw = *(uchar*)a & RD2H; e->wdata01 = 0; n = uh->write(uh, e, a, n, 0LL, TokSETUP); if(nw == 0) { /* host to device: use IN[DATA1] to ack */ e->rdata01 = 1; nw = uh->read(uh, e, cmd, 0LL, 8); if(nw != 0) error(Eio); /* could provide more status */ }else e->setin = 1; /* two-phase */ break; default: /* sends DATA[01] */ t -= Qep0; if(t < 0 || t >= nelem(d->ep)) error(Egreg); e = d->ep[t]; if(e == nil || e->mode == OREAD) error(Egreg); n = uh->write(uh, e, a, n, offset, TokOUT); break; } return n;}Dev usbdevtab = { 'U', "usb", usbreset, usbinit, devshutdown, usbattach, usbwalk, usbstat, usbopen, devcreate, usbclose, usbread, devbread, usbwrite, devbwrite, devremove, devwstat,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -