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