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