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