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