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