1 /* 2 * Framework for USB devices. 3 * Some of them may be embedded into usbd and some of 4 * them may exist as /bin/usb/* binaries on their own. 5 * 6 * When embedded, devmain() is given a ref of an already 7 * configured and open Dev. If devmain() 8 * does not fail it should release this ref when done and 9 * use incref to add further refs to it. 10 */ 11 #include <u.h> 12 #include <libc.h> 13 #include <thread.h> 14 #include "usb.h" 15 #include "usbd.h" 16 17 static Lock masklck; 18 extern Devtab devtab[]; 19 static char* cputype; 20 21 int 22 getdevnb(uvlong *maskp) 23 { 24 int i; 25 26 lock(&masklck); 27 for(i = 0; i < 8 * sizeof *maskp; i++) 28 if((*maskp & (1ULL<<i)) == 0){ 29 *maskp |= 1ULL<<i; 30 unlock(&masklck); 31 return i; 32 } 33 unlock(&masklck); 34 return -1; 35 } 36 37 void 38 putdevnb(uvlong *maskp, int id) 39 { 40 lock(&masklck); 41 if(id >= 0) 42 *maskp &= ~(1ULL<<id); 43 unlock(&masklck); 44 } 45 46 static int 47 cspmatch(Devtab *dt, int dcsp) 48 { 49 int i; 50 int csp; 51 52 for(i = 0; i < nelem(dt->csps); i++) 53 if((csp=dt->csps[i]) != 0) 54 if(csp == dcsp) 55 return 1; 56 else if((csp&DCL) && (csp&~DCL) == Class(dcsp)) 57 return 1; 58 return 0; 59 } 60 61 static int 62 devmatch(Devtab *dt, Usbdev *d) 63 { 64 int i; 65 int c; 66 Conf *cp; 67 68 if(dt->noauto) 69 return 0; 70 if(dt->vid != -1 && d->vid != dt->vid) 71 return 0; 72 if(dt->did != -1 && d->did != dt->did) 73 return 0; 74 if(cspmatch(dt, d->csp)) 75 return 1; 76 for(c = 0; c < Nconf; c++) 77 if((cp=d->conf[c]) != nil) 78 for(i = 0; i < Niface; i++) 79 if(cp->iface[i] != nil) 80 if(cspmatch(dt, cp->iface[i]->csp)) 81 return 1; 82 return 0; 83 } 84 85 /* We can't use procexec to execute drivers, because 86 * procexec mounts #| at /mnt/temp and we do *not* 87 * have /mnt/temp at boot time. 88 * Instead, we use access to guess if we can execute the file. 89 * and reply as procexec. Be careful that the child inherits 90 * all the shared state of the thread library. It should run unnoticed. 91 */ 92 static void 93 xexec(Channel *c, char *nm, char *args[]) 94 { 95 int pid; 96 97 if(access(nm, AEXEC) == 0){ 98 pid = rfork(RFFDG|RFREND|RFPROC); 99 switch(pid){ 100 case 0: 101 exec(nm, args); 102 _exits("exec"); 103 case -1: 104 break; 105 default: 106 sendul(c, pid); 107 threadexits(nil); 108 } 109 } 110 } 111 112 typedef struct Sarg Sarg; 113 struct Sarg{ 114 Port *pp; 115 Devtab* dt; 116 Channel*rc; 117 char fname[80]; 118 char args[128]; 119 char *argv[40]; 120 }; 121 122 static void 123 startdevproc(void *a) 124 { 125 Sarg *sa = a; 126 Dev *d; 127 Devtab *dt; 128 int argc; 129 char *args, *argse, **argv; 130 char *fname; 131 132 threadsetgrp(threadid()); 133 d = sa->pp->dev; 134 dt = sa->dt; 135 args = sa->args; 136 argse = sa->args + sizeof sa->args; 137 argv = sa->argv; 138 fname = sa->fname; 139 sa->pp->devmaskp = &dt->devmask; 140 sa->pp->devnb = getdevnb(&dt->devmask); 141 if(sa->pp->devnb < 0){ 142 sa->pp->devmaskp = nil; 143 sa->pp->devnb = 0; 144 }else 145 args = seprint(args, argse, "-N %d", sa->pp->devnb); 146 if(dt->args != nil) 147 seprint(args, argse, " %s", dt->args); 148 args = sa->args; 149 dprint(2, "%s: start: %s %s\n", argv0, dt->name, args); 150 argv[0] = dt->name; 151 argc = 1; 152 if(args[0] != 0) 153 argc += tokenize(args, argv+1, nelem(sa->argv)-2); 154 argv[argc] = nil; 155 if(dt->init == nil){ 156 if(d->dfd > 0 ){ 157 close(d->dfd); 158 d->dfd = -1; 159 } 160 rfork(RFCFDG); 161 open("/dev/null", OREAD); 162 open("/dev/cons", OWRITE); 163 open("/dev/cons", OWRITE); 164 165 xexec(sa->rc, argv[0], argv); 166 snprint(fname, sizeof(sa->fname), "/bin/usb/%s", dt->name); 167 xexec(sa->rc, fname, argv); 168 snprint(fname, sizeof(sa->fname), "/boot/%s", dt->name); 169 xexec(sa->rc, fname, argv); 170 if(cputype == nil) 171 cputype = getenv("cputype"); 172 if(cputype != nil){ 173 snprint(fname, sizeof(sa->fname), "/%s/bin/%s", 174 cputype, dt->name); 175 argv[0] = fname; 176 xexec(sa->rc, fname, argv); 177 } 178 fprint(2, "%s: %s: not found. can't exec\n", argv0, dt->name); 179 sendul(sa->rc, -1); 180 threadexits("exec"); 181 }else{ 182 sa->pp->dev = opendev(d->dir); 183 sendul(sa->rc, 0); 184 if(dt->init(d, argc, argv) < 0) 185 fprint(2, "%s: %s: %r\n", argv0, dt->name); 186 closedev(d); 187 free(sa); 188 } 189 threadexits(nil); 190 } 191 192 static void 193 writeinfo(Dev *d) 194 { 195 char buf[128]; 196 char *s; 197 char *se; 198 Usbdev *ud; 199 Conf *c; 200 Iface *ifc; 201 int i, j; 202 203 ud = d->usb; 204 s = buf; 205 se = buf+sizeof(buf); 206 s = seprint(s, se, "info %s csp %#08ulx", classname(ud->class), ud->csp); 207 for(i = 0; i < ud->nconf; i++){ 208 c = ud->conf[i]; 209 if(c == nil) 210 break; 211 for(j = 0; j < nelem(c->iface); j++){ 212 ifc = c->iface[j]; 213 if(ifc == nil) 214 break; 215 if(ifc->csp != ud->csp) 216 s = seprint(s, se, " csp %#08ulx", ifc->csp); 217 } 218 } 219 s = seprint(s, se, " vid %06#x did %06#x", ud->vid, ud->did); 220 seprint(s, se, " %q %q", ud->vendor, ud->product); 221 devctl(d, "%s", buf); 222 } 223 224 int 225 startdev(Port *pp) 226 { 227 Dev *d; 228 Usbdev *ud; 229 Devtab *dt; 230 Sarg *sa; 231 Channel *rc; 232 233 d = pp->dev; 234 assert(d); 235 ud = d->usb; 236 assert(ud != nil); 237 238 writeinfo(d); 239 240 if(ud->class == Clhub){ 241 /* 242 * Hubs are handled directly by this process avoiding 243 * concurrent operation so that at most one device 244 * has the config address in use. 245 * We cancel kernel debug for these eps. too chatty. 246 */ 247 pp->hub = newhub(d->dir, d); 248 if(pp->hub == nil) 249 fprint(2, "%s: %s: %r\n", argv0, d->dir); 250 else 251 fprint(2, "usb/hub... "); 252 if(usbdebug > 1) 253 devctl(d, "debug 0"); /* polled hubs are chatty */ 254 return pp->hub == nil ? -1 : 0; 255 } 256 257 for(dt = devtab; dt->name != nil; dt++) 258 if(devmatch(dt, ud)) 259 break; 260 /* 261 * From here on the device is for the driver. 262 * When we return pp->dev contains a Dev just for us 263 * with only the ctl open. Both devs are released on the last closedev: 264 * driver's upon I/O errors and ours upon port dettach. 265 */ 266 if(dt->name == nil){ 267 dprint(2, "%s: no configured entry for %s (csp %#08lx)\n", 268 argv0, d->dir, ud->csp); 269 close(d->dfd); 270 d->dfd = -1; 271 return 0; 272 } 273 sa = emallocz(sizeof(Sarg), 1); 274 sa->pp = pp; 275 sa->dt = dt; 276 rc = sa->rc = chancreate(sizeof(ulong), 1); 277 procrfork(startdevproc, sa, Stack, RFNOTEG); 278 if(recvul(rc) != 0) 279 free(sa); 280 chanfree(rc); 281 fprint(2, "usb/%s... ", dt->name); 282 283 sleep(Spawndelay); /* in case we re-spawn too fast */ 284 return 0; 285 } 286