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