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, "hid too short\n"); 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: fprint(2, "Input"); tab = ioflags; break; 179 case Toutput: fprint(2, "Output"); tab = ioflags; break; 180 case Tfeature: fprint(2, "Feature"); tab = ioflags; break; 181 case Tcoll: fprint(2, "Collection"); indent++; break; 182 case Tecoll: fprint(2, "End Collection"); indent--; break; 183 default: fprint(2, "unexpected item %.2x", tag); 184 } 185 fprint(2, "=%#ux", v); 186 if(tab != nil) 187 pflag(tab, v); 188 } 189 break; 190 case Tglobal: 191 if (debug & Dbginfo) { 192 fprint(2, "Global %#ux: ", v); 193 switch(tag & Tmitem){ 194 case Tusagepage: 195 fprint(2, "Usage Page %#ux", v); 196 break; 197 case Tlmin: 198 fprint(2, "Logical Min %d", v); 199 break; 200 case Tlmax: 201 fprint(2, "Logical Max %d", v); 202 break; 203 case Tpmin: 204 fprint(2, "Physical Min %d", v); 205 break; 206 case Tpmax: 207 fprint(2, "Physical Max %d", v); 208 break; 209 case Tunitexp: 210 fprint(2, "Unit Exponent %d", v); 211 break; 212 case Tunit: 213 fprint(2, "Unit %d", v); 214 break; 215 case Trepsize: 216 fprint(2, "Report size %d", v); 217 break; 218 case TrepID: 219 fprint(2, "Report ID %#x", v); 220 break; 221 case Trepcount: 222 fprint(2, "Report Count %d", v); 223 break; 224 case Tpush: 225 fprint(2, "Push %d", v); 226 break; 227 case Tpop: 228 fprint(2, "Pop %d", v); 229 break; 230 default: 231 fprint(2, "Unknown %#ux", v); 232 break; 233 } 234 } 235 break; 236 case Tlocal: 237 if (debug & Dbginfo) { 238 fprint(2, "Local %#ux: ", v); 239 switch(tag & Tmitem){ 240 case Tusage: 241 fprint(2, "Usage %d", v); 242 break; 243 case Tumin: 244 fprint(2, "Usage min %d", v); 245 break; 246 case Tumax: 247 fprint(2, "Usage max %d", v); 248 break; 249 case Tdindex: 250 fprint(2, "Designator index %d", v); 251 break; 252 case Tdmin: 253 fprint(2, "Designator min %d", v); 254 break; 255 case Tdmax: 256 fprint(2, "Designator max %d", v); 257 break; 258 case Tsindex: 259 fprint(2, "String index %d", v); 260 break; 261 case Tsmin: 262 fprint(2, "String min %d", v); 263 break; 264 case Tsmax: 265 fprint(2, "String max %d", v); 266 break; 267 case Tsetdelim: 268 fprint(2, "Set delim %#ux", v); 269 break; 270 default: 271 fprint(2, "Unknown %#ux", v); 272 break; 273 } 274 } 275 break; 276 } 277 fprint(2, "\n"); 278 s += nb; 279 } 280 } 281 282 void 283 phub(Device *, int, ulong, void *b, int n) 284 { 285 DHub *d; 286 287 if(n < DHUBLEN) 288 return; 289 d = b; 290 if (debug & Dbginfo) 291 fprint(2, "nport %d charac %#.4x pwr %dms current %dmA remov %#.2x", 292 d->bNbrPorts, GET2(d->wHubCharacteristics), d->bPwrOn2PwrGood*2, 293 d->bHubContrCurrent, d->DeviceRemovable[0]); 294 } 295 296 void 297 pstring(Device *, int, ulong, void *b, int n) 298 { 299 byte *rb; 300 char *s; 301 Rune r; 302 int l; 303 304 if(n <= 2){ 305 fprint(2, "\"\""); 306 return; 307 } 308 if(n & 1){ 309 fprint(2, "illegal count\n"); 310 return; 311 } 312 n = (n - 2)/2; 313 rb = (byte*)b + 2; 314 s = malloc(n*UTFmax+1); 315 for(l=0; --n >= 0; rb += 2){ 316 r = GET2(rb); 317 l += runetochar(s+l, &r); 318 } 319 s[l] = 0; 320 fprint(2, "\"%s\"", s); 321 free(s); 322 } 323 324 void 325 pcs_raw(char *tag, byte *b, int n) 326 { 327 int i; 328 329 if (debug & Dbginfo) { 330 fprint(2, "%s", tag); 331 for(i=2; i<n; i++) 332 fprint(2, " %.2x", b[i]); 333 } 334 } 335 336 static void 337 pcs_config(Device *, int, ulong, void *b, int n) 338 { 339 pcs_raw("CS_CONFIG", b, n); 340 } 341 342 static void 343 pcs_string(Device *, ulong, void *b, int n) 344 { 345 pcs_raw("CS_STRING", b, n); 346 } 347 348 static void 349 pcs_endpoint(Device *, int, ulong, void *bb, int n) 350 { 351 byte *b = bb; 352 353 if (debug & Dbginfo) { 354 switch(b[2]) { 355 case 0x01: 356 fprint(2, "CS_ENDPOINT for TerminalID %d, delay %d, format_tag %#ux\n", 357 b[3], b[4], b[5] | (b[6]<<8)); 358 break; 359 case 0x02: 360 fprint(2, "CS_INTERFACE FORMAT_TYPE %d, channels %d, subframesize %d, resolution %d, freqtype %d, ", 361 b[3], b[4], b[5], b[6], b[7]); 362 fprint(2, "freq0 %d, freq1 %d\n", 363 b[8] | (b[9]<<8) | (b[10]<<16), b[11] | (b[12]<<8) | (b[13]<<16)); 364 break; 365 default: 366 pcs_raw("CS_INTERFACE", bb, n); 367 } 368 } 369 } 370 371 static void 372 pcs_interface(Device *, int n, ulong, void *bb, int nb) { 373 374 if ((debug & Dbginfo) && n >= 0) { 375 pcs_raw("CS_INTERFACE", bb, nb); 376 } 377 } 378 379 void 380 pdesc(Device *d, int c, ulong csp, byte *b, int n) 381 { 382 void (*f)(Device *, int, ulong, void*, int); 383 int ifc = -1; 384 int dalt = -1; 385 int ep; 386 int class, subclass, proto; 387 DConfig *dc; 388 DInterface *di; 389 DEndpoint *de; 390 int i; 391 392 class = Class(csp); 393 394 if (c >= nelem(d->config)) { 395 fprint(2, "Too many interfaces (%d of %d)\n", 396 c, nelem(d->config)); 397 return; 398 } 399 if (debug & Dbginfo) 400 fprint(2, "pdesc %d.%d [%d]\n", d->id, c, n); 401 for(; n > 2 && b[0] && b[0] <= n; b += b[0]){ 402 if (debug & Dbginfo) 403 fprint(2, "desc %d.%d [%d] %#2.2x: ", d->id, c, b[0], b[1]); 404 switch (b[1]) { 405 case CONFIGURATION: 406 if(b[0] < DCONFLEN) 407 return; 408 dc = (DConfig*)b; 409 d->config[c]->nif = dc->bNumInterfaces; 410 d->config[c]->cval = dc->bConfigurationValue; 411 d->config[c]->attrib = dc->bmAttributes; 412 d->config[c]->milliamps = dc->MaxPower*2; 413 d->nif += d->config[c]->nif; 414 if (debug & Dbginfo) 415 fprint(2, "config %d: tdlen %d ninterface %d iconfig %d attr %#.2x power %dmA\n", 416 dc->bConfigurationValue, GET2(dc->wTotalLength), 417 dc->bNumInterfaces, dc->iConfiguration, dc->bmAttributes, 418 dc->MaxPower*2); 419 break; 420 case INTERFACE: 421 if(n < DINTERLEN) 422 return; 423 di = (DInterface *)b; 424 class = di->bInterfaceClass; 425 subclass = di->bInterfaceSubClass; 426 proto = di->bInterfaceProtocol; 427 csp = CSP(class, subclass, proto); 428 if (debug & Dbginfo) 429 fprint(2, "interface %d: alt %d nept %d class %#x subclass %#x proto %d [%s] iinterface %d\n", 430 di->bInterfaceNumber, di->bAlternateSetting, 431 di->bNumEndpoints, class, subclass, proto, 432 sclass(csp), 433 di->iInterface); 434 if (c < 0) { 435 fprint(2, "Unexpected INTERFACE message\n"); 436 return; 437 } 438 ifc = di->bInterfaceNumber; 439 dalt = di->bAlternateSetting; 440 if (ifc < 0 || ifc >= nelem(d->config[c]->iface)) 441 sysfatal("Bad interface number %d", ifc); 442 if (dalt < 0 || dalt >= nelem(d->config[c]->iface[ifc]->dalt)) 443 sysfatal("Bad alternate number %d", dalt); 444 if (d->config[c] == nil) 445 sysfatal("No config"); 446 if (ifc == 0) { 447 if (c == 0) 448 d->ep[0]->csp = csp; 449 d->config[c]->csp = csp; 450 } 451 if (d->config[c]->iface[ifc] == nil) { 452 d->config[c]->iface[ifc] = mallocz(sizeof(Dinf), 1); 453 d->config[c]->iface[ifc]->csp = csp; 454 } 455 d->config[c]->iface[ifc]->interface = di->bInterfaceNumber; 456 break; 457 case ENDPOINT: 458 if(n < DENDPLEN) 459 return; 460 de = (DEndpoint *)b; 461 if (debug & Dbginfo) { 462 fprint(2, "addr %#2.2x attrib %#2.2x maxpkt %d interval %dms", 463 de->bEndpointAddress, de->bmAttributes, 464 GET2(de->wMaxPacketSize), de->bInterval); 465 if(de->bEndpointAddress & 0x80) 466 fprint(2, " [IN]"); 467 else 468 fprint(2, " [OUT]"); 469 switch(de->bmAttributes&0x33){ 470 case 0: fprint(2, " [Control]"); break; 471 case 1: fprint(2, " [Iso]"); 472 switch(de->bmAttributes&0xc){ 473 case 0x4: fprint(2, " [Asynchronous]"); break; 474 case 0x8: fprint(2, " [Adaptive]"); break; 475 case 0xc: fprint(2, " [Synchronous]"); break; 476 } 477 break; 478 case 2: fprint(2, " [Bulk]"); break; 479 case 3: fprint(2, " [Interrupt]"); break; 480 } 481 if(b[0] == 9) 482 fprint(2, "refresh %d synchaddress %d", b[7], b[8]); 483 fprint(2, "\n"); 484 } 485 if (c < 0 || ifc < 0 || dalt < 0) { 486 fprint(2, "Unexpected ENDPOINT message\n"); 487 return; 488 } 489 if (d->config[c]->iface[ifc] == nil) 490 sysfatal("d->config[c]->iface[ifc] == nil"); 491 if (d->config[c]->iface[ifc]->dalt[dalt] == nil) 492 d->config[c]->iface[ifc]->dalt[dalt] = mallocz(sizeof(Dalt),1); 493 d->config[c]->iface[ifc]->dalt[dalt]->attrib = de->bmAttributes; 494 d->config[c]->iface[ifc]->dalt[dalt]->interval = de->bInterval; 495 ep = de->bEndpointAddress & 0xf; 496 if (debug) print("endpoint addr %d\n", ep); // DEBUG 497 if (d->ep[ep] == nil) 498 d->ep[ep] = newendpt(d, ep, class); 499 else print("endpoint already in use!\n"); // DEBUG 500 if(d->ep[ep]->maxpkt < GET2(de->wMaxPacketSize)) 501 d->ep[ep]->maxpkt = GET2(de->wMaxPacketSize); 502 d->ep[ep]->addr = de->bEndpointAddress; 503 d->ep[ep]->dir = (de->bEndpointAddress & 0x80) ? Ein : Eout; 504 d->ep[ep]->type = de->bmAttributes & 0x03; 505 d->ep[ep]->isotype = (de->bmAttributes>>2) & 0x03; 506 d->ep[ep]->csp = csp; 507 d->ep[ep]->conf = d->config[c]; 508 d->ep[ep]->iface = d->config[c]->iface[ifc]; 509 for(i = 0; i < nelem(d->config[c]->iface[ifc]->endpt); i++){ 510 if(d->config[c]->iface[ifc]->endpt[i] == nil){ 511 d->config[c]->iface[ifc]->endpt[i] = d->ep[ep]; 512 break; 513 } 514 } 515 if(i == nelem(d->config[c]->iface[ifc]->endpt)) 516 fprint(2, "Too many endpoints\n"); 517 if (d->nif <= ep) d->nif = ep+1; 518 break; 519 default: 520 assert(nelem(dprinter) == 0x100); 521 f = dprinter[b[1]]; 522 if(f != nil) { 523 (*f)(d, c, (dalt<<24) | (ifc<<16) | (csp&0xffff), b, b[0]); 524 if (debug & Dbginfo) 525 fprint(2, "\n"); 526 } 527 else { 528 if (verbose) { 529 int i; 530 531 fprint(2, "(unknown type)"); 532 for(i=1; i<b[0]; i++) 533 fprint(2, " %.2x", b[i]); 534 fprint(2, "\n"); 535 } 536 else if (debug & Dbginfo) 537 fprint(2, "\n"); 538 } 539 } 540 n -= b[0]; 541 } 542 } 543