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 77f0337cdSDavid du Colombier int verbose; 87f0337cdSDavid du Colombier 97f0337cdSDavid du Colombier typedef struct Flags Flags; 107f0337cdSDavid du Colombier typedef struct Classes Classes; 117f0337cdSDavid du Colombier 127f0337cdSDavid du Colombier struct Flags { 137f0337cdSDavid du Colombier int bit; 147f0337cdSDavid du Colombier char* name0; 157f0337cdSDavid du Colombier char* name1; 169a747e4fSDavid du Colombier }; 179a747e4fSDavid du Colombier 187f0337cdSDavid du Colombier struct Classes { 197f0337cdSDavid du Colombier char* name; 207f0337cdSDavid du Colombier struct { 217f0337cdSDavid du Colombier char* name; 227f0337cdSDavid du Colombier char* proto[4]; 237f0337cdSDavid du Colombier } subclass[4]; 249a747e4fSDavid du Colombier }; 259a747e4fSDavid du Colombier 267f0337cdSDavid du Colombier static Classes classname[] = { 277f0337cdSDavid du Colombier [CL_AUDIO] {"audio", {[1]{"control"}, [2]{"stream"}, [3]{"midi"}}}, 287f0337cdSDavid du Colombier [CL_COMMS] {"comms", {[1] {"abstract", {[1]"AT"}}}}, 297f0337cdSDavid du Colombier [CL_HID] {"hid", {[1] {"boot", {[1]"kbd", [2]"mouse"}}}}, 307f0337cdSDavid du Colombier [CL_PRINTER] {"printer", {[1]"printer", {[1]"uni", [2]"bi"}}}, 317f0337cdSDavid du Colombier [CL_HUB] {"hub", {[1]{"hub"}}}, 327f0337cdSDavid du Colombier [CL_DATA] {"data"}, 337f0337cdSDavid du Colombier }; 349a747e4fSDavid du Colombier 357f0337cdSDavid du Colombier static void pflag(Flags*, uint); 367f0337cdSDavid du Colombier 377f0337cdSDavid du Colombier char * 387f0337cdSDavid du Colombier sclass(ulong csp) 397f0337cdSDavid du Colombier { 407f0337cdSDavid du Colombier Classes *cs; 417f0337cdSDavid du Colombier int n; 427f0337cdSDavid du Colombier static char buf[64]; 437f0337cdSDavid du Colombier int c, s, p; 447f0337cdSDavid du Colombier 457f0337cdSDavid du Colombier c = Class(csp); 467f0337cdSDavid du Colombier s = Subclass(csp); 477f0337cdSDavid du Colombier p = Proto(csp); 487f0337cdSDavid du Colombier if(c < 0 || c >= nelem(classname) || (cs = &classname[c])->name == nil){ 497f0337cdSDavid du Colombier sprint(buf, "%d.%d.%d", c, s, p); 507f0337cdSDavid du Colombier return buf; 517f0337cdSDavid du Colombier } 527f0337cdSDavid du Colombier n = sprint(buf, "%s.", cs->name); 537f0337cdSDavid du Colombier if(s < 0 || s >= nelem(cs->subclass) || cs->subclass[s].name == nil) 547f0337cdSDavid du Colombier sprint(buf+n, "%d.%d", s, p); 557f0337cdSDavid du Colombier else{ 567f0337cdSDavid du Colombier n += sprint(buf+n, "%s.", cs->subclass[s].name); 577f0337cdSDavid du Colombier if(p < 0 || p >= nelem(cs->subclass[s].proto) || cs->subclass[s].proto[p] == nil) 587f0337cdSDavid du Colombier sprint(buf+n, "%d", p); 599a747e4fSDavid du Colombier else 607f0337cdSDavid du Colombier sprint(buf+n, "%s", cs->subclass[s].proto[p]); 617f0337cdSDavid du Colombier } 627f0337cdSDavid du Colombier return buf; 639a747e4fSDavid du Colombier } 649a747e4fSDavid du Colombier 659a747e4fSDavid du Colombier void 667f0337cdSDavid du Colombier pdevice(Device *, int, ulong, void *b, int n) 679a747e4fSDavid du Colombier { 687f0337cdSDavid du Colombier DDevice *d; 699a747e4fSDavid du Colombier 707f0337cdSDavid du Colombier if(n < DDEVLEN) 719a747e4fSDavid du Colombier return; 727f0337cdSDavid du Colombier d = b; 737f0337cdSDavid du Colombier if (debug & Dbginfo) { 747f0337cdSDavid du Colombier fprint(2, "usb (bcd)%c%c%c%c", 757f0337cdSDavid du Colombier '0'+((d->bcdUSB[1]>>4)&0xf), '0'+(d->bcdUSB[1]&0xf), 767f0337cdSDavid du Colombier '0'+((d->bcdUSB[0]>>4)&0xf), '0'+(d->bcdUSB[0]&0xf)); 777f0337cdSDavid du Colombier fprint(2, " class %d subclass %d proto %d [%s] max0 %d", 787f0337cdSDavid du Colombier d->bDeviceClass, d->bDeviceSubClass, d->bDeviceProtocol, 797f0337cdSDavid du Colombier sclass(CSP(d->bDeviceClass, d->bDeviceSubClass, d->bDeviceProtocol)), 807f0337cdSDavid du Colombier d->bMaxPacketSize0); 817f0337cdSDavid du Colombier fprint(2, " vendor %#x product %#x device (bcd)%c%c%c%c", 827f0337cdSDavid du Colombier GET2(d->idVendor), GET2(d->idProduct), 837f0337cdSDavid du Colombier '0'+((d->bcdDevice[1]>>4)&0xf), '0'+(d->bcdDevice[1]&0xf), 847f0337cdSDavid du Colombier '0'+((d->bcdDevice[0]>>4)&0xf), '0'+(d->bcdDevice[0]&0xf)); 857f0337cdSDavid du Colombier fprint(2, " man %d prod %d serial %d nconfig %d", 867f0337cdSDavid du Colombier d->iManufacturer, d->iProduct, d->iSerialNumber, 877f0337cdSDavid du Colombier d->bNumConfigurations); 889a747e4fSDavid du Colombier } 899a747e4fSDavid du Colombier } 909a747e4fSDavid du Colombier 919a747e4fSDavid du Colombier void 927f0337cdSDavid du Colombier phid(Device *, int, ulong, void *b, int n) 939a747e4fSDavid du Colombier { 947f0337cdSDavid du Colombier DHid *d; 959a747e4fSDavid du Colombier 967f0337cdSDavid du Colombier if(n < DHIDLEN){ 97096dd9ddSDavid du Colombier fprint(2, "%s: hid too short\n", argv0); 987f0337cdSDavid du Colombier return; 997f0337cdSDavid du Colombier } 1007f0337cdSDavid du Colombier d = b; 1017f0337cdSDavid du Colombier if (debug & Dbginfo) 1027f0337cdSDavid du Colombier fprint(2, "HID (bcd)%c%c%c%c country %d nhidclass %d classdtype %#x dlen %d\n", 1037f0337cdSDavid du Colombier '0'+((d->bcdHID[1]>>4)&0xf), '0'+(d->bcdHID[1]&0xf), 1047f0337cdSDavid du Colombier '0'+((d->bcdHID[0]>>4)&0xf), '0'+(d->bcdHID[0]&0xf), 1057f0337cdSDavid du Colombier d->bCountryCode, d->bNumDescriptors, 1067f0337cdSDavid du Colombier d->bClassDescriptorType, GET2(d->wItemLength)); 1077f0337cdSDavid du Colombier } 1087f0337cdSDavid du Colombier 1097f0337cdSDavid du Colombier static Flags ioflags[] = { 1107f0337cdSDavid du Colombier {0, "Data", "Constant"}, 1117f0337cdSDavid du Colombier {1, "Array", "Variable"}, 1127f0337cdSDavid du Colombier {2, "Absolute", "Relative"}, 1137f0337cdSDavid du Colombier {3, "NoWrap", "Wrap"}, 1147f0337cdSDavid du Colombier {4, "Linear", "NonLinear"}, 1157f0337cdSDavid du Colombier {5, "PreferredState", "No Preferred State"}, 1167f0337cdSDavid du Colombier {6, "No Null position", "Null state"}, 1177f0337cdSDavid du Colombier {7, "Non Volatile", "Volatile"}, 1187f0337cdSDavid du Colombier {8, "Bit Field", "Buffered Bytes"}, 1197f0337cdSDavid du Colombier {-1, nil, nil}, 1207f0337cdSDavid du Colombier }; 1217f0337cdSDavid du Colombier 1227f0337cdSDavid du Colombier static void 1237f0337cdSDavid du Colombier pflag(Flags *tab, uint v) 1247f0337cdSDavid du Colombier { 1257f0337cdSDavid du Colombier char buf[200], *s; 1267f0337cdSDavid du Colombier int n; 1277f0337cdSDavid du Colombier 1287f0337cdSDavid du Colombier n = 0; 1297f0337cdSDavid du Colombier buf[0] = 0; 1307f0337cdSDavid du Colombier for(; tab->name0 != nil; tab++){ 1317f0337cdSDavid du Colombier if(v & (1<<tab->bit)) 1327f0337cdSDavid du Colombier s = tab->name1; 1337f0337cdSDavid du Colombier else 1347f0337cdSDavid du Colombier s = tab->name0; 1357f0337cdSDavid du Colombier if(s != nil && *s) 1367f0337cdSDavid du Colombier n += snprint(buf+n, sizeof(buf)-n, ", %s", s); 1377f0337cdSDavid du Colombier } 1387f0337cdSDavid du Colombier if((debug & Dbginfo) && buf[0]) 1397f0337cdSDavid du Colombier fprint(2, "[%s]", buf+2); 1407f0337cdSDavid du Colombier } 1417f0337cdSDavid du Colombier 1427f0337cdSDavid du Colombier void 1437f0337cdSDavid du Colombier preport(Device *, int, ulong, byte *b, int n) 1447f0337cdSDavid du Colombier { 1457f0337cdSDavid du Colombier byte *s, *es; 1467f0337cdSDavid du Colombier int tag, nb, i, indent; 1477f0337cdSDavid du Colombier int v; 1487f0337cdSDavid du Colombier Flags *tab; 1497f0337cdSDavid du Colombier 1507f0337cdSDavid du Colombier s = b+2; 1517f0337cdSDavid du Colombier es = b+n; 1527f0337cdSDavid du Colombier indent = 0; 1537f0337cdSDavid du Colombier while(s < es){ 1547f0337cdSDavid du Colombier for(i=0; i<indent; i++) 1557f0337cdSDavid du Colombier fprint(2, " "); 1567f0337cdSDavid du Colombier tag = *s++; 1577f0337cdSDavid du Colombier if(tag == Tlong){ 1587f0337cdSDavid du Colombier fprint(2, "long report tag"); 1597f0337cdSDavid du Colombier return; 1607f0337cdSDavid du Colombier } 1617f0337cdSDavid du Colombier if((nb = tag&3) == 3) 1627f0337cdSDavid du Colombier nb = 4; 1637f0337cdSDavid du Colombier v = 0; 1647f0337cdSDavid du Colombier for(i=0; i<nb; i++) 1657f0337cdSDavid du Colombier v |= s[i] << (i*8); 1667f0337cdSDavid du Colombier switch(tag & Tmtype){ 1677f0337cdSDavid du Colombier case Treserved: 1687f0337cdSDavid du Colombier if(tag == Tlong){ 1697f0337cdSDavid du Colombier fprint(2, "long report tag"); 1707f0337cdSDavid du Colombier return; 1717f0337cdSDavid du Colombier } 1727f0337cdSDavid du Colombier fprint(2, "illegal tag"); 1737f0337cdSDavid du Colombier return; 1747f0337cdSDavid du Colombier case Tmain: 1757f0337cdSDavid du Colombier tab = nil; 1767f0337cdSDavid du Colombier if (debug & Dbginfo) { 1777f0337cdSDavid du Colombier switch(tag & Tmitem){ 178*208510e1SDavid du Colombier case Tinput: 179*208510e1SDavid du Colombier fprint(2, "Input"); 180*208510e1SDavid du Colombier tab = ioflags; 181*208510e1SDavid du Colombier break; 182*208510e1SDavid du Colombier case Toutput: 183*208510e1SDavid du Colombier fprint(2, "Output"); 184*208510e1SDavid du Colombier tab = ioflags; 185*208510e1SDavid du Colombier break; 186*208510e1SDavid du Colombier case Tfeature: 187*208510e1SDavid du Colombier fprint(2, "Feature"); 188*208510e1SDavid du Colombier tab = ioflags; 189*208510e1SDavid du Colombier break; 190*208510e1SDavid du Colombier case Tcoll: 191*208510e1SDavid du Colombier fprint(2, "Collection"); 192*208510e1SDavid du Colombier indent++; 193*208510e1SDavid du Colombier break; 194*208510e1SDavid du Colombier case Tecoll: 195*208510e1SDavid du Colombier fprint(2, "End Collection"); 196*208510e1SDavid du Colombier indent--; 197*208510e1SDavid du Colombier break; 198*208510e1SDavid du Colombier default: 199*208510e1SDavid du Colombier fprint(2, "unexpected item %.2x", tag); 2007f0337cdSDavid du Colombier } 2017f0337cdSDavid du Colombier fprint(2, "=%#ux", v); 2027f0337cdSDavid du Colombier if(tab != nil) 2037f0337cdSDavid du Colombier pflag(tab, v); 2047f0337cdSDavid du Colombier } 2057f0337cdSDavid du Colombier break; 2067f0337cdSDavid du Colombier case Tglobal: 2077f0337cdSDavid du Colombier if (debug & Dbginfo) { 2087f0337cdSDavid du Colombier fprint(2, "Global %#ux: ", v); 2097f0337cdSDavid du Colombier switch(tag & Tmitem){ 2107f0337cdSDavid du Colombier case Tusagepage: 2117f0337cdSDavid du Colombier fprint(2, "Usage Page %#ux", v); 2127f0337cdSDavid du Colombier break; 2137f0337cdSDavid du Colombier case Tlmin: 2147f0337cdSDavid du Colombier fprint(2, "Logical Min %d", v); 2157f0337cdSDavid du Colombier break; 2167f0337cdSDavid du Colombier case Tlmax: 2177f0337cdSDavid du Colombier fprint(2, "Logical Max %d", v); 2187f0337cdSDavid du Colombier break; 2197f0337cdSDavid du Colombier case Tpmin: 2207f0337cdSDavid du Colombier fprint(2, "Physical Min %d", v); 2217f0337cdSDavid du Colombier break; 2227f0337cdSDavid du Colombier case Tpmax: 2237f0337cdSDavid du Colombier fprint(2, "Physical Max %d", v); 2247f0337cdSDavid du Colombier break; 2257f0337cdSDavid du Colombier case Tunitexp: 2267f0337cdSDavid du Colombier fprint(2, "Unit Exponent %d", v); 2277f0337cdSDavid du Colombier break; 2287f0337cdSDavid du Colombier case Tunit: 2297f0337cdSDavid du Colombier fprint(2, "Unit %d", v); 2307f0337cdSDavid du Colombier break; 2317f0337cdSDavid du Colombier case Trepsize: 2327f0337cdSDavid du Colombier fprint(2, "Report size %d", v); 2337f0337cdSDavid du Colombier break; 2347f0337cdSDavid du Colombier case TrepID: 2357f0337cdSDavid du Colombier fprint(2, "Report ID %#x", v); 2367f0337cdSDavid du Colombier break; 2377f0337cdSDavid du Colombier case Trepcount: 2387f0337cdSDavid du Colombier fprint(2, "Report Count %d", v); 2397f0337cdSDavid du Colombier break; 2407f0337cdSDavid du Colombier case Tpush: 2417f0337cdSDavid du Colombier fprint(2, "Push %d", v); 2427f0337cdSDavid du Colombier break; 2437f0337cdSDavid du Colombier case Tpop: 2447f0337cdSDavid du Colombier fprint(2, "Pop %d", v); 2457f0337cdSDavid du Colombier break; 2467f0337cdSDavid du Colombier default: 2477f0337cdSDavid du Colombier fprint(2, "Unknown %#ux", v); 2487f0337cdSDavid du Colombier break; 2497f0337cdSDavid du Colombier } 2507f0337cdSDavid du Colombier } 2517f0337cdSDavid du Colombier break; 2527f0337cdSDavid du Colombier case Tlocal: 2537f0337cdSDavid du Colombier if (debug & Dbginfo) { 2547f0337cdSDavid du Colombier fprint(2, "Local %#ux: ", v); 2557f0337cdSDavid du Colombier switch(tag & Tmitem){ 2567f0337cdSDavid du Colombier case Tusage: 2577f0337cdSDavid du Colombier fprint(2, "Usage %d", v); 2587f0337cdSDavid du Colombier break; 2597f0337cdSDavid du Colombier case Tumin: 2607f0337cdSDavid du Colombier fprint(2, "Usage min %d", v); 2617f0337cdSDavid du Colombier break; 2627f0337cdSDavid du Colombier case Tumax: 2637f0337cdSDavid du Colombier fprint(2, "Usage max %d", v); 2647f0337cdSDavid du Colombier break; 2657f0337cdSDavid du Colombier case Tdindex: 2667f0337cdSDavid du Colombier fprint(2, "Designator index %d", v); 2677f0337cdSDavid du Colombier break; 2687f0337cdSDavid du Colombier case Tdmin: 2697f0337cdSDavid du Colombier fprint(2, "Designator min %d", v); 2707f0337cdSDavid du Colombier break; 2717f0337cdSDavid du Colombier case Tdmax: 2727f0337cdSDavid du Colombier fprint(2, "Designator max %d", v); 2737f0337cdSDavid du Colombier break; 2747f0337cdSDavid du Colombier case Tsindex: 2757f0337cdSDavid du Colombier fprint(2, "String index %d", v); 2767f0337cdSDavid du Colombier break; 2777f0337cdSDavid du Colombier case Tsmin: 2787f0337cdSDavid du Colombier fprint(2, "String min %d", v); 2797f0337cdSDavid du Colombier break; 2807f0337cdSDavid du Colombier case Tsmax: 2817f0337cdSDavid du Colombier fprint(2, "String max %d", v); 2827f0337cdSDavid du Colombier break; 2837f0337cdSDavid du Colombier case Tsetdelim: 2847f0337cdSDavid du Colombier fprint(2, "Set delim %#ux", v); 2857f0337cdSDavid du Colombier break; 2867f0337cdSDavid du Colombier default: 2877f0337cdSDavid du Colombier fprint(2, "Unknown %#ux", v); 2887f0337cdSDavid du Colombier break; 2897f0337cdSDavid du Colombier } 2907f0337cdSDavid du Colombier } 2917f0337cdSDavid du Colombier break; 2927f0337cdSDavid du Colombier } 2937f0337cdSDavid du Colombier fprint(2, "\n"); 2947f0337cdSDavid du Colombier s += nb; 2957f0337cdSDavid du Colombier } 2967f0337cdSDavid du Colombier } 2977f0337cdSDavid du Colombier 2987f0337cdSDavid du Colombier void 2997f0337cdSDavid du Colombier phub(Device *, int, ulong, void *b, int n) 3007f0337cdSDavid du Colombier { 3017f0337cdSDavid du Colombier DHub *d; 3027f0337cdSDavid du Colombier 3037f0337cdSDavid du Colombier if(n < DHUBLEN) 3047f0337cdSDavid du Colombier return; 3057f0337cdSDavid du Colombier d = b; 3067f0337cdSDavid du Colombier if (debug & Dbginfo) 3077f0337cdSDavid du Colombier fprint(2, "nport %d charac %#.4x pwr %dms current %dmA remov %#.2x", 308*208510e1SDavid du Colombier d->bNbrPorts, GET2(d->wHubCharacteristics), 309*208510e1SDavid du Colombier d->bPwrOn2PwrGood*2, d->bHubContrCurrent, 310*208510e1SDavid du Colombier d->DeviceRemovable[0]); 3117f0337cdSDavid du Colombier } 3127f0337cdSDavid du Colombier 3137f0337cdSDavid du Colombier void 3147f0337cdSDavid du Colombier pstring(Device *, int, ulong, void *b, int n) 3157f0337cdSDavid du Colombier { 3167f0337cdSDavid du Colombier byte *rb; 3177f0337cdSDavid du Colombier char *s; 3187f0337cdSDavid du Colombier Rune r; 3197f0337cdSDavid du Colombier int l; 3207f0337cdSDavid du Colombier 3217f0337cdSDavid du Colombier if(n <= 2){ 3227f0337cdSDavid du Colombier fprint(2, "\"\""); 3237f0337cdSDavid du Colombier return; 3247f0337cdSDavid du Colombier } 3257f0337cdSDavid du Colombier if(n & 1){ 3267f0337cdSDavid du Colombier fprint(2, "illegal count\n"); 3277f0337cdSDavid du Colombier return; 3287f0337cdSDavid du Colombier } 329de8abbc9SDavid du Colombier n = (n - 2)/2; 3307f0337cdSDavid du Colombier rb = (byte*)b + 2; 3317f0337cdSDavid du Colombier s = malloc(n*UTFmax+1); 3327f0337cdSDavid du Colombier for(l=0; --n >= 0; rb += 2){ 3337f0337cdSDavid du Colombier r = GET2(rb); 3347f0337cdSDavid du Colombier l += runetochar(s+l, &r); 3357f0337cdSDavid du Colombier } 3367f0337cdSDavid du Colombier s[l] = 0; 3377f0337cdSDavid du Colombier fprint(2, "\"%s\"", s); 3387f0337cdSDavid du Colombier free(s); 3397f0337cdSDavid du Colombier } 3407f0337cdSDavid du Colombier 3417f0337cdSDavid du Colombier void 3427f0337cdSDavid du Colombier pcs_raw(char *tag, byte *b, int n) 3437f0337cdSDavid du Colombier { 3447f0337cdSDavid du Colombier int i; 3457f0337cdSDavid du Colombier 3467f0337cdSDavid du Colombier if (debug & Dbginfo) { 3477f0337cdSDavid du Colombier fprint(2, "%s", tag); 3487f0337cdSDavid du Colombier for(i=2; i<n; i++) 3497f0337cdSDavid du Colombier fprint(2, " %.2x", b[i]); 3507f0337cdSDavid du Colombier } 3517f0337cdSDavid du Colombier } 3527f0337cdSDavid du Colombier 3537f0337cdSDavid du Colombier static void 3547f0337cdSDavid du Colombier pcs_config(Device *, int, ulong, void *b, int n) 3557f0337cdSDavid du Colombier { 3567f0337cdSDavid du Colombier pcs_raw("CS_CONFIG", b, n); 3577f0337cdSDavid du Colombier } 3587f0337cdSDavid du Colombier 3597f0337cdSDavid du Colombier static void 3607f0337cdSDavid du Colombier pcs_string(Device *, ulong, void *b, int n) 3617f0337cdSDavid du Colombier { 3627f0337cdSDavid du Colombier pcs_raw("CS_STRING", b, n); 3637f0337cdSDavid du Colombier } 3647f0337cdSDavid du Colombier 3657f0337cdSDavid du Colombier static void 3667f0337cdSDavid du Colombier pcs_endpoint(Device *, int, ulong, void *bb, int n) 3677f0337cdSDavid du Colombier { 3687f0337cdSDavid du Colombier byte *b = bb; 3697f0337cdSDavid du Colombier 3707f0337cdSDavid du Colombier if (debug & Dbginfo) { 3717f0337cdSDavid du Colombier switch(b[2]) { 3727f0337cdSDavid du Colombier case 0x01: 373*208510e1SDavid du Colombier fprint(2, 374*208510e1SDavid du Colombier "CS_ENDPOINT for TerminalID %d, delay %d, format_tag %#ux\n", 3757f0337cdSDavid du Colombier b[3], b[4], b[5] | (b[6]<<8)); 3767f0337cdSDavid du Colombier break; 3777f0337cdSDavid du Colombier case 0x02: 378*208510e1SDavid du Colombier fprint(2, 379*208510e1SDavid du Colombier "CS_INTERFACE FORMAT_TYPE %d, channels %d, subframesize %d, resolution %d, freqtype %d, ", 3807f0337cdSDavid du Colombier b[3], b[4], b[5], b[6], b[7]); 3817f0337cdSDavid du Colombier fprint(2, "freq0 %d, freq1 %d\n", 382*208510e1SDavid du Colombier b[8] | b[9]<<8 | b[10]<<16, 383*208510e1SDavid du Colombier b[11] | b[12]<<8 | b[13]<<16); 3847f0337cdSDavid du Colombier break; 3857f0337cdSDavid du Colombier default: 3867f0337cdSDavid du Colombier pcs_raw("CS_INTERFACE", bb, n); 3879a747e4fSDavid du Colombier } 3889a747e4fSDavid du Colombier } 3899a747e4fSDavid du Colombier } 3907f0337cdSDavid du Colombier 3917f0337cdSDavid du Colombier static void 392*208510e1SDavid du Colombier pcs_interface(Device *, int n, ulong, void *bb, int nb) 393*208510e1SDavid du Colombier { 3947f0337cdSDavid du Colombier 395*208510e1SDavid du Colombier if ((debug & Dbginfo) && n >= 0) 3967f0337cdSDavid du Colombier pcs_raw("CS_INTERFACE", bb, nb); 3977f0337cdSDavid du Colombier } 3987f0337cdSDavid du Colombier 3997f0337cdSDavid du Colombier void 4007f0337cdSDavid du Colombier pdesc(Device *d, int c, ulong csp, byte *b, int n) 4017f0337cdSDavid du Colombier { 402*208510e1SDavid du Colombier int class, subclass, proto, dalt = -1, i, ep, ifc = -1; 4037f0337cdSDavid du Colombier DConfig *dc; 4047f0337cdSDavid du Colombier DEndpoint *de; 405*208510e1SDavid du Colombier DInterface *di; 406096dd9ddSDavid du Colombier Dinf *dif; 407*208510e1SDavid du Colombier Endpt *dep; 408*208510e1SDavid du Colombier void (*f)(Device *, int, ulong, void*, int); 4097f0337cdSDavid du Colombier 4107f0337cdSDavid du Colombier class = Class(csp); 4117f0337cdSDavid du Colombier 4127f0337cdSDavid du Colombier if (c >= nelem(d->config)) { 4137f0337cdSDavid du Colombier fprint(2, "Too many interfaces (%d of %d)\n", 4147f0337cdSDavid du Colombier c, nelem(d->config)); 4157f0337cdSDavid du Colombier return; 4167f0337cdSDavid du Colombier } 4177f0337cdSDavid du Colombier if (debug & Dbginfo) 4187f0337cdSDavid du Colombier fprint(2, "pdesc %d.%d [%d]\n", d->id, c, n); 4197f0337cdSDavid du Colombier for(; n > 2 && b[0] && b[0] <= n; b += b[0]){ 4207f0337cdSDavid du Colombier if (debug & Dbginfo) 4217f0337cdSDavid du Colombier fprint(2, "desc %d.%d [%d] %#2.2x: ", d->id, c, b[0], b[1]); 4227f0337cdSDavid du Colombier switch (b[1]) { 4237f0337cdSDavid du Colombier case CONFIGURATION: 4247f0337cdSDavid du Colombier if(b[0] < DCONFLEN) 4257f0337cdSDavid du Colombier return; 4267f0337cdSDavid du Colombier dc = (DConfig*)b; 4277f0337cdSDavid du Colombier d->config[c]->nif = dc->bNumInterfaces; 4287f0337cdSDavid du Colombier d->config[c]->cval = dc->bConfigurationValue; 4297f0337cdSDavid du Colombier d->config[c]->attrib = dc->bmAttributes; 4307f0337cdSDavid du Colombier d->config[c]->milliamps = dc->MaxPower*2; 4317f0337cdSDavid du Colombier d->nif += d->config[c]->nif; 4327f0337cdSDavid du Colombier if (debug & Dbginfo) 4337f0337cdSDavid du Colombier fprint(2, "config %d: tdlen %d ninterface %d iconfig %d attr %#.2x power %dmA\n", 434*208510e1SDavid du Colombier dc->bConfigurationValue, 435*208510e1SDavid du Colombier GET2(dc->wTotalLength), 436*208510e1SDavid du Colombier dc->bNumInterfaces, dc->iConfiguration, 437*208510e1SDavid du Colombier dc->bmAttributes, dc->MaxPower*2); 4387f0337cdSDavid du Colombier break; 4397f0337cdSDavid du Colombier case INTERFACE: 4407f0337cdSDavid du Colombier if(n < DINTERLEN) 4417f0337cdSDavid du Colombier return; 4427f0337cdSDavid du Colombier di = (DInterface *)b; 4437f0337cdSDavid du Colombier class = di->bInterfaceClass; 4447f0337cdSDavid du Colombier subclass = di->bInterfaceSubClass; 4457f0337cdSDavid du Colombier proto = di->bInterfaceProtocol; 4467f0337cdSDavid du Colombier csp = CSP(class, subclass, proto); 4477f0337cdSDavid du Colombier if (debug & Dbginfo) 4487f0337cdSDavid du Colombier fprint(2, "interface %d: alt %d nept %d class %#x subclass %#x proto %d [%s] iinterface %d\n", 449*208510e1SDavid du Colombier di->bInterfaceNumber, 450*208510e1SDavid du Colombier di->bAlternateSetting, 451*208510e1SDavid du Colombier di->bNumEndpoints, class, subclass, 452*208510e1SDavid du Colombier proto, sclass(csp), di->iInterface); 4537f0337cdSDavid du Colombier if (c < 0) { 4547f0337cdSDavid du Colombier fprint(2, "Unexpected INTERFACE message\n"); 4557f0337cdSDavid du Colombier return; 4567f0337cdSDavid du Colombier } 4577f0337cdSDavid du Colombier ifc = di->bInterfaceNumber; 4587f0337cdSDavid du Colombier dalt = di->bAlternateSetting; 4597f0337cdSDavid du Colombier if (ifc < 0 || ifc >= nelem(d->config[c]->iface)) 4607f0337cdSDavid du Colombier sysfatal("Bad interface number %d", ifc); 461*208510e1SDavid du Colombier if (dalt < 0 || 462*208510e1SDavid du Colombier dalt >= nelem(d->config[c]->iface[ifc]->dalt)) 4637f0337cdSDavid du Colombier sysfatal("Bad alternate number %d", dalt); 4647f0337cdSDavid du Colombier if (d->config[c] == nil) 4657f0337cdSDavid du Colombier sysfatal("No config"); 4667f0337cdSDavid du Colombier if (ifc == 0) { 4677f0337cdSDavid du Colombier if (c == 0) 4687f0337cdSDavid du Colombier d->ep[0]->csp = csp; 4697f0337cdSDavid du Colombier d->config[c]->csp = csp; 4707f0337cdSDavid du Colombier } 471096dd9ddSDavid du Colombier dif = d->config[c]->iface[ifc]; 472096dd9ddSDavid du Colombier if (dif == nil) { 473096dd9ddSDavid du Colombier d->config[c]->iface[ifc] = dif = 474096dd9ddSDavid du Colombier mallocz(sizeof(Dinf), 1); 475096dd9ddSDavid du Colombier dif->csp = csp; 4767f0337cdSDavid du Colombier } 477096dd9ddSDavid du Colombier dif->interface = di->bInterfaceNumber; 4787f0337cdSDavid du Colombier break; 4797f0337cdSDavid du Colombier case ENDPOINT: 4807f0337cdSDavid du Colombier if(n < DENDPLEN) 4817f0337cdSDavid du Colombier return; 4827f0337cdSDavid du Colombier de = (DEndpoint *)b; 4837f0337cdSDavid du Colombier if (debug & Dbginfo) { 4847f0337cdSDavid du Colombier fprint(2, "addr %#2.2x attrib %#2.2x maxpkt %d interval %dms", 4857f0337cdSDavid du Colombier de->bEndpointAddress, de->bmAttributes, 4867f0337cdSDavid du Colombier GET2(de->wMaxPacketSize), de->bInterval); 4877f0337cdSDavid du Colombier if(de->bEndpointAddress & 0x80) 4887f0337cdSDavid du Colombier fprint(2, " [IN]"); 4897f0337cdSDavid du Colombier else 4907f0337cdSDavid du Colombier fprint(2, " [OUT]"); 4917f0337cdSDavid du Colombier switch(de->bmAttributes&0x33){ 492*208510e1SDavid du Colombier case 0: 493*208510e1SDavid du Colombier fprint(2, " [Control]"); 494*208510e1SDavid du Colombier break; 495*208510e1SDavid du Colombier case 1: 496*208510e1SDavid du Colombier fprint(2, " [Iso]"); 4977f0337cdSDavid du Colombier switch(de->bmAttributes&0xc){ 498*208510e1SDavid du Colombier case 0x4: 499*208510e1SDavid du Colombier fprint(2, " [Asynchronous]"); 500*208510e1SDavid du Colombier break; 501*208510e1SDavid du Colombier case 0x8: 502*208510e1SDavid du Colombier fprint(2, " [Adaptive]"); 503*208510e1SDavid du Colombier break; 504*208510e1SDavid du Colombier case 0xc: 505*208510e1SDavid du Colombier fprint(2, " [Synchronous]"); 506*208510e1SDavid du Colombier break; 5077f0337cdSDavid du Colombier } 5087f0337cdSDavid du Colombier break; 509*208510e1SDavid du Colombier case 2: 510*208510e1SDavid du Colombier fprint(2, " [Bulk]"); 511*208510e1SDavid du Colombier break; 512*208510e1SDavid du Colombier case 3: 513*208510e1SDavid du Colombier fprint(2, " [Interrupt]"); 514*208510e1SDavid du Colombier break; 5157f0337cdSDavid du Colombier } 5167f0337cdSDavid du Colombier if(b[0] == 9) 517*208510e1SDavid du Colombier fprint(2, "refresh %d synchaddress %d", 518*208510e1SDavid du Colombier b[7], b[8]); 5197f0337cdSDavid du Colombier fprint(2, "\n"); 5207f0337cdSDavid du Colombier } 5217f0337cdSDavid du Colombier if (c < 0 || ifc < 0 || dalt < 0) { 5227f0337cdSDavid du Colombier fprint(2, "Unexpected ENDPOINT message\n"); 5237f0337cdSDavid du Colombier return; 5247f0337cdSDavid du Colombier } 525096dd9ddSDavid du Colombier dif = d->config[c]->iface[ifc]; 526096dd9ddSDavid du Colombier if (dif == nil) 527096dd9ddSDavid du Colombier sysfatal("d->config[%d]->iface[%d] == nil", 528096dd9ddSDavid du Colombier c, ifc); 529096dd9ddSDavid du Colombier if (dif->dalt[dalt] == nil) 530096dd9ddSDavid du Colombier dif->dalt[dalt] = mallocz(sizeof(Dalt),1); 531096dd9ddSDavid du Colombier dif->dalt[dalt]->attrib = de->bmAttributes; 532096dd9ddSDavid du Colombier dif->dalt[dalt]->interval = de->bInterval; 5337f0337cdSDavid du Colombier ep = de->bEndpointAddress & 0xf; 534096dd9ddSDavid du Colombier dep = d->ep[ep]; 535096dd9ddSDavid du Colombier if (debug) 536096dd9ddSDavid du Colombier fprint(2, "%s: endpoint addr %d\n", argv0, ep); 537096dd9ddSDavid du Colombier if (dep == nil) { 538096dd9ddSDavid du Colombier d->ep[ep] = dep = newendpt(d, ep, class); 539096dd9ddSDavid du Colombier dep->dir = (de->bEndpointAddress & 0x80)? 540096dd9ddSDavid du Colombier Ein: Eout; 541096dd9ddSDavid du Colombier } else if ((dep->addr&0x80) != 542096dd9ddSDavid du Colombier (de->bEndpointAddress&0x80)) 543096dd9ddSDavid du Colombier dep->dir = Eboth; 544096dd9ddSDavid du Colombier else 545096dd9ddSDavid du Colombier fprint(2, "%s: endpoint %d already in use!\n", 546096dd9ddSDavid du Colombier argv0, ep); // DEBUG 547096dd9ddSDavid du Colombier if(dep->maxpkt < GET2(de->wMaxPacketSize)) 548096dd9ddSDavid du Colombier dep->maxpkt = GET2(de->wMaxPacketSize); 549096dd9ddSDavid du Colombier dep->addr = de->bEndpointAddress; 550096dd9ddSDavid du Colombier dep->type = de->bmAttributes & 0x03; 551096dd9ddSDavid du Colombier dep->isotype = (de->bmAttributes>>2) & 0x03; 552096dd9ddSDavid du Colombier dep->csp = csp; 553096dd9ddSDavid du Colombier dep->conf = d->config[c]; 554096dd9ddSDavid du Colombier dep->iface = dif; 555*208510e1SDavid du Colombier for(i = 0; i < nelem(dif->endpt); i++) 556096dd9ddSDavid du Colombier if(dif->endpt[i] == nil){ 557096dd9ddSDavid du Colombier dif->endpt[i] = dep; 55815174232SDavid du Colombier break; 55915174232SDavid du Colombier } 560096dd9ddSDavid du Colombier if(i == nelem(dif->endpt)) 56115174232SDavid du Colombier fprint(2, "Too many endpoints\n"); 562096dd9ddSDavid du Colombier if (d->nif <= ep) 563096dd9ddSDavid du Colombier d->nif = ep+1; 5647f0337cdSDavid du Colombier break; 5657f0337cdSDavid du Colombier default: 5668ccd4a63SDavid du Colombier assert(nelem(dprinter) == 0x100); 5677f0337cdSDavid du Colombier f = dprinter[b[1]]; 5687f0337cdSDavid du Colombier if(f != nil) { 569096dd9ddSDavid du Colombier (*f)(d, c, dalt<<24 | ifc<<16 | (csp&0xffff), 570096dd9ddSDavid du Colombier b, b[0]); 5717f0337cdSDavid du Colombier if (debug & Dbginfo) 5727f0337cdSDavid du Colombier fprint(2, "\n"); 573*208510e1SDavid du Colombier } else 5747f0337cdSDavid du Colombier if (verbose) { 5757f0337cdSDavid du Colombier int i; 5767f0337cdSDavid du Colombier 5777f0337cdSDavid du Colombier fprint(2, "(unknown type)"); 5787f0337cdSDavid du Colombier for(i=1; i<b[0]; i++) 5797f0337cdSDavid du Colombier fprint(2, " %.2x", b[i]); 5807f0337cdSDavid du Colombier fprint(2, "\n"); 581*208510e1SDavid du Colombier } else if (debug & Dbginfo) 5827f0337cdSDavid du Colombier fprint(2, "\n"); 583*208510e1SDavid du Colombier break; 5847f0337cdSDavid du Colombier } 5857f0337cdSDavid du Colombier n -= b[0]; 5869a747e4fSDavid du Colombier } 5879a747e4fSDavid du Colombier } 588