]> 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 297cd3db96c0891614e76669b5d7a1293e201261..2e96df07f92a248bef1a11d1c7d0ad64bbe6eb74 100644 (file)
@@ -26,7 +26,10 @@ struct Event {
        char *data;
        int len;
        Event *link;
-       int ref, prev;
+       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 *evlast;
@@ -59,7 +62,21 @@ fulfill(Req *req, Event *e)
 static void
 initevent(void)
 {
-       evlast = mallocz(sizeof(Event), 1);
+       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
@@ -77,11 +94,8 @@ readevent(Req *req)
        fulfill(req, e);
        req->fid->aux = e->link;
        e->link->ref++;
-       if(--e->ref == 0 && e->prev == 0){
-               e->link->prev--;
-               free(e->data);
-               free(e);
-       }
+       e->ref--;
+       putevent(e);
        qunlock(&evlock);
        respond(req, nil);
 }
@@ -95,8 +109,6 @@ 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);
@@ -111,11 +123,7 @@ pushevent(char *data)
                fulfill(r, e);
                respond(r, nil);
        }
-       if(e->ref == 0 && e->prev == 0){
-               ee->prev--;
-               free(e->data);
-               free(e);
-       }
+       putevent(e);
        reqfirst = nil;
        reqlast = nil;
        qunlock(&evlock);
@@ -180,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:
@@ -198,35 +210,37 @@ usbdstat(Req *req)
 }
 
 static char *
-formatdev(Dev *d)
+formatdev(Dev *d, int type)
 {
        Usbdev *u;
        
        u = d->usb;
-       return smprint("in id %d vid 0x%.4x did 0x%.4x csp 0x%.8lx\n",
-               d->id, u->vid, u->did, u->csp);
+       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;
-       extern Hub *hubs;
+       int i;
        
        for(h = hubs; h != nil; h = h->next){
-               for(p = h->port; p < h->port + h->nport; p++){
+               for(i = 1; i <= h->nport; i++){
+                       p = &h->port[i];
+
                        if(p->dev == nil || p->dev->usb == nil || p->hub != nil)
                                continue;
-                       e = mallocz(sizeof(Event), 1);
-                       if(e == nil)
-                               sysfatal("malloc: %r");
-                       e->data = formatdev(p->dev);
+                       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;
@@ -236,12 +250,21 @@ enumerate(Event **l)
 static void
 usbdopen(Req *req)
 {
+       extern QLock hublock;
+
        if(req->fid->qid.path == Qusbevent){
+               Event *e;
+
+               qlock(&hublock);
                qlock(&evlock);
+
                enumerate(&req->fid->aux);
-               ((Event *)req->fid->aux)->ref++;
-               ((Event *)req->fid->aux)->prev--;
+               e = req->fid->aux;
+               e->ref++;
+               e->prev--;
+
                qunlock(&evlock);
+               qunlock(&hublock);
        }
        respond(req, nil);
 }
@@ -249,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->prev == 0){
-                       while(e->ref == 0 && e->prev == 0 && e != evlast){
-                               ee = e->link;
-                               ee->prev--;
-                               free(e->data);
-                               free(e);
-                               e = ee;
-                       }
-               }
+               if(--e->ref == 0 && e->prev == 0)
+                       while(e->ref == 0 && e->prev == 0 && e != evlast)
+                               e = putevent(e);
                qunlock(&evlock);
        }
 }
@@ -296,39 +313,66 @@ Srv usbdsrv = {
 };
 
 int
-startdev(Port *p)
+attachdev(Port *p)
 {
-       Dev *d;
+       Dev *d = p->dev;
 
-       if((d = p->dev) == nil || 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(formatdev(d));
+
+       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));
@@ -337,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);
 }