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);
380 if(d->usb->class == Clhub){
382 * Hubs are handled directly by this process avoiding
383 * concurrent operation so that at most one device
384 * has the config address in use.
385 * We cancel kernel debug for these eps. too chatty.
387 if((p->hub = newhub(d->dir, d)) == nil)
392 /* close control endpoint so driver can open it */
396 /* assign stable name based on device descriptor */
399 /* set device info for ctl file */
400 devctl(d, "info %s csp %#08lux vid %#.4ux did %#.4ux %q %q %s",
401 classname(Class(d->usb->csp)), d->usb->csp, d->usb->vid, d->usb->did,
402 d->usb->vendor, d->usb->product, d->hname);
404 pushevent(d, formatdev(d, 0));
413 if(d->usb->class == Clhub)
415 pushevent(d, formatdev(d, 1));
419 * we create /env/usbbusy on startup and once all devices have been
420 * enumerated and readers have consumed all the events, we remove the
421 * file so nusbrc can continue.
423 static int busyfd = -1;
428 if(busyfd < 0 || reqlast == nil || evlast == nil || evlast->prev > 0)
436 main(int argc, char **argv)
450 busyfd = create("/env/usbbusy", ORCLOSE, 0600);
454 switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
455 case -1: sysfatal("rfork: %r");
456 case 0: work(); exits(nil);
459 if((fd = open("/dev/usb", OREAD)) < 0){
460 rendezvous(work, nil);
461 sysfatal("/dev/usb: %r");
463 nd = dirreadall(fd, &d);
466 rendezvous(work, nil);
467 sysfatal("/dev/usb: no hubs");
469 for(i = 0; i < nd; i++)
470 if(strcmp(d[i].name, "ctl") != 0)
471 rendezvous(work, smprint("/dev/usb/%s", d[i].name));
474 for(i = 0; i < argc; i++)
475 rendezvous(work, estrdup9p(argv[i]));
476 rendezvous(work, nil);
477 postsharesrv(&usbdsrv, nil, "usb", "usbd");