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