123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- /*
- * Framework for USB devices.
- * Some of them may be embedded into usbd and some of
- * them may exist as /bin/usb/* binaries on their own.
- *
- * When embedded, devmain() is given a ref of an already
- * configured and open Dev. If devmain()
- * does not fail it should release this ref when done and
- * use incref to add further refs to it.
- */
- #include <u.h>
- #include <libc.h>
- #include <thread.h>
- #include "usb.h"
- #include "usbd.h"
- static Lock masklck;
- extern Devtab devtab[];
- static char* cputype;
- int
- getdevnb(uvlong *maskp)
- {
- int i;
- lock(&masklck);
- for(i = 0; i < 8 * sizeof *maskp; i++)
- if((*maskp & (1ULL<<i)) == 0){
- *maskp |= 1ULL<<i;
- unlock(&masklck);
- return i;
- }
- unlock(&masklck);
- return -1;
- }
- void
- putdevnb(uvlong *maskp, int id)
- {
- lock(&masklck);
- if(id >= 0)
- *maskp &= ~(1ULL<<id);
- unlock(&masklck);
- }
-
- static int
- cspmatch(Devtab *dt, int dcsp)
- {
- int i;
- int csp;
- for(i = 0; i < nelem(dt->csps); i++)
- if((csp=dt->csps[i]) != 0)
- if(csp == dcsp)
- return 1;
- else if((csp&DCL) && (csp&~DCL) == Class(dcsp))
- return 1;
- return 0;
- }
- static int
- devmatch(Devtab *dt, Usbdev *d)
- {
- int i;
- int c;
- Conf *cp;
- if(dt->noauto)
- return 0;
- if(dt->vid != -1 && d->vid != dt->vid)
- return 0;
- if(dt->did != -1 && d->did != dt->did)
- return 0;
- if(cspmatch(dt, d->csp))
- return 1;
- for(c = 0; c < Nconf; c++)
- if((cp=d->conf[c]) != nil)
- for(i = 0; i < Niface; i++)
- if(cp->iface[i] != nil)
- if(cspmatch(dt, cp->iface[i]->csp))
- return 1;
- return 0;
- }
- /* We can't use procexec to execute drivers, because
- * procexec mounts #| at /mnt/temp and we do *not*
- * have /mnt/temp at boot time.
- * Instead, we use access to guess if we can execute the file.
- * and reply as procexec. Be careful that the child inherits
- * all the shared state of the thread library. It should run unnoticed.
- */
- static void
- xexec(Channel *c, char *nm, char *args[])
- {
- int pid;
- if(access(nm, AEXEC) == 0){
- pid = rfork(RFFDG|RFREND|RFPROC);
- switch(pid){
- case 0:
- exec(nm, args);
- _exits("exec");
- case -1:
- break;
- default:
- sendul(c, pid);
- threadexits(nil);
- }
- }
- }
- typedef struct Sarg Sarg;
- struct Sarg{
- Port *pp;
- Devtab* dt;
- Channel*rc;
- char fname[80];
- char args[128];
- char *argv[40];
- };
- static void
- startdevproc(void *a)
- {
- Sarg *sa = a;
- Dev *d;
- Devtab *dt;
- int argc;
- char *args, *argse, **argv;
- char *fname;
- threadsetgrp(threadid());
- d = sa->pp->dev;
- dt = sa->dt;
- args = sa->args;
- argse = sa->args + sizeof sa->args;
- argv = sa->argv;
- fname = sa->fname;
- sa->pp->devmaskp = &dt->devmask;
- sa->pp->devnb = getdevnb(&dt->devmask);
- if(sa->pp->devnb < 0){
- sa->pp->devmaskp = nil;
- sa->pp->devnb = 0;
- }else
- args = seprint(args, argse, "-N %d", sa->pp->devnb);
- if(dt->args != nil)
- seprint(args, argse, " %s", dt->args);
- args = sa->args;
- dprint(2, "%s: start: %s %s\n", argv0, dt->name, args);
- argv[0] = dt->name;
- argc = 1;
- if(args[0] != 0)
- argc += tokenize(args, argv+1, nelem(sa->argv)-2);
- argv[argc] = nil;
- if(dt->init == nil){
- if(d->dfd > 0 ){
- close(d->dfd);
- d->dfd = -1;
- }
- rfork(RFCFDG);
- open("/dev/null", OREAD);
- open("/dev/cons", OWRITE);
- open("/dev/cons", OWRITE);
- xexec(sa->rc, argv[0], argv);
- snprint(fname, sizeof(sa->fname), "/bin/usb/%s", dt->name);
- xexec(sa->rc, fname, argv);
- snprint(fname, sizeof(sa->fname), "/boot/%s", dt->name);
- xexec(sa->rc, fname, argv);
- if(cputype == nil)
- cputype = getenv("cputype");
- if(cputype != nil){
- snprint(fname, sizeof(sa->fname), "/%s/bin/%s",
- cputype, dt->name);
- argv[0] = fname;
- xexec(sa->rc, fname, argv);
- }
- fprint(2, "%s: %s: not found. can't exec\n", argv0, dt->name);
- sendul(sa->rc, -1);
- threadexits("exec");
- }else{
- sa->pp->dev = opendev(d->dir);
- sendul(sa->rc, 0);
- if(dt->init(d, argc, argv) < 0)
- fprint(2, "%s: %s: %r\n", argv0, dt->name);
- closedev(d);
- free(sa);
- }
- threadexits(nil);
- }
- static void
- writeinfo(Dev *d)
- {
- char buf[128];
- char *s;
- char *se;
- Usbdev *ud;
- Conf *c;
- Iface *ifc;
- int i, j;
- ud = d->usb;
- s = buf;
- se = buf+sizeof(buf);
- s = seprint(s, se, "info %s csp %#08ulx", classname(ud->class), ud->csp);
- for(i = 0; i < ud->nconf; i++){
- c = ud->conf[i];
- if(c == nil)
- break;
- for(j = 0; j < nelem(c->iface); j++){
- ifc = c->iface[j];
- if(ifc == nil)
- break;
- if(ifc->csp != ud->csp)
- s = seprint(s, se, " csp %#08ulx", ifc->csp);
- }
- }
- s = seprint(s, se, " vid %06#x did %06#x", ud->vid, ud->did);
- seprint(s, se, " %q %q", ud->vendor, ud->product);
- devctl(d, "%s", buf);
- }
- int
- startdev(Port *pp)
- {
- Dev *d;
- Usbdev *ud;
- Devtab *dt;
- Sarg *sa;
- Channel *rc;
- d = pp->dev;
- assert(d);
- ud = d->usb;
- assert(ud != nil);
- writeinfo(d);
- if(ud->class == Clhub){
- /*
- * Hubs are handled directly by this process avoiding
- * concurrent operation so that at most one device
- * has the config address in use.
- * We cancel kernel debug for these eps. too chatty.
- */
- pp->hub = newhub(d->dir, d);
- if(pp->hub == nil)
- fprint(2, "%s: %s: %r\n", argv0, d->dir);
- else
- fprint(2, "usb/hub... ");
- if(usbdebug > 1)
- devctl(d, "debug 0"); /* polled hubs are chatty */
- return pp->hub == nil ? -1 : 0;
- }
- for(dt = devtab; dt->name != nil; dt++)
- if(devmatch(dt, ud))
- break;
- /*
- * From here on the device is for the driver.
- * When we return pp->dev contains a Dev just for us
- * with only the ctl open. Both devs are released on the last closedev:
- * driver's upon I/O errors and ours upon port dettach.
- */
- if(dt->name == nil){
- dprint(2, "%s: no configured entry for %s (csp %#08lx)\n",
- argv0, d->dir, ud->csp);
- close(d->dfd);
- d->dfd = -1;
- return 0;
- }
- sa = emallocz(sizeof(Sarg), 1);
- sa->pp = pp;
- sa->dt = dt;
- rc = sa->rc = chancreate(sizeof(ulong), 1);
- procrfork(startdevproc, sa, Stack, RFNOTEG);
- if(recvul(rc) != 0)
- free(sa);
- chanfree(rc);
- fprint(2, "usb/%s... ", dt->name);
- sleep(Spawndelay); /* in case we re-spawn too fast */
- return 0;
- }
|