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->vid != -1 && d->vid != dt->vid) 69 return 0; 70 if(dt->did != -1 && d->did != dt->did) 71 return 0; 72 if(cspmatch(dt, d->csp)) 73 return 1; 74 for(c = 0; c < Nconf; c++) 75 if((cp=d->conf[c]) != nil) 76 for(i = 0; i < Niface; i++) 77 if(cp->iface[i] != nil) 78 if(cspmatch(dt, cp->iface[i]->csp)) 79 return 1; 80 return 0; 81 } 82 83 /* We can't use procexec to execute drivers, because 84 * procexec mounts #| at /mnt/temp and we do *not* 85 * have /mnt/temp at boot time. 86 * Instead, we use access to guess if we can execute the file. 87 * and reply as procexec. Be careful that the child inherits 88 * all the shared state of the thread library. It should run unnoticed. 89 */ 90 static void 91 xexec(Channel *c, char *nm, char *args[]) 92 { 93 int pid; 94 95 if(access(nm, AEXEC) == 0){ 96 pid = rfork(RFFDG|RFREND|RFPROC); 97 switch(pid){ 98 case 0: 99 exec(nm, args); 100 _exits("exec"); 101 case -1: 102 break; 103 default: 104 sendul(c, pid); 105 threadexits(nil); 106 } 107 } 108 } 109 110 typedef struct Sarg Sarg; 111 struct Sarg{ 112 Port *pp; 113 Devtab* dt; 114 Channel*rc; 115 char fname[80]; 116 char args[128]; 117 char *argv[40]; 118 }; 119 120 static void 121 startdevproc(void *a) 122 { 123 Sarg *sa = a; 124 Dev *d; 125 Devtab *dt; 126 int argc; 127 char *args, *argse, **argv; 128 char *fname; 129 130 threadsetgrp(threadid()); 131 d = sa->pp->dev; 132 dt = sa->dt; 133 args = sa->args; 134 argse = sa->args + sizeof sa->args; 135 argv = sa->argv; 136 fname = sa->fname; 137 sa->pp->devmaskp = &dt->devmask; 138 sa->pp->devnb = getdevnb(&dt->devmask); 139 if(sa->pp->devnb < 0){ 140 sa->pp->devmaskp = nil; 141 sa->pp->devnb = 0; 142 }else 143 args = seprint(args, argse, "-N %d", sa->pp->devnb); 144 if(dt->args != nil) 145 seprint(args, argse, " %s", dt->args); 146 args = sa->args; 147 dprint(2, "%s: start: %s %s\n", argv0, dt->name, args); 148 argv[0] = dt->name; 149 argc = 1; 150 if(args[0] != 0) 151 argc += tokenize(args, argv+1, nelem(sa->argv)-2); 152 argv[argc] = nil; 153 if(dt->init == nil){ 154 if(d->dfd > 0 ){ 155 close(d->dfd); 156 d->dfd = -1; 157 } 158 rfork(RFCFDG); 159 open("/dev/null", OREAD); 160 open("/dev/cons", OWRITE); 161 open("/dev/cons", OWRITE); 162 163 xexec(sa->rc, argv[0], argv); 164 snprint(fname, sizeof(sa->fname), "/bin/usb/%s", dt->name); 165 xexec(sa->rc, fname, argv); 166 snprint(fname, sizeof(sa->fname), "/boot/%s", dt->name); 167 xexec(sa->rc, fname, argv); 168 if(cputype == nil) 169 cputype = getenv("cputype"); 170 if(cputype != nil){ 171 snprint(fname, sizeof(sa->fname), "/%s/bin/%s", 172 cputype, dt->name); 173 argv[0] = fname; 174 xexec(sa->rc, fname, argv); 175 } 176 fprint(2, "%s: %s: not found. can't exec\n", argv0, dt->name); 177 sendul(sa->rc, -1); 178 threadexits("exec"); 179 }else{ 180 sa->pp->dev = opendev(d->dir); 181 sendul(sa->rc, 0); 182 if(dt->init(d, argc, argv) < 0) 183 fprint(2, "%s: %s: %r\n", argv0, dt->name); 184 closedev(d); 185 free(sa); 186 } 187 threadexits(nil); 188 } 189 190 static void 191 writeinfo(Dev *d) 192 { 193 char buf[128]; 194 char *s; 195 char *se; 196 Usbdev *ud; 197 Conf *c; 198 Iface *ifc; 199 int i, j; 200 201 ud = d->usb; 202 s = buf; 203 se = buf+sizeof(buf); 204 s = seprint(s, se, "info %s csp %#08ulx", classname(ud->class), ud->csp); 205 for(i = 0; i < ud->nconf; i++){ 206 c = ud->conf[i]; 207 if(c == nil) 208 break; 209 for(j = 0; j < nelem(c->iface); j++){ 210 ifc = c->iface[j]; 211 if(ifc == nil) 212 break; 213 if(ifc->csp != ud->csp) 214 s = seprint(s, se, " csp %#08ulx", ifc->csp); 215 } 216 } 217 s = seprint(s, se, " vid %06#x did %06#x", ud->vid, ud->did); 218 seprint(s, se, " %q %q", ud->vendor, ud->product); 219 devctl(d, "%s", buf); 220 } 221 222 int 223 startdev(Port *pp) 224 { 225 Dev *d; 226 Usbdev *ud; 227 Devtab *dt; 228 Sarg *sa; 229 Channel *rc; 230 231 d = pp->dev; 232 assert(d); 233 ud = d->usb; 234 assert(ud != nil); 235 236 writeinfo(d); 237 238 if(ud->class == Clhub){ 239 /* 240 * Hubs are handled directly by this process avoiding 241 * concurrent operation so that at most one device 242 * has the config address in use. 243 * We cancel kernel debug for these eps. too chatty. 244 */ 245 pp->hub = newhub(d->dir, d); 246 if(pp->hub == nil) 247 fprint(2, "%s: %s: %r\n", argv0, d->dir); 248 else 249 fprint(2, "usb/hub... "); 250 if(usbdebug > 1) 251 devctl(d, "debug 0"); /* polled hubs are chatty */ 252 return pp->hub == nil ? -1 : 0; 253 } 254 255 for(dt = devtab; dt->name != nil; dt++) 256 if(devmatch(dt, ud)) 257 break; 258 /* 259 * From here on the device is for the driver. 260 * When we return pp->dev contains a Dev just for us 261 * with only the ctl open. Both devs are released on the last closedev: 262 * driver's upon I/O errors and ours upon port dettach. 263 */ 264 if(dt->name == nil){ 265 dprint(2, "%s: no configured entry for %s (csp %#08lx)\n", 266 argv0, d->dir, ud->csp); 267 close(d->dfd); 268 d->dfd = -1; 269 return 0; 270 } 271 sa = emallocz(sizeof(Sarg), 1); 272 sa->pp = pp; 273 sa->dt = dt; 274 rc = sa->rc = chancreate(sizeof(ulong), 1); 275 procrfork(startdevproc, sa, Stack, RFNOTEG); 276 if(recvul(rc) != 0) 277 free(sa); 278 chanfree(rc); 279 fprint(2, "usb/%s... ", dt->name); 280 281 sleep(Spawndelay); /* in case we re-spawn too fast */ 282 return 0; 283 } 284