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;
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
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);
}
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;
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);
respond(req, nil);
break;
case Qusbevent:
+ if(req->fid->aux == nil){
+ respond(req, "the front fell off");
+ return;
+ }
readevent(req);
break;
default:
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);
}
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);
}
}
};
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));
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);
}