1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <fcall.h>
5 #include "usb.h"
6 #include "usbfs.h"
7
8 typedef struct Rpc Rpc;
9
10 enum
11 {
12 Incr = 3, /* increments for fs array */
13 Dtop = 0, /* high 32 bits for / */
14 Qdir = 0, /* low 32 bits for /devdir */
15 };
16
17 QLock fslck;
18 static Usbfs** fs;
19 static int nfs;
20 static int fsused;
21 static int exitonclose = 1;
22
23 void
usbfsexits(int y)24 usbfsexits(int y)
25 {
26 exitonclose = y;
27 }
28
29 static int
qiddev(uvlong path)30 qiddev(uvlong path)
31 {
32 return (int)(path>>32) & 0xFF;
33 }
34
35 static int
qidfile(uvlong path)36 qidfile(uvlong path)
37 {
38 return (int)(path & 0xFFFFFFFFULL);
39 }
40
41 static uvlong
mkqid(int qd,int qf)42 mkqid(int qd, int qf)
43 {
44 return ((uvlong)qd << 32) | (uvlong)qf;
45 }
46
47 void
usbfsdirdump(void)48 usbfsdirdump(void)
49 {
50 int i;
51
52 qlock(&fslck);
53 fprint(2, "%s: fs list: (%d used %d total)\n", argv0, fsused, nfs);
54 for(i = 1; i < nfs; i++)
55 if(fs[i] != nil)
56 if(fs[i]->dev != nil)
57 fprint(2, "%s\t%s dev %#p refs %ld\n",
58 argv0, fs[i]->name, fs[i]->dev, fs[i]->dev->ref);
59 else
60 fprint(2, "%s:\t%s\n", argv0, fs[i]->name);
61 qunlock(&fslck);
62 }
63
64 void
usbfsadd(Usbfs * dfs)65 usbfsadd(Usbfs *dfs)
66 {
67 int i, j;
68
69 dprint(2, "%s: fsadd %s\n", argv0, dfs->name);
70 qlock(&fslck);
71 for(i = 1; i < nfs; i++)
72 if(fs[i] == nil)
73 break;
74 if(i >= nfs){
75 if((nfs%Incr) == 0){
76 fs = realloc(fs, sizeof(Usbfs*) * (nfs+Incr));
77 if(fs == nil)
78 sysfatal("realloc: %r");
79 for(j = nfs; j < nfs+Incr; j++)
80 fs[j] = nil;
81 }
82 if(nfs == 0) /* do not use entry 0 */
83 nfs++;
84 fs[nfs++] = dfs;
85 }else
86 fs[i] = dfs;
87 dfs->qid = mkqid(i, 0);
88 fsused++;
89 qunlock(&fslck);
90 }
91
92 static void
usbfsdelnth(int i)93 usbfsdelnth(int i)
94 {
95 if(fs[i] != nil){
96 dprint(2, "%s: fsdel %s", argv0, fs[i]->name);
97 if(fs[i]->dev != nil){
98 dprint(2, " dev %#p ref %ld\n",
99 fs[i]->dev, fs[i]->dev->ref);
100 }else
101 dprint(2, "no dev\n");
102 if(fs[i]->end != nil)
103 fs[i]->end(fs[i]);
104 closedev(fs[i]->dev);
105 fsused--;
106 }
107 fs[i] = nil;
108 if(fsused == 0 && exitonclose != 0){
109 fprint(2, "%s: all file systems gone: exiting\n", argv0);
110 threadexitsall(nil);
111 }
112 }
113
114 void
usbfsdel(Usbfs * dfs)115 usbfsdel(Usbfs *dfs)
116 {
117 int i;
118
119 qlock(&fslck);
120 for(i = 0; i < nfs; i++)
121 if(dfs == nil || fs[i] == dfs){
122 usbfsdelnth(i);
123 if(dfs != nil)
124 break;
125 }
126 qunlock(&fslck);
127 }
128
129 static void
fsend(Usbfs *)130 fsend(Usbfs*)
131 {
132 dprint(2, "%s: fsend\n", argv0);
133 usbfsdel(nil);
134 }
135
136 void
usbfsgone(char * dir)137 usbfsgone(char *dir)
138 {
139 int i;
140
141 qlock(&fslck);
142 /* devices may have more than one fs */
143 for(i = 0; i < nfs; i++)
144 if(fs[i] != nil && fs[i]->dev != nil)
145 if(strcmp(fs[i]->dev->dir, dir) == 0)
146 usbfsdelnth(i);
147 qunlock(&fslck);
148 }
149
150 static void
fsclone(Usbfs *,Fid * o,Fid * n)151 fsclone(Usbfs*, Fid *o, Fid *n)
152 {
153 int qd;
154 Dev *dev;
155 void (*xfsclone)(Usbfs *fs, Fid *of, Fid *nf);
156
157 xfsclone = nil;
158 dev = nil;
159 qd = qiddev(o->qid.path);
160 qlock(&fslck);
161 if(qd != Dtop && fs[qd] != nil && fs[qd]->clone != nil){
162 dev = fs[qd]->dev;
163 if(dev != nil)
164 incref(dev);
165 xfsclone = fs[qd]->clone;
166 }
167 qunlock(&fslck);
168 if(xfsclone != nil){
169 xfsclone(fs[qd], o, n);
170 }
171 if(dev != nil)
172 closedev(dev);
173 }
174
175 static int
fswalk(Usbfs *,Fid * fid,char * name)176 fswalk(Usbfs*, Fid *fid, char *name)
177 {
178 Qid q;
179 int qd, qf;
180 int i;
181 int rc;
182 Dev *dev;
183 Dir d;
184 int (*xfswalk)(Usbfs *fs, Fid *f, char *name);
185
186 q = fid->qid;
187 qd = qiddev(q.path);
188 qf = qidfile(q.path);
189
190 q.type = QTDIR;
191 q.vers = 0;
192 if(strcmp(name, "..") == 0)
193 if(qd == Dtop || qf == Qdir){
194 q.path = mkqid(Dtop, Qdir);
195 fid->qid = q;
196 return 0;
197 }
198 if(qd != 0){
199 qlock(&fslck);
200 if(fs[qd] == nil){
201 qunlock(&fslck);
202 werrstr(Eio);
203 return -1;
204 }
205 dev = fs[qd]->dev;
206 if(dev != nil)
207 incref(dev);
208 xfswalk = fs[qd]->walk;
209 qunlock(&fslck);
210 rc = xfswalk(fs[qd], fid, name);
211 if(dev != nil)
212 closedev(dev);
213 return rc;
214 }
215 qlock(&fslck);
216 for(i = 0; i < nfs; i++)
217 if(fs[i] != nil && strcmp(name, fs[i]->name) == 0){
218 q.path = mkqid(i, Qdir);
219 fs[i]->stat(fs[i], q, &d); /* may be a file */
220 fid->qid = d.qid;
221 qunlock(&fslck);
222 return 0;
223 }
224 qunlock(&fslck);
225 werrstr(Enotfound);
226 return -1;
227 }
228
229 static int
fsopen(Usbfs *,Fid * fid,int mode)230 fsopen(Usbfs*, Fid *fid, int mode)
231 {
232 int qd;
233 int rc;
234 Dev *dev;
235 int (*xfsopen)(Usbfs *fs, Fid *f, int mode);
236
237 qd = qiddev(fid->qid.path);
238 if(qd == Dtop)
239 return 0;
240 qlock(&fslck);
241 if(fs[qd] == nil){
242 qunlock(&fslck);
243 werrstr(Eio);
244 return -1;
245 }
246 dev = fs[qd]->dev;
247 if(dev != nil)
248 incref(dev);
249 xfsopen = fs[qd]->open;
250 qunlock(&fslck);
251 if(xfsopen != nil)
252 rc = xfsopen(fs[qd], fid, mode);
253 else
254 rc = 0;
255 if(dev != nil)
256 closedev(dev);
257 return rc;
258 }
259
260 static int
dirgen(Usbfs *,Qid,int n,Dir * d,void *)261 dirgen(Usbfs*, Qid, int n, Dir *d, void *)
262 {
263 int i;
264 Dev *dev;
265 char *nm;
266
267 qlock(&fslck);
268 for(i = 0; i < nfs; i++)
269 if(fs[i] != nil && n-- == 0){
270 d->qid.type = QTDIR;
271 d->qid.path = mkqid(i, Qdir);
272 d->qid.vers = 0;
273 dev = fs[i]->dev;
274 if(dev != nil)
275 incref(dev);
276 nm = d->name;
277 fs[i]->stat(fs[i], d->qid, d);
278 d->name = nm;
279 strncpy(d->name, fs[i]->name, Namesz);
280 if(dev != nil)
281 closedev(dev);
282 qunlock(&fslck);
283 return 0;
284 }
285 qunlock(&fslck);
286 return -1;
287 }
288
289 static long
fsread(Usbfs *,Fid * fid,void * data,long cnt,vlong off)290 fsread(Usbfs*, Fid *fid, void *data, long cnt, vlong off)
291 {
292 int qd;
293 int rc;
294 Dev *dev;
295 Qid q;
296 long (*xfsread)(Usbfs *fs, Fid *f, void *data, long count, vlong );
297
298 q = fid->qid;
299 qd = qiddev(q.path);
300 if(qd == Dtop)
301 return usbdirread(nil, q, data, cnt, off, dirgen, nil);
302 qlock(&fslck);
303 if(fs[qd] == nil){
304 qunlock(&fslck);
305 werrstr(Eio);
306 return -1;
307 }
308 dev = fs[qd]->dev;
309 if(dev != nil)
310 incref(dev);
311 xfsread = fs[qd]->read;
312 qunlock(&fslck);
313 rc = xfsread(fs[qd], fid, data, cnt, off);
314 if(dev != nil)
315 closedev(dev);
316 return rc;
317 }
318
319 static long
fswrite(Usbfs *,Fid * fid,void * data,long cnt,vlong off)320 fswrite(Usbfs*, Fid *fid, void *data, long cnt, vlong off)
321 {
322 int qd;
323 int rc;
324 Dev *dev;
325 long (*xfswrite)(Usbfs *fs, Fid *f, void *data, long count, vlong );
326
327 qd = qiddev(fid->qid.path);
328 if(qd == Dtop)
329 sysfatal("fswrite: not for usbd /");
330 qlock(&fslck);
331 if(fs[qd] == nil){
332 qunlock(&fslck);
333 werrstr(Eio);
334 return -1;
335 }
336 dev = fs[qd]->dev;
337 if(dev != nil)
338 incref(dev);
339 xfswrite = fs[qd]->write;
340 qunlock(&fslck);
341 rc = xfswrite(fs[qd], fid, data, cnt, off);
342 if(dev != nil)
343 closedev(dev);
344 return rc;
345 }
346
347
348 static void
fsclunk(Usbfs *,Fid * fid)349 fsclunk(Usbfs*, Fid* fid)
350 {
351 int qd;
352 Dev *dev;
353 void (*xfsclunk)(Usbfs *fs, Fid *f);
354
355 dev = nil;
356 qd = qiddev(fid->qid.path);
357 qlock(&fslck);
358 if(qd != Dtop && fs[qd] != nil){
359 dev=fs[qd]->dev;
360 if(dev != nil)
361 incref(dev);
362 xfsclunk = fs[qd]->clunk;
363 }else
364 xfsclunk = nil;
365 qunlock(&fslck);
366 if(xfsclunk != nil){
367 xfsclunk(fs[qd], fid);
368 }
369 if(dev != nil)
370 closedev(dev);
371 }
372
373 static int
fsstat(Usbfs *,Qid qid,Dir * d)374 fsstat(Usbfs*, Qid qid, Dir *d)
375 {
376 int qd;
377 int rc;
378 Dev *dev;
379 int (*xfsstat)(Usbfs *fs, Qid q, Dir *d);
380
381 qd = qiddev(qid.path);
382 if(qd == Dtop){
383 d->qid = qid;
384 d->name = "usb";
385 d->length = 0;
386 d->mode = 0555|DMDIR;
387 return 0;
388 }
389 qlock(&fslck);
390 if(fs[qd] == nil){
391 qunlock(&fslck);
392 werrstr(Eio);
393 return -1;
394 }
395 xfsstat = fs[qd]->stat;
396 dev = fs[qd]->dev;
397 if(dev != nil)
398 incref(dev);
399 qunlock(&fslck);
400 rc = xfsstat(fs[qd], qid, d);
401 if(dev != nil)
402 closedev(dev);
403 return rc;
404 }
405
406 Usbfs usbdirfs =
407 {
408 .walk = fswalk,
409 .clone = fsclone,
410 .clunk = fsclunk,
411 .open = fsopen,
412 .read = fsread,
413 .write = fswrite,
414 .stat = fsstat,
415 .end = fsend,
416 };
417
418