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