1 #include <u.h> 2 #include <libc.h> 3 #include <thread.h> 4 #include <bio.h> 5 #include "usb.h" 6 7 int verbose; 8 9 typedef struct Flags Flags; 10 typedef struct Classes Classes; 11 12 struct Flags { 13 int bit; 14 char* name0; 15 char* name1; 16 }; 17 18 struct Classes { 19 char* name; 20 struct { 21 char* name; 22 char* proto[4]; 23 } subclass[4]; 24 }; 25 26 static Classes classname[] = { 27 [CL_AUDIO] {"audio", {[1]{"control"}, [2]{"stream"}, [3]{"midi"}}}, 28 [CL_COMMS] {"comms", {[1] {"abstract", {[1]"AT"}}}}, 29 [CL_HID] {"hid", {[1] {"boot", {[1]"kbd", [2]"mouse"}}}}, 30 [CL_PRINTER] {"printer", {[1]"printer", {[1]"uni", [2]"bi"}}}, 31 [CL_HUB] {"hub", {[1]{"hub"}}}, 32 [CL_DATA] {"data"}, 33 }; 34 35 static void pflag(Flags*, uint); 36 37 char * 38 sclass(char *p, char *e, ulong csp) 39 { 40 Classes *cs; 41 int c, s, pr; 42 43 c = Class(csp); 44 s = Subclass(csp); 45 pr = Proto(csp); 46 if(c < 0 || c >= nelem(classname) || (cs = &classname[c])->name == nil) 47 return seprint(p, e, "%d.%d.%d", c, s, pr); 48 p = seprint(p, e, "%s.", cs->name); 49 if(s < 0 || s >= nelem(cs->subclass) || cs->subclass[s].name == nil) 50 p = seprint(p, e, "%d.%d", s, pr); 51 else{ 52 p = seprint(p, e, "%s.", cs->subclass[s].name); 53 if(pr < 0 || pr >= nelem(cs->subclass[s].proto) || cs->subclass[s].proto[pr] == nil) 54 p = seprint(p, e, "%d", pr); 55 else 56 p = seprint(p, e, "%s", cs->subclass[s].proto[pr]); 57 } 58 return p; 59 } 60 61 void 62 pdevice(Device *, int, ulong, void *b, int n) 63 { 64 DDevice *d; 65 char scbuf[64]; 66 67 if(n < DDEVLEN) 68 return; 69 d = b; 70 if(debug & Dbginfo) { 71 fprint(2, "usb (bcd)%c%c%c%c", 72 '0'+((d->bcdUSB[1]>>4)&0xf), '0'+(d->bcdUSB[1]&0xf), 73 '0'+((d->bcdUSB[0]>>4)&0xf), '0'+(d->bcdUSB[0]&0xf)); 74 sclass(scbuf, scbuf + sizeof scbuf, 75 CSP(d->bDeviceClass, d->bDeviceSubClass, d->bDeviceProtocol)), 76 fprint(2, " class %d subclass %d proto %d [%s] max0 %d", 77 d->bDeviceClass, d->bDeviceSubClass, d->bDeviceProtocol, 78 scbuf, 79 d->bMaxPacketSize0); 80 fprint(2, " vendor %#x product %#x device (bcd)%c%c%c%c", 81 GET2(d->idVendor), GET2(d->idProduct), 82 '0'+((d->bcdDevice[1]>>4)&0xf), '0'+(d->bcdDevice[1]&0xf), 83 '0'+((d->bcdDevice[0]>>4)&0xf), '0'+(d->bcdDevice[0]&0xf)); 84 fprint(2, " man %d prod %d serial %d nconfig %d", 85 d->iManufacturer, d->iProduct, d->iSerialNumber, 86 d->bNumConfigurations); 87 } 88 } 89 90 void 91 phid(Device *, int, ulong, void *b, int n) 92 { 93 DHid *d; 94 95 if(n < DHIDLEN){ 96 fprint(2, "%s: hid too short\n", argv0); 97 return; 98 } 99 d = b; 100 if(debug & Dbginfo) 101 fprint(2, "HID (bcd)%c%c%c%c country %d nhidclass %d classdtype %#x dlen %d\n", 102 '0'+((d->bcdHID[1]>>4)&0xf), '0'+(d->bcdHID[1]&0xf), 103 '0'+((d->bcdHID[0]>>4)&0xf), '0'+(d->bcdHID[0]&0xf), 104 d->bCountryCode, d->bNumDescriptors, 105 d->bClassDescriptorType, GET2(d->wItemLength)); 106 } 107 108 static Flags ioflags[] = { 109 {0, "Data", "Constant"}, 110 {1, "Array", "Variable"}, 111 {2, "Absolute", "Relative"}, 112 {3, "NoWrap", "Wrap"}, 113 {4, "Linear", "NonLinear"}, 114 {5, "PreferredState", "No Preferred State"}, 115 {6, "No Null position", "Null state"}, 116 {7, "Non Volatile", "Volatile"}, 117 {8, "Bit Field", "Buffered Bytes"}, 118 {-1, nil, nil}, 119 }; 120 121 static void 122 pflag(Flags *tab, uint v) 123 { 124 char buf[200], *s; 125 int n; 126 127 n = 0; 128 buf[0] = 0; 129 for(; tab->name0 != nil; tab++){ 130 if(v & (1<<tab->bit)) 131 s = tab->name1; 132 else 133 s = tab->name0; 134 if(s != nil && *s) 135 n += snprint(buf+n, sizeof(buf)-n, ", %s", s); 136 } 137 if((debug & Dbginfo) && buf[0]) 138 fprint(2, "[%s]", buf+2); 139 } 140 141 void 142 preport(Device *, int, ulong, byte *b, int n) 143 { 144 byte *s, *es; 145 int tag, nb, i, indent; 146 int v; 147 Flags *tab; 148 149 s = b+2; 150 es = b+n; 151 indent = 0; 152 while(s < es){ 153 for(i=0; i<indent; i++) 154 fprint(2, " "); 155 tag = *s++; 156 if(tag == Tlong){ 157 fprint(2, "long report tag"); 158 return; 159 } 160 if((nb = tag&3) == 3) 161 nb = 4; 162 v = 0; 163 for(i=0; i<nb; i++) 164 v |= s[i] << (i*8); 165 switch(tag & Tmtype){ 166 case Treserved: 167 if(tag == Tlong){ 168 fprint(2, "long report tag"); 169 return; 170 } 171 fprint(2, "illegal tag"); 172 return; 173 case Tmain: 174 tab = nil; 175 if (debug & Dbginfo) { 176 switch(tag & Tmitem){ 177 case Tinput: 178 fprint(2, "Input"); 179 tab = ioflags; 180 break; 181 case Toutput: 182 fprint(2, "Output"); 183 tab = ioflags; 184 break; 185 case Tfeature: 186 fprint(2, "Feature"); 187 tab = ioflags; 188 break; 189 case Tcoll: 190 fprint(2, "Collection"); 191 indent++; 192 break; 193 case Tecoll: 194 fprint(2, "End Collection"); 195 indent--; 196 break; 197 default: 198 fprint(2, "unexpected item %.2x", tag); 199 } 200 fprint(2, "=%#ux", v); 201 if(tab != nil) 202 pflag(tab, v); 203 } 204 break; 205 case Tglobal: 206 if (debug & Dbginfo) { 207 fprint(2, "Global %#ux: ", v); 208 switch(tag & Tmitem){ 209 case Tusagepage: 210 fprint(2, "Usage Page %#ux", v); 211 break; 212 case Tlmin: 213 fprint(2, "Logical Min %d", v); 214 break; 215 case Tlmax: 216 fprint(2, "Logical Max %d", v); 217 break; 218 case Tpmin: 219 fprint(2, "Physical Min %d", v); 220 break; 221 case Tpmax: 222 fprint(2, "Physical Max %d", v); 223 break; 224 case Tunitexp: 225 fprint(2, "Unit Exponent %d", v); 226 break; 227 case Tunit: 228 fprint(2, "Unit %d", v); 229 break; 230 case Trepsize: 231 fprint(2, "Report size %d", v); 232 break; 233 case TrepID: 234 fprint(2, "Report ID %#x", v); 235 break; 236 case Trepcount: 237 fprint(2, "Report Count %d", v); 238 break; 239 case Tpush: 240 fprint(2, "Push %d", v); 241 break; 242 case Tpop: 243 fprint(2, "Pop %d", v); 244 break; 245 default: 246 fprint(2, "Unknown %#ux", v); 247 break; 248 } 249 } 250 break; 251 case Tlocal: 252 if (debug & Dbginfo) { 253 fprint(2, "Local %#ux: ", v); 254 switch(tag & Tmitem){ 255 case Tusage: 256 fprint(2, "Usage %d", v); 257 break; 258 case Tumin: 259 fprint(2, "Usage min %d", v); 260 break; 261 case Tumax: 262 fprint(2, "Usage max %d", v); 263 break; 264 case Tdindex: 265 fprint(2, "Designator index %d", v); 266 break; 267 case Tdmin: 268 fprint(2, "Designator min %d", v); 269 break; 270 case Tdmax: 271 fprint(2, "Designator max %d", v); 272 break; 273 case Tsindex: 274 fprint(2, "String index %d", v); 275 break; 276 case Tsmin: 277 fprint(2, "String min %d", v); 278 break; 279 case Tsmax: 280 fprint(2, "String max %d", v); 281 break; 282 case Tsetdelim: 283 fprint(2, "Set delim %#ux", v); 284 break; 285 default: 286 fprint(2, "Unknown %#ux", v); 287 break; 288 } 289 } 290 break; 291 } 292 fprint(2, "\n"); 293 s += nb; 294 } 295 } 296 297 void 298 phub(Device *, int, ulong, void *b, int n) 299 { 300 DHub *d; 301 302 if(n < DHUBLEN) 303 return; 304 d = b; 305 if (debug & Dbginfo) 306 fprint(2, "nport %d charac %#.4x pwr %dms current %dmA remov %#.2x", 307 d->bNbrPorts, GET2(d->wHubCharacteristics), 308 d->bPwrOn2PwrGood*2, d->bHubContrCurrent, 309 d->DeviceRemovable[0]); 310 } 311 312 void 313 pstring(Device *, int, ulong, void *b, int n) 314 { 315 byte *rb; 316 char *s; 317 Rune r; 318 int l; 319 320 if(n <= 2){ 321 fprint(2, "\"\""); 322 return; 323 } 324 if(n & 1){ 325 fprint(2, "illegal count\n"); 326 return; 327 } 328 n = (n - 2)/2; 329 rb = (byte*)b + 2; 330 s = malloc(n*UTFmax+1); 331 for(l=0; --n >= 0; rb += 2){ 332 r = GET2(rb); 333 l += runetochar(s+l, &r); 334 } 335 s[l] = 0; 336 fprint(2, "\"%s\"", s); 337 free(s); 338 } 339 340 void 341 pcs_raw(char *tag, byte *b, int n) 342 { 343 int i; 344 345 if (debug & Dbginfo) { 346 fprint(2, "%s", tag); 347 for(i=2; i<n; i++) 348 fprint(2, " %.2x", b[i]); 349 } 350 } 351 352 static void 353 pcs_config(Device *, int, ulong, void *b, int n) 354 { 355 pcs_raw("CS_CONFIG", b, n); 356 } 357 358 static void 359 pcs_string(Device *, ulong, void *b, int n) 360 { 361 pcs_raw("CS_STRING", b, n); 362 } 363 364 static void 365 pcs_endpoint(Device *, int, ulong, void *bb, int n) 366 { 367 byte *b = bb; 368 369 if (debug & Dbginfo) { 370 switch(b[2]) { 371 case 0x01: 372 fprint(2, 373 "CS_ENDPOINT for TerminalID %d, delay %d, format_tag %#ux\n", 374 b[3], b[4], b[5] | (b[6]<<8)); 375 break; 376 case 0x02: 377 fprint(2, 378 "CS_INTERFACE FORMAT_TYPE %d, channels %d, subframesize %d, resolution %d, freqtype %d, ", 379 b[3], b[4], b[5], b[6], b[7]); 380 fprint(2, "freq0 %d, freq1 %d\n", 381 b[8] | b[9]<<8 | b[10]<<16, 382 b[11] | b[12]<<8 | b[13]<<16); 383 break; 384 default: 385 pcs_raw("CS_INTERFACE", bb, n); 386 } 387 } 388 } 389 390 static void 391 pcs_interface(Device *, int n, ulong, void *bb, int nb) 392 { 393 394 if ((debug & Dbginfo) && n >= 0) 395 pcs_raw("CS_INTERFACE", bb, nb); 396 } 397 398 void 399 pdesc(Device *d, int c, ulong csp, byte *b, int n) 400 { 401 int class, subclass, proto, dalt, i, ep, ifc, len; 402 DConfig *dc; 403 DEndpoint *de; 404 DInterface *di; 405 Dinf *dif; 406 Endpt *dep; 407 void (*f)(Device *, int, ulong, void*, int); 408 char scbuf[64]; 409 410 class = Class(csp); 411 dalt = -1; 412 ifc = -1; 413 if (c >= nelem(d->config)) { 414 fprint(2, "Too many interfaces (%d of %d)\n", 415 c, nelem(d->config)); 416 return; 417 } 418 if(debug & Dbginfo) 419 fprint(2, "pdesc %d.%d [%d]\n", d->id, c, n); 420 len = -1; 421 while(n > 2 && b[0] && b[0] <= n){ 422 if (debug & Dbginfo) 423 fprint(2, "desc %d.%d [%d] %#2.2x: ", d->id, c, b[0], b[1]); 424 switch (b[1]) { 425 case CONFIGURATION: 426 if(b[0] < DCONFLEN){ 427 if(debug & Dbginfo) 428 fprint(2, "short config %d < %d", b[0], DCONFLEN); 429 return; 430 } 431 dc = (DConfig*)b; 432 d->config[c]->nif = dc->bNumInterfaces; 433 d->config[c]->cval = dc->bConfigurationValue; 434 d->config[c]->attrib = dc->bmAttributes; 435 d->config[c]->milliamps = dc->MaxPower*2; 436 d->nif += d->config[c]->nif; 437 if (debug & Dbginfo) 438 fprint(2, "config %d: tdlen %d ninterface %d iconfig %d attr %#.2x power %dmA\n", 439 dc->bConfigurationValue, 440 GET2(dc->wTotalLength), 441 dc->bNumInterfaces, dc->iConfiguration, 442 dc->bmAttributes, dc->MaxPower*2); 443 break; 444 case INTERFACE: 445 if(n < DINTERLEN){ 446 if(debug & Dbginfo) 447 fprint(2, "short interface %d < %d", b[0], DINTERLEN); 448 return; 449 } 450 di = (DInterface *)b; 451 class = di->bInterfaceClass; 452 subclass = di->bInterfaceSubClass; 453 proto = di->bInterfaceProtocol; 454 csp = CSP(class, subclass, proto); 455 if(debug & Dbginfo){ 456 sclass(scbuf, scbuf + sizeof scbuf, csp); 457 fprint(2, "interface %d: alt %d nept %d class %#x subclass %#x proto %d [%s] iinterface %d\n", 458 di->bInterfaceNumber, 459 di->bAlternateSetting, 460 di->bNumEndpoints, class, subclass, 461 proto, scbuf, di->iInterface); 462 } 463 if (c < 0) { 464 fprint(2, "Unexpected INTERFACE message\n"); 465 return; 466 } 467 ifc = di->bInterfaceNumber; 468 dalt = di->bAlternateSetting; 469 if (ifc < 0 || ifc >= nelem(d->config[c]->iface)) 470 sysfatal("Bad interface number %d", ifc); 471 if (dalt < 0 || 472 dalt >= nelem(d->config[c]->iface[ifc]->dalt)) 473 sysfatal("Bad alternate number %d", dalt); 474 if (d->config[c] == nil) 475 sysfatal("No config"); 476 if (ifc == 0) { 477 if (c == 0) 478 d->ep[0]->csp = csp; 479 d->config[c]->csp = csp; 480 } 481 dif = d->config[c]->iface[ifc]; 482 if (dif == nil) { 483 d->config[c]->iface[ifc] = dif = 484 mallocz(sizeof(Dinf), 1); 485 dif->csp = csp; 486 } 487 dif->interface = di->bInterfaceNumber; 488 break; 489 case ENDPOINT: 490 if(n < DENDPLEN) 491 return; 492 de = (DEndpoint *)b; 493 if(debug & Dbginfo) { 494 fprint(2, "addr %#2.2x attrib %#2.2x maxpkt %d interval %dms", 495 de->bEndpointAddress, de->bmAttributes, 496 GET2(de->wMaxPacketSize), de->bInterval); 497 if(de->bEndpointAddress & 0x80) 498 fprint(2, " [IN]"); 499 else 500 fprint(2, " [OUT]"); 501 switch(de->bmAttributes&0x33){ 502 case 0: 503 fprint(2, " [Control]"); 504 break; 505 case 1: 506 fprint(2, " [Iso]"); 507 switch(de->bmAttributes&0xc){ 508 case 0x4: 509 fprint(2, " [Asynchronous]"); 510 break; 511 case 0x8: 512 fprint(2, " [Adaptive]"); 513 break; 514 case 0xc: 515 fprint(2, " [Synchronous]"); 516 break; 517 } 518 break; 519 case 2: 520 fprint(2, " [Bulk]"); 521 break; 522 case 3: 523 fprint(2, " [Interrupt]"); 524 break; 525 } 526 if(b[0] == 9) 527 fprint(2, "refresh %d synchaddress %d", 528 b[7], b[8]); 529 fprint(2, "\n"); 530 } 531 if (c < 0 || ifc < 0 || dalt < 0) { 532 fprint(2, "Unexpected ENDPOINT message\n"); 533 return; 534 } 535 dif = d->config[c]->iface[ifc]; 536 if (dif == nil) 537 sysfatal("d->config[%d]->iface[%d] == nil", 538 c, ifc); 539 if (dif->dalt[dalt] == nil) 540 dif->dalt[dalt] = mallocz(sizeof(Dalt),1); 541 dif->dalt[dalt]->attrib = de->bmAttributes; 542 dif->dalt[dalt]->interval = de->bInterval; 543 ep = de->bEndpointAddress & 0xf; 544 dep = d->ep[ep]; 545 if(debug) 546 fprint(2, "%s: endpoint addr %d\n", argv0, ep); 547 if(dep == nil){ 548 d->ep[ep] = dep = newendpt(d, ep, class); 549 dep->dir = de->bEndpointAddress & 0x80 550 ? Ein : Eout; 551 }else if ((dep->addr&0x80) != 552 (de->bEndpointAddress&0x80)) 553 dep->dir = Eboth; 554 dep->maxpkt = GET2(de->wMaxPacketSize); 555 dep->addr = de->bEndpointAddress; 556 dep->type = de->bmAttributes & 0x03; 557 dep->isotype = (de->bmAttributes>>2) & 0x03; 558 dep->csp = csp; 559 dep->conf = d->config[c]; 560 dep->iface = dif; 561 for(i = 0; i < nelem(dif->endpt); i++) 562 if(dif->endpt[i] == nil){ 563 dif->endpt[i] = dep; 564 break; 565 } 566 if(i == nelem(dif->endpt)) 567 fprint(2, "Too many endpoints\n"); 568 if (d->nif <= ep) 569 d->nif = ep+1; 570 break; 571 default: 572 assert(nelem(dprinter) == 0x100); 573 f = dprinter[b[1]]; 574 if(f != nil){ 575 (*f)(d, c, dalt<<24 | ifc<<16 | (csp&0xffff), 576 b, b[0]); 577 if(debug & Dbginfo) 578 fprint(2, "\n"); 579 }else 580 if(verbose){ 581 int i; 582 583 switch(b[1]){ 584 case DEVICE: 585 fprint(2, "(device)"); 586 break; 587 case STRING: 588 fprint(2, "(string)"); 589 break; 590 default: 591 fprint(2, "(unknown type)"); 592 } 593 for(i=1; i<b[0]; i++) 594 fprint(2, " %.2x", b[i]); 595 fprint(2, "\n"); 596 }else if(debug & Dbginfo) 597 fprint(2, "\n"); 598 break; 599 } 600 len = b[0]; 601 n -= len; 602 b += len; 603 } 604 if(n) 605 fprint(2, "pdesc: %d bytes left unparsed, b[0]=%d, b[-len]=%d, len=%d\n", n, b[0], b[-len], len); 606 } 607