]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/cmd/nusb/usbd/usbd.c
nusbd: properly terminate worker proc if no hubs can be found
[plan9front.git] / sys / src / cmd / nusb / usbd / usbd.c
index 81aedcdb359894b25f9787bdb129358627cfe492..2e96df07f92a248bef1a11d1c7d0ad64bbe6eb74 100644 (file)
@@ -26,10 +26,13 @@ struct Event {
        char *data;
        int len;
        Event *link;
-       int ref;
+       int ref;  /* number of readers which will read this one
+                     the next time they'll read */
+       int prev; /* number of events pointing to this one with
+                     their link pointers */
 };
 
-static Event *evfirst, *evlast;
+static Event *evlast;
 static Req *reqfirst, *reqlast;
 static QLock evlock;
 
@@ -59,10 +62,21 @@ fulfill(Req *req, Event *e)
 static void
 initevent(void)
 {
-       evfirst = mallocz(sizeof(*evfirst), 1);
-       if(evfirst == nil)
-               sysfatal("malloc: %r");
-       evlast = evfirst;
+       evlast = emallocz(sizeof(Event), 1);
+}
+
+static Event*
+putevent(Event *e)
+{
+       Event *ee;
+
+       ee = e->link;
+       if(e->ref || e->prev)
+               return ee;
+       ee->prev--;
+       free(e->data);
+       free(e);
+       return ee;
 }
 
 static void
@@ -80,11 +94,8 @@ readevent(Req *req)
        fulfill(req, e);
        req->fid->aux = e->link;
        e->link->ref++;
-       if(--e->ref == 0 && e == evfirst){
-               evfirst = e->link;
-               free(e->data);
-               free(e);
-       }
+       e->ref--;
+       putevent(e);
        qunlock(&evlock);
        respond(req, nil);
 }
@@ -98,12 +109,11 @@ pushevent(char *data)
        qlock(&evlock);
        e = evlast;
        ee = emallocz(sizeof(Event), 1);
-       if(ee == nil)
-               sysfatal("malloc: %r");
        evlast = ee;
        e->data = data;
        e->len = strlen(data);
        e->link = ee;
+       ee->prev++;
        for(r = reqfirst; r != nil; r = rr){
                rr = r->aux;
                r->aux = nil;
@@ -113,11 +123,7 @@ pushevent(char *data)
                fulfill(r, e);
                respond(r, nil);
        }
-       if(e->ref == 0 && e == evfirst){
-               evfirst = ee;
-               free(e->data);
-               free(e);
-       }
+       putevent(e);
        reqfirst = nil;
        reqlast = nil;
        qunlock(&evlock);
@@ -182,6 +188,10 @@ usbdread(Req *req)
                respond(req, nil);
                break;
        case Qusbevent:
+               if(req->fid->aux == nil){
+                       respond(req, "the front fell off");
+                       return;
+               }
                readevent(req);
                break;
        default:
@@ -199,14 +209,62 @@ usbdstat(Req *req)
                respond(req, nil);
 }
 
+static char *
+formatdev(Dev *d, int type)
+{
+       Usbdev *u;
+       
+       u = d->usb;
+       return smprint("%s %d %.4x %.4x %.8lx\n", type ? "detach" : "attach", d->id, u->vid, u->did, u->csp);
+}
+
+static void
+enumerate(Event **l)
+{
+       extern Hub *hubs;
+
+       Event *e;
+       Hub *h;
+       Port *p;
+       int i;
+       
+       for(h = hubs; h != nil; h = h->next){
+               for(i = 1; i <= h->nport; i++){
+                       p = &h->port[i];
+
+                       if(p->dev == nil || p->dev->usb == nil || p->hub != nil)
+                               continue;
+                       e = emallocz(sizeof(Event), 1);
+                       e->data = formatdev(p->dev, 0);
+                       e->len = strlen(e->data);
+                       e->prev = 1;
+                       *l = e;
+                       l = &e->link;
+
+               }
+       }
+       *l = evlast;
+       evlast->prev++;
+}
+
 static void
 usbdopen(Req *req)
 {
+       extern QLock hublock;
+
        if(req->fid->qid.path == Qusbevent){
+               Event *e;
+
+               qlock(&hublock);
                qlock(&evlock);
-               req->fid->aux = evlast;
-               evlast->ref++;
+
+               enumerate(&req->fid->aux);
+               e = req->fid->aux;
+               e->ref++;
+               e->prev--;
+
                qunlock(&evlock);
+               qunlock(&hublock);
        }
        respond(req, nil);
 }
@@ -214,20 +272,14 @@ usbdopen(Req *req)
 static void
 usbddestroyfid(Fid *fid)
 {
-       Event *e, *ee;
+       Event *e;
 
-       if(fid->qid.path == Qusbevent){
+       if(fid->qid.path == Qusbevent && fid->aux != nil){
                qlock(&evlock);
                e = fid->aux;
-               if(--e->ref == 0 && e == evfirst){
-                       while(e->ref == 0 && e != evlast){
-                               ee = e->link;
-                               free(e->data);
-                               free(e);
-                               e = ee;
-                       }
-                       evfirst = e;
-               }
+               if(--e->ref == 0 && e->prev == 0)
+                       while(e->ref == 0 && e->prev == 0 && e != evlast)
+                               e = putevent(e);
                qunlock(&evlock);
        }
 }
@@ -261,42 +313,66 @@ Srv usbdsrv = {
 };
 
 int
-startdev(Port *p)
+attachdev(Port *p)
 {
-       Dev *d;
-       Usbdev *u;
+       Dev *d = p->dev;
 
-       if((d = p->dev) == nil || (u = p->dev->usb) == nil){
-               fprint(2, "okay what?\n");
-               return -1;
+       if(d->usb->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.
+                */
+               if((p->hub = newhub(d->dir, d)) == nil)
+                       return -1;
+               return 0;
        }
-       pushevent(smprint("in id %d vid 0x%.4x did 0x%.4x csp 0x%.8x\n",
-               d->id, u->vid, u->did, u->csp));
-       closedev(p->dev);
+
+       close(d->dfd);
+       d->dfd = -1;
+       pushevent(formatdev(d, 0));
        return 0;
 }
 
+void
+detachdev(Port *p)
+{
+       pushevent(formatdev(p->dev, 1));
+}
+
 void
 main(int argc, char **argv)
 {
        int fd, i, nd;
        Dir *d;
-       
-       argc--; argv++;
+
+       ARGBEGIN {
+       case 'D':
+               chatty9p++;
+               break;
+       case 'd':
+               usbdebug++;
+               break;
+       } ARGEND;
+
        initevent();
        rfork(RFNOTEG);
-       switch(rfork(RFPROC|RFMEM)){
+       switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
        case -1: sysfatal("rfork: %r");
        case 0: work(); exits(nil);
        }
        if(argc == 0){
-               fd = open("/dev/usb", OREAD);
-               if(fd < 0)
+               if((fd = open("/dev/usb", OREAD)) < 0){
+                       rendezvous(work, nil);
                        sysfatal("/dev/usb: %r");
+               }
                nd = dirreadall(fd, &d);
                close(fd);
-               if(nd < 2)
+               if(nd < 2){
+                       rendezvous(work, nil);
                        sysfatal("/dev/usb: no hubs");
+               }
                for(i = 0; i < nd; i++)
                        if(strcmp(d[i].name, "ctl") != 0)
                                rendezvous(work, smprint("/dev/usb/%s", d[i].name));
@@ -305,5 +381,6 @@ main(int argc, char **argv)
                for(i = 0; i < argc; i++)
                        rendezvous(work, strdup(argv[i]));
        rendezvous(work, nil);
-       postsharesrv(&usbdsrv, nil, "usb", "usbd", "b");
+       postsharesrv(&usbdsrv, nil, "usb", "usbd");
+       exits(nil);
 }