1 #include <u.h> 2 #include <libc.h> 3 #include <thread.h> 4 #include "usb.h" 5 6 typedef struct Parg Parg; 7 8 enum { 9 Ndevs = 32, 10 Arglen = 500, 11 Nargs = 64, 12 Stack = 16 * 1024, 13 }; 14 15 struct Parg { 16 char* args; 17 Dev* dev; 18 int (*f)(Dev*,int,char**); 19 Channel*rc; 20 }; 21 22 static void 23 workproc(void *a) 24 { 25 Parg *pa; 26 char args[Arglen]; 27 char *argv[Nargs]; 28 int argc; 29 Channel *rc; 30 Dev *d; 31 int (*f)(Dev*,int,char**); 32 33 pa = a; 34 strecpy(args, args+sizeof(args), pa->args); /* don't leak */ 35 d = pa->dev; 36 f = pa->f; 37 rc = pa->rc; 38 free(pa->args); 39 free(pa); 40 argc = tokenize(args, argv, nelem(argv)-1); 41 argv[argc] = nil; 42 if(f(d, argc, argv) < 0){ 43 closedev(d); 44 fprint(2, "%s: devmain: %r\n", argv0); 45 sendul(rc, -1); 46 threadexits("devmain: %r"); 47 } 48 sendul(rc, 0); 49 threadexits(nil); 50 51 } 52 53 int 54 matchdevcsp(char *info, void *a) 55 { 56 char sbuf[40]; 57 int *csps; 58 59 csps = a; 60 for(; *csps != 0; csps++){ 61 snprint(sbuf, sizeof(sbuf), "csp %#08ux", *csps); 62 if(strstr(info, sbuf) != nil) 63 return 0; 64 } 65 return -1; 66 } 67 68 int 69 finddevs(int (*matchf)(char*,void*), void *farg, char** dirs, int ndirs) 70 { 71 int fd, i, n, nd, nr; 72 char *nm; 73 char dbuf[512], fbuf[40]; 74 Dir *d; 75 76 fd = open("/dev/usb", OREAD); 77 if(fd < 0) 78 sysfatal("/dev/usb: %r"); 79 nd = dirreadall(fd, &d); 80 close(fd); 81 if(nd < 2) 82 sysfatal("/dev/usb: no devs"); 83 for(i = n = 0; i < nd && n < ndirs; i++){ 84 nm = d[i].name; 85 if(strcmp(nm, "ctl") == 0 || strstr(nm, ".0") == nil) 86 continue; 87 snprint(fbuf, sizeof(fbuf), "/dev/usb/%s/ctl", nm); 88 fd = open(fbuf, OREAD); 89 if(fd < 0) 90 continue; /* may be gone */ 91 nr = read(fd, dbuf, sizeof(dbuf)-1); 92 close(fd); 93 if(nr < 0) 94 continue; 95 dbuf[nr] = 0; 96 if(strstr(dbuf, "enabled ") != nil && strstr(dbuf, " busy") == nil) 97 if(matchf(dbuf, farg) == 0) 98 dirs[n++] = smprint("/dev/usb/%s", nm); 99 } 100 free(d); 101 if(usbdebug > 1) 102 for(nd = 0; nd < n; nd++) 103 fprint(2, "finddevs: %s\n", dirs[nd]); 104 return n; 105 } 106 107 void 108 startdevs(char *args, char *argv[], int argc, int (*mf)(char*, void*), 109 void *ma, int (*df)(Dev*, int, char**)) 110 { 111 int i, ndirs, ndevs; 112 char *dirs[Ndevs]; 113 char **dp; 114 Parg *parg; 115 Dev *dev; 116 Channel *rc; 117 118 if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0) 119 sysfatal("#u: %r"); 120 121 if(argc > 0){ 122 ndirs = argc; 123 dp = argv; 124 }else{ 125 dp = dirs; 126 ndirs = finddevs(mf, ma, dp, Ndevs); 127 if(ndirs == nelem(dirs)) 128 fprint(2, "%s: too many devices\n", argv0); 129 } 130 ndevs = 0; 131 rc = chancreate(sizeof(ulong), 0); 132 if(rc == nil) 133 sysfatal("no memory"); 134 for(i = 0; i < ndirs; i++){ 135 fprint(2, "%s: startdevs: opening #%d %s\n", argv0, i, dp[i]); 136 dev = opendev(dp[i]); 137 if(dev == nil) 138 fprint(2, "%s: %s: %r\n", argv0, dp[i]); 139 else if(configdev(dev) < 0){ 140 fprint(2, "%s: %s: config: %r\n", argv0, dp[i]); 141 closedev(dev); 142 }else{ 143 dprint(2, "%s: %U", argv0, dev); 144 parg = emallocz(sizeof(Parg), 0); 145 parg->args = estrdup(args); 146 parg->dev = dev; 147 parg->rc = rc; 148 parg->f = df; 149 proccreate(workproc, parg, Stack); 150 if(recvul(rc) == 0) 151 ndevs++; 152 } 153 if(dp != argv) 154 free(dirs[i]); 155 } 156 chanfree(rc); 157 if(ndevs == 0) 158 sysfatal("no unhandled devices found"); 159 } 160