]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/nusb/usbd/usbd.c
merge
[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;
30 };
31
32 static Event *evfirst, *evlast;
33 static Req *reqfirst, *reqlast;
34 static QLock evlock;
35
36 static void
37 addreader(Req *req)
38 {
39         req->aux = nil;
40         if(reqfirst == nil)
41                 reqfirst = req;
42         else
43                 reqlast->aux = req;
44         reqlast = req;
45 }
46
47 static void
48 fulfill(Req *req, Event *e)
49 {
50         int n;
51         
52         n = e->len;
53         if(n > req->ifcall.count)
54                 n = req->ifcall.count;
55         memmove(req->ofcall.data, e->data, n);
56         req->ofcall.count = n;
57 }
58
59 static void
60 initevent(void)
61 {
62         evfirst = mallocz(sizeof(*evfirst), 1);
63         if(evfirst == nil)
64                 sysfatal("malloc: %r");
65         evlast = evfirst;
66 }
67
68 static void
69 readevent(Req *req)
70 {
71         Event *e;
72
73         qlock(&evlock);
74         e = req->fid->aux;
75         if(e == evlast){
76                 addreader(req);
77                 qunlock(&evlock);
78                 return;
79         }
80         fulfill(req, e);
81         req->fid->aux = e->link;
82         e->link->ref++;
83         if(--e->ref == 0 && e == evfirst){
84                 evfirst = e->link;
85                 free(e->data);
86                 free(e);
87         }
88         qunlock(&evlock);
89         respond(req, nil);
90 }
91
92 static void
93 pushevent(char *data)
94 {
95         Event *e, *ee;
96         Req *r, *rr;
97         
98         qlock(&evlock);
99         e = evlast;
100         ee = emallocz(sizeof(Event), 1);
101         if(ee == nil)
102                 sysfatal("malloc: %r");
103         evlast = ee;
104         e->data = data;
105         e->len = strlen(data);
106         e->link = ee;
107         for(r = reqfirst; r != nil; r = rr){
108                 rr = r->aux;
109                 r->aux = nil;
110                 r->fid->aux = ee;
111                 ee->ref++;
112                 e->ref--;
113                 fulfill(r, e);
114                 respond(r, nil);
115         }
116         if(e->ref == 0 && e == evfirst){
117                 evfirst = ee;
118                 free(e->data);
119                 free(e);
120         }
121         reqfirst = nil;
122         reqlast = nil;
123         qunlock(&evlock);
124 }
125
126 static int
127 dirgen(int n, Dir *d, void *)
128 {
129         if(n >= Qmax - 1)
130                 return -1;
131         d->qid.path = n + 1;
132         d->qid.vers = 0;
133         if(n >= 0)
134                 d->qid.type = 0;
135         else
136                 d->qid.type = QTDIR;
137         d->uid = strdup(getuser());
138         d->gid = strdup(d->uid);
139         d->muid = strdup(d->uid);
140         d->name = strdup(names[n+1]);
141         d->mode = 0555 | (d->qid.type << 24);
142         d->atime = d->mtime = time(0);
143         d->length = 0;
144         return 0;
145 }
146
147 static void
148 usbdattach(Req *req)
149 {
150         req->fid->qid = (Qid) {Qroot, 0, QTDIR};
151         req->ofcall.qid = req->fid->qid;
152         respond(req, nil);
153 }
154
155 static char *
156 usbdwalk(Fid *fid, char *name, Qid *qid)
157 {
158         int i;
159
160         if(strcmp(name, "..") == 0){
161                 fid->qid = (Qid) {Qroot, 0, QTDIR};
162                 *qid = fid->qid;
163                 return nil;
164         }
165         if(fid->qid.path != Qroot)
166                 return "not a directory";
167         for(i = 0; i < Qmax; i++)
168                 if(strcmp(name, names[i]) == 0){
169                         fid->qid = (Qid) {i, 0, 0};
170                         *qid = fid->qid;
171                         return nil;
172                 }
173         return "does not exist";
174 }
175
176 static void
177 usbdread(Req *req)
178 {
179         switch((long)req->fid->qid.path){
180         case Qroot:
181                 dirread9p(req, dirgen, nil);
182                 respond(req, nil);
183                 break;
184         case Qusbevent:
185                 readevent(req);
186                 break;
187         default:
188                 respond(req, Enonexist);
189                 break;
190         }
191 }
192
193 static void
194 usbdstat(Req *req)
195 {
196         if(dirgen(req->fid->qid.path - 1, &req->d, nil) < 0)
197                 respond(req, "the front fell off");
198         else
199                 respond(req, nil);
200 }
201
202 static void
203 usbdopen(Req *req)
204 {
205         if(req->fid->qid.path == Qusbevent){
206                 qlock(&evlock);
207                 req->fid->aux = evlast;
208                 evlast->ref++;
209                 qunlock(&evlock);
210         }
211         respond(req, nil);
212 }
213
214 static void
215 usbddestroyfid(Fid *fid)
216 {
217         Event *e, *ee;
218
219         if(fid->qid.path == Qusbevent){
220                 qlock(&evlock);
221                 e = fid->aux;
222                 if(--e->ref == 0 && e == evfirst){
223                         while(e->ref == 0 && e != evlast){
224                                 ee = e->link;
225                                 free(e->data);
226                                 free(e);
227                                 e = ee;
228                         }
229                         evfirst = e;
230                 }
231                 qunlock(&evlock);
232         }
233 }
234
235 static void
236 usbdflush(Req *req)
237 {
238         Req **l, *r;
239         qlock(&evlock);
240         l = &reqfirst;
241         while(r = *l){
242                 if(r == req->oldreq){
243                         *l = r->aux;
244                         break;
245                 }
246                 l = &r->aux;
247         }
248         qunlock(&evlock);
249         respond(req->oldreq, "interrupted");
250         respond(req, nil);
251 }
252
253 Srv usbdsrv = {
254         .attach = usbdattach,
255         .walk1 = usbdwalk,
256         .read = usbdread,
257         .stat = usbdstat,
258         .open = usbdopen,
259         .flush = usbdflush,
260         .destroyfid = usbddestroyfid,
261 };
262
263 int
264 startdev(Port *p)
265 {
266         Dev *d;
267         Usbdev *u;
268
269         if((d = p->dev) == nil || (u = p->dev->usb) == nil){
270                 fprint(2, "okay what?\n");
271                 return -1;
272         }
273         pushevent(smprint("in id %d vid 0x%.4x did 0x%.4x csp 0x%.8x\n",
274                 d->id, u->vid, u->did, u->csp));
275         closedev(p->dev);
276         return 0;
277 }
278
279 void
280 main(int argc, char **argv)
281 {
282         int fd, i, nd;
283         Dir *d;
284         
285         argc--; argv++;
286         initevent();
287         rfork(RFNOTEG);
288         switch(rfork(RFPROC|RFMEM)){
289         case -1: sysfatal("rfork: %r");
290         case 0: work(); exits(nil);
291         }
292         if(argc == 0){
293                 fd = open("/dev/usb", OREAD);
294                 if(fd < 0)
295                         sysfatal("/dev/usb: %r");
296                 nd = dirreadall(fd, &d);
297                 close(fd);
298                 if(nd < 2)
299                         sysfatal("/dev/usb: no hubs");
300                 for(i = 0; i < nd; i++)
301                         if(strcmp(d[i].name, "ctl") != 0)
302                                 rendezvous(work, smprint("/dev/usb/%s", d[i].name));
303                 free(d);
304         }else
305                 for(i = 0; i < argc; i++)
306                         rendezvous(work, strdup(argv[i]));
307         rendezvous(work, nil);
308         postsharesrv(&usbdsrv, nil, "usb", "usbd", "b");
309 }