1 #include <u.h> 2 #include <libc.h> 3 #include <thread.h> 4 #include "usb.h" 5 6 /* 7 * epN.M -> N 8 */ 9 static int 10 nameid(char *s) 11 { 12 char *r; 13 char nm[20]; 14 15 r = strrchr(s, 'p'); 16 if(r == nil) 17 return -1; 18 strecpy(nm, nm+sizeof(nm), r+1); 19 r = strchr(nm, '.'); 20 if(r == nil) 21 return -1; 22 *r = 0; 23 return atoi(nm); 24 } 25 26 Dev* 27 openep(Dev *d, int id) 28 { 29 char *mode; /* How many modes? */ 30 Ep *ep; 31 Altc *ac; 32 Dev *epd; 33 Usbdev *ud; 34 char name[40]; 35 36 if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0) 37 return nil; 38 if(d->cfd < 0 || d->usb == nil){ 39 werrstr("device not configured"); 40 return nil; 41 } 42 ud = d->usb; 43 if(id < 0 || id >= nelem(ud->ep) || ud->ep[id] == nil){ 44 werrstr("bad enpoint number"); 45 return nil; 46 } 47 ep = ud->ep[id]; 48 mode = "rw"; 49 if(ep->dir == Ein) 50 mode = "r"; 51 if(ep->dir == Eout) 52 mode = "w"; 53 snprint(name, sizeof(name), "/dev/usb/ep%d.%d", d->id, id); 54 if(access(name, AEXIST) == 0){ 55 dprint(2, "%s: %s already exists; trying to open\n", argv0, name); 56 epd = opendev(name); 57 if(epd != nil) 58 epd->maxpkt = ep->maxpkt; /* guess */ 59 return epd; 60 } 61 if(devctl(d, "new %d %d %s", id, ep->type, mode) < 0){ 62 dprint(2, "%s: %s: new: %r\n", argv0, d->dir); 63 return nil; 64 } 65 epd = opendev(name); 66 if(epd == nil) 67 return nil; 68 epd->id = id; 69 if(devctl(epd, "maxpkt %d", ep->maxpkt) < 0) 70 fprint(2, "%s: %s: openep: maxpkt: %r\n", argv0, epd->dir); 71 else 72 dprint(2, "%s: %s: maxpkt %d\n", argv0, epd->dir, ep->maxpkt); 73 epd->maxpkt = ep->maxpkt; 74 ac = ep->iface->altc[0]; 75 if(ep->ntds > 1 && devctl(epd, "ntds %d", ep->ntds) < 0) 76 fprint(2, "%s: %s: openep: ntds: %r\n", argv0, epd->dir); 77 else 78 dprint(2, "%s: %s: ntds %d\n", argv0, epd->dir, ep->ntds); 79 80 /* 81 * For iso endpoints and high speed interrupt endpoints the pollival is 82 * actually 2ⁿ and not n. 83 * The kernel usb driver must take that into account. 84 * It's simpler this way. 85 */ 86 87 if(ac != nil && (ep->type == Eintr || ep->type == Eiso) && ac->interval != 0) 88 if(devctl(epd, "pollival %d", ac->interval) < 0) 89 fprint(2, "%s: %s: openep: pollival: %r\n", argv0, epd->dir); 90 return epd; 91 } 92 93 Dev* 94 opendev(char *fn) 95 { 96 Dev *d; 97 int l; 98 99 if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0) 100 return nil; 101 d = emallocz(sizeof(Dev), 1); 102 incref(d); 103 104 l = strlen(fn); 105 d->dfd = -1; 106 /* 107 * +30 to allocate extra size to concat "/<epfilename>" 108 * we should probably remove that feature from the manual 109 * and from the code after checking out that nobody relies on 110 * that. 111 */ 112 d->dir = emallocz(l + 30, 0); 113 strcpy(d->dir, fn); 114 strcpy(d->dir+l, "/ctl"); 115 d->cfd = open(d->dir, ORDWR|OCEXEC); 116 d->dir[l] = 0; 117 d->id = nameid(fn); 118 if(d->cfd < 0){ 119 werrstr("can't open endpoint %s: %r", d->dir); 120 free(d->dir); 121 free(d); 122 return nil; 123 } 124 dprint(2, "%s: opendev %#p %s\n", argv0, d, fn); 125 return d; 126 } 127 128 int 129 opendevdata(Dev *d, int mode) 130 { 131 char buf[80]; /* more than enough for a usb path */ 132 133 seprint(buf, buf+sizeof(buf), "%s/data", d->dir); 134 d->dfd = open(buf, mode|OCEXEC); 135 return d->dfd; 136 } 137 138 enum 139 { 140 /* 141 * Max device conf is also limited by max control request size as 142 * limited by Maxctllen in the kernel usb.h (both limits are arbitrary). 143 */ 144 Maxdevconf = 4 * 1024, /* asking for 16K kills Newsham's disk */ 145 }; 146 147 int 148 loaddevconf(Dev *d, int n) 149 { 150 uchar *buf; 151 int nr; 152 int type; 153 154 if(n >= nelem(d->usb->conf)){ 155 werrstr("loaddevconf: bug: out of configurations in device"); 156 fprint(2, "%s: %r\n", argv0); 157 return -1; 158 } 159 buf = emallocz(Maxdevconf, 0); 160 type = Rd2h|Rstd|Rdev; 161 nr = usbcmd(d, type, Rgetdesc, Dconf<<8|n, 0, buf, Maxdevconf); 162 if(nr < Dconflen){ 163 free(buf); 164 return -1; 165 } 166 if(d->usb->conf[n] == nil) 167 d->usb->conf[n] = emallocz(sizeof(Conf), 1); 168 nr = parseconf(d->usb, d->usb->conf[n], buf, nr); 169 free(buf); 170 return nr; 171 } 172 173 Ep* 174 mkep(Usbdev *d, int id) 175 { 176 Ep *ep; 177 178 d->ep[id] = ep = emallocz(sizeof(Ep), 1); 179 ep->id = id; 180 return ep; 181 } 182 183 static char* 184 mkstr(uchar *b, int n) 185 { 186 Rune r; 187 char *us; 188 char *s; 189 char *e; 190 191 if(n <= 2 || (n & 1) != 0) 192 return strdup("none"); 193 n = (n - 2)/2; 194 b += 2; 195 us = s = emallocz(n*UTFmax+1, 0); 196 e = s + n*UTFmax+1; 197 for(; --n >= 0; b += 2){ 198 r = GET2(b); 199 s = seprint(s, e, "%C", r); 200 } 201 return us; 202 } 203 204 char* 205 loaddevstr(Dev *d, int sid) 206 { 207 uchar buf[128]; 208 int type; 209 int nr; 210 211 if(sid == 0) 212 return estrdup("none"); 213 type = Rd2h|Rstd|Rdev; 214 nr=usbcmd(d, type, Rgetdesc, Dstr<<8|sid, 0, buf, sizeof(buf)); 215 return mkstr(buf, nr); 216 } 217 218 int 219 loaddevdesc(Dev *d) 220 { 221 uchar buf[Ddevlen+255]; 222 int nr; 223 int type; 224 Ep *ep0; 225 226 type = Rd2h|Rstd|Rdev; 227 nr = sizeof(buf); 228 memset(buf, 0, Ddevlen); 229 if((nr=usbcmd(d, type, Rgetdesc, Ddev<<8|0, 0, buf, nr)) < 0) 230 return -1; 231 /* 232 * Several hubs are returning descriptors of 17 bytes, not 18. 233 * We accept them and leave number of configurations as zero. 234 * (a get configuration descriptor also fails for them!) 235 */ 236 if(nr < Ddevlen){ 237 print("%s: %s: warning: device with short descriptor\n", 238 argv0, d->dir); 239 if(nr < Ddevlen-1){ 240 werrstr("short device descriptor (%d bytes)", nr); 241 return -1; 242 } 243 } 244 d->usb = emallocz(sizeof(Usbdev), 1); 245 ep0 = mkep(d->usb, 0); 246 ep0->dir = Eboth; 247 ep0->type = Econtrol; 248 ep0->maxpkt = d->maxpkt = 8; /* a default */ 249 nr = parsedev(d, buf, nr); 250 if(nr >= 0){ 251 d->usb->vendor = loaddevstr(d, d->usb->vsid); 252 if(strcmp(d->usb->vendor, "none") != 0){ 253 d->usb->product = loaddevstr(d, d->usb->psid); 254 d->usb->serial = loaddevstr(d, d->usb->ssid); 255 } 256 } 257 return nr; 258 } 259 260 int 261 configdev(Dev *d) 262 { 263 int i; 264 265 if(d->dfd < 0) 266 opendevdata(d, ORDWR); 267 if(loaddevdesc(d) < 0) 268 return -1; 269 for(i = 0; i < d->usb->nconf; i++) 270 if(loaddevconf(d, i) < 0) 271 return -1; 272 return 0; 273 } 274 275 static void 276 closeconf(Conf *c) 277 { 278 int i; 279 int a; 280 281 if(c == nil) 282 return; 283 for(i = 0; i < nelem(c->iface); i++) 284 if(c->iface[i] != nil){ 285 for(a = 0; a < nelem(c->iface[i]->altc); a++) 286 free(c->iface[i]->altc[a]); 287 free(c->iface[i]); 288 } 289 free(c); 290 } 291 292 void 293 closedev(Dev *d) 294 { 295 int i; 296 Usbdev *ud; 297 298 if(d==nil || decref(d) != 0) 299 return; 300 dprint(2, "%s: closedev %#p %s\n", argv0, d, d->dir); 301 if(d->free != nil) 302 d->free(d->aux); 303 if(d->cfd >= 0) 304 close(d->cfd); 305 if(d->dfd >= 0) 306 close(d->dfd); 307 d->cfd = d->dfd = -1; 308 free(d->dir); 309 d->dir = nil; 310 ud = d->usb; 311 d->usb = nil; 312 if(ud != nil){ 313 free(ud->vendor); 314 free(ud->product); 315 free(ud->serial); 316 for(i = 0; i < nelem(ud->ep); i++) 317 free(ud->ep[i]); 318 for(i = 0; i < nelem(ud->ddesc); i++) 319 free(ud->ddesc[i]); 320 321 for(i = 0; i < nelem(ud->conf); i++) 322 closeconf(ud->conf[i]); 323 free(ud); 324 } 325 free(d); 326 } 327 328 static char* 329 reqstr(int type, int req) 330 { 331 char *s; 332 static char* ds[] = { "dev", "if", "ep", "oth" }; 333 static char buf[40]; 334 335 if(type&Rd2h) 336 s = seprint(buf, buf+sizeof(buf), "d2h"); 337 else 338 s = seprint(buf, buf+sizeof(buf), "h2d"); 339 if(type&Rclass) 340 s = seprint(s, buf+sizeof(buf), "|cls"); 341 else if(type&Rvendor) 342 s = seprint(s, buf+sizeof(buf), "|vnd"); 343 else 344 s = seprint(s, buf+sizeof(buf), "|std"); 345 s = seprint(s, buf+sizeof(buf), "|%s", ds[type&3]); 346 347 switch(req){ 348 case Rgetstatus: s = seprint(s, buf+sizeof(buf), " getsts"); break; 349 case Rclearfeature: s = seprint(s, buf+sizeof(buf), " clrfeat"); break; 350 case Rsetfeature: s = seprint(s, buf+sizeof(buf), " setfeat"); break; 351 case Rsetaddress: s = seprint(s, buf+sizeof(buf), " setaddr"); break; 352 case Rgetdesc: s = seprint(s, buf+sizeof(buf), " getdesc"); break; 353 case Rsetdesc: s = seprint(s, buf+sizeof(buf), " setdesc"); break; 354 case Rgetconf: s = seprint(s, buf+sizeof(buf), " getcnf"); break; 355 case Rsetconf: s = seprint(s, buf+sizeof(buf), " setcnf"); break; 356 case Rgetiface: s = seprint(s, buf+sizeof(buf), " getif"); break; 357 case Rsetiface: s = seprint(s, buf+sizeof(buf), " setif"); break; 358 } 359 USED(s); 360 return buf; 361 } 362 363 static int 364 cmdreq(Dev *d, int type, int req, int value, int index, uchar *data, int count) 365 { 366 int ndata, n; 367 uchar *wp; 368 uchar buf[8]; 369 char *hd, *rs; 370 371 assert(d != nil); 372 if(data == nil){ 373 wp = buf; 374 ndata = 0; 375 }else{ 376 ndata = count; 377 wp = emallocz(8+ndata, 0); 378 } 379 wp[0] = type; 380 wp[1] = req; 381 PUT2(wp+2, value); 382 PUT2(wp+4, index); 383 PUT2(wp+6, count); 384 if(data != nil) 385 memmove(wp+8, data, ndata); 386 if(usbdebug>2){ 387 hd = hexstr(wp, ndata+8); 388 rs = reqstr(type, req); 389 fprint(2, "%s: %s val %d|%d idx %d cnt %d out[%d] %s\n", 390 d->dir, rs, value>>8, value&0xFF, 391 index, count, ndata+8, hd); 392 free(hd); 393 } 394 n = write(d->dfd, wp, 8+ndata); 395 if(wp != buf) 396 free(wp); 397 if(n < 0) 398 return -1; 399 if(n != 8+ndata){ 400 dprint(2, "%s: cmd: short write: %d\n", argv0, n); 401 return -1; 402 } 403 return n; 404 } 405 406 static int 407 cmdrep(Dev *d, void *buf, int nb) 408 { 409 char *hd; 410 411 nb = read(d->dfd, buf, nb); 412 if(nb >0 && usbdebug > 2){ 413 hd = hexstr(buf, nb); 414 fprint(2, "%s: in[%d] %s\n", d->dir, nb, hd); 415 free(hd); 416 } 417 return nb; 418 } 419 420 int 421 usbcmd(Dev *d, int type, int req, int value, int index, uchar *data, int count) 422 { 423 int i, r, nerr; 424 char err[64]; 425 426 /* 427 * Some devices do not respond to commands some times. 428 * Others even report errors but later work just fine. Retry. 429 */ 430 r = -1; 431 *err = 0; 432 for(i = nerr = 0; i < Uctries; i++){ 433 if(type & Rd2h) 434 r = cmdreq(d, type, req, value, index, nil, count); 435 else 436 r = cmdreq(d, type, req, value, index, data, count); 437 if(r > 0){ 438 if((type & Rd2h) == 0) 439 break; 440 r = cmdrep(d, data, count); 441 if(r > 0) 442 break; 443 if(r == 0) 444 werrstr("no data from device"); 445 } 446 nerr++; 447 if(*err == 0) 448 rerrstr(err, sizeof(err)); 449 sleep(Ucdelay); 450 } 451 if(r > 0 && i >= 2) 452 /* let the user know the device is not in good shape */ 453 fprint(2, "%s: usbcmd: %s: required %d attempts (%s)\n", 454 argv0, d->dir, i, err); 455 return r; 456 } 457 458 int 459 unstall(Dev *dev, Dev *ep, int dir) 460 { 461 int r; 462 463 if(dir == Ein) 464 dir = 0x80; 465 else 466 dir = 0; 467 r = Rh2d|Rstd|Rep; 468 if(usbcmd(dev, r, Rclearfeature, Fhalt, ep->id|dir, nil, 0)<0){ 469 werrstr("unstall: %s: %r", ep->dir); 470 return -1; 471 } 472 if(devctl(ep, "clrhalt") < 0){ 473 werrstr("clrhalt: %s: %r", ep->dir); 474 return -1; 475 } 476 return 0; 477 } 478 479 /* 480 * To be sure it uses a single write. 481 */ 482 int 483 devctl(Dev *dev, char *fmt, ...) 484 { 485 char buf[128]; 486 va_list arg; 487 char *e; 488 489 va_start(arg, fmt); 490 e = vseprint(buf, buf+sizeof(buf), fmt, arg); 491 va_end(arg); 492 return write(dev->cfd, buf, e-buf); 493 } 494