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 /= 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 391 class = Class(csp); 392 393 if (c >= nelem(d->config)) { 394 fprint(2, "Too many interfaces (%d of %d)\n", 395 c, nelem(d->config)); 396 return; 397 } 398 if (debug & Dbginfo) 399 fprint(2, "pdesc %d.%d [%d]\n", d->id, c, n); 400 for(; n > 2 && b[0] && b[0] <= n; b += b[0]){ 401 if (debug & Dbginfo) 402 fprint(2, "desc %d.%d [%d] %#2.2x: ", d->id, c, b[0], b[1]); 403 switch (b[1]) { 404 case CONFIGURATION: 405 if(b[0] < DCONFLEN) 406 return; 407 dc = (DConfig*)b; 408 d->config[c]->nif = dc->bNumInterfaces; 409 d->config[c]->cval = dc->bConfigurationValue; 410 d->config[c]->attrib = dc->bmAttributes; 411 d->config[c]->milliamps = dc->MaxPower*2; 412 d->nif += d->config[c]->nif; 413 if (debug & Dbginfo) 414 fprint(2, "config %d: tdlen %d ninterface %d iconfig %d attr %#.2x power %dmA\n", 415 dc->bConfigurationValue, GET2(dc->wTotalLength), 416 dc->bNumInterfaces, dc->iConfiguration, dc->bmAttributes, 417 dc->MaxPower*2); 418 break; 419 case INTERFACE: 420 if(n < DINTERLEN) 421 return; 422 di = (DInterface *)b; 423 class = di->bInterfaceClass; 424 subclass = di->bInterfaceSubClass; 425 proto = di->bInterfaceProtocol; 426 csp = CSP(class, subclass, proto); 427 if (debug & Dbginfo) 428 fprint(2, "interface %d: alt %d nept %d class %#x subclass %#x proto %d [%s] iinterface %d\n", 429 di->bInterfaceNumber, di->bAlternateSetting, 430 di->bNumEndpoints, class, subclass, proto, 431 sclass(csp), 432 di->iInterface); 433 if (c < 0) { 434 fprint(2, "Unexpected INTERFACE message\n"); 435 return; 436 } 437 ifc = di->bInterfaceNumber; 438 dalt = di->bAlternateSetting; 439 if (ifc < 0 || ifc >= nelem(d->config[c]->iface)) 440 sysfatal("Bad interface number %d", ifc); 441 if (dalt < 0 || dalt >= nelem(d->config[c]->iface[ifc]->dalt)) 442 sysfatal("Bad alternate number %d", dalt); 443 if (d->config[c] == nil) 444 sysfatal("No config"); 445 if (ifc == 0) { 446 if (c == 0) 447 d->ep[0]->csp = csp; 448 d->config[c]->csp = csp; 449 } 450 if (d->config[c]->iface[ifc] == nil) { 451 d->config[c]->iface[ifc] = mallocz(sizeof(Dinf), 1); 452 d->config[c]->iface[ifc]->csp = csp; 453 } 454 d->config[c]->iface[ifc]->interface = di->bInterfaceNumber; 455 break; 456 case ENDPOINT: 457 if(n < DENDPLEN) 458 return; 459 de = (DEndpoint *)b; 460 if (debug & Dbginfo) { 461 fprint(2, "addr %#2.2x attrib %#2.2x maxpkt %d interval %dms", 462 de->bEndpointAddress, de->bmAttributes, 463 GET2(de->wMaxPacketSize), de->bInterval); 464 if(de->bEndpointAddress & 0x80) 465 fprint(2, " [IN]"); 466 else 467 fprint(2, " [OUT]"); 468 switch(de->bmAttributes&0x33){ 469 case 0: fprint(2, " [Control]"); break; 470 case 1: fprint(2, " [Iso]"); 471 switch(de->bmAttributes&0xc){ 472 case 0x4: fprint(2, " [Asynchronous]"); break; 473 case 0x8: fprint(2, " [Adaptive]"); break; 474 case 0xc: fprint(2, " [Synchronous]"); break; 475 } 476 break; 477 case 2: fprint(2, " [Bulk]"); break; 478 case 3: fprint(2, " [Interrupt]"); break; 479 } 480 if(b[0] == 9) 481 fprint(2, "refresh %d synchaddress %d", b[7], b[8]); 482 fprint(2, "\n"); 483 } 484 if (c < 0 || ifc < 0 || dalt < 0) { 485 fprint(2, "Unexpected ENDPOINT message\n"); 486 return; 487 } 488 if (d->config[c]->iface[ifc] == nil) 489 sysfatal("d->config[c]->iface[ifc] == nil"); 490 if (d->config[c]->iface[ifc]->dalt[dalt] == nil) 491 d->config[c]->iface[ifc]->dalt[dalt] = mallocz(sizeof(Dalt),1); 492 d->config[c]->iface[ifc]->addr = de->bEndpointAddress; 493 d->config[c]->iface[ifc]->dalt[dalt]->maxpkt = GET2(de->wMaxPacketSize); 494 d->config[c]->iface[ifc]->dalt[dalt]->attrib = de->bmAttributes; 495 d->config[c]->iface[ifc]->dalt[dalt]->interval = de->bInterval; 496 ep = de->bEndpointAddress & 0xf; 497 if (d->ep[ep] == nil) 498 d->ep[ep] = newendpt(d, ep, class); 499 d->ep[ep]->csp = csp; 500 d->ep[ep]->conf = d->config[c]; 501 d->ep[ep]->iface = d->config[c]->iface[ifc]; 502 if (d->nif <= ep) d->nif = ep+1; 503 break; 504 default: 505 f = nil; 506 if(b[1] < nelem(dprinter)) 507 f = dprinter[b[1]]; 508 if(f != nil) { 509 (*f)(d, c, (dalt<<24) | (ifc<<16) | (csp&0xffff), b, b[0]); 510 if (debug & Dbginfo) 511 fprint(2, "\n"); 512 } 513 else { 514 if (verbose) { 515 int i; 516 517 fprint(2, "(unknown type)"); 518 for(i=1; i<b[0]; i++) 519 fprint(2, " %.2x", b[i]); 520 fprint(2, "\n"); 521 } 522 else if (debug & Dbginfo) 523 fprint(2, "\n"); 524 } 525 } 526 n -= b[0]; 527 } 528 } 529