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