xref: /plan9-contrib/sys/src/cmd/usb/kb/hid.c (revision d40255d87ccd1acd15b87823a96efd7b6296fadd)
1*d40255d8SDavid du Colombier #include <u.h>
2*d40255d8SDavid du Colombier #include <libc.h>
3*d40255d8SDavid du Colombier #include <thread.h>
4*d40255d8SDavid du Colombier #include "usb.h"
5*d40255d8SDavid du Colombier #include "hid.h"
6*d40255d8SDavid du Colombier 
7*d40255d8SDavid du Colombier /*
8*d40255d8SDavid du Colombier  * Rough hid descriptor parsing and interpretation for mice
9*d40255d8SDavid du Colombier  *
10*d40255d8SDavid du Colombier  * Chain and its operations build the infrastructure needed
11*d40255d8SDavid du Colombier  * to manipulate non-aligned fields, which do appear (sigh!).
12*d40255d8SDavid du Colombier  */
13*d40255d8SDavid du Colombier 
14*d40255d8SDavid du Colombier /* Get, at most, 8 bits*/
15*d40255d8SDavid du Colombier static uchar
16*d40255d8SDavid du Colombier get8bits(Chain *ch, int nbits)
17*d40255d8SDavid du Colombier {
18*d40255d8SDavid du Colombier 	int b, nbyb, nbib, nlb;
19*d40255d8SDavid du Colombier 	uchar low, high;
20*d40255d8SDavid du Colombier 
21*d40255d8SDavid du Colombier 	b = ch->b + nbits - 1;
22*d40255d8SDavid du Colombier 	nbib = ch->b % 8;
23*d40255d8SDavid du Colombier 	nbyb = ch->b / 8;
24*d40255d8SDavid du Colombier 	nlb = 8 - nbib;
25*d40255d8SDavid du Colombier 	if(nlb > nbits)
26*d40255d8SDavid du Colombier 		nlb = nbits;
27*d40255d8SDavid du Colombier 
28*d40255d8SDavid du Colombier 	low = MSK(nlb) & (ch->buf[nbyb] >> nbib);
29*d40255d8SDavid du Colombier 	if(IsCut(ch->b, b))
30*d40255d8SDavid du Colombier 		high = (ch->buf[nbyb + 1] & MSK(nbib)) << nlb;
31*d40255d8SDavid du Colombier 	else
32*d40255d8SDavid du Colombier 		high = 0;
33*d40255d8SDavid du Colombier 	ch->b += nbits;
34*d40255d8SDavid du Colombier 	return high | low;
35*d40255d8SDavid du Colombier }
36*d40255d8SDavid du Colombier 
37*d40255d8SDavid du Colombier static void
38*d40255d8SDavid du Colombier getbits(void *p, Chain *ch, int nbits)
39*d40255d8SDavid du Colombier {
40*d40255d8SDavid du Colombier 	int nby, nbi, i;
41*d40255d8SDavid du Colombier 	uchar *vp;
42*d40255d8SDavid du Colombier 
43*d40255d8SDavid du Colombier 	assert(ch->e >= ch->b);
44*d40255d8SDavid du Colombier 	nby = nbits / 8;
45*d40255d8SDavid du Colombier 	nbi = nbits % 8;
46*d40255d8SDavid du Colombier 
47*d40255d8SDavid du Colombier 	vp = p;
48*d40255d8SDavid du Colombier 	for(i = 0; i < nby; i++)
49*d40255d8SDavid du Colombier 		*vp++ = get8bits(ch, 8);
50*d40255d8SDavid du Colombier 
51*d40255d8SDavid du Colombier 	if(nbi != 0)
52*d40255d8SDavid du Colombier 		*vp = get8bits(ch, nbi);
53*d40255d8SDavid du Colombier }
54*d40255d8SDavid du Colombier 
55*d40255d8SDavid du Colombier /* TODO check report id, when it does appear (not all devices) */
56*d40255d8SDavid du Colombier int
57*d40255d8SDavid du Colombier parsereportdesc(HidRepTempl *temp, uchar *repdesc, int repsz)
58*d40255d8SDavid du Colombier {
59*d40255d8SDavid du Colombier 	int i, j, l, n, isptr, hasxy, hasbut, nk;
60*d40255d8SDavid du Colombier 	int ks[MaxVals];
61*d40255d8SDavid du Colombier 	HidInterface *ifs;
62*d40255d8SDavid du Colombier 
63*d40255d8SDavid du Colombier 	ifs = temp->ifcs;
64*d40255d8SDavid du Colombier 	isptr = 0;
65*d40255d8SDavid du Colombier 	hasxy = hasbut = 0;
66*d40255d8SDavid du Colombier 	n = 0;
67*d40255d8SDavid du Colombier 	nk = 0;
68*d40255d8SDavid du Colombier 	memset(ifs, 0, sizeof *ifs * MaxIfc);
69*d40255d8SDavid du Colombier 	for(i = 0; i < repsz / 2; i += 2){
70*d40255d8SDavid du Colombier 		if(n == MaxIfc || repdesc[i] == HidEnd)
71*d40255d8SDavid du Colombier 			break;
72*d40255d8SDavid du Colombier 
73*d40255d8SDavid du Colombier 		switch(repdesc[i]){
74*d40255d8SDavid du Colombier 		case HidTypeUsg:
75*d40255d8SDavid du Colombier 			switch(repdesc[i+1]){
76*d40255d8SDavid du Colombier 			case HidX:
77*d40255d8SDavid du Colombier 				hasxy++;
78*d40255d8SDavid du Colombier 				ks[nk++] = KindX;
79*d40255d8SDavid du Colombier 				break;
80*d40255d8SDavid du Colombier 			case HidY:
81*d40255d8SDavid du Colombier 				hasxy++;
82*d40255d8SDavid du Colombier 				ks[nk++] = KindY;
83*d40255d8SDavid du Colombier 				break;
84*d40255d8SDavid du Colombier 			case HidWheel:
85*d40255d8SDavid du Colombier 				ks[nk++] = KindWheel;
86*d40255d8SDavid du Colombier 				break;
87*d40255d8SDavid du Colombier 			case HidPtr:
88*d40255d8SDavid du Colombier 				isptr++;
89*d40255d8SDavid du Colombier 				break;
90*d40255d8SDavid du Colombier 			}
91*d40255d8SDavid du Colombier 			break;
92*d40255d8SDavid du Colombier 		case HidTypeUsgPg:
93*d40255d8SDavid du Colombier 			switch(repdesc[i+1]){
94*d40255d8SDavid du Colombier 			case HidPgButts:
95*d40255d8SDavid du Colombier 				hasbut++;
96*d40255d8SDavid du Colombier 				ks[nk++] = KindButtons;
97*d40255d8SDavid du Colombier 				break;
98*d40255d8SDavid du Colombier 			}
99*d40255d8SDavid du Colombier 			break;
100*d40255d8SDavid du Colombier 		case HidTypeRepSz:
101*d40255d8SDavid du Colombier 			ifs[n].nbits = repdesc[i+1];
102*d40255d8SDavid du Colombier 			break;
103*d40255d8SDavid du Colombier 		case HidTypeCnt:
104*d40255d8SDavid du Colombier 			ifs[n].count = repdesc[i+1];
105*d40255d8SDavid du Colombier 			break;
106*d40255d8SDavid du Colombier 		case HidInput:
107*d40255d8SDavid du Colombier 			for(j = 0; j <nk; j++)
108*d40255d8SDavid du Colombier 				ifs[n].kind[j] = ks[j];
109*d40255d8SDavid du Colombier 			if(nk < ifs[n].count)
110*d40255d8SDavid du Colombier 				for(l = j; l <ifs[n].count; l++)
111*d40255d8SDavid du Colombier 					ifs[n].kind[l] = ks[j-1];
112*d40255d8SDavid du Colombier 			n++;
113*d40255d8SDavid du Colombier 			nk = 0;
114*d40255d8SDavid du Colombier 			break;
115*d40255d8SDavid du Colombier 		}
116*d40255d8SDavid du Colombier 	}
117*d40255d8SDavid du Colombier 	temp->nifcs = n;
118*d40255d8SDavid du Colombier 	if(isptr && hasxy && hasbut)
119*d40255d8SDavid du Colombier 		return 0;
120*d40255d8SDavid du Colombier 	fprint(2, "bad report: isptr %d, hasxy %d, hasbut %d\n",
121*d40255d8SDavid du Colombier 		isptr, hasxy, hasbut);
122*d40255d8SDavid du Colombier 	return -1;
123*d40255d8SDavid du Colombier }
124*d40255d8SDavid du Colombier 
125*d40255d8SDavid du Colombier int
126*d40255d8SDavid du Colombier parsereport(HidRepTempl *templ, Chain *rep)
127*d40255d8SDavid du Colombier {
128*d40255d8SDavid du Colombier 	int i, j, k, ifssz;
129*d40255d8SDavid du Colombier 	ulong u;
130*d40255d8SDavid du Colombier 	uchar *p;
131*d40255d8SDavid du Colombier 	HidInterface *ifs;
132*d40255d8SDavid du Colombier 
133*d40255d8SDavid du Colombier 	ifssz = templ->nifcs;
134*d40255d8SDavid du Colombier 	ifs = templ->ifcs;
135*d40255d8SDavid du Colombier 	for(i = 0; i < ifssz; i++)
136*d40255d8SDavid du Colombier 		for(j = 0; j < ifs[i].count; j++){
137*d40255d8SDavid du Colombier 			if(ifs[i].nbits > 8 * sizeof ifs[i].v[0]){
138*d40255d8SDavid du Colombier 				fprint(2, "ptr: bad bits in parsereport");
139*d40255d8SDavid du Colombier 				return -1;
140*d40255d8SDavid du Colombier 			}
141*d40255d8SDavid du Colombier 			u =0;
142*d40255d8SDavid du Colombier 			getbits(&u, rep, ifs[i].nbits);
143*d40255d8SDavid du Colombier 			p = (uchar *)&u;
144*d40255d8SDavid du Colombier 			/* le to host */
145*d40255d8SDavid du Colombier 			ifs[i].v[j] = p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0]<<0;
146*d40255d8SDavid du Colombier 			k = ifs[i].kind[j];
147*d40255d8SDavid du Colombier 			if(k == KindX || k == KindY || k == KindWheel){
148*d40255d8SDavid du Colombier 				/* propagate sign */
149*d40255d8SDavid du Colombier 				if(ifs[i].v[j] & (1 << (ifs[i].nbits - 1)))
150*d40255d8SDavid du Colombier 					ifs[i].v[j] |= ~MSK(ifs[i].nbits);
151*d40255d8SDavid du Colombier 			}
152*d40255d8SDavid du Colombier 		}
153*d40255d8SDavid du Colombier 	return 0;
154*d40255d8SDavid du Colombier }
155*d40255d8SDavid du Colombier 
156*d40255d8SDavid du Colombier /* TODO: fmt representation */
157*d40255d8SDavid du Colombier void
158*d40255d8SDavid du Colombier dumpreport(HidRepTempl *templ)
159*d40255d8SDavid du Colombier {
160*d40255d8SDavid du Colombier 	int i, j, ifssz;
161*d40255d8SDavid du Colombier 	HidInterface *ifs;
162*d40255d8SDavid du Colombier 
163*d40255d8SDavid du Colombier 	ifssz = templ->nifcs;
164*d40255d8SDavid du Colombier 	ifs = templ->ifcs;
165*d40255d8SDavid du Colombier 	for(i = 0; i < ifssz; i++){
166*d40255d8SDavid du Colombier 		fprint(2, "\tcount %#ux", ifs[i].count);
167*d40255d8SDavid du Colombier 		fprint(2, " nbits %d ", ifs[i].nbits);
168*d40255d8SDavid du Colombier 		fprint(2, "\n");
169*d40255d8SDavid du Colombier 		for(j = 0; j < ifs[i].count; j++){
170*d40255d8SDavid du Colombier 			fprint(2, "\t\tkind %#ux ", ifs[i].kind[j]);
171*d40255d8SDavid du Colombier 			fprint(2, "v %#lux\n", ifs[i].v[j]);
172*d40255d8SDavid du Colombier 		}
173*d40255d8SDavid du Colombier 		fprint(2, "\n");
174*d40255d8SDavid du Colombier 	}
175*d40255d8SDavid du Colombier 	fprint(2, "\n");
176*d40255d8SDavid du Colombier }
177*d40255d8SDavid du Colombier 
178*d40255d8SDavid du Colombier /* could cache indices after parsing the descriptor */
179*d40255d8SDavid du Colombier int
180*d40255d8SDavid du Colombier hidifcval(HidRepTempl *templ, int kind, int n)
181*d40255d8SDavid du Colombier {
182*d40255d8SDavid du Colombier 	int i, j, ifssz;
183*d40255d8SDavid du Colombier 	HidInterface *ifs;
184*d40255d8SDavid du Colombier 
185*d40255d8SDavid du Colombier 	ifssz = templ->nifcs;
186*d40255d8SDavid du Colombier 	ifs = templ->ifcs;
187*d40255d8SDavid du Colombier 	assert(n <= nelem(ifs[i].v));
188*d40255d8SDavid du Colombier 	for(i = 0; i < ifssz; i++)
189*d40255d8SDavid du Colombier 		for(j = 0; j < ifs[i].count; j++)
190*d40255d8SDavid du Colombier 			if(ifs[i].kind[j] == kind && n-- == 0)
191*d40255d8SDavid du Colombier 				return (int)ifs[i].v[j];
192*d40255d8SDavid du Colombier 	return 0;		/* least damage (no buttons, no movement) */
193*d40255d8SDavid du Colombier }
194