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