123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include <u.h>
- #include <libc.h>
- #include <thread.h>
- #include <fcall.h>
- #include <usb/usb.h>
- #include <usb/usbfs.h>
- #include "usbd.h"
- static Channel *portc;
- int mainstacksize = Stack;
- static Hub *hubs;
- static int nhubs;
- static int mustdump;
- static int pollms = Pollms;
- // Wow, did anyone really use this code?
- //static char *dsname[] = { "disabled", "attached", "configed" };
- static int
- hubfeature(Hub *h, int port, int f, int on)
- {
- int cmd;
- if(on)
- cmd = Rsetfeature;
- else
- cmd = Rclearfeature;
- return usbcmd(h->dev, Rh2d|Rclass|Rother, cmd, f, port, nil, 0);
- }
- // Never used, but too handy to remove just now?
- #if 0
- /*
- * This may be used to detect overcurrent on the hub
- */
- static void
- checkhubstatus(Hub *h)
- {
- uint8_t buf[4];
- int sts;
- if(h->isroot) /* not for root hubs */
- return;
- if(usbcmd(h->dev, Rd2h|Rclass|Rdev, Rgetstatus, 0, 0, buf, 4) < 0){
- dprint(2, "%s: get hub status: %r\n", h->dev->dir);
- return;
- }
- sts = GET2(buf);
- dprint(2, "hub %s: status %#x\n", h->dev->dir, sts);
- }
- #endif
- static int
- confighub(Hub *h)
- {
- int type;
- uint8_t buf[128]; /* room for extra descriptors */
- int i;
- Usbdev *d;
- DHub *dd;
- Port *pp;
- int nr;
- int nmap;
- uint8_t *PortPwrCtrlMask;
- int offset;
- int mask;
- d = h->dev->usb;
- for(i = 0; i < nelem(d->ddesc); i++)
- if(d->ddesc[i] == nil)
- break;
- else if(d->ddesc[i]->data.bDescriptorType == Dhub){
- dd = (DHub*)&d->ddesc[i]->data;
- nr = Dhublen;
- goto Config;
- }
- type = Rd2h|Rclass|Rdev;
- nr = usbcmd(h->dev, type, Rgetdesc, Dhub<<8|0, 0, buf, sizeof buf);
- if(nr < Dhublen){
- dprint(2, "%s: %s: getdesc hub: %r\n", argv0, h->dev->dir);
- return -1;
- }
- dd = (DHub*)buf;
- Config:
- h->nport = dd->bNbrPorts;
- nmap = 1 + h->nport/8;
- if(nr < 7 + 2*nmap){
- fprint(2, "%s: %s: descr. too small\n", argv0, h->dev->dir);
- return -1;
- }
- h->port = emallocz((h->nport+1)*sizeof(Port), 1);
- h->pwrms = dd->bPwrOn2PwrGood*2;
- if(h->pwrms < Powerdelay)
- h->pwrms = Powerdelay;
- h->maxcurrent = dd->bHubContrCurrent;
- h->pwrmode = dd->wHubCharacteristics[0] & 3;
- h->compound = (dd->wHubCharacteristics[0] & (1<<2))!=0;
- h->leds = (dd->wHubCharacteristics[0] & (1<<7)) != 0;
- PortPwrCtrlMask = dd->DeviceRemovable + nmap;
- for(i = 1; i <= h->nport; i++){
- pp = &h->port[i];
- offset = i/8;
- mask = 1<<(i%8);
- pp->removable = (dd->DeviceRemovable[offset] & mask) != 0;
- pp->pwrctl = (PortPwrCtrlMask[offset] & mask) != 0;
- }
- return 0;
- }
- static void
- configroothub(Hub *h)
- {
- Dev *d;
- char buf[128];
- char *p;
- int nr;
- d = h->dev;
- h->nport = 2;
- h->maxpkt = 8;
- seek(d->cfd, 0, 0);
- nr = read(d->cfd, buf, sizeof(buf)-1);
- if(nr < 0)
- goto Done;
- buf[nr] = 0;
- p = strstr(buf, "ports ");
- if(p == nil)
- fprint(2, "%s: %s: no port information\n", argv0, d->dir);
- else
- h->nport = atoi(p+6);
- p = strstr(buf, "maxpkt ");
- if(p == nil)
- fprint(2, "%s: %s: no maxpkt information\n", argv0, d->dir);
- else
- h->maxpkt = atoi(p+7);
- Done:
- h->port = emallocz((h->nport+1)*sizeof(Port), 1);
- dprint(2, "%s: %s: ports %d maxpkt %d\n", argv0, d->dir, h->nport, h->maxpkt);
- }
- Hub*
- newhub(char *fn, Dev *d)
- {
- Hub *h;
- int i;
- Usbdev *ud;
- h = emallocz(sizeof(Hub), 1);
- h->isroot = (d == nil);
- if(h->isroot){
- h->dev = opendev(fn);
- if(h->dev == nil){
- fprint(2, "%s: opendev: %s: %r\n", argv0, fn);
- goto Fail;
- }
- if(opendevdata(h->dev, ORDWR) < 0){
- fprint(2, "%s: opendevdata: %s: %r\n", argv0, fn);
- goto Fail;
- }
- configroothub(h); /* never fails */
- }else{
- h->dev = d;
- if(confighub(h) < 0){
- fprint(2, "%s: %s: config: %r\n", argv0, fn);
- goto Fail;
- }
- }
- if(h->dev == nil){
- fprint(2, "%s: opendev: %s: %r\n", argv0, fn);
- goto Fail;
- }
- devctl(h->dev, "hub");
- ud = h->dev->usb;
- if (h->isroot) {
- devctl(h->dev, "info roothub csp %#08x ports %d",
- 0x000009, h->nport);
- } else {
- devctl(h->dev, "info hub csp %#08x ports %d %q %q",
- ud->csp, h->nport, ud->vendor, ud->product);
- for(i = 1; i <= h->nport; i++)
- if(hubfeature(h, i, Fportpower, 1) < 0)
- fprint(2, "%s: %s: power: %r\n", argv0, fn);
- sleep(h->pwrms);
- for(i = 1; i <= h->nport; i++)
- if(h->leds != 0)
- hubfeature(h, i, Fportindicator, 1);
- }
- h->next = hubs;
- hubs = h;
- nhubs++;
- dprint(2, "%s: hub %#p allocated:", argv0, h);
- dprint(2, " ports %d pwrms %d max curr %d pwrm %d cmp %d leds %d\n",
- h->nport, h->pwrms, h->maxcurrent,
- h->pwrmode, h->compound, h->leds);
- incref(&h->dev->Ref);
- return h;
- Fail:
- if(d != nil)
- devctl(d, "detach");
- free(h->port);
- free(h);
- dprint(2, "%s: hub %#p failed to start\n", argv0, h);
- return nil;
- }
- static void portdetach(Hub *h, int p);
- /*
- * If during enumeration we get an I/O error the hub is gone or
- * in pretty bad shape. Because of retries of failed usb commands
- * (and the sleeps they include) it can take a while to detach all
- * ports for the hub. This detaches all ports and makes the hub void.
- * The parent hub will detect a detach (probably right now) and
- * close it later.
- */
- static void
- hubfail(Hub *h)
- {
- int i;
- for(i = 1; i <= h->nport; i++)
- portdetach(h, i);
- h->failed = 1;
- }
- static void
- closehub(Hub *h)
- {
- Hub **hl;
- dprint(2, "%s: closing hub %#p\n", argv0, h);
- for(hl = &hubs; *hl != nil; hl = &(*hl)->next)
- if(*hl == h)
- break;
- if(*hl == nil)
- sysfatal("closehub: no hub");
- *hl = h->next;
- nhubs--;
- hubfail(h); /* detach all ports */
- free(h->port);
- assert(h->dev != nil);
- devctl(h->dev, "detach");
- closedev(h->dev);
- free(h);
- }
- static int
- portstatus(Hub *h, int p)
- {
- Dev *d;
- uint8_t buf[4];
- int t;
- int sts;
- int dbg;
- dbg = usbdebug;
- if(dbg != 0 && dbg < 4)
- usbdebug = 1; /* do not be too chatty */
- d = h->dev;
- t = Rd2h|Rclass|Rother;
- if(usbcmd(d, t, Rgetstatus, 0, p, buf, sizeof(buf)) < 0)
- sts = -1;
- else
- sts = GET2(buf);
- usbdebug = dbg;
- return sts;
- }
- static char*
- stsstr(int sts)
- {
- static char s[80];
- char *e;
- e = s;
- if(sts&PSsuspend)
- *e++ = 'z';
- if(sts&PSreset)
- *e++ = 'r';
- if(sts&PSslow)
- *e++ = 'l';
- if(sts&PShigh)
- *e++ = 'h';
- if(sts&PSchange)
- *e++ = 'c';
- if(sts&PSenable)
- *e++ = 'e';
- if(sts&PSstatuschg)
- *e++ = 's';
- if(sts&PSpresent)
- *e++ = 'p';
- if(e == s)
- *e++ = '-';
- *e = 0;
- return s;
- }
- static int
- getmaxpkt(Dev *d, int islow)
- {
- uint8_t buf[64]; /* More room to try to get device-specific descriptors */
- DDev *dd;
- dd = (DDev*)buf;
- if(islow)
- dd->bMaxPacketSize0 = 8;
- else
- dd->bMaxPacketSize0 = 64;
- if(usbcmd(d, Rd2h|Rstd|Rdev, Rgetdesc, Ddev<<8|0, 0, buf, sizeof(buf)) < 0)
- return -1;
- return dd->bMaxPacketSize0;
- }
- /*
- * BUG: does not consider max. power avail.
- */
- static Dev*
- portattach(Hub *h, int p, int sts)
- {
- Dev *d;
- Port *pp;
- Dev *nd;
- char fname[80];
- char buf[40];
- char *sp;
- int mp;
- int nr;
- d = h->dev;
- pp = &h->port[p];
- nd = nil;
- pp->state = Pattached;
- dprint(2, "%s: %s: port %d attach sts %#x\n", argv0, d->dir, p, sts);
- sleep(Connectdelay);
- if(hubfeature(h, p, Fportenable, 1) < 0)
- dprint(2, "%s: %s: port %d: enable: %r\n", argv0, d->dir, p);
- sleep(Enabledelay);
- if(hubfeature(h, p, Fportreset, 1) < 0){
- dprint(2, "%s: %s: port %d: reset: %r\n", argv0, d->dir, p);
- goto Fail;
- }
- sleep(Resetdelay);
- sts = portstatus(h, p);
- if(sts < 0)
- goto Fail;
- if((sts & PSenable) == 0){
- dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p);
- hubfeature(h, p, Fportenable, 1);
- sts = portstatus(h, p);
- if((sts & PSenable) == 0)
- goto Fail;
- }
- sp = "full";
- if(sts & PSslow)
- sp = "low";
- if(sts & PShigh)
- sp = "high";
- dprint(2, "%s: %s: port %d: attached status %#x\n", argv0, d->dir, p, sts);
- if(devctl(d, "newdev %s %d", sp, p) < 0){
- fprint(2, "%s: %s: port %d: newdev: %r\n", argv0, d->dir, p);
- goto Fail;
- }
- seek(d->cfd, 0, 0);
- nr = read(d->cfd, buf, sizeof(buf)-1);
- if(nr == 0){
- fprint(2, "%s: %s: port %d: newdev: eof\n", argv0, d->dir, p);
- goto Fail;
- }
- if(nr < 0){
- fprint(2, "%s: %s: port %d: newdev: %r\n", argv0, d->dir, p);
- goto Fail;
- }
- buf[nr] = 0;
- snprint(fname, sizeof(fname), "/dev/usb/%s", buf);
- nd = opendev(fname);
- if(nd == nil){
- fprint(2, "%s: %s: port %d: opendev: %r\n", argv0, d->dir, p);
- goto Fail;
- }
- if(usbdebug > 2)
- devctl(nd, "debug 1");
- if(opendevdata(nd, ORDWR) < 0){
- fprint(2, "%s: %s: opendevdata: %r\n", argv0, nd->dir);
- goto Fail;
- }
- if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetaddress, nd->id, 0, nil, 0) < 0){
- dprint(2, "%s: %s: port %d: setaddress: %r\n", argv0, d->dir, p);
- goto Fail;
- }
- if(devctl(nd, "address") < 0){
- dprint(2, "%s: %s: port %d: set address: %r\n", argv0, d->dir, p);
- goto Fail;
- }
- mp=getmaxpkt(nd, strcmp(sp, "low") == 0);
- if(mp < 0){
- dprint(2, "%s: %s: port %d: getmaxpkt: %r\n", argv0, d->dir, p);
- goto Fail;
- }else{
- dprint(2, "%s; %s: port %d: maxpkt %d\n", argv0, d->dir, p, mp);
- devctl(nd, "maxpkt %d", mp);
- }
- if((sts & PSslow) != 0 && strcmp(sp, "full") == 0)
- dprint(2, "%s: %s: port %d: %s is full speed when port is low\n",
- argv0, d->dir, p, nd->dir);
- if(configdev(nd) < 0){
- dprint(2, "%s: %s: port %d: configdev: %r\n", argv0, d->dir, p);
- goto Fail;
- }
- /*
- * We always set conf #1. BUG.
- */
- if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0){
- dprint(2, "%s: %s: port %d: setconf: %r\n", argv0, d->dir, p);
- unstall(nd, nd, Eout);
- if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0)
- goto Fail;
- }
- dprint(2, "%s: %U\n", argv0, nd);
- pp->state = Pconfiged;
- dprint(2, "%s: %s: port %d: configed: %s\n",
- argv0, d->dir, p, nd->dir);
- return pp->dev = nd;
- Fail:
- pp->state = Pdisabled;
- pp->sts = 0;
- if(pp->hub != nil)
- pp->hub = nil; /* hub closed by enumhub */
- hubfeature(h, p, Fportenable, 0);
- if(nd != nil)
- devctl(nd, "detach");
- closedev(nd);
- return nil;
- }
- static void
- portdetach(Hub *h, int p)
- {
- Dev *d;
- Port *pp;
- extern void usbfsgone(char*);
- d = h->dev;
- pp = &h->port[p];
- /*
- * Clear present, so that we detect an attach on reconnects.
- */
- pp->sts &= ~(PSpresent|PSenable);
- if(pp->state == Pdisabled)
- return;
- pp->state = Pdisabled;
- dprint(2, "%s: %s: port %d: detached\n", argv0, d->dir, p);
- if(pp->hub != nil){
- closehub(pp->hub);
- pp->hub = nil;
- }
- if(pp->devmaskp != nil)
- putdevnb(pp->devmaskp, pp->devnb);
- pp->devmaskp = nil;
- if(pp->dev != nil){
- devctl(pp->dev, "detach");
- usbfsgone(pp->dev->dir);
- closedev(pp->dev);
- pp->dev = nil;
- }
- }
- /*
- * The next two functions are included to
- * perform a port reset asked for by someone (usually a driver).
- * This must be done while no other device is in using the
- * configuration address and with care to keep the old address.
- * To keep drivers decoupled from usbd they write the reset request
- * to the #u/usb/epN.0/ctl file and then exit.
- * This is unfortunate because usbd must now poll twice as much.
- *
- * An alternative to this reset process would be for the driver to detach
- * the device. The next function could see that, issue a port reset, and
- * then restart the driver once to see if it's a temporary error.
- *
- * The real fix would be to use interrupt endpoints for non-root hubs
- * (would probably make some hubs fail) and add an events file to
- * the kernel to report events to usbd. This is a severe change not
- * yet implemented.
- */
- static int
- portresetwanted(Hub *h, int p)
- {
- char buf[5];
- Port *pp;
- Dev *nd;
- pp = &h->port[p];
- nd = pp->dev;
- if(nd != nil && nd->cfd >= 0 && pread(nd->cfd, buf, 5, 0LL) == 5)
- return strncmp(buf, "reset", 5) == 0;
- else
- return 0;
- }
- static void
- portreset(Hub *h, int p)
- {
- int sts;
- Dev *d, *nd;
- Port *pp;
- d = h->dev;
- pp = &h->port[p];
- nd = pp->dev;
- dprint(2, "%s: %s: port %d: resetting\n", argv0, d->dir, p);
- if(hubfeature(h, p, Fportreset, 1) < 0){
- dprint(2, "%s: %s: port %d: reset: %r\n", argv0, d->dir, p);
- goto Fail;
- }
- sleep(Resetdelay);
- sts = portstatus(h, p);
- if(sts < 0)
- goto Fail;
- if((sts & PSenable) == 0){
- dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p);
- hubfeature(h, p, Fportenable, 1);
- sts = portstatus(h, p);
- if((sts & PSenable) == 0)
- goto Fail;
- }
- nd = pp->dev;
- opendevdata(nd, ORDWR);
- if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetaddress, nd->id, 0, nil, 0) < 0){
- dprint(2, "%s: %s: port %d: setaddress: %r\n", argv0, d->dir, p);
- goto Fail;
- }
- if(devctl(nd, "address") < 0){
- dprint(2, "%s: %s: port %d: set address: %r\n", argv0, d->dir, p);
- goto Fail;
- }
- if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0){
- dprint(2, "%s: %s: port %d: setconf: %r\n", argv0, d->dir, p);
- unstall(nd, nd, Eout);
- if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0)
- goto Fail;
- }
- if(nd->dfd >= 0)
- close(nd->dfd);
- return;
- Fail:
- pp->state = Pdisabled;
- pp->sts = 0;
- if(pp->hub != nil)
- pp->hub = nil; /* hub closed by enumhub */
- hubfeature(h, p, Fportenable, 0);
- if(nd != nil)
- devctl(nd, "detach");
- closedev(nd);
- }
- static int
- portgone(Port *pp, int sts)
- {
- if(sts < 0)
- return 1;
- /*
- * If it was enabled and it's not now then it may be reconnect.
- * We pretend it's gone and later we'll see it as attached.
- */
- if((pp->sts & PSenable) != 0 && (sts & PSenable) == 0)
- return 1;
- return (pp->sts & PSpresent) != 0 && (sts & PSpresent) == 0;
- }
- static int
- enumhub(Hub *h, int p)
- {
- int sts;
- Dev *d;
- Port *pp;
- int onhubs;
- if(h->failed)
- return 0;
- d = h->dev;
- if(usbdebug > 3)
- fprint(2, "%s: %s: port %d enumhub\n", argv0, d->dir, p);
- sts = portstatus(h, p);
- if(sts < 0){
- hubfail(h); /* avoid delays on detachment */
- return -1;
- }
- pp = &h->port[p];
- onhubs = nhubs;
- if((sts & PSsuspend) != 0){
- if(hubfeature(h, p, Fportenable, 1) < 0)
- dprint(2, "%s: %s: port %d: enable: %r\n", argv0, d->dir, p);
- sleep(Enabledelay);
- sts = portstatus(h, p);
- fprint(2, "%s: %s: port %d: resumed (sts %#x)\n", argv0, d->dir, p, sts);
- }
- if((pp->sts & PSpresent) == 0 && (sts & PSpresent) != 0){
- if(portattach(h, p, sts) != nil)
- if(startdev(pp) < 0)
- portdetach(h, p);
- }else if(portgone(pp, sts))
- portdetach(h, p);
- else if(portresetwanted(h, p))
- portreset(h, p);
- else if(pp->sts != sts){
- dprint(2, "%s: %s port %d: sts %s %#x ->",
- argv0, d->dir, p, stsstr(pp->sts), pp->sts);
- dprint(2, " %s %#x\n",stsstr(sts), sts);
- }
- pp->sts = sts;
- if(onhubs != nhubs)
- return -1;
- return 0;
- }
- static void
- dump(void)
- {
- Hub *h;
- int i;
- mustdump = 0;
- for(h = hubs; h != nil; h = h->next)
- for(i = 1; i <= h->nport; i++)
- fprint(2, "%s: hub %#p %s port %d: %U",
- argv0, h, h->dev->dir, i, h->port[i].dev);
- usbfsdirdump();
- }
- static void
- work(void *a)
- {
- Channel *portc;
- char *fn;
- Hub *h;
- int i;
- portc = a;
- threadsetname("work");
- hubs = nil;
- /*
- * Receive requests for root hubs
- */
- while((fn = recvp(portc)) != nil){
- dprint(2, "%s: %s starting\n", argv0, fn);
- h = newhub(fn, nil);
- if(h == nil)
- fprint(2, "%s: %s: newhub failed: %r\n", argv0, fn);
- free(fn);
- }
- /*
- * Enumerate (and acknowledge after first enumeration).
- * Do NOT perform enumeration concurrently for the same
- * controller. new devices attached respond to a default
- * address (0) after reset, thus enumeration has to work
- * one device at a time at least before addresses have been
- * assigned.
- * Do not use hub interrupt endpoint because we
- * have to poll the root hub(s) in any case.
- */
- for(;;){
- Again:
- for(h = hubs; h != nil; h = h->next)
- for(i = 1; i <= h->nport; i++)
- if(enumhub(h, i) < 0){
- /* changes in hub list; repeat */
- goto Again;
- }
- if(portc != nil){
- sendp(portc, nil);
- portc = nil;
- }
- sleep(pollms);
- if(mustdump)
- dump();
- }
- }
- static int
- cfswalk(Usbfs*_1, Fid *_2, char *_3)
- {
- werrstr(Enotfound);
- return -1;
- }
- static int
- cfsopen(Usbfs*_1, Fid *_2, int _3)
- {
- return 0;
- }
- static int32_t
- cfsread(Usbfs*_1, Fid *_2, void *_3, int32_t _4, int64_t _5)
- {
- return 0;
- }
- static void
- setdrvargs(char *name, char *args)
- {
- Devtab *dt;
- extern Devtab devtab[];
- for(dt = devtab; dt->name != nil; dt++)
- if(strstr(dt->name, name) != nil)
- dt->args = estrdup(args);
- }
- static void
- setdrvauto(char *name, int on)
- {
- Devtab *dt;
- extern Devtab devtab[];
- for(dt = devtab; dt->name != nil; dt++)
- if(strstr(dt->name, name) != nil)
- dt->noauto = !on;
- }
- static int32_t
- cfswrite(Usbfs*_1, Fid *_2, void *data, int32_t cnt, int64_t _3)
- {
- char *cmd, *arg;
- char buf[80];
- char *toks[4];
- if(cnt > sizeof(buf))
- cnt = sizeof(buf) - 1;
- strncpy(buf, data, cnt);
- buf[cnt] = 0;
- if(cnt > 0 && buf[cnt-1] == '\n')
- buf[cnt-1] = 0;
- if(strncmp(buf, "dump", 4) == 0){
- mustdump = 1;
- return cnt;
- }
- if(strncmp(buf, "reset", 5) == 0){
- werrstr("reset not implemented");
- return -1;
- }
- if(strncmp(buf, "exit", 4) == 0){
- threadexitsall(nil);
- return cnt;
- }
- if(tokenize(buf, toks, nelem(toks)) != 2){
- werrstr("usage: auto|debug|diskargs|fsdebug|kbargs|noauto n");
- return -1;
- }
- cmd = toks[0];
- arg = toks[1];
- if(strcmp(cmd, "auto") == 0)
- setdrvauto(arg, 1);
- else if(strcmp(cmd, "debug") == 0)
- usbdebug = atoi(arg);
- else if(strcmp(cmd, "diskargs") == 0)
- setdrvargs("disk", arg);
- else if(strcmp(cmd, "etherargs") == 0)
- setdrvargs("ether", arg);
- else if(strcmp(cmd, "fsdebug") == 0)
- usbfsdebug = atoi(arg);
- else if(strcmp(cmd, "kbargs") == 0)
- setdrvargs("kb", arg);
- else if(strcmp(cmd, "noauto") == 0)
- setdrvauto(arg, 0);
- else{
- werrstr("unknown ctl '%s'", buf);
- return -1;
- }
- fprint(2, "%s: debug %d fsdebug %d\n", argv0, usbdebug, usbfsdebug);
- return cnt;
- }
- static int
- cfsstat(Usbfs* fs, Qid qid, Dir *d)
- {
- d->qid = qid;
- d->qid.path |= fs->qid;
- d->qid.type = 0;
- d->qid.vers = 0;
- d->name = "usbdctl";
- d->length = 0;
- d->mode = 0664;
- return 0;
- }
- static Usbfs ctlfs =
- {
- .walk = cfswalk,
- .open = cfsopen,
- .read = cfsread,
- .write = cfswrite,
- .stat = cfsstat
- };
- static void
- getenvint(char *env, int *lp)
- {
- char *s;
- s = getenv(env);
- if (s != nil)
- *lp = atoi(s);
- free(s);
- }
- static void
- getenvdrvargs(char *env, char *argname)
- {
- char *s;
- s = getenv(env);
- if(s != nil)
- setdrvargs(argname, s);
- free(s);
- }
- static void
- args(void)
- {
- getenvint("usbdebug", &usbdebug);
- getenvint("usbfsdebug", &usbfsdebug);
- getenvdrvargs("kbargs", "kb");
- getenvdrvargs("diskargs", "disk");
- getenvdrvargs("etherargs", "ether");
- }
- static void
- usage(void)
- {
- fprint(2, "usage: %s [-Dd] [-s srv] [-m mnt] [dev...]\n", argv0);
- threadexitsall("usage");
- }
- extern void usbfsexits(int);
- void
- threadmain(int argc, char **argv)
- {
- int fd, i, nd;
- char *err, *mnt, *srv;
- Dir *d;
- srv = "usb";
- mnt = "/dev";
- ARGBEGIN{
- case 'D':
- usbfsdebug++;
- break;
- case 'd':
- usbdebug++;
- break;
- case 's':
- srv = EARGF(usage());
- break;
- case 'i':
- pollms = atoi(EARGF(usage()));
- break;
- case 'm':
- mnt = EARGF(usage());
- break;
- default:
- usage();
- }ARGEND;
- if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0)
- sysfatal("#u: %r");
- args();
- fmtinstall('U', Ufmt);
- quotefmtinstall();
- rfork(RFNOTEG);
- portc = chancreate(sizeof(char *), 0);
- if(portc == nil)
- sysfatal("chancreate");
- proccreate(work, portc, Stack);
- if(argc == 0){
- fd = open("/dev/usb", OREAD);
- if(fd < 0)
- sysfatal("/dev/usb: %r");
- nd = dirreadall(fd, &d);
- close(fd);
- if(nd < 2)
- sysfatal("/dev/usb: no hubs");
- for(i = 0; i < nd; i++)
- if(strcmp(d[i].name, "ctl") != 0)
- sendp(portc, smprint("/dev/usb/%s", d[i].name));
- free(d);
- }else
- for(i = 0; i < argc; i++)
- sendp(portc, strdup(argv[i]));
- sendp(portc, nil);
- err = recvp(portc);
- chanfree(portc);
- usbfsexits(0);
- usbfsinit(srv, mnt, &usbdirfs, MAFTER);
- snprint(ctlfs.name, sizeof(ctlfs.name), "usbdctl");
- usbfsadd(&ctlfs);
- threadexits(err);
- }
|