21 static char Enonexist[] = "does not exist";
23 typedef struct Event Event;
26 Dev *dev; /* the device producing the event,
27 dev->aux points to Fid processing the event */
31 int ref; /* number of readers which will read this one
32 the next time they'll read */
33 int prev; /* number of events pointing to this one with
34 their link pointers */
38 static Req *reqfirst, *reqlast;
53 fulfill(Req *req, Event *e)
58 if(n > req->ifcall.count)
59 n = req->ifcall.count;
60 memmove(req->ofcall.data, e->data, n);
61 req->ofcall.count = n;
67 evlast = emallocz(sizeof(Event), 1);
93 for(p = nil, r = reqfirst; r != nil; p = r, r = x){
100 e->dev->aux = nil; /* release device */
107 if(e->dev->aux == nil){
108 e->dev->aux = f; /* claim device */
124 pushevent(Dev *d, char *data)
130 evlast = emallocz(sizeof(Event), 1);
134 e->len = strlen(data);
143 dirgen(int n, Dir *d, void *)
154 d->mode = 0555 | DMDIR;
156 d->uid = estrdup9p(getuser());
157 d->gid = estrdup9p(d->uid);
158 d->muid = estrdup9p(d->uid);
159 d->name = estrdup9p(names[n+1]);
160 d->atime = d->mtime = time(0);
168 req->fid->qid = (Qid) {Qroot, 0, QTDIR};
169 req->ofcall.qid = req->fid->qid;
174 usbdwalk(Fid *fid, char *name, Qid *qid)
178 if(fid->qid.path != Qroot)
179 return "not a directory";
180 if(strcmp(name, "..") == 0){
184 for(i = Qroot+1; i < Qmax; i++)
185 if(strcmp(name, names[i]) == 0){
186 fid->qid = (Qid) {i, 0, 0};
196 switch((long)req->fid->qid.path){
198 dirread9p(req, dirgen, nil);
208 respond(req, Enonexist);
216 if(dirgen(req->fid->qid.path - 1, &req->d, nil) < 0)
217 respond(req, Enonexist);
223 formatdev(Dev *d, int type)
226 return smprint("%s %d %.4x %.4x %.6lx %s\n",
227 type ? "detach" : "attach",
228 d->id, u->vid, u->did, u->csp,
229 d->hname != nil ? d->hname : "");
243 for(h = hubs; h != nil; h = h->next){
244 for(i = 1; i <= h->nport; i++){
247 if(d == nil || d->usb == nil || p->hub != nil)
249 e = emallocz(sizeof(Event), 1);
252 e->data = formatdev(d, 0);
253 e->len = strlen(e->data);
267 extern QLock hublock;
269 if(req->fid->qid.path == Qusbevent){
287 usbddestroyfid(Fid *fid)
289 if(fid->qid.path == Qusbevent){
296 if(e->dev != nil && e->dev->aux == fid){
297 e->dev->aux = nil; /* release device */
301 while(e->ref == 0 && e->prev == 0 && e != evlast)
314 for(p = nil, r = reqfirst; r != nil; p = r, r = x){
316 if(r == req->oldreq){
324 respond(r, "interrupted");
333 .attach = usbdattach,
339 .destroyfid = usbddestroyfid,
343 assignhname(Dev *dev)
353 /* build string of device unique stuff */
354 snprint(buf, sizeof(buf), "%.4x%.4x%.4x%.6lx%s",
355 ud->vid, ud->did, ud->dno, ud->csp, ud->serial);
359 /* check for collisions */
360 for(h = hubs; h != nil; h = h->next){
361 for(i = 1; i <= h->nport; i++){
362 if(h->port[i].dev == nil)
364 if(h->port[i].dev->hname == nil || h->port[i].dev == dev)
366 if(strcmp(h->port[i].dev->hname, buf) == 0){
367 dev->hname = smprint("%s%d", buf, dev->id);
372 dev->hname = strdup(buf);
381 if(d->usb->class == Clhub){
383 * Hubs are handled directly by this process avoiding
384 * concurrent operation so that at most one device
385 * has the config address in use.
386 * We cancel kernel debug for these eps. too chatty.
388 if((p->hub = newhub(d->dir, d)) == nil)
393 /* create all endpoint files for default conf #1 */
394 for(id=1; id<nelem(d->usb->ep); id++){
395 Ep *ep = d->usb->ep[id];
396 if(ep != nil && ep->conf != nil && ep->conf->cval == 1){
397 Dev *epd = openep(d, id);
403 /* close control endpoint so driver can open it */
407 /* assign stable name based on device descriptor */
410 /* set device info for ctl file */
411 devctl(d, "info %s csp %#08lux vid %#.4ux did %#.4ux %q %q %s",
412 classname(Class(d->usb->csp)), d->usb->csp, d->usb->vid, d->usb->did,
413 d->usb->vendor, d->usb->product, d->hname);
415 pushevent(d, formatdev(d, 0));
424 if(d->usb->class == Clhub)
426 pushevent(d, formatdev(d, 1));
430 * we create /env/usbbusy on startup and once all devices have been
431 * enumerated and readers have consumed all the events, we remove the
432 * file so nusbrc can continue.
434 static int busyfd = -1;
439 if(busyfd < 0 || reqlast == nil || evlast == nil || evlast->prev > 0)
447 main(int argc, char **argv)
461 busyfd = create("/env/usbbusy", ORCLOSE, 0600);
465 switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
466 case -1: sysfatal("rfork: %r");
467 case 0: work(); exits(nil);
470 if((fd = open("/dev/usb", OREAD)) < 0){
471 rendezvous(work, nil);
472 sysfatal("/dev/usb: %r");
474 nd = dirreadall(fd, &d);
477 rendezvous(work, nil);
478 sysfatal("/dev/usb: no hubs");
480 for(i = 0; i < nd; i++)
481 if(strcmp(d[i].name, "ctl") != 0)
482 rendezvous(work, smprint("/dev/usb/%s", d[i].name));
485 for(i = 0; i < argc; i++)
486 rendezvous(work, estrdup9p(argv[i]));
487 rendezvous(work, nil);
488 postsharesrv(&usbdsrv, nil, "usb", "usbd");