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