xref: /plan9-contrib/sys/src/cmd/usb/lib/dump.c (revision 208510e168b9c00c3c6969f56b807dc03575167d)
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