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