xref: /plan9/sys/src/cmd/usb/kb/hid.c (revision 9b7bf7df4595c26f1e9b67beb0c6e44c9876fb05)
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
get8bits(Chain * ch,int nbits)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;
34f7db6155SDavid du Colombier 	return MSK(nbits)&(high | low);
35d40255d8SDavid du Colombier }
36d40255d8SDavid du Colombier 
37d40255d8SDavid du Colombier static void
getbits(void * p,Chain * ch,int nbits)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 int
parsereportdesc(HidRepTempl * temp,uchar * repdesc,int repsz)56d40255d8SDavid du Colombier parsereportdesc(HidRepTempl *temp, uchar *repdesc, int repsz)
57d40255d8SDavid du Colombier {
58*9b7bf7dfSDavid du Colombier 	int i, j, l, n, isptr, hasxy, hasbut, nk, ncoll, dsize;
59*9b7bf7dfSDavid du Colombier 	uchar ks[MaxVals+1];
60d40255d8SDavid du Colombier 	HidInterface *ifs;
61d40255d8SDavid du Colombier 
62d40255d8SDavid du Colombier 	ifs = temp->ifcs;
63d40255d8SDavid du Colombier 	isptr = 0;
64d40255d8SDavid du Colombier 	hasxy = hasbut = 0;
65f7db6155SDavid du Colombier 	ncoll = 0;
66d40255d8SDavid du Colombier 	n = 0;
67d40255d8SDavid du Colombier 	nk = 0;
68d40255d8SDavid du Colombier 	memset(ifs, 0, sizeof *ifs * MaxIfc);
69*9b7bf7dfSDavid du Colombier 	for(i = 0; i < repsz; i += dsize+1){
70*9b7bf7dfSDavid du Colombier 		dsize = (1 << (repdesc[i] & 03)) >> 1;
71*9b7bf7dfSDavid du Colombier 		if(nk > MaxVals){
72*9b7bf7dfSDavid du Colombier 			fprint(2, "bad report: too many input types\n");
73*9b7bf7dfSDavid du Colombier 			return -1;
74*9b7bf7dfSDavid du Colombier 		}
75f7db6155SDavid du Colombier 		if(n == MaxIfc)
76d40255d8SDavid du Colombier 			break;
77f7db6155SDavid du Colombier 		if(repdesc[i] == HidEnd){
78f7db6155SDavid du Colombier 			ncoll--;
79f7db6155SDavid du Colombier 			if(ncoll == 0)
80f7db6155SDavid du Colombier 				break;
81f7db6155SDavid du Colombier 		}
82d40255d8SDavid du Colombier 
83d40255d8SDavid du Colombier 		switch(repdesc[i]){
84f7db6155SDavid du Colombier 		case HidReportId:
85f7db6155SDavid du Colombier 			switch(repdesc[i+1]){
86*9b7bf7dfSDavid du Colombier 			case HidReportIdPtr:
87f7db6155SDavid du Colombier 				temp->id = repdesc[i+1];
88f7db6155SDavid du Colombier 				break;
89f7db6155SDavid du Colombier 			default:
90f7db6155SDavid du Colombier 				fprint(2, "report type %#ux bad\n",
91f7db6155SDavid du Colombier 					repdesc[i+1]);
92f7db6155SDavid du Colombier 				return -1;
93f7db6155SDavid du Colombier 			}
94f7db6155SDavid du Colombier 			break;
95d40255d8SDavid du Colombier 		case HidTypeUsg:
96d40255d8SDavid du Colombier 			switch(repdesc[i+1]){
97d40255d8SDavid du Colombier 			case HidX:
98d40255d8SDavid du Colombier 				hasxy++;
99d40255d8SDavid du Colombier 				ks[nk++] = KindX;
100d40255d8SDavid du Colombier 				break;
101d40255d8SDavid du Colombier 			case HidY:
102d40255d8SDavid du Colombier 				hasxy++;
103d40255d8SDavid du Colombier 				ks[nk++] = KindY;
104d40255d8SDavid du Colombier 				break;
105*9b7bf7dfSDavid du Colombier 			case HidZ:
106*9b7bf7dfSDavid du Colombier 				ks[nk++] = KindPad;
107*9b7bf7dfSDavid du Colombier 				break;
108d40255d8SDavid du Colombier 			case HidWheel:
109d40255d8SDavid du Colombier 				ks[nk++] = KindWheel;
110d40255d8SDavid du Colombier 				break;
111d40255d8SDavid du Colombier 			case HidPtr:
112d40255d8SDavid du Colombier 				isptr++;
113d40255d8SDavid du Colombier 				break;
114d40255d8SDavid du Colombier 			}
115d40255d8SDavid du Colombier 			break;
116d40255d8SDavid du Colombier 		case HidTypeUsgPg:
117d40255d8SDavid du Colombier 			switch(repdesc[i+1]){
118d40255d8SDavid du Colombier 			case HidPgButts:
119d40255d8SDavid du Colombier 				hasbut++;
120d40255d8SDavid du Colombier 				ks[nk++] = KindButtons;
121d40255d8SDavid du Colombier 				break;
122d40255d8SDavid du Colombier 			}
123d40255d8SDavid du Colombier 			break;
124d40255d8SDavid du Colombier 		case HidTypeRepSz:
125d40255d8SDavid du Colombier 			ifs[n].nbits = repdesc[i+1];
126d40255d8SDavid du Colombier 			break;
127d40255d8SDavid du Colombier 		case HidTypeCnt:
128d40255d8SDavid du Colombier 			ifs[n].count = repdesc[i+1];
129d40255d8SDavid du Colombier 			break;
130d40255d8SDavid du Colombier 		case HidInput:
131*9b7bf7dfSDavid du Colombier 			if(ifs[n].count > MaxVals){
132*9b7bf7dfSDavid du Colombier 				fprint(2, "bad report: input count too big\n");
133*9b7bf7dfSDavid du Colombier 				return -1;
134*9b7bf7dfSDavid du Colombier 			}
135d40255d8SDavid du Colombier 			for(j = 0; j <nk; j++)
136d40255d8SDavid du Colombier 				ifs[n].kind[j] = ks[j];
137eb2d6162SDavid du Colombier 			if(nk != 0 && nk < ifs[n].count)
138d40255d8SDavid du Colombier 				for(l = j; l <ifs[n].count; l++)
139d40255d8SDavid du Colombier 					ifs[n].kind[l] = ks[j-1];
140d40255d8SDavid du Colombier 			n++;
141eb2d6162SDavid du Colombier 			if(n < MaxIfc){
142eb2d6162SDavid du Colombier 				ifs[n].count = ifs[n-1].count;	/* inherit values */
143eb2d6162SDavid du Colombier 				ifs[n].nbits = ifs[n-1].nbits;
144eb2d6162SDavid du Colombier 				if(ifs[n].nbits == 0)
145eb2d6162SDavid du Colombier 					ifs[n].nbits = 1;
146*9b7bf7dfSDavid du Colombier 			}
147d40255d8SDavid du Colombier 			nk = 0;
148d40255d8SDavid du Colombier 			break;
149f7db6155SDavid du Colombier 		case HidCollection:
150f7db6155SDavid du Colombier 			ncoll++;
151f7db6155SDavid du Colombier 			break;
152d40255d8SDavid du Colombier 		}
153d40255d8SDavid du Colombier 	}
154d40255d8SDavid du Colombier 	temp->nifcs = n;
155f7db6155SDavid du Colombier 	for(i = 0; i < n; i++)
156f7db6155SDavid du Colombier 		temp->sz += temp->ifcs[i].nbits * temp->ifcs[i].count;
157f7db6155SDavid du Colombier 	temp->sz = (temp->sz + 7) / 8;
158f7db6155SDavid du Colombier 
159d40255d8SDavid du Colombier 	if(isptr && hasxy && hasbut)
160d40255d8SDavid du Colombier 		return 0;
161d40255d8SDavid du Colombier 	fprint(2, "bad report: isptr %d, hasxy %d, hasbut %d\n",
162d40255d8SDavid du Colombier 		isptr, hasxy, hasbut);
163d40255d8SDavid du Colombier 	return -1;
164d40255d8SDavid du Colombier }
165d40255d8SDavid du Colombier 
166d40255d8SDavid du Colombier int
parsereport(HidRepTempl * templ,Chain * rep)167d40255d8SDavid du Colombier parsereport(HidRepTempl *templ, Chain *rep)
168d40255d8SDavid du Colombier {
169d40255d8SDavid du Colombier 	int i, j, k, ifssz;
170d40255d8SDavid du Colombier 	ulong u;
171d40255d8SDavid du Colombier 	uchar *p;
172d40255d8SDavid du Colombier 	HidInterface *ifs;
173d40255d8SDavid du Colombier 
174d40255d8SDavid du Colombier 	ifssz = templ->nifcs;
175d40255d8SDavid du Colombier 	ifs = templ->ifcs;
176d40255d8SDavid du Colombier 	for(i = 0; i < ifssz; i++)
177d40255d8SDavid du Colombier 		for(j = 0; j < ifs[i].count; j++){
178d40255d8SDavid du Colombier 			if(ifs[i].nbits > 8 * sizeof ifs[i].v[0]){
179d40255d8SDavid du Colombier 				fprint(2, "ptr: bad bits in parsereport");
180d40255d8SDavid du Colombier 				return -1;
181d40255d8SDavid du Colombier 			}
182d40255d8SDavid du Colombier 			u =0;
183d40255d8SDavid du Colombier 			getbits(&u, rep, ifs[i].nbits);
184d40255d8SDavid du Colombier 			p = (uchar *)&u;
185d40255d8SDavid du Colombier 			/* le to host */
186d40255d8SDavid du Colombier 			ifs[i].v[j] = p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0]<<0;
187d40255d8SDavid du Colombier 			k = ifs[i].kind[j];
188d40255d8SDavid du Colombier 			if(k == KindX || k == KindY || k == KindWheel){
189d40255d8SDavid du Colombier 				/* propagate sign */
190d40255d8SDavid du Colombier 				if(ifs[i].v[j] & (1 << (ifs[i].nbits - 1)))
191d40255d8SDavid du Colombier 					ifs[i].v[j] |= ~MSK(ifs[i].nbits);
192d40255d8SDavid du Colombier 			}
193d40255d8SDavid du Colombier 		}
194d40255d8SDavid du Colombier 	return 0;
195d40255d8SDavid du Colombier }
196d40255d8SDavid du Colombier 
197d40255d8SDavid du Colombier /* TODO: fmt representation */
198d40255d8SDavid du Colombier void
dumpreport(HidRepTempl * templ)199d40255d8SDavid du Colombier dumpreport(HidRepTempl *templ)
200d40255d8SDavid du Colombier {
201d40255d8SDavid du Colombier 	int i, j, ifssz;
202d40255d8SDavid du Colombier 	HidInterface *ifs;
203d40255d8SDavid du Colombier 
204d40255d8SDavid du Colombier 	ifssz = templ->nifcs;
205d40255d8SDavid du Colombier 	ifs = templ->ifcs;
206d40255d8SDavid du Colombier 	for(i = 0; i < ifssz; i++){
207d40255d8SDavid du Colombier 		fprint(2, "\tcount %#ux", ifs[i].count);
208d40255d8SDavid du Colombier 		fprint(2, " nbits %d ", ifs[i].nbits);
209d40255d8SDavid du Colombier 		fprint(2, "\n");
210d40255d8SDavid du Colombier 		for(j = 0; j < ifs[i].count; j++){
211d40255d8SDavid du Colombier 			fprint(2, "\t\tkind %#ux ", ifs[i].kind[j]);
212d40255d8SDavid du Colombier 			fprint(2, "v %#lux\n", ifs[i].v[j]);
213d40255d8SDavid du Colombier 		}
214d40255d8SDavid du Colombier 		fprint(2, "\n");
215d40255d8SDavid du Colombier 	}
216d40255d8SDavid du Colombier 	fprint(2, "\n");
217d40255d8SDavid du Colombier }
218d40255d8SDavid du Colombier 
219eb2d6162SDavid du Colombier /* could precalculate indices after parsing the descriptor */
220d40255d8SDavid du Colombier int
hidifcval(HidRepTempl * templ,int kind,int n)221d40255d8SDavid du Colombier hidifcval(HidRepTempl *templ, int kind, int n)
222d40255d8SDavid du Colombier {
223d40255d8SDavid du Colombier 	int i, j, ifssz;
224d40255d8SDavid du Colombier 	HidInterface *ifs;
225d40255d8SDavid du Colombier 
226d40255d8SDavid du Colombier 	ifssz = templ->nifcs;
227d40255d8SDavid du Colombier 	ifs = templ->ifcs;
228d40255d8SDavid du Colombier 	assert(n <= nelem(ifs[i].v));
229d40255d8SDavid du Colombier 	for(i = 0; i < ifssz; i++)
230d40255d8SDavid du Colombier 		for(j = 0; j < ifs[i].count; j++)
231d40255d8SDavid du Colombier 			if(ifs[i].kind[j] == kind && n-- == 0)
232d40255d8SDavid du Colombier 				return (int)ifs[i].v[j];
233d40255d8SDavid du Colombier 	return 0;		/* least damage (no buttons, no movement) */
234d40255d8SDavid du Colombier }
235