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