#include #include #include #include #include "usb.h" int verbose; typedef struct Flags Flags; typedef struct Classes Classes; struct Flags { int bit; char* name0; char* name1; }; struct Classes { char* name; struct { char* name; char* proto[4]; } subclass[4]; }; static Classes classname[] = { [CL_AUDIO] {"audio", {[1] {"control"}, [2] {"stream"}, [3]{"midi"}}}, [CL_COMMS] {"comms", {[1] {"abstract", {[1]"AT"}}}}, [CL_HID] {"hid", {[1]{"boot", {[1]"kbd", [2]"mouse"}}}}, [CL_PRINTER] {"printer", {[1]"printer", {[1] "uni", [2]"bi"}}}, [CL_HUB] {"hub", {[1]{"hub"}}}, [CL_DATA] {"data"}, }; static void pflag(Flags*, uint); char * sclass(ulong csp) { Classes *cs; int n; static char buf[64]; int c, s, p; c = Class(csp); s = Subclass(csp); p = Proto(csp); if(c < 0 || c >= nelem(classname) || (cs = &classname[c])->name == nil){ sprint(buf, "%d.%d.%d", c, s, p); return buf; } n = sprint(buf, "%s.", cs->name); if(s < 0 || s >= nelem(cs->subclass) || cs->subclass[s].name == nil) sprint(buf+n, "%d.%d", s, p); else{ n += sprint(buf+n, "%s.", cs->subclass[s].name); if(p < 0 || p >= nelem(cs->subclass[s].proto) || cs->subclass[s].proto[p] == nil) sprint(buf+n, "%d", p); else sprint(buf+n, "%s", cs->subclass[s].proto[p]); } return buf; } void pdevice(Device *, int, ulong, void *b, int n) { DDevice *d; if(n < DDEVLEN) return; d = b; if (debug & Dbginfo) { fprint(2, "usb (bcd)%c%c%c%c", '0'+((d->bcdUSB[1]>>4)&0xf), '0'+(d->bcdUSB[1]&0xf), '0'+((d->bcdUSB[0]>>4)&0xf), '0'+(d->bcdUSB[0]&0xf)); fprint(2, " class %d subclass %d proto %d [%s] max0 %d", d->bDeviceClass, d->bDeviceSubClass, d->bDeviceProtocol, sclass(CSP(d->bDeviceClass, d->bDeviceSubClass, d->bDeviceProtocol)), d->bMaxPacketSize0); fprint(2, " vendor %#x product %#x device (bcd)%c%c%c%c", GET2(d->idVendor), GET2(d->idProduct), '0'+((d->bcdDevice[1]>>4)&0xf), '0'+(d->bcdDevice[1]&0xf), '0'+((d->bcdDevice[0]>>4)&0xf), '0'+(d->bcdDevice[0]&0xf)); fprint(2, " man %d prod %d serial %d nconfig %d", d->iManufacturer, d->iProduct, d->iSerialNumber, d->bNumConfigurations); } } void phid(Device *, int, ulong, void *b, int n) { DHid *d; if(n < DHIDLEN){ fprint(2, "hid too short\n"); return; } d = b; if (debug & Dbginfo) fprint(2, "HID (bcd)%c%c%c%c country %d nhidclass %d classdtype %#x dlen %d\n", '0'+((d->bcdHID[1]>>4)&0xf), '0'+(d->bcdHID[1]&0xf), '0'+((d->bcdHID[0]>>4)&0xf), '0'+(d->bcdHID[0]&0xf), d->bCountryCode, d->bNumDescriptors, d->bClassDescriptorType, GET2(d->wItemLength)); } static Flags ioflags[] = { {0, "Data", "Constant"}, {1, "Array", "Variable"}, {2, "Absolute", "Relative"}, {3, "NoWrap", "Wrap"}, {4, "Linear", "NonLinear"}, {5, "PreferredState", "No Preferred State"}, {6, "No Null position", "Null state"}, {7, "Non Volatile", "Volatile"}, {8, "Bit Field", "Buffered Bytes"}, {-1, nil, nil}, }; static void pflag(Flags *tab, uint v) { char buf[200], *s; int n; n = 0; buf[0] = 0; for(; tab->name0 != nil; tab++){ if(v & (1<bit)) s = tab->name1; else s = tab->name0; if(s != nil && *s) n += snprint(buf+n, sizeof(buf)-n, ", %s", s); } if((debug & Dbginfo) && buf[0]) fprint(2, "[%s]", buf+2); } void preport(Device *, int, ulong, byte *b, int n) { byte *s, *es; int tag, nb, i, indent; int v; Flags *tab; s = b+2; es = b+n; indent = 0; while(s < es){ for(i=0; ibNbrPorts, GET2(d->wHubCharacteristics), d->bPwrOn2PwrGood*2, d->bHubContrCurrent, d->DeviceRemovable[0]); } void pstring(Device *, int, ulong, void *b, int n) { byte *rb; char *s; Rune r; int l; if(n <= 2){ fprint(2, "\"\""); return; } if(n & 1){ fprint(2, "illegal count\n"); return; } n /= 2; rb = (byte*)b + 2; s = malloc(n*UTFmax+1); for(l=0; --n >= 0; rb += 2){ r = GET2(rb); l += runetochar(s+l, &r); } s[l] = 0; fprint(2, "\"%s\"", s); free(s); } void pcs_raw(char *tag, byte *b, int n) { int i; if (debug & Dbginfo) { fprint(2, "%s", tag); for(i=2; i= 0) { pcs_raw("CS_INTERFACE", bb, nb); } } void pdesc(Device *d, int c, ulong csp, byte *b, int n) { void (*f)(Device *, int, ulong, void*, int); int ifc = -1; int dalt = -1; int ep; int class, subclass, proto; DConfig *dc; DInterface *di; DEndpoint *de; int i; class = Class(csp); if (c >= nelem(d->config)) { fprint(2, "Too many interfaces (%d of %d)\n", c, nelem(d->config)); return; } if (debug & Dbginfo) fprint(2, "pdesc %d.%d [%d]\n", d->id, c, n); for(; n > 2 && b[0] && b[0] <= n; b += b[0]){ if (debug & Dbginfo) fprint(2, "desc %d.%d [%d] %#2.2x: ", d->id, c, b[0], b[1]); switch (b[1]) { case CONFIGURATION: if(b[0] < DCONFLEN) return; dc = (DConfig*)b; d->config[c]->nif = dc->bNumInterfaces; d->config[c]->cval = dc->bConfigurationValue; d->config[c]->attrib = dc->bmAttributes; d->config[c]->milliamps = dc->MaxPower*2; d->nif += d->config[c]->nif; if (debug & Dbginfo) fprint(2, "config %d: tdlen %d ninterface %d iconfig %d attr %#.2x power %dmA\n", dc->bConfigurationValue, GET2(dc->wTotalLength), dc->bNumInterfaces, dc->iConfiguration, dc->bmAttributes, dc->MaxPower*2); break; case INTERFACE: if(n < DINTERLEN) return; di = (DInterface *)b; class = di->bInterfaceClass; subclass = di->bInterfaceSubClass; proto = di->bInterfaceProtocol; csp = CSP(class, subclass, proto); if (debug & Dbginfo) fprint(2, "interface %d: alt %d nept %d class %#x subclass %#x proto %d [%s] iinterface %d\n", di->bInterfaceNumber, di->bAlternateSetting, di->bNumEndpoints, class, subclass, proto, sclass(csp), di->iInterface); if (c < 0) { fprint(2, "Unexpected INTERFACE message\n"); return; } ifc = di->bInterfaceNumber; dalt = di->bAlternateSetting; if (ifc < 0 || ifc >= nelem(d->config[c]->iface)) sysfatal("Bad interface number %d", ifc); if (dalt < 0 || dalt >= nelem(d->config[c]->iface[ifc]->dalt)) sysfatal("Bad alternate number %d", dalt); if (d->config[c] == nil) sysfatal("No config"); if (ifc == 0) { if (c == 0) d->ep[0]->csp = csp; d->config[c]->csp = csp; } if (d->config[c]->iface[ifc] == nil) { d->config[c]->iface[ifc] = mallocz(sizeof(Dinf), 1); d->config[c]->iface[ifc]->csp = csp; } d->config[c]->iface[ifc]->interface = di->bInterfaceNumber; break; case ENDPOINT: if(n < DENDPLEN) return; de = (DEndpoint *)b; if (debug & Dbginfo) { fprint(2, "addr %#2.2x attrib %#2.2x maxpkt %d interval %dms", de->bEndpointAddress, de->bmAttributes, GET2(de->wMaxPacketSize), de->bInterval); if(de->bEndpointAddress & 0x80) fprint(2, " [IN]"); else fprint(2, " [OUT]"); switch(de->bmAttributes&0x33){ case 0: fprint(2, " [Control]"); break; case 1: fprint(2, " [Iso]"); switch(de->bmAttributes&0xc){ case 0x4: fprint(2, " [Asynchronous]"); break; case 0x8: fprint(2, " [Adaptive]"); break; case 0xc: fprint(2, " [Synchronous]"); break; } break; case 2: fprint(2, " [Bulk]"); break; case 3: fprint(2, " [Interrupt]"); break; } if(b[0] == 9) fprint(2, "refresh %d synchaddress %d", b[7], b[8]); fprint(2, "\n"); } if (c < 0 || ifc < 0 || dalt < 0) { fprint(2, "Unexpected ENDPOINT message\n"); return; } if (d->config[c]->iface[ifc] == nil) sysfatal("d->config[c]->iface[ifc] == nil"); if (d->config[c]->iface[ifc]->dalt[dalt] == nil) d->config[c]->iface[ifc]->dalt[dalt] = mallocz(sizeof(Dalt),1); d->config[c]->iface[ifc]->dalt[dalt]->attrib = de->bmAttributes; d->config[c]->iface[ifc]->dalt[dalt]->interval = de->bInterval; ep = de->bEndpointAddress & 0xf; if (d->ep[ep] == nil) d->ep[ep] = newendpt(d, ep, class); d->ep[ep]->maxpkt = GET2(de->wMaxPacketSize); d->ep[ep]->addr = de->bEndpointAddress; d->ep[ep]->csp = csp; d->ep[ep]->conf = d->config[c]; d->ep[ep]->iface = d->config[c]->iface[ifc]; for(i = 0; i < nelem(d->config[c]->iface[ifc]->endpt); i++){ if(d->config[c]->iface[ifc]->endpt[i] == nil){ d->config[c]->iface[ifc]->endpt[i] = d->ep[ep]; break; } } if(i == nelem(d->config[c]->iface[ifc]->endpt)) fprint(2, "Too many endpoints\n"); if (d->nif <= ep) d->nif = ep+1; break; default: f = nil; if(b[1] < nelem(dprinter)) f = dprinter[b[1]]; if(f != nil) { (*f)(d, c, (dalt<<24) | (ifc<<16) | (csp&0xffff), b, b[0]); if (debug & Dbginfo) fprint(2, "\n"); } else { if (verbose) { int i; fprint(2, "(unknown type)"); for(i=1; i