]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/nusb/usbd/usbd.c
nusb: debug flags
[plan9front.git] / sys / src / cmd / nusb / usbd / usbd.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <fcall.h>
5 #include <9p.h>
6 #include "usb.h"
7 #include "dat.h"
8 #include "fns.h"
9
10 enum {
11         Qroot,
12         Qusbevent,
13         Qmax
14 };
15
16 char *names[] = {
17         "",
18         "usbevent",
19 };
20
21 static char Enonexist[] = "does not exist";
22
23 typedef struct Event Event;
24
25 struct Event {
26         char *data;
27         int len;
28         Event *link;
29         int ref;  /* number of readers which will read this one
30                      the next time they'll read */
31         int prev; /* number of events pointing to this one with
32                      their link pointers */
33 };
34
35 static Event *evlast;
36 static Req *reqfirst, *reqlast;
37 static QLock evlock;
38
39 static void
40 addreader(Req *req)
41 {
42         req->aux = nil;
43         if(reqfirst == nil)
44                 reqfirst = req;
45         else
46                 reqlast->aux = req;
47         reqlast = req;
48 }
49
50 static void
51 fulfill(Req *req, Event *e)
52 {
53         int n;
54         
55         n = e->len;
56         if(n > req->ifcall.count)
57                 n = req->ifcall.count;
58         memmove(req->ofcall.data, e->data, n);
59         req->ofcall.count = n;
60 }
61
62 static void
63 initevent(void)
64 {
65         evlast = emallocz(sizeof(Event), 1);
66 }
67
68 static Event*
69 putevent(Event *e)
70 {
71         Event *ee;
72
73         ee = e->link;
74         if(e->ref || e->prev)
75                 return ee;
76         ee->prev--;
77         free(e->data);
78         free(e);
79         return ee;
80 }
81
82 static void
83 readevent(Req *req)
84 {
85         Event *e;
86
87         qlock(&evlock);
88         e = req->fid->aux;
89         if(e == evlast){
90                 addreader(req);
91                 qunlock(&evlock);
92                 return;
93         }
94         fulfill(req, e);
95         req->fid->aux = e->link;
96         e->link->ref++;
97         e->ref--;
98         putevent(e);
99         qunlock(&evlock);
100         respond(req, nil);
101 }
102
103 static void
104 pushevent(char *data)
105 {
106         Event *e, *ee;
107         Req *r, *rr;
108         
109         qlock(&evlock);
110         e = evlast;
111         ee = emallocz(sizeof(Event), 1);
112         evlast = ee;
113         e->data = data;
114         e->len = strlen(data);
115         e->link = ee;
116         ee->prev++;
117         for(r = reqfirst; r != nil; r = rr){
118                 rr = r->aux;
119                 r->aux = nil;
120                 r->fid->aux = ee;
121                 ee->ref++;
122                 e->ref--;
123                 fulfill(r, e);
124                 respond(r, nil);
125         }
126         putevent(e);
127         reqfirst = nil;
128         reqlast = nil;
129         qunlock(&evlock);
130 }
131
132 static int
133 dirgen(int n, Dir *d, void *)
134 {
135         if(n >= Qmax - 1)
136                 return -1;
137         d->qid.path = n + 1;
138         d->qid.vers = 0;
139         if(n >= 0)
140                 d->qid.type = 0;
141         else
142                 d->qid.type = QTDIR;
143         d->uid = strdup(getuser());
144         d->gid = strdup(d->uid);
145         d->muid = strdup(d->uid);
146         d->name = strdup(names[n+1]);
147         d->mode = 0555 | (d->qid.type << 24);
148         d->atime = d->mtime = time(0);
149         d->length = 0;
150         return 0;
151 }
152
153 static void
154 usbdattach(Req *req)
155 {
156         req->fid->qid = (Qid) {Qroot, 0, QTDIR};
157         req->ofcall.qid = req->fid->qid;
158         respond(req, nil);
159 }
160
161 static char *
162 usbdwalk(Fid *fid, char *name, Qid *qid)
163 {
164         int i;
165
166         if(strcmp(name, "..") == 0){
167                 fid->qid = (Qid) {Qroot, 0, QTDIR};
168                 *qid = fid->qid;
169                 return nil;
170         }
171         if(fid->qid.path != Qroot)
172                 return "not a directory";
173         for(i = 0; i < Qmax; i++)
174                 if(strcmp(name, names[i]) == 0){
175                         fid->qid = (Qid) {i, 0, 0};
176                         *qid = fid->qid;
177                         return nil;
178                 }
179         return "does not exist";
180 }
181
182 static void
183 usbdread(Req *req)
184 {
185         switch((long)req->fid->qid.path){
186         case Qroot:
187                 dirread9p(req, dirgen, nil);
188                 respond(req, nil);
189                 break;
190         case Qusbevent:
191                 if(req->fid->aux == nil){
192                         respond(req, "the front fell off");
193                         return;
194                 }
195                 readevent(req);
196                 break;
197         default:
198                 respond(req, Enonexist);
199                 break;
200         }
201 }
202
203 static void
204 usbdstat(Req *req)
205 {
206         if(dirgen(req->fid->qid.path - 1, &req->d, nil) < 0)
207                 respond(req, "the front fell off");
208         else
209                 respond(req, nil);
210 }
211
212 static char *
213 formatdev(Dev *d, int type)
214 {
215         Usbdev *u;
216         
217         u = d->usb;
218         return smprint("%s %d %.4x %.4x %.8lx\n", type ? "detach" : "attach", d->id, u->vid, u->did, u->csp);
219 }
220
221 static void
222 enumerate(Event **l)
223 {
224         extern Hub *hubs;
225
226         Event *e;
227         Hub *h;
228         Port *p;
229         int i;
230         
231         for(h = hubs; h != nil; h = h->next){
232                 for(i = 1; i <= h->nport; i++){
233                         p = &h->port[i];
234
235                         if(p->dev == nil || p->dev->usb == nil || p->hub != nil)
236                                 continue;
237                         e = emallocz(sizeof(Event), 1);
238                         e->data = formatdev(p->dev, 0);
239                         e->len = strlen(e->data);
240                         e->prev = 1;
241                         *l = e;
242                         l = &e->link;
243
244                 }
245         }
246         *l = evlast;
247         evlast->prev++;
248 }
249
250 static void
251 usbdopen(Req *req)
252 {
253         extern QLock hublock;
254
255         if(req->fid->qid.path == Qusbevent){
256                 Event *e;
257
258                 qlock(&hublock);
259                 qlock(&evlock);
260
261                 enumerate(&req->fid->aux);
262                 e = req->fid->aux;
263                 e->ref++;
264                 e->prev--;
265
266                 qunlock(&evlock);
267                 qunlock(&hublock);
268         }
269         respond(req, nil);
270 }
271
272 static void
273 usbddestroyfid(Fid *fid)
274 {
275         Event *e;
276
277         if(fid->qid.path == Qusbevent && fid->aux != nil){
278                 qlock(&evlock);
279                 e = fid->aux;
280                 if(--e->ref == 0 && e->prev == 0)
281                         while(e->ref == 0 && e->prev == 0 && e != evlast)
282                                 e = putevent(e);
283                 qunlock(&evlock);
284         }
285 }
286
287 static void
288 usbdflush(Req *req)
289 {
290         Req **l, *r;
291         qlock(&evlock);
292         l = &reqfirst;
293         while(r = *l){
294                 if(r == req->oldreq){
295                         *l = r->aux;
296                         break;
297                 }
298                 l = &r->aux;
299         }
300         qunlock(&evlock);
301         respond(req->oldreq, "interrupted");
302         respond(req, nil);
303 }
304
305 Srv usbdsrv = {
306         .attach = usbdattach,
307         .walk1 = usbdwalk,
308         .read = usbdread,
309         .stat = usbdstat,
310         .open = usbdopen,
311         .flush = usbdflush,
312         .destroyfid = usbddestroyfid,
313 };
314
315 int
316 attachdev(Port *p)
317 {
318         Dev *d = p->dev;
319
320         if(d->usb->class == Clhub){
321                 /*
322                  * Hubs are handled directly by this process avoiding
323                  * concurrent operation so that at most one device
324                  * has the config address in use.
325                  * We cancel kernel debug for these eps. too chatty.
326                  */
327                 if((p->hub = newhub(d->dir, d)) == nil)
328                         return -1;
329                 return 0;
330         }
331
332         close(d->dfd);
333         d->dfd = -1;
334         pushevent(formatdev(d, 0));
335         return 0;
336 }
337
338 void
339 detachdev(Port *p)
340 {
341         pushevent(formatdev(p->dev, 1));
342 }
343
344 void
345 main(int argc, char **argv)
346 {
347         int fd, i, nd;
348         Dir *d;
349
350         ARGBEGIN {
351         case 'D':
352                 chatty9p++;
353                 break;
354         case 'd':
355                 usbdebug++;
356                 break;
357         } ARGEND;
358
359         initevent();
360         rfork(RFNOTEG);
361         switch(rfork(RFPROC|RFMEM)){
362         case -1: sysfatal("rfork: %r");
363         case 0: work(); exits(nil);
364         }
365         if(argc == 0){
366                 fd = open("/dev/usb", OREAD);
367                 if(fd < 0)
368                         sysfatal("/dev/usb: %r");
369                 nd = dirreadall(fd, &d);
370                 close(fd);
371                 if(nd < 2)
372                         sysfatal("/dev/usb: no hubs");
373                 for(i = 0; i < nd; i++)
374                         if(strcmp(d[i].name, "ctl") != 0)
375                                 rendezvous(work, smprint("/dev/usb/%s", d[i].name));
376                 free(d);
377         }else
378                 for(i = 0; i < argc; i++)
379                         rendezvous(work, strdup(argv[i]));
380         rendezvous(work, nil);
381         postsharesrv(&usbdsrv, nil, "usb", "usbd");
382         exits(nil);
383 }