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