xref: /plan9-contrib/sys/src/cmd/usb/lib/dump.c (revision de8abbc9164dc026cdaba4729bbacf0991ad2be6)
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){
977f0337cdSDavid du Colombier 		fprint(2, "hid too short\n");
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 	}
312*de8abbc9SDavid 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;
3857f0337cdSDavid du Colombier 	int ep;
3867f0337cdSDavid du Colombier 	int class, subclass, proto;
3877f0337cdSDavid du Colombier 	DConfig *dc;
3887f0337cdSDavid du Colombier 	DInterface *di;
3897f0337cdSDavid du Colombier 	DEndpoint *de;
39015174232SDavid du Colombier 	int i;
3917f0337cdSDavid du Colombier 
3927f0337cdSDavid du Colombier 	class = Class(csp);
3937f0337cdSDavid du Colombier 
3947f0337cdSDavid du Colombier 	if (c >= nelem(d->config)) {
3957f0337cdSDavid du Colombier 		fprint(2, "Too many interfaces (%d of %d)\n",
3967f0337cdSDavid du Colombier 			c, nelem(d->config));
3977f0337cdSDavid du Colombier 		return;
3987f0337cdSDavid du Colombier 	}
3997f0337cdSDavid du Colombier 	if (debug & Dbginfo)
4007f0337cdSDavid du Colombier 		fprint(2, "pdesc %d.%d [%d]\n", d->id, c, n);
4017f0337cdSDavid du Colombier 	for(; n > 2 && b[0] && b[0] <= n; b += b[0]){
4027f0337cdSDavid du Colombier 		if (debug & Dbginfo)
4037f0337cdSDavid du Colombier 			fprint(2, "desc %d.%d [%d] %#2.2x: ", d->id, c, b[0], b[1]);
4047f0337cdSDavid du Colombier 		switch (b[1]) {
4057f0337cdSDavid du Colombier 		case CONFIGURATION:
4067f0337cdSDavid du Colombier 			if(b[0] < DCONFLEN)
4077f0337cdSDavid du Colombier 				return;
4087f0337cdSDavid du Colombier 			dc = (DConfig*)b;
4097f0337cdSDavid du Colombier 			d->config[c]->nif = dc->bNumInterfaces;
4107f0337cdSDavid du Colombier 			d->config[c]->cval = dc->bConfigurationValue;
4117f0337cdSDavid du Colombier 			d->config[c]->attrib = dc->bmAttributes;
4127f0337cdSDavid du Colombier 			d->config[c]->milliamps = dc->MaxPower*2;
4137f0337cdSDavid du Colombier 			d->nif += d->config[c]->nif;
4147f0337cdSDavid du Colombier 			if (debug & Dbginfo)
4157f0337cdSDavid du Colombier 				fprint(2, "config %d: tdlen %d ninterface %d iconfig %d attr %#.2x power %dmA\n",
4167f0337cdSDavid du Colombier 					dc->bConfigurationValue, GET2(dc->wTotalLength),
4177f0337cdSDavid du Colombier 					dc->bNumInterfaces, dc->iConfiguration, dc->bmAttributes,
4187f0337cdSDavid du Colombier 					dc->MaxPower*2);
4197f0337cdSDavid du Colombier 			break;
4207f0337cdSDavid du Colombier 		case INTERFACE:
4217f0337cdSDavid du Colombier 			if(n < DINTERLEN)
4227f0337cdSDavid du Colombier 				return;
4237f0337cdSDavid du Colombier 			di = (DInterface *)b;
4247f0337cdSDavid du Colombier 			class = di->bInterfaceClass;
4257f0337cdSDavid du Colombier 			subclass = di->bInterfaceSubClass;
4267f0337cdSDavid du Colombier 			proto = di->bInterfaceProtocol;
4277f0337cdSDavid du Colombier 			csp = CSP(class, subclass, proto);
4287f0337cdSDavid du Colombier 			if (debug & Dbginfo)
4297f0337cdSDavid du Colombier 				fprint(2, "interface %d: alt %d nept %d class %#x subclass %#x proto %d [%s] iinterface %d\n",
4307f0337cdSDavid du Colombier 					di->bInterfaceNumber, di->bAlternateSetting,
4317f0337cdSDavid du Colombier 					di->bNumEndpoints, class, subclass, proto,
4327f0337cdSDavid du Colombier 					sclass(csp),
4337f0337cdSDavid du Colombier 					di->iInterface);
4347f0337cdSDavid du Colombier 			if (c < 0) {
4357f0337cdSDavid du Colombier 				fprint(2, "Unexpected INTERFACE message\n");
4367f0337cdSDavid du Colombier 				return;
4377f0337cdSDavid du Colombier 			}
4387f0337cdSDavid du Colombier 			ifc = di->bInterfaceNumber;
4397f0337cdSDavid du Colombier 			dalt = di->bAlternateSetting;
4407f0337cdSDavid du Colombier 			if (ifc < 0 || ifc >= nelem(d->config[c]->iface))
4417f0337cdSDavid du Colombier 				sysfatal("Bad interface number %d", ifc);
4427f0337cdSDavid du Colombier 			if (dalt < 0 || dalt >= nelem(d->config[c]->iface[ifc]->dalt))
4437f0337cdSDavid du Colombier 				sysfatal("Bad alternate number %d", dalt);
4447f0337cdSDavid du Colombier 			if (d->config[c] == nil)
4457f0337cdSDavid du Colombier 				sysfatal("No config");
4467f0337cdSDavid du Colombier 			if (ifc == 0) {
4477f0337cdSDavid du Colombier 				if (c == 0)
4487f0337cdSDavid du Colombier 					d->ep[0]->csp = csp;
4497f0337cdSDavid du Colombier 				d->config[c]->csp = csp;
4507f0337cdSDavid du Colombier 			}
4517f0337cdSDavid du Colombier 			if (d->config[c]->iface[ifc] == nil) {
4527f0337cdSDavid du Colombier 				d->config[c]->iface[ifc] = mallocz(sizeof(Dinf), 1);
4537f0337cdSDavid du Colombier 				d->config[c]->iface[ifc]->csp = csp;
4547f0337cdSDavid du Colombier 			}
4557f0337cdSDavid du Colombier 			d->config[c]->iface[ifc]->interface = di->bInterfaceNumber;
4567f0337cdSDavid du Colombier 			break;
4577f0337cdSDavid du Colombier 		case ENDPOINT:
4587f0337cdSDavid du Colombier 			if(n < DENDPLEN)
4597f0337cdSDavid du Colombier 				return;
4607f0337cdSDavid du Colombier 			de = (DEndpoint *)b;
4617f0337cdSDavid du Colombier 			if (debug & Dbginfo) {
4627f0337cdSDavid du Colombier 				fprint(2, "addr %#2.2x attrib %#2.2x maxpkt %d interval %dms",
4637f0337cdSDavid du Colombier 					de->bEndpointAddress, de->bmAttributes,
4647f0337cdSDavid du Colombier 					GET2(de->wMaxPacketSize), de->bInterval);
4657f0337cdSDavid du Colombier 				if(de->bEndpointAddress & 0x80)
4667f0337cdSDavid du Colombier 					fprint(2, " [IN]");
4677f0337cdSDavid du Colombier 				else
4687f0337cdSDavid du Colombier 					fprint(2, " [OUT]");
4697f0337cdSDavid du Colombier 				switch(de->bmAttributes&0x33){
4707f0337cdSDavid du Colombier 				case 0:	fprint(2, " [Control]"); break;
4717f0337cdSDavid du Colombier 				case 1:	fprint(2, " [Iso]");
4727f0337cdSDavid du Colombier 						switch(de->bmAttributes&0xc){
4737f0337cdSDavid du Colombier 						case 0x4:	fprint(2, " [Asynchronous]"); break;
4747f0337cdSDavid du Colombier 						case 0x8:	fprint(2, " [Adaptive]"); break;
4757f0337cdSDavid du Colombier 						case 0xc:	fprint(2, " [Synchronous]"); break;
4767f0337cdSDavid du Colombier 						}
4777f0337cdSDavid du Colombier 						break;
4787f0337cdSDavid du Colombier 				case 2:	fprint(2, " [Bulk]"); break;
4797f0337cdSDavid du Colombier 				case 3:	fprint(2, " [Interrupt]"); break;
4807f0337cdSDavid du Colombier 				}
4817f0337cdSDavid du Colombier 				if(b[0] == 9)
4827f0337cdSDavid du Colombier 					fprint(2, "refresh %d synchaddress %d", b[7], b[8]);
4837f0337cdSDavid du Colombier 				fprint(2, "\n");
4847f0337cdSDavid du Colombier 			}
4857f0337cdSDavid du Colombier 			if (c < 0 || ifc < 0 || dalt < 0) {
4867f0337cdSDavid du Colombier 				fprint(2, "Unexpected ENDPOINT message\n");
4877f0337cdSDavid du Colombier 				return;
4887f0337cdSDavid du Colombier 			}
4897f0337cdSDavid du Colombier 			if (d->config[c]->iface[ifc] == nil)
4907f0337cdSDavid du Colombier 				sysfatal("d->config[c]->iface[ifc] == nil");
4917f0337cdSDavid du Colombier 			if (d->config[c]->iface[ifc]->dalt[dalt] == nil)
4927f0337cdSDavid du Colombier 				d->config[c]->iface[ifc]->dalt[dalt] = mallocz(sizeof(Dalt),1);
4937f0337cdSDavid du Colombier 			d->config[c]->iface[ifc]->dalt[dalt]->attrib = de->bmAttributes;
4947f0337cdSDavid du Colombier 			d->config[c]->iface[ifc]->dalt[dalt]->interval = de->bInterval;
4957f0337cdSDavid du Colombier 			ep = de->bEndpointAddress & 0xf;
496*de8abbc9SDavid du Colombier 			if (debug) print("endpoint addr %d\n", ep); // DEBUG
4977f0337cdSDavid du Colombier 			if (d->ep[ep] == nil)
4987f0337cdSDavid du Colombier 				d->ep[ep] = newendpt(d, ep, class);
499*de8abbc9SDavid du Colombier 			else print("endpoint already in use!\n"); // DEBUG
5004b30ca09SDavid du Colombier 			if(d->ep[ep]->maxpkt < GET2(de->wMaxPacketSize))
50115174232SDavid du Colombier 				d->ep[ep]->maxpkt = GET2(de->wMaxPacketSize);
50215174232SDavid du Colombier 			d->ep[ep]->addr = de->bEndpointAddress;
5033b88a4f0SDavid du Colombier 			d->ep[ep]->dir = (de->bEndpointAddress & 0x80) ? Ein : Eout;
5043b88a4f0SDavid du Colombier 			d->ep[ep]->type = de->bmAttributes & 0x03;
5053b88a4f0SDavid du Colombier 			d->ep[ep]->isotype = (de->bmAttributes>>2) & 0x03;
5067f0337cdSDavid du Colombier 			d->ep[ep]->csp = csp;
5077f0337cdSDavid du Colombier 			d->ep[ep]->conf = d->config[c];
5087f0337cdSDavid du Colombier 			d->ep[ep]->iface = d->config[c]->iface[ifc];
50915174232SDavid du Colombier 			for(i = 0; i < nelem(d->config[c]->iface[ifc]->endpt); i++){
51015174232SDavid du Colombier 				if(d->config[c]->iface[ifc]->endpt[i] == nil){
51115174232SDavid du Colombier 					d->config[c]->iface[ifc]->endpt[i] = d->ep[ep];
51215174232SDavid du Colombier 					break;
51315174232SDavid du Colombier 				}
51415174232SDavid du Colombier 			}
51515174232SDavid du Colombier 			if(i == nelem(d->config[c]->iface[ifc]->endpt))
51615174232SDavid du Colombier 				fprint(2, "Too many endpoints\n");
5177f0337cdSDavid du Colombier 			if (d->nif <= ep) d->nif = ep+1;
5187f0337cdSDavid du Colombier 			break;
5197f0337cdSDavid du Colombier 		default:
5208ccd4a63SDavid du Colombier 			assert(nelem(dprinter) == 0x100);
5217f0337cdSDavid du Colombier 			f = dprinter[b[1]];
5227f0337cdSDavid du Colombier 			if(f != nil) {
5237f0337cdSDavid du Colombier 				(*f)(d, c, (dalt<<24) | (ifc<<16) | (csp&0xffff), b, b[0]);
5247f0337cdSDavid du Colombier 				if (debug & Dbginfo)
5257f0337cdSDavid du Colombier 					fprint(2, "\n");
5267f0337cdSDavid du Colombier 			}
5277f0337cdSDavid du Colombier 			else {
5287f0337cdSDavid du Colombier 				if (verbose) {
5297f0337cdSDavid du Colombier 					int i;
5307f0337cdSDavid du Colombier 
5317f0337cdSDavid du Colombier 					fprint(2, "(unknown type)");
5327f0337cdSDavid du Colombier 					for(i=1; i<b[0]; i++)
5337f0337cdSDavid du Colombier 						fprint(2, " %.2x", b[i]);
5347f0337cdSDavid du Colombier 					fprint(2, "\n");
5357f0337cdSDavid du Colombier 				}
5367f0337cdSDavid du Colombier 				else if (debug & Dbginfo)
5377f0337cdSDavid du Colombier 					fprint(2, "\n");
5387f0337cdSDavid du Colombier 			}
5397f0337cdSDavid du Colombier 		}
5407f0337cdSDavid du Colombier 		n -= b[0];
5419a747e4fSDavid du Colombier 	}
5429a747e4fSDavid du Colombier }
543