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