hid.c revision 1.1.2.2 1 1.1.2.2 pgoyette /* $NetBSD: hid.c,v 1.1.2.2 2018/11/26 01:52:31 pgoyette Exp $ */
2 1.1 bouyer /* $FreeBSD: src/sys/dev/usb/hid.c,v 1.11 1999/11/17 22:33:39 n_hibma Exp $ */
3 1.1 bouyer
4 1.1 bouyer /*
5 1.1 bouyer * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 1.1 bouyer * All rights reserved.
7 1.1 bouyer *
8 1.1 bouyer * This code is derived from software contributed to The NetBSD Foundation
9 1.1 bouyer * by Lennart Augustsson (lennart (at) augustsson.net) at
10 1.1 bouyer * Carlstedt Research & Technology.
11 1.1 bouyer *
12 1.1 bouyer * Redistribution and use in source and binary forms, with or without
13 1.1 bouyer * modification, are permitted provided that the following conditions
14 1.1 bouyer * are met:
15 1.1 bouyer * 1. Redistributions of source code must retain the above copyright
16 1.1 bouyer * notice, this list of conditions and the following disclaimer.
17 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright
18 1.1 bouyer * notice, this list of conditions and the following disclaimer in the
19 1.1 bouyer * documentation and/or other materials provided with the distribution.
20 1.1 bouyer *
21 1.1 bouyer * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 1.1 bouyer * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 1.1 bouyer * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 1.1 bouyer * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 1.1 bouyer * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 1.1 bouyer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 1.1 bouyer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 1.1 bouyer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 1.1 bouyer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 1.1 bouyer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 1.1 bouyer * POSSIBILITY OF SUCH DAMAGE.
32 1.1 bouyer */
33 1.1 bouyer
34 1.1 bouyer #include <sys/cdefs.h>
35 1.1.2.2 pgoyette __KERNEL_RCSID(0, "$NetBSD: hid.c,v 1.1.2.2 2018/11/26 01:52:31 pgoyette Exp $");
36 1.1 bouyer
37 1.1 bouyer #ifdef _KERNEL_OPT
38 1.1 bouyer #include "opt_usb.h"
39 1.1 bouyer #endif
40 1.1 bouyer
41 1.1 bouyer #include <sys/param.h>
42 1.1 bouyer #include <sys/systm.h>
43 1.1 bouyer #include <sys/kernel.h>
44 1.1 bouyer #include <sys/kmem.h>
45 1.1 bouyer
46 1.1 bouyer #include <dev/usb/usb.h>
47 1.1 bouyer #include <dev/usb/usbhid.h>
48 1.1 bouyer
49 1.1 bouyer #include <dev/hid/hid.h>
50 1.1 bouyer
51 1.1 bouyer #ifdef UHIDEV_DEBUG
52 1.1 bouyer #define DPRINTF(x) if (uhidevdebug) printf x
53 1.1 bouyer #define DPRINTFN(n,x) if (uhidevdebug>(n)) printf x
54 1.1 bouyer extern int uhidevdebug;
55 1.1 bouyer #else
56 1.1 bouyer #define DPRINTF(x)
57 1.1 bouyer #define DPRINTFN(n,x)
58 1.1 bouyer #endif
59 1.1 bouyer
60 1.1 bouyer Static void hid_clear_local(struct hid_item *);
61 1.1 bouyer
62 1.1 bouyer #define MAXUSAGE 256
63 1.1 bouyer struct hid_data {
64 1.1 bouyer const u_char *start;
65 1.1 bouyer const u_char *end;
66 1.1 bouyer const u_char *p;
67 1.1 bouyer struct hid_item cur;
68 1.1 bouyer int32_t usages[MAXUSAGE];
69 1.1 bouyer int nu;
70 1.1 bouyer int minset;
71 1.1 bouyer int multi;
72 1.1 bouyer int multimax;
73 1.1 bouyer enum hid_kind kind;
74 1.1 bouyer };
75 1.1 bouyer
76 1.1 bouyer Static void
77 1.1 bouyer hid_clear_local(struct hid_item *c)
78 1.1 bouyer {
79 1.1 bouyer
80 1.1 bouyer DPRINTFN(5,("hid_clear_local\n"));
81 1.1 bouyer c->usage = 0;
82 1.1 bouyer c->usage_minimum = 0;
83 1.1 bouyer c->usage_maximum = 0;
84 1.1 bouyer c->designator_index = 0;
85 1.1 bouyer c->designator_minimum = 0;
86 1.1 bouyer c->designator_maximum = 0;
87 1.1 bouyer c->string_index = 0;
88 1.1 bouyer c->string_minimum = 0;
89 1.1 bouyer c->string_maximum = 0;
90 1.1 bouyer c->set_delimiter = 0;
91 1.1 bouyer }
92 1.1 bouyer
93 1.1 bouyer struct hid_data *
94 1.1 bouyer hid_start_parse(const void *d, int len, enum hid_kind kind)
95 1.1 bouyer {
96 1.1 bouyer struct hid_data *s;
97 1.1 bouyer
98 1.1 bouyer s = kmem_zalloc(sizeof(*s), KM_SLEEP);
99 1.1 bouyer s->start = s->p = d;
100 1.1 bouyer s->end = (const char *)d + len;
101 1.1 bouyer s->kind = kind;
102 1.1 bouyer return s;
103 1.1 bouyer }
104 1.1 bouyer
105 1.1 bouyer void
106 1.1 bouyer hid_end_parse(struct hid_data *s)
107 1.1 bouyer {
108 1.1 bouyer
109 1.1 bouyer while (s->cur.next != NULL) {
110 1.1 bouyer struct hid_item *hi = s->cur.next->next;
111 1.1 bouyer kmem_free(s->cur.next, sizeof(*s->cur.next));
112 1.1 bouyer s->cur.next = hi;
113 1.1 bouyer }
114 1.1 bouyer kmem_free(s, sizeof(*s));
115 1.1 bouyer }
116 1.1 bouyer
117 1.1 bouyer int
118 1.1 bouyer hid_get_item(struct hid_data *s, struct hid_item *h)
119 1.1 bouyer {
120 1.1 bouyer struct hid_item *c = &s->cur;
121 1.1 bouyer unsigned int bTag, bType, bSize;
122 1.1 bouyer uint32_t oldpos;
123 1.1 bouyer const u_char *data;
124 1.1 bouyer int32_t dval;
125 1.1.2.2 pgoyette uint32_t uval;
126 1.1 bouyer const u_char *p;
127 1.1 bouyer struct hid_item *hi;
128 1.1 bouyer int i;
129 1.1 bouyer enum hid_kind retkind;
130 1.1 bouyer
131 1.1 bouyer top:
132 1.1 bouyer DPRINTFN(5,("hid_get_item: multi=%d multimax=%d\n",
133 1.1 bouyer s->multi, s->multimax));
134 1.1 bouyer if (s->multimax != 0) {
135 1.1 bouyer if (s->multi < s->multimax) {
136 1.1.2.1 pgoyette c->usage = s->usages[uimin(s->multi, s->nu-1)];
137 1.1 bouyer s->multi++;
138 1.1 bouyer *h = *c;
139 1.1 bouyer c->loc.pos += c->loc.size;
140 1.1 bouyer h->next = NULL;
141 1.1 bouyer DPRINTFN(5,("return multi\n"));
142 1.1 bouyer return 1;
143 1.1 bouyer } else {
144 1.1 bouyer c->loc.count = s->multimax;
145 1.1 bouyer s->multimax = 0;
146 1.1 bouyer s->nu = 0;
147 1.1 bouyer hid_clear_local(c);
148 1.1 bouyer }
149 1.1 bouyer }
150 1.1 bouyer for (;;) {
151 1.1 bouyer p = s->p;
152 1.1 bouyer if (p >= s->end)
153 1.1 bouyer return 0;
154 1.1 bouyer
155 1.1 bouyer bSize = *p++;
156 1.1 bouyer if (bSize == 0xfe) {
157 1.1 bouyer /* long item */
158 1.1 bouyer bSize = *p++;
159 1.1 bouyer bSize |= *p++ << 8;
160 1.1 bouyer bTag = *p++;
161 1.1 bouyer data = p;
162 1.1 bouyer p += bSize;
163 1.1 bouyer bType = 0xff; /* XXX what should it be */
164 1.1 bouyer } else {
165 1.1 bouyer /* short item */
166 1.1 bouyer bTag = bSize >> 4;
167 1.1 bouyer bType = (bSize >> 2) & 3;
168 1.1 bouyer bSize &= 3;
169 1.1 bouyer if (bSize == 3) bSize = 4;
170 1.1 bouyer data = p;
171 1.1 bouyer p += bSize;
172 1.1 bouyer }
173 1.1 bouyer s->p = p;
174 1.1 bouyer switch(bSize) {
175 1.1 bouyer case 0:
176 1.1 bouyer dval = 0;
177 1.1.2.2 pgoyette uval = dval;
178 1.1 bouyer break;
179 1.1 bouyer case 1:
180 1.1.2.2 pgoyette dval = *data++;
181 1.1.2.2 pgoyette uval = dval;
182 1.1.2.2 pgoyette dval = (int8_t)dval;
183 1.1 bouyer break;
184 1.1 bouyer case 2:
185 1.1 bouyer dval = *data++;
186 1.1 bouyer dval |= *data++ << 8;
187 1.1.2.2 pgoyette uval = dval;
188 1.1 bouyer dval = (int16_t)dval;
189 1.1 bouyer break;
190 1.1 bouyer case 4:
191 1.1 bouyer dval = *data++;
192 1.1 bouyer dval |= *data++ << 8;
193 1.1 bouyer dval |= *data++ << 16;
194 1.1 bouyer dval |= *data++ << 24;
195 1.1.2.2 pgoyette uval = dval;
196 1.1 bouyer dval = (int32_t)dval;
197 1.1 bouyer break;
198 1.1 bouyer default:
199 1.1 bouyer aprint_normal("BAD LENGTH %d\n", bSize);
200 1.1 bouyer continue;
201 1.1 bouyer }
202 1.1 bouyer
203 1.1.2.2 pgoyette DPRINTFN(5,("hid_get_item: bType=%d bTag=%d dval=%d uval=%u\n",
204 1.1.2.2 pgoyette bType, bTag, dval, uval));
205 1.1 bouyer switch (bType) {
206 1.1 bouyer case 0: /* Main */
207 1.1 bouyer switch (bTag) {
208 1.1 bouyer case 8: /* Input */
209 1.1 bouyer retkind = hid_input;
210 1.1 bouyer ret:
211 1.1 bouyer if (s->kind != retkind) {
212 1.1 bouyer s->minset = 0;
213 1.1 bouyer s->nu = 0;
214 1.1 bouyer hid_clear_local(c);
215 1.1 bouyer continue;
216 1.1 bouyer }
217 1.1 bouyer c->kind = retkind;
218 1.1.2.2 pgoyette c->flags = uval;
219 1.1 bouyer if (c->flags & HIO_VARIABLE) {
220 1.1 bouyer s->multimax = c->loc.count;
221 1.1 bouyer s->multi = 0;
222 1.1 bouyer c->loc.count = 1;
223 1.1 bouyer if (s->minset) {
224 1.1 bouyer for (i = c->usage_minimum;
225 1.1 bouyer i <= c->usage_maximum;
226 1.1 bouyer i++) {
227 1.1 bouyer s->usages[s->nu] = i;
228 1.1 bouyer if (s->nu < MAXUSAGE-1)
229 1.1 bouyer s->nu++;
230 1.1 bouyer }
231 1.1 bouyer s->minset = 0;
232 1.1 bouyer }
233 1.1 bouyer goto top;
234 1.1 bouyer } else {
235 1.1 bouyer if (s->minset)
236 1.1 bouyer c->usage = c->usage_minimum;
237 1.1 bouyer *h = *c;
238 1.1 bouyer h->next = NULL;
239 1.1 bouyer c->loc.pos +=
240 1.1 bouyer c->loc.size * c->loc.count;
241 1.1 bouyer s->minset = 0;
242 1.1 bouyer s->nu = 0;
243 1.1 bouyer hid_clear_local(c);
244 1.1 bouyer return 1;
245 1.1 bouyer }
246 1.1 bouyer case 9: /* Output */
247 1.1 bouyer retkind = hid_output;
248 1.1 bouyer goto ret;
249 1.1 bouyer case 10: /* Collection */
250 1.1 bouyer c->kind = hid_collection;
251 1.1.2.2 pgoyette c->collection = uval;
252 1.1 bouyer c->collevel++;
253 1.1 bouyer *h = *c;
254 1.1 bouyer hid_clear_local(c);
255 1.1 bouyer s->nu = 0;
256 1.1 bouyer return 1;
257 1.1 bouyer case 11: /* Feature */
258 1.1 bouyer retkind = hid_feature;
259 1.1 bouyer goto ret;
260 1.1 bouyer case 12: /* End collection */
261 1.1 bouyer c->kind = hid_endcollection;
262 1.1 bouyer c->collevel--;
263 1.1 bouyer *h = *c;
264 1.1 bouyer s->nu = 0;
265 1.1 bouyer return 1;
266 1.1 bouyer default:
267 1.1 bouyer aprint_normal("Main bTag=%d\n", bTag);
268 1.1 bouyer break;
269 1.1 bouyer }
270 1.1 bouyer break;
271 1.1 bouyer case 1: /* Global */
272 1.1 bouyer switch (bTag) {
273 1.1 bouyer case 0:
274 1.1.2.2 pgoyette c->_usage_page = uval << 16;
275 1.1 bouyer break;
276 1.1 bouyer case 1:
277 1.1 bouyer c->logical_minimum = dval;
278 1.1 bouyer break;
279 1.1 bouyer case 2:
280 1.1 bouyer c->logical_maximum = dval;
281 1.1 bouyer break;
282 1.1 bouyer case 3:
283 1.1 bouyer c->physical_minimum = dval;
284 1.1 bouyer break;
285 1.1 bouyer case 4:
286 1.1 bouyer c->physical_maximum = dval;
287 1.1 bouyer break;
288 1.1 bouyer case 5:
289 1.1.2.2 pgoyette c->unit_exponent = uval;
290 1.1 bouyer break;
291 1.1 bouyer case 6:
292 1.1.2.2 pgoyette c->unit = uval;
293 1.1 bouyer break;
294 1.1 bouyer case 7:
295 1.1.2.2 pgoyette c->loc.size = uval;
296 1.1 bouyer break;
297 1.1 bouyer case 8:
298 1.1.2.2 pgoyette c->report_ID = uval;
299 1.1 bouyer c->loc.pos = 0;
300 1.1 bouyer break;
301 1.1 bouyer case 9:
302 1.1.2.2 pgoyette c->loc.count = uval;
303 1.1 bouyer break;
304 1.1 bouyer case 10: /* Push */
305 1.1 bouyer hi = kmem_alloc(sizeof(*hi), KM_SLEEP);
306 1.1 bouyer *hi = *c;
307 1.1 bouyer c->next = hi;
308 1.1 bouyer break;
309 1.1 bouyer case 11: /* Pop */
310 1.1 bouyer hi = c->next;
311 1.1 bouyer if (hi == NULL)
312 1.1 bouyer break;
313 1.1 bouyer oldpos = c->loc.pos;
314 1.1 bouyer *c = *hi;
315 1.1 bouyer c->loc.pos = oldpos;
316 1.1 bouyer kmem_free(hi, sizeof(*hi));
317 1.1 bouyer break;
318 1.1 bouyer default:
319 1.1 bouyer aprint_normal("Global bTag=%d\n", bTag);
320 1.1 bouyer break;
321 1.1 bouyer }
322 1.1 bouyer break;
323 1.1 bouyer case 2: /* Local */
324 1.1 bouyer switch (bTag) {
325 1.1 bouyer case 0:
326 1.1.2.2 pgoyette if (bSize < 4)
327 1.1.2.2 pgoyette uval = c->_usage_page | uval;
328 1.1.2.2 pgoyette c->usage = uval;
329 1.1 bouyer if (s->nu < MAXUSAGE)
330 1.1.2.2 pgoyette s->usages[s->nu++] = uval;
331 1.1 bouyer /* else XXX */
332 1.1 bouyer break;
333 1.1 bouyer case 1:
334 1.1 bouyer s->minset = 1;
335 1.1.2.2 pgoyette if (bSize < 4)
336 1.1.2.2 pgoyette uval = c->_usage_page | uval;
337 1.1.2.2 pgoyette c->usage_minimum = uval;
338 1.1 bouyer break;
339 1.1 bouyer case 2:
340 1.1.2.2 pgoyette if (bSize < 4)
341 1.1.2.2 pgoyette uval = c->_usage_page | uval;
342 1.1.2.2 pgoyette c->usage_maximum = uval;
343 1.1 bouyer break;
344 1.1 bouyer case 3:
345 1.1.2.2 pgoyette c->designator_index = uval;
346 1.1 bouyer break;
347 1.1 bouyer case 4:
348 1.1.2.2 pgoyette c->designator_minimum = uval;
349 1.1 bouyer break;
350 1.1 bouyer case 5:
351 1.1.2.2 pgoyette c->designator_maximum = uval;
352 1.1 bouyer break;
353 1.1 bouyer case 7:
354 1.1.2.2 pgoyette c->string_index = uval;
355 1.1 bouyer break;
356 1.1 bouyer case 8:
357 1.1.2.2 pgoyette c->string_minimum = uval;
358 1.1 bouyer break;
359 1.1 bouyer case 9:
360 1.1.2.2 pgoyette c->string_maximum = uval;
361 1.1 bouyer break;
362 1.1 bouyer case 10:
363 1.1.2.2 pgoyette c->set_delimiter = uval;
364 1.1 bouyer break;
365 1.1 bouyer default:
366 1.1 bouyer aprint_normal("Local bTag=%d\n", bTag);
367 1.1 bouyer break;
368 1.1 bouyer }
369 1.1 bouyer break;
370 1.1 bouyer default:
371 1.1 bouyer aprint_normal("default bType=%d\n", bType);
372 1.1 bouyer break;
373 1.1 bouyer }
374 1.1 bouyer }
375 1.1 bouyer }
376 1.1 bouyer
377 1.1 bouyer int
378 1.1 bouyer hid_report_size(const void *buf, int len, enum hid_kind k, uint8_t id)
379 1.1 bouyer {
380 1.1 bouyer struct hid_data *d;
381 1.1 bouyer struct hid_item h;
382 1.1 bouyer int lo, hi;
383 1.1 bouyer
384 1.1 bouyer h.report_ID = 0;
385 1.1 bouyer lo = hi = -1;
386 1.1 bouyer DPRINTFN(2,("hid_report_size: kind=%d id=%d\n", k, id));
387 1.1 bouyer for (d = hid_start_parse(buf, len, k); hid_get_item(d, &h); ) {
388 1.1 bouyer DPRINTFN(2,("hid_report_size: item kind=%d id=%d pos=%d "
389 1.1 bouyer "size=%d count=%d\n",
390 1.1 bouyer h.kind, h.report_ID, h.loc.pos, h.loc.size,
391 1.1 bouyer h.loc.count));
392 1.1 bouyer if (h.report_ID == id && h.kind == k) {
393 1.1 bouyer if (lo < 0) {
394 1.1 bouyer lo = h.loc.pos;
395 1.1 bouyer #ifdef DIAGNOSTIC
396 1.1 bouyer if (lo != 0) {
397 1.1 bouyer aprint_normal("hid_report_size:"
398 1.1 bouyer " lo != 0\n");
399 1.1 bouyer }
400 1.1 bouyer #endif
401 1.1 bouyer }
402 1.1 bouyer hi = h.loc.pos + h.loc.size * h.loc.count;
403 1.1 bouyer DPRINTFN(2,("hid_report_size: lo=%d hi=%d\n", lo, hi));
404 1.1 bouyer }
405 1.1 bouyer }
406 1.1 bouyer hid_end_parse(d);
407 1.1 bouyer return (hi - lo + 7) / 8;
408 1.1 bouyer }
409 1.1 bouyer
410 1.1 bouyer int
411 1.1 bouyer hid_locate(const void *desc, int size, uint32_t u, uint8_t id, enum hid_kind k,
412 1.1 bouyer struct hid_location *loc, uint32_t *flags)
413 1.1 bouyer {
414 1.1 bouyer struct hid_data *d;
415 1.1 bouyer struct hid_item h;
416 1.1 bouyer
417 1.1 bouyer h.report_ID = 0;
418 1.1 bouyer DPRINTFN(5,("hid_locate: enter usage=0x%x kind=%d id=%d\n", u, k, id));
419 1.1 bouyer for (d = hid_start_parse(desc, size, k); hid_get_item(d, &h); ) {
420 1.1 bouyer DPRINTFN(5,("hid_locate: usage=0x%x kind=%d id=%d flags=0x%x\n",
421 1.1 bouyer h.usage, h.kind, h.report_ID, h.flags));
422 1.1 bouyer if (h.kind == k && !(h.flags & HIO_CONST) &&
423 1.1 bouyer h.usage == u && h.report_ID == id) {
424 1.1 bouyer if (loc != NULL)
425 1.1 bouyer *loc = h.loc;
426 1.1 bouyer if (flags != NULL)
427 1.1 bouyer *flags = h.flags;
428 1.1 bouyer hid_end_parse(d);
429 1.1 bouyer return 1;
430 1.1 bouyer }
431 1.1 bouyer }
432 1.1 bouyer hid_end_parse(d);
433 1.1 bouyer if (loc != NULL)
434 1.1 bouyer loc->size = 0;
435 1.1 bouyer return 0;
436 1.1 bouyer }
437 1.1 bouyer
438 1.1 bouyer long
439 1.1 bouyer hid_get_data(const u_char *buf, const struct hid_location *loc)
440 1.1 bouyer {
441 1.1 bouyer u_int hsize = loc->size;
442 1.1 bouyer u_long data;
443 1.1 bouyer
444 1.1 bouyer if (hsize == 0)
445 1.1 bouyer return 0;
446 1.1 bouyer
447 1.1 bouyer data = hid_get_udata(buf, loc);
448 1.1 bouyer if (data < (1UL << (hsize - 1)) || hsize == sizeof(data) * NBBY)
449 1.1 bouyer return data;
450 1.1 bouyer return data - (1UL << hsize);
451 1.1 bouyer }
452 1.1 bouyer
453 1.1 bouyer u_long
454 1.1 bouyer hid_get_udata(const u_char *buf, const struct hid_location *loc)
455 1.1 bouyer {
456 1.1 bouyer u_int hpos = loc->pos;
457 1.1 bouyer u_int hsize = loc->size;
458 1.1 bouyer u_int i, num, off;
459 1.1 bouyer u_long data;
460 1.1 bouyer
461 1.1 bouyer if (hsize == 0)
462 1.1 bouyer return 0;
463 1.1 bouyer
464 1.1 bouyer data = 0;
465 1.1 bouyer off = hpos / 8;
466 1.1 bouyer num = (hpos + hsize + 7) / 8 - off;
467 1.1 bouyer
468 1.1 bouyer for (i = 0; i < num; i++)
469 1.1 bouyer data |= (unsigned long)buf[off + i] << (i * 8);
470 1.1 bouyer
471 1.1 bouyer data >>= hpos % 8;
472 1.1 bouyer if (hsize < sizeof(data) * NBBY)
473 1.1 bouyer data &= (1UL << hsize) - 1;
474 1.1 bouyer
475 1.1 bouyer DPRINTFN(10,("hid_get_udata: loc %d/%d = %lu\n", hpos, hsize, data));
476 1.1 bouyer return data;
477 1.1 bouyer }
478 1.1 bouyer
479 1.1 bouyer /*
480 1.1 bouyer * hid_is_collection(desc, size, id, usage)
481 1.1 bouyer *
482 1.1 bouyer * This function is broken in the following way.
483 1.1 bouyer *
484 1.1 bouyer * It is used to discover if the given 'id' is part of 'usage' collection
485 1.1 bouyer * in the descriptor in order to match report id against device type.
486 1.1 bouyer *
487 1.1 bouyer * The semantics of hid_start_parse() means though, that only a single
488 1.1 bouyer * kind of report is considered. The current HID code that uses this for
489 1.1 bouyer * matching is actually only looking for input reports, so this works
490 1.1 bouyer * for now.
491 1.1 bouyer *
492 1.1 bouyer * This function could try all report kinds (input, output and feature)
493 1.1 bouyer * consecutively if necessary, but it may be better to integrate the
494 1.1 bouyer * libusbhid code which can consider multiple report kinds simultaneously
495 1.1 bouyer *
496 1.1 bouyer * Needs some thought.
497 1.1 bouyer */
498 1.1 bouyer int
499 1.1 bouyer hid_is_collection(const void *desc, int size, uint8_t id, uint32_t usage)
500 1.1 bouyer {
501 1.1 bouyer struct hid_data *hd;
502 1.1 bouyer struct hid_item hi;
503 1.1 bouyer uint32_t coll_usage = ~0;
504 1.1 bouyer
505 1.1 bouyer hd = hid_start_parse(desc, size, hid_input);
506 1.1 bouyer if (hd == NULL)
507 1.1 bouyer return 0;
508 1.1 bouyer
509 1.1 bouyer DPRINTFN(2,("hid_is_collection: id=%d usage=0x%x\n", id, usage));
510 1.1 bouyer while (hid_get_item(hd, &hi)) {
511 1.1 bouyer DPRINTFN(2,("hid_is_collection: kind=%d id=%d usage=0x%x"
512 1.1 bouyer "(0x%x)\n",
513 1.1 bouyer hi.kind, hi.report_ID, hi.usage, coll_usage));
514 1.1 bouyer
515 1.1 bouyer if (hi.kind == hid_collection &&
516 1.1 bouyer hi.collection == HCOLL_APPLICATION)
517 1.1 bouyer coll_usage = hi.usage;
518 1.1 bouyer
519 1.1 bouyer if (hi.kind == hid_endcollection)
520 1.1 bouyer coll_usage = ~0;
521 1.1 bouyer
522 1.1 bouyer if (hi.kind == hid_input &&
523 1.1 bouyer coll_usage == usage &&
524 1.1 bouyer hi.report_ID == id) {
525 1.1 bouyer DPRINTFN(2,("hid_is_collection: found\n"));
526 1.1 bouyer hid_end_parse(hd);
527 1.1 bouyer return 1;
528 1.1 bouyer }
529 1.1 bouyer }
530 1.1 bouyer DPRINTFN(2,("hid_is_collection: not found\n"));
531 1.1 bouyer hid_end_parse(hd);
532 1.1 bouyer return 0;
533 1.1 bouyer }
534