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){ 97*096dd9ddSDavid 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){ 1787f0337cdSDavid du Colombier case Tinput: fprint(2, "Input"); tab = ioflags; break; 1797f0337cdSDavid du Colombier case Toutput: fprint(2, "Output"); tab = ioflags; break; 1807f0337cdSDavid du Colombier case Tfeature: fprint(2, "Feature"); tab = ioflags; break; 1817f0337cdSDavid du Colombier case Tcoll: fprint(2, "Collection"); indent++; break; 1827f0337cdSDavid du Colombier case Tecoll: fprint(2, "End Collection"); indent--; break; 1837f0337cdSDavid du Colombier default: fprint(2, "unexpected item %.2x", tag); 1847f0337cdSDavid du Colombier } 1857f0337cdSDavid du Colombier fprint(2, "=%#ux", v); 1867f0337cdSDavid du Colombier if(tab != nil) 1877f0337cdSDavid du Colombier pflag(tab, v); 1887f0337cdSDavid du Colombier } 1897f0337cdSDavid du Colombier break; 1907f0337cdSDavid du Colombier case Tglobal: 1917f0337cdSDavid du Colombier if (debug & Dbginfo) { 1927f0337cdSDavid du Colombier fprint(2, "Global %#ux: ", v); 1937f0337cdSDavid du Colombier switch(tag & Tmitem){ 1947f0337cdSDavid du Colombier case Tusagepage: 1957f0337cdSDavid du Colombier fprint(2, "Usage Page %#ux", v); 1967f0337cdSDavid du Colombier break; 1977f0337cdSDavid du Colombier case Tlmin: 1987f0337cdSDavid du Colombier fprint(2, "Logical Min %d", v); 1997f0337cdSDavid du Colombier break; 2007f0337cdSDavid du Colombier case Tlmax: 2017f0337cdSDavid du Colombier fprint(2, "Logical Max %d", v); 2027f0337cdSDavid du Colombier break; 2037f0337cdSDavid du Colombier case Tpmin: 2047f0337cdSDavid du Colombier fprint(2, "Physical Min %d", v); 2057f0337cdSDavid du Colombier break; 2067f0337cdSDavid du Colombier case Tpmax: 2077f0337cdSDavid du Colombier fprint(2, "Physical Max %d", v); 2087f0337cdSDavid du Colombier break; 2097f0337cdSDavid du Colombier case Tunitexp: 2107f0337cdSDavid du Colombier fprint(2, "Unit Exponent %d", v); 2117f0337cdSDavid du Colombier break; 2127f0337cdSDavid du Colombier case Tunit: 2137f0337cdSDavid du Colombier fprint(2, "Unit %d", v); 2147f0337cdSDavid du Colombier break; 2157f0337cdSDavid du Colombier case Trepsize: 2167f0337cdSDavid du Colombier fprint(2, "Report size %d", v); 2177f0337cdSDavid du Colombier break; 2187f0337cdSDavid du Colombier case TrepID: 2197f0337cdSDavid du Colombier fprint(2, "Report ID %#x", v); 2207f0337cdSDavid du Colombier break; 2217f0337cdSDavid du Colombier case Trepcount: 2227f0337cdSDavid du Colombier fprint(2, "Report Count %d", v); 2237f0337cdSDavid du Colombier break; 2247f0337cdSDavid du Colombier case Tpush: 2257f0337cdSDavid du Colombier fprint(2, "Push %d", v); 2267f0337cdSDavid du Colombier break; 2277f0337cdSDavid du Colombier case Tpop: 2287f0337cdSDavid du Colombier fprint(2, "Pop %d", v); 2297f0337cdSDavid du Colombier break; 2307f0337cdSDavid du Colombier default: 2317f0337cdSDavid du Colombier fprint(2, "Unknown %#ux", v); 2327f0337cdSDavid du Colombier break; 2337f0337cdSDavid du Colombier } 2347f0337cdSDavid du Colombier } 2357f0337cdSDavid du Colombier break; 2367f0337cdSDavid du Colombier case Tlocal: 2377f0337cdSDavid du Colombier if (debug & Dbginfo) { 2387f0337cdSDavid du Colombier fprint(2, "Local %#ux: ", v); 2397f0337cdSDavid du Colombier switch(tag & Tmitem){ 2407f0337cdSDavid du Colombier case Tusage: 2417f0337cdSDavid du Colombier fprint(2, "Usage %d", v); 2427f0337cdSDavid du Colombier break; 2437f0337cdSDavid du Colombier case Tumin: 2447f0337cdSDavid du Colombier fprint(2, "Usage min %d", v); 2457f0337cdSDavid du Colombier break; 2467f0337cdSDavid du Colombier case Tumax: 2477f0337cdSDavid du Colombier fprint(2, "Usage max %d", v); 2487f0337cdSDavid du Colombier break; 2497f0337cdSDavid du Colombier case Tdindex: 2507f0337cdSDavid du Colombier fprint(2, "Designator index %d", v); 2517f0337cdSDavid du Colombier break; 2527f0337cdSDavid du Colombier case Tdmin: 2537f0337cdSDavid du Colombier fprint(2, "Designator min %d", v); 2547f0337cdSDavid du Colombier break; 2557f0337cdSDavid du Colombier case Tdmax: 2567f0337cdSDavid du Colombier fprint(2, "Designator max %d", v); 2577f0337cdSDavid du Colombier break; 2587f0337cdSDavid du Colombier case Tsindex: 2597f0337cdSDavid du Colombier fprint(2, "String index %d", v); 2607f0337cdSDavid du Colombier break; 2617f0337cdSDavid du Colombier case Tsmin: 2627f0337cdSDavid du Colombier fprint(2, "String min %d", v); 2637f0337cdSDavid du Colombier break; 2647f0337cdSDavid du Colombier case Tsmax: 2657f0337cdSDavid du Colombier fprint(2, "String max %d", v); 2667f0337cdSDavid du Colombier break; 2677f0337cdSDavid du Colombier case Tsetdelim: 2687f0337cdSDavid du Colombier fprint(2, "Set delim %#ux", v); 2697f0337cdSDavid du Colombier break; 2707f0337cdSDavid du Colombier default: 2717f0337cdSDavid du Colombier fprint(2, "Unknown %#ux", v); 2727f0337cdSDavid du Colombier break; 2737f0337cdSDavid du Colombier } 2747f0337cdSDavid du Colombier } 2757f0337cdSDavid du Colombier break; 2767f0337cdSDavid du Colombier } 2777f0337cdSDavid du Colombier fprint(2, "\n"); 2787f0337cdSDavid du Colombier s += nb; 2797f0337cdSDavid du Colombier } 2807f0337cdSDavid du Colombier } 2817f0337cdSDavid du Colombier 2827f0337cdSDavid du Colombier void 2837f0337cdSDavid du Colombier phub(Device *, int, ulong, void *b, int n) 2847f0337cdSDavid du Colombier { 2857f0337cdSDavid du Colombier DHub *d; 2867f0337cdSDavid du Colombier 2877f0337cdSDavid du Colombier if(n < DHUBLEN) 2887f0337cdSDavid du Colombier return; 2897f0337cdSDavid du Colombier d = b; 2907f0337cdSDavid du Colombier if (debug & Dbginfo) 2917f0337cdSDavid du Colombier fprint(2, "nport %d charac %#.4x pwr %dms current %dmA remov %#.2x", 2927f0337cdSDavid du Colombier d->bNbrPorts, GET2(d->wHubCharacteristics), d->bPwrOn2PwrGood*2, 2937f0337cdSDavid du Colombier d->bHubContrCurrent, d->DeviceRemovable[0]); 2947f0337cdSDavid du Colombier } 2957f0337cdSDavid du Colombier 2967f0337cdSDavid du Colombier void 2977f0337cdSDavid du Colombier pstring(Device *, int, ulong, void *b, int n) 2987f0337cdSDavid du Colombier { 2997f0337cdSDavid du Colombier byte *rb; 3007f0337cdSDavid du Colombier char *s; 3017f0337cdSDavid du Colombier Rune r; 3027f0337cdSDavid du Colombier int l; 3037f0337cdSDavid du Colombier 3047f0337cdSDavid du Colombier if(n <= 2){ 3057f0337cdSDavid du Colombier fprint(2, "\"\""); 3067f0337cdSDavid du Colombier return; 3077f0337cdSDavid du Colombier } 3087f0337cdSDavid du Colombier if(n & 1){ 3097f0337cdSDavid du Colombier fprint(2, "illegal count\n"); 3107f0337cdSDavid du Colombier return; 3117f0337cdSDavid du Colombier } 312de8abbc9SDavid du Colombier n = (n - 2)/2; 3137f0337cdSDavid du Colombier rb = (byte*)b + 2; 3147f0337cdSDavid du Colombier s = malloc(n*UTFmax+1); 3157f0337cdSDavid du Colombier for(l=0; --n >= 0; rb += 2){ 3167f0337cdSDavid du Colombier r = GET2(rb); 3177f0337cdSDavid du Colombier l += runetochar(s+l, &r); 3187f0337cdSDavid du Colombier } 3197f0337cdSDavid du Colombier s[l] = 0; 3207f0337cdSDavid du Colombier fprint(2, "\"%s\"", s); 3217f0337cdSDavid du Colombier free(s); 3227f0337cdSDavid du Colombier } 3237f0337cdSDavid du Colombier 3247f0337cdSDavid du Colombier void 3257f0337cdSDavid du Colombier pcs_raw(char *tag, byte *b, int n) 3267f0337cdSDavid du Colombier { 3277f0337cdSDavid du Colombier int i; 3287f0337cdSDavid du Colombier 3297f0337cdSDavid du Colombier if (debug & Dbginfo) { 3307f0337cdSDavid du Colombier fprint(2, "%s", tag); 3317f0337cdSDavid du Colombier for(i=2; i<n; i++) 3327f0337cdSDavid du Colombier fprint(2, " %.2x", b[i]); 3337f0337cdSDavid du Colombier } 3347f0337cdSDavid du Colombier } 3357f0337cdSDavid du Colombier 3367f0337cdSDavid du Colombier static void 3377f0337cdSDavid du Colombier pcs_config(Device *, int, ulong, void *b, int n) 3387f0337cdSDavid du Colombier { 3397f0337cdSDavid du Colombier pcs_raw("CS_CONFIG", b, n); 3407f0337cdSDavid du Colombier } 3417f0337cdSDavid du Colombier 3427f0337cdSDavid du Colombier static void 3437f0337cdSDavid du Colombier pcs_string(Device *, ulong, void *b, int n) 3447f0337cdSDavid du Colombier { 3457f0337cdSDavid du Colombier pcs_raw("CS_STRING", b, n); 3467f0337cdSDavid du Colombier } 3477f0337cdSDavid du Colombier 3487f0337cdSDavid du Colombier static void 3497f0337cdSDavid du Colombier pcs_endpoint(Device *, int, ulong, void *bb, int n) 3507f0337cdSDavid du Colombier { 3517f0337cdSDavid du Colombier byte *b = bb; 3527f0337cdSDavid du Colombier 3537f0337cdSDavid du Colombier if (debug & Dbginfo) { 3547f0337cdSDavid du Colombier switch(b[2]) { 3557f0337cdSDavid du Colombier case 0x01: 3567f0337cdSDavid du Colombier fprint(2, "CS_ENDPOINT for TerminalID %d, delay %d, format_tag %#ux\n", 3577f0337cdSDavid du Colombier b[3], b[4], b[5] | (b[6]<<8)); 3587f0337cdSDavid du Colombier break; 3597f0337cdSDavid du Colombier case 0x02: 3607f0337cdSDavid du Colombier fprint(2, "CS_INTERFACE FORMAT_TYPE %d, channels %d, subframesize %d, resolution %d, freqtype %d, ", 3617f0337cdSDavid du Colombier b[3], b[4], b[5], b[6], b[7]); 3627f0337cdSDavid du Colombier fprint(2, "freq0 %d, freq1 %d\n", 3637f0337cdSDavid du Colombier b[8] | (b[9]<<8) | (b[10]<<16), b[11] | (b[12]<<8) | (b[13]<<16)); 3647f0337cdSDavid du Colombier break; 3657f0337cdSDavid du Colombier default: 3667f0337cdSDavid du Colombier pcs_raw("CS_INTERFACE", bb, n); 3679a747e4fSDavid du Colombier } 3689a747e4fSDavid du Colombier } 3699a747e4fSDavid du Colombier } 3707f0337cdSDavid du Colombier 3717f0337cdSDavid du Colombier static void 3727f0337cdSDavid du Colombier pcs_interface(Device *, int n, ulong, void *bb, int nb) { 3737f0337cdSDavid du Colombier 3747f0337cdSDavid du Colombier if ((debug & Dbginfo) && n >= 0) { 3757f0337cdSDavid du Colombier pcs_raw("CS_INTERFACE", bb, nb); 3767f0337cdSDavid du Colombier } 3777f0337cdSDavid du Colombier } 3787f0337cdSDavid du Colombier 3797f0337cdSDavid du Colombier void 3807f0337cdSDavid du Colombier pdesc(Device *d, int c, ulong csp, byte *b, int n) 3817f0337cdSDavid du Colombier { 3827f0337cdSDavid du Colombier void (*f)(Device *, int, ulong, void*, int); 3837f0337cdSDavid du Colombier int ifc = -1; 3847f0337cdSDavid du Colombier int dalt = -1; 385*096dd9ddSDavid du Colombier int i, ep; 3867f0337cdSDavid du Colombier int class, subclass, proto; 3877f0337cdSDavid du Colombier DConfig *dc; 3887f0337cdSDavid du Colombier DInterface *di; 3897f0337cdSDavid du Colombier DEndpoint *de; 390*096dd9ddSDavid du Colombier Endpt *dep; 391*096dd9ddSDavid du Colombier Dinf *dif; 3927f0337cdSDavid du Colombier 3937f0337cdSDavid du Colombier class = Class(csp); 3947f0337cdSDavid du Colombier 3957f0337cdSDavid du Colombier if (c >= nelem(d->config)) { 3967f0337cdSDavid du Colombier fprint(2, "Too many interfaces (%d of %d)\n", 3977f0337cdSDavid du Colombier c, nelem(d->config)); 3987f0337cdSDavid du Colombier return; 3997f0337cdSDavid du Colombier } 4007f0337cdSDavid du Colombier if (debug & Dbginfo) 4017f0337cdSDavid du Colombier fprint(2, "pdesc %d.%d [%d]\n", d->id, c, n); 4027f0337cdSDavid du Colombier for(; n > 2 && b[0] && b[0] <= n; b += b[0]){ 4037f0337cdSDavid du Colombier if (debug & Dbginfo) 4047f0337cdSDavid du Colombier fprint(2, "desc %d.%d [%d] %#2.2x: ", d->id, c, b[0], b[1]); 4057f0337cdSDavid du Colombier switch (b[1]) { 4067f0337cdSDavid du Colombier case CONFIGURATION: 4077f0337cdSDavid du Colombier if(b[0] < DCONFLEN) 4087f0337cdSDavid du Colombier return; 4097f0337cdSDavid du Colombier dc = (DConfig*)b; 4107f0337cdSDavid du Colombier d->config[c]->nif = dc->bNumInterfaces; 4117f0337cdSDavid du Colombier d->config[c]->cval = dc->bConfigurationValue; 4127f0337cdSDavid du Colombier d->config[c]->attrib = dc->bmAttributes; 4137f0337cdSDavid du Colombier d->config[c]->milliamps = dc->MaxPower*2; 4147f0337cdSDavid du Colombier d->nif += d->config[c]->nif; 4157f0337cdSDavid du Colombier if (debug & Dbginfo) 4167f0337cdSDavid du Colombier fprint(2, "config %d: tdlen %d ninterface %d iconfig %d attr %#.2x power %dmA\n", 4177f0337cdSDavid du Colombier dc->bConfigurationValue, GET2(dc->wTotalLength), 4187f0337cdSDavid du Colombier dc->bNumInterfaces, dc->iConfiguration, dc->bmAttributes, 4197f0337cdSDavid du Colombier dc->MaxPower*2); 4207f0337cdSDavid du Colombier break; 4217f0337cdSDavid du Colombier case INTERFACE: 4227f0337cdSDavid du Colombier if(n < DINTERLEN) 4237f0337cdSDavid du Colombier return; 4247f0337cdSDavid du Colombier di = (DInterface *)b; 4257f0337cdSDavid du Colombier class = di->bInterfaceClass; 4267f0337cdSDavid du Colombier subclass = di->bInterfaceSubClass; 4277f0337cdSDavid du Colombier proto = di->bInterfaceProtocol; 4287f0337cdSDavid du Colombier csp = CSP(class, subclass, proto); 4297f0337cdSDavid du Colombier if (debug & Dbginfo) 4307f0337cdSDavid du Colombier fprint(2, "interface %d: alt %d nept %d class %#x subclass %#x proto %d [%s] iinterface %d\n", 4317f0337cdSDavid du Colombier di->bInterfaceNumber, di->bAlternateSetting, 4327f0337cdSDavid du Colombier di->bNumEndpoints, class, subclass, proto, 4337f0337cdSDavid du Colombier sclass(csp), 4347f0337cdSDavid du Colombier di->iInterface); 4357f0337cdSDavid du Colombier if (c < 0) { 4367f0337cdSDavid du Colombier fprint(2, "Unexpected INTERFACE message\n"); 4377f0337cdSDavid du Colombier return; 4387f0337cdSDavid du Colombier } 4397f0337cdSDavid du Colombier ifc = di->bInterfaceNumber; 4407f0337cdSDavid du Colombier dalt = di->bAlternateSetting; 4417f0337cdSDavid du Colombier if (ifc < 0 || ifc >= nelem(d->config[c]->iface)) 4427f0337cdSDavid du Colombier sysfatal("Bad interface number %d", ifc); 4437f0337cdSDavid du Colombier if (dalt < 0 || dalt >= nelem(d->config[c]->iface[ifc]->dalt)) 4447f0337cdSDavid du Colombier sysfatal("Bad alternate number %d", dalt); 4457f0337cdSDavid du Colombier if (d->config[c] == nil) 4467f0337cdSDavid du Colombier sysfatal("No config"); 4477f0337cdSDavid du Colombier if (ifc == 0) { 4487f0337cdSDavid du Colombier if (c == 0) 4497f0337cdSDavid du Colombier d->ep[0]->csp = csp; 4507f0337cdSDavid du Colombier d->config[c]->csp = csp; 4517f0337cdSDavid du Colombier } 452*096dd9ddSDavid du Colombier dif = d->config[c]->iface[ifc]; 453*096dd9ddSDavid du Colombier if (dif == nil) { 454*096dd9ddSDavid du Colombier d->config[c]->iface[ifc] = dif = 455*096dd9ddSDavid du Colombier mallocz(sizeof(Dinf), 1); 456*096dd9ddSDavid du Colombier dif->csp = csp; 4577f0337cdSDavid du Colombier } 458*096dd9ddSDavid du Colombier dif->interface = di->bInterfaceNumber; 4597f0337cdSDavid du Colombier break; 4607f0337cdSDavid du Colombier case ENDPOINT: 4617f0337cdSDavid du Colombier if(n < DENDPLEN) 4627f0337cdSDavid du Colombier return; 4637f0337cdSDavid du Colombier de = (DEndpoint *)b; 4647f0337cdSDavid du Colombier if (debug & Dbginfo) { 4657f0337cdSDavid du Colombier fprint(2, "addr %#2.2x attrib %#2.2x maxpkt %d interval %dms", 4667f0337cdSDavid du Colombier de->bEndpointAddress, de->bmAttributes, 4677f0337cdSDavid du Colombier GET2(de->wMaxPacketSize), de->bInterval); 4687f0337cdSDavid du Colombier if(de->bEndpointAddress & 0x80) 4697f0337cdSDavid du Colombier fprint(2, " [IN]"); 4707f0337cdSDavid du Colombier else 4717f0337cdSDavid du Colombier fprint(2, " [OUT]"); 4727f0337cdSDavid du Colombier switch(de->bmAttributes&0x33){ 4737f0337cdSDavid du Colombier case 0: fprint(2, " [Control]"); break; 4747f0337cdSDavid du Colombier case 1: fprint(2, " [Iso]"); 4757f0337cdSDavid du Colombier switch(de->bmAttributes&0xc){ 4767f0337cdSDavid du Colombier case 0x4: fprint(2, " [Asynchronous]"); break; 4777f0337cdSDavid du Colombier case 0x8: fprint(2, " [Adaptive]"); break; 4787f0337cdSDavid du Colombier case 0xc: fprint(2, " [Synchronous]"); break; 4797f0337cdSDavid du Colombier } 4807f0337cdSDavid du Colombier break; 4817f0337cdSDavid du Colombier case 2: fprint(2, " [Bulk]"); break; 4827f0337cdSDavid du Colombier case 3: fprint(2, " [Interrupt]"); break; 4837f0337cdSDavid du Colombier } 4847f0337cdSDavid du Colombier if(b[0] == 9) 4857f0337cdSDavid du Colombier fprint(2, "refresh %d synchaddress %d", b[7], b[8]); 4867f0337cdSDavid du Colombier fprint(2, "\n"); 4877f0337cdSDavid du Colombier } 4887f0337cdSDavid du Colombier if (c < 0 || ifc < 0 || dalt < 0) { 4897f0337cdSDavid du Colombier fprint(2, "Unexpected ENDPOINT message\n"); 4907f0337cdSDavid du Colombier return; 4917f0337cdSDavid du Colombier } 492*096dd9ddSDavid du Colombier dif = d->config[c]->iface[ifc]; 493*096dd9ddSDavid du Colombier if (dif == nil) 494*096dd9ddSDavid du Colombier sysfatal("d->config[%d]->iface[%d] == nil", 495*096dd9ddSDavid du Colombier c, ifc); 496*096dd9ddSDavid du Colombier if (dif->dalt[dalt] == nil) 497*096dd9ddSDavid du Colombier dif->dalt[dalt] = mallocz(sizeof(Dalt),1); 498*096dd9ddSDavid du Colombier dif->dalt[dalt]->attrib = de->bmAttributes; 499*096dd9ddSDavid du Colombier dif->dalt[dalt]->interval = de->bInterval; 5007f0337cdSDavid du Colombier ep = de->bEndpointAddress & 0xf; 501*096dd9ddSDavid du Colombier dep = d->ep[ep]; 502*096dd9ddSDavid du Colombier if (debug) 503*096dd9ddSDavid du Colombier fprint(2, "%s: endpoint addr %d\n", argv0, ep); 504*096dd9ddSDavid du Colombier if (dep == nil) { 505*096dd9ddSDavid du Colombier d->ep[ep] = dep = newendpt(d, ep, class); 506*096dd9ddSDavid du Colombier dep->dir = (de->bEndpointAddress & 0x80)? 507*096dd9ddSDavid du Colombier Ein: Eout; 508*096dd9ddSDavid du Colombier } else if ((dep->addr&0x80) != 509*096dd9ddSDavid du Colombier (de->bEndpointAddress&0x80)) 510*096dd9ddSDavid du Colombier dep->dir = Eboth; 511*096dd9ddSDavid du Colombier else 512*096dd9ddSDavid du Colombier fprint(2, "%s: endpoint %d already in use!\n", 513*096dd9ddSDavid du Colombier argv0, ep); // DEBUG 514*096dd9ddSDavid du Colombier if(dep->maxpkt < GET2(de->wMaxPacketSize)) 515*096dd9ddSDavid du Colombier dep->maxpkt = GET2(de->wMaxPacketSize); 516*096dd9ddSDavid du Colombier dep->addr = de->bEndpointAddress; 517*096dd9ddSDavid du Colombier dep->type = de->bmAttributes & 0x03; 518*096dd9ddSDavid du Colombier dep->isotype = (de->bmAttributes>>2) & 0x03; 519*096dd9ddSDavid du Colombier dep->csp = csp; 520*096dd9ddSDavid du Colombier dep->conf = d->config[c]; 521*096dd9ddSDavid du Colombier dep->iface = dif; 522*096dd9ddSDavid du Colombier for(i = 0; i < nelem(dif->endpt); i++){ 523*096dd9ddSDavid du Colombier if(dif->endpt[i] == nil){ 524*096dd9ddSDavid du Colombier dif->endpt[i] = dep; 52515174232SDavid du Colombier break; 52615174232SDavid du Colombier } 52715174232SDavid du Colombier } 528*096dd9ddSDavid du Colombier if(i == nelem(dif->endpt)) 52915174232SDavid du Colombier fprint(2, "Too many endpoints\n"); 530*096dd9ddSDavid du Colombier if (d->nif <= ep) 531*096dd9ddSDavid du Colombier d->nif = ep+1; 5327f0337cdSDavid du Colombier break; 5337f0337cdSDavid du Colombier default: 5348ccd4a63SDavid du Colombier assert(nelem(dprinter) == 0x100); 5357f0337cdSDavid du Colombier f = dprinter[b[1]]; 5367f0337cdSDavid du Colombier if(f != nil) { 537*096dd9ddSDavid du Colombier (*f)(d, c, dalt<<24 | ifc<<16 | (csp&0xffff), 538*096dd9ddSDavid du Colombier b, b[0]); 5397f0337cdSDavid du Colombier if (debug & Dbginfo) 5407f0337cdSDavid du Colombier fprint(2, "\n"); 5417f0337cdSDavid du Colombier } 5427f0337cdSDavid du Colombier else { 5437f0337cdSDavid du Colombier if (verbose) { 5447f0337cdSDavid du Colombier int i; 5457f0337cdSDavid du Colombier 5467f0337cdSDavid du Colombier fprint(2, "(unknown type)"); 5477f0337cdSDavid du Colombier for(i=1; i<b[0]; i++) 5487f0337cdSDavid du Colombier fprint(2, " %.2x", b[i]); 5497f0337cdSDavid du Colombier fprint(2, "\n"); 5507f0337cdSDavid du Colombier } 5517f0337cdSDavid du Colombier else if (debug & Dbginfo) 5527f0337cdSDavid du Colombier fprint(2, "\n"); 5537f0337cdSDavid du Colombier } 5547f0337cdSDavid du Colombier } 5557f0337cdSDavid du Colombier n -= b[0]; 5569a747e4fSDavid du Colombier } 5579a747e4fSDavid du Colombier } 558