hid.c revision 1.8 1 1.7 jmcneill /* $NetBSD: hid.c,v 1.8 2024/12/19 00:50:47 jmcneill 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.8 jmcneill __KERNEL_RCSID(0, "$NetBSD: hid.c,v 1.8 2024/12/19 00:50:47 jmcneill 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.3 jakllsch 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.2 riastrad 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.4 maxv
153 1.5 riastrad if (s->end - p < 1)
154 1.1 bouyer return 0;
155 1.4 maxv bSize = *p++;
156 1.1 bouyer
157 1.1 bouyer if (bSize == 0xfe) {
158 1.1 bouyer /* long item */
159 1.4 maxv if (p + 3 > s->end)
160 1.4 maxv return 0;
161 1.1 bouyer bSize = *p++;
162 1.1 bouyer bSize |= *p++ << 8;
163 1.1 bouyer bTag = *p++;
164 1.1 bouyer bType = 0xff; /* XXX what should it be */
165 1.1 bouyer } else {
166 1.1 bouyer /* short item */
167 1.1 bouyer bTag = bSize >> 4;
168 1.1 bouyer bType = (bSize >> 2) & 3;
169 1.1 bouyer bSize &= 3;
170 1.4 maxv if (bSize == 3)
171 1.4 maxv bSize = 4;
172 1.1 bouyer }
173 1.4 maxv
174 1.4 maxv data = p;
175 1.5 riastrad if (bSize > s->end - p)
176 1.4 maxv return 0;
177 1.4 maxv p += bSize;
178 1.4 maxv
179 1.1 bouyer s->p = p;
180 1.1 bouyer switch(bSize) {
181 1.1 bouyer case 0:
182 1.1 bouyer dval = 0;
183 1.3 jakllsch uval = dval;
184 1.1 bouyer break;
185 1.1 bouyer case 1:
186 1.3 jakllsch dval = *data++;
187 1.3 jakllsch uval = dval;
188 1.3 jakllsch dval = (int8_t)dval;
189 1.1 bouyer break;
190 1.1 bouyer case 2:
191 1.1 bouyer dval = *data++;
192 1.1 bouyer dval |= *data++ << 8;
193 1.3 jakllsch uval = dval;
194 1.1 bouyer dval = (int16_t)dval;
195 1.1 bouyer break;
196 1.1 bouyer case 4:
197 1.1 bouyer dval = *data++;
198 1.1 bouyer dval |= *data++ << 8;
199 1.1 bouyer dval |= *data++ << 16;
200 1.1 bouyer dval |= *data++ << 24;
201 1.3 jakllsch uval = dval;
202 1.1 bouyer dval = (int32_t)dval;
203 1.1 bouyer break;
204 1.1 bouyer default:
205 1.1 bouyer aprint_normal("BAD LENGTH %d\n", bSize);
206 1.1 bouyer continue;
207 1.1 bouyer }
208 1.1 bouyer
209 1.3 jakllsch DPRINTFN(5,("hid_get_item: bType=%d bTag=%d dval=%d uval=%u\n",
210 1.3 jakllsch bType, bTag, dval, uval));
211 1.1 bouyer switch (bType) {
212 1.1 bouyer case 0: /* Main */
213 1.1 bouyer switch (bTag) {
214 1.1 bouyer case 8: /* Input */
215 1.1 bouyer retkind = hid_input;
216 1.1 bouyer ret:
217 1.1 bouyer if (s->kind != retkind) {
218 1.1 bouyer s->minset = 0;
219 1.1 bouyer s->nu = 0;
220 1.1 bouyer hid_clear_local(c);
221 1.1 bouyer continue;
222 1.1 bouyer }
223 1.1 bouyer c->kind = retkind;
224 1.3 jakllsch c->flags = uval;
225 1.1 bouyer if (c->flags & HIO_VARIABLE) {
226 1.1 bouyer s->multimax = c->loc.count;
227 1.1 bouyer s->multi = 0;
228 1.1 bouyer c->loc.count = 1;
229 1.1 bouyer if (s->minset) {
230 1.1 bouyer for (i = c->usage_minimum;
231 1.1 bouyer i <= c->usage_maximum;
232 1.1 bouyer i++) {
233 1.1 bouyer s->usages[s->nu] = i;
234 1.1 bouyer if (s->nu < MAXUSAGE-1)
235 1.1 bouyer s->nu++;
236 1.1 bouyer }
237 1.1 bouyer s->minset = 0;
238 1.1 bouyer }
239 1.1 bouyer goto top;
240 1.1 bouyer } else {
241 1.1 bouyer if (s->minset)
242 1.1 bouyer c->usage = c->usage_minimum;
243 1.1 bouyer *h = *c;
244 1.1 bouyer h->next = NULL;
245 1.1 bouyer c->loc.pos +=
246 1.1 bouyer c->loc.size * c->loc.count;
247 1.1 bouyer s->minset = 0;
248 1.1 bouyer s->nu = 0;
249 1.1 bouyer hid_clear_local(c);
250 1.1 bouyer return 1;
251 1.1 bouyer }
252 1.1 bouyer case 9: /* Output */
253 1.1 bouyer retkind = hid_output;
254 1.1 bouyer goto ret;
255 1.1 bouyer case 10: /* Collection */
256 1.1 bouyer c->kind = hid_collection;
257 1.3 jakllsch c->collection = uval;
258 1.1 bouyer c->collevel++;
259 1.1 bouyer *h = *c;
260 1.1 bouyer hid_clear_local(c);
261 1.1 bouyer s->nu = 0;
262 1.1 bouyer return 1;
263 1.1 bouyer case 11: /* Feature */
264 1.1 bouyer retkind = hid_feature;
265 1.1 bouyer goto ret;
266 1.1 bouyer case 12: /* End collection */
267 1.1 bouyer c->kind = hid_endcollection;
268 1.1 bouyer c->collevel--;
269 1.1 bouyer *h = *c;
270 1.1 bouyer s->nu = 0;
271 1.1 bouyer return 1;
272 1.1 bouyer default:
273 1.1 bouyer aprint_normal("Main bTag=%d\n", bTag);
274 1.1 bouyer break;
275 1.1 bouyer }
276 1.1 bouyer break;
277 1.1 bouyer case 1: /* Global */
278 1.1 bouyer switch (bTag) {
279 1.1 bouyer case 0:
280 1.3 jakllsch c->_usage_page = uval << 16;
281 1.1 bouyer break;
282 1.1 bouyer case 1:
283 1.1 bouyer c->logical_minimum = dval;
284 1.1 bouyer break;
285 1.1 bouyer case 2:
286 1.1 bouyer c->logical_maximum = dval;
287 1.1 bouyer break;
288 1.1 bouyer case 3:
289 1.1 bouyer c->physical_minimum = dval;
290 1.1 bouyer break;
291 1.1 bouyer case 4:
292 1.1 bouyer c->physical_maximum = dval;
293 1.1 bouyer break;
294 1.1 bouyer case 5:
295 1.3 jakllsch c->unit_exponent = uval;
296 1.1 bouyer break;
297 1.1 bouyer case 6:
298 1.3 jakllsch c->unit = uval;
299 1.1 bouyer break;
300 1.1 bouyer case 7:
301 1.3 jakllsch c->loc.size = uval;
302 1.1 bouyer break;
303 1.1 bouyer case 8:
304 1.3 jakllsch c->report_ID = uval;
305 1.1 bouyer c->loc.pos = 0;
306 1.1 bouyer break;
307 1.1 bouyer case 9:
308 1.3 jakllsch c->loc.count = uval;
309 1.1 bouyer break;
310 1.1 bouyer case 10: /* Push */
311 1.1 bouyer hi = kmem_alloc(sizeof(*hi), KM_SLEEP);
312 1.1 bouyer *hi = *c;
313 1.1 bouyer c->next = hi;
314 1.1 bouyer break;
315 1.1 bouyer case 11: /* Pop */
316 1.1 bouyer hi = c->next;
317 1.1 bouyer if (hi == NULL)
318 1.1 bouyer break;
319 1.1 bouyer oldpos = c->loc.pos;
320 1.1 bouyer *c = *hi;
321 1.1 bouyer c->loc.pos = oldpos;
322 1.1 bouyer kmem_free(hi, sizeof(*hi));
323 1.1 bouyer break;
324 1.1 bouyer default:
325 1.1 bouyer aprint_normal("Global bTag=%d\n", bTag);
326 1.1 bouyer break;
327 1.1 bouyer }
328 1.1 bouyer break;
329 1.1 bouyer case 2: /* Local */
330 1.1 bouyer switch (bTag) {
331 1.1 bouyer case 0:
332 1.3 jakllsch if (bSize < 4)
333 1.3 jakllsch uval = c->_usage_page | uval;
334 1.3 jakllsch c->usage = uval;
335 1.1 bouyer if (s->nu < MAXUSAGE)
336 1.3 jakllsch s->usages[s->nu++] = uval;
337 1.1 bouyer /* else XXX */
338 1.1 bouyer break;
339 1.1 bouyer case 1:
340 1.1 bouyer s->minset = 1;
341 1.3 jakllsch if (bSize < 4)
342 1.3 jakllsch uval = c->_usage_page | uval;
343 1.3 jakllsch c->usage_minimum = uval;
344 1.1 bouyer break;
345 1.1 bouyer case 2:
346 1.3 jakllsch if (bSize < 4)
347 1.3 jakllsch uval = c->_usage_page | uval;
348 1.3 jakllsch c->usage_maximum = uval;
349 1.1 bouyer break;
350 1.1 bouyer case 3:
351 1.3 jakllsch c->designator_index = uval;
352 1.1 bouyer break;
353 1.1 bouyer case 4:
354 1.3 jakllsch c->designator_minimum = uval;
355 1.1 bouyer break;
356 1.1 bouyer case 5:
357 1.3 jakllsch c->designator_maximum = uval;
358 1.1 bouyer break;
359 1.1 bouyer case 7:
360 1.3 jakllsch c->string_index = uval;
361 1.1 bouyer break;
362 1.1 bouyer case 8:
363 1.3 jakllsch c->string_minimum = uval;
364 1.1 bouyer break;
365 1.1 bouyer case 9:
366 1.3 jakllsch c->string_maximum = uval;
367 1.1 bouyer break;
368 1.1 bouyer case 10:
369 1.3 jakllsch c->set_delimiter = uval;
370 1.1 bouyer break;
371 1.1 bouyer default:
372 1.1 bouyer aprint_normal("Local bTag=%d\n", bTag);
373 1.1 bouyer break;
374 1.1 bouyer }
375 1.1 bouyer break;
376 1.1 bouyer default:
377 1.1 bouyer aprint_normal("default bType=%d\n", bType);
378 1.1 bouyer break;
379 1.1 bouyer }
380 1.1 bouyer }
381 1.1 bouyer }
382 1.1 bouyer
383 1.1 bouyer int
384 1.1 bouyer hid_report_size(const void *buf, int len, enum hid_kind k, uint8_t id)
385 1.1 bouyer {
386 1.1 bouyer struct hid_data *d;
387 1.1 bouyer struct hid_item h;
388 1.1 bouyer int lo, hi;
389 1.1 bouyer
390 1.1 bouyer h.report_ID = 0;
391 1.1 bouyer lo = hi = -1;
392 1.1 bouyer DPRINTFN(2,("hid_report_size: kind=%d id=%d\n", k, id));
393 1.1 bouyer for (d = hid_start_parse(buf, len, k); hid_get_item(d, &h); ) {
394 1.1 bouyer DPRINTFN(2,("hid_report_size: item kind=%d id=%d pos=%d "
395 1.1 bouyer "size=%d count=%d\n",
396 1.1 bouyer h.kind, h.report_ID, h.loc.pos, h.loc.size,
397 1.1 bouyer h.loc.count));
398 1.1 bouyer if (h.report_ID == id && h.kind == k) {
399 1.1 bouyer if (lo < 0) {
400 1.1 bouyer lo = h.loc.pos;
401 1.1 bouyer #ifdef DIAGNOSTIC
402 1.1 bouyer if (lo != 0) {
403 1.1 bouyer aprint_normal("hid_report_size:"
404 1.1 bouyer " lo != 0\n");
405 1.1 bouyer }
406 1.1 bouyer #endif
407 1.1 bouyer }
408 1.1 bouyer hi = h.loc.pos + h.loc.size * h.loc.count;
409 1.1 bouyer DPRINTFN(2,("hid_report_size: lo=%d hi=%d\n", lo, hi));
410 1.1 bouyer }
411 1.1 bouyer }
412 1.1 bouyer hid_end_parse(d);
413 1.1 bouyer return (hi - lo + 7) / 8;
414 1.1 bouyer }
415 1.1 bouyer
416 1.1 bouyer int
417 1.1 bouyer hid_locate(const void *desc, int size, uint32_t u, uint8_t id, enum hid_kind k,
418 1.1 bouyer struct hid_location *loc, uint32_t *flags)
419 1.1 bouyer {
420 1.1 bouyer struct hid_data *d;
421 1.1 bouyer struct hid_item h;
422 1.1 bouyer
423 1.1 bouyer h.report_ID = 0;
424 1.1 bouyer DPRINTFN(5,("hid_locate: enter usage=0x%x kind=%d id=%d\n", u, k, id));
425 1.1 bouyer for (d = hid_start_parse(desc, size, k); hid_get_item(d, &h); ) {
426 1.1 bouyer DPRINTFN(5,("hid_locate: usage=0x%x kind=%d id=%d flags=0x%x\n",
427 1.1 bouyer h.usage, h.kind, h.report_ID, h.flags));
428 1.1 bouyer if (h.kind == k && !(h.flags & HIO_CONST) &&
429 1.1 bouyer h.usage == u && h.report_ID == id) {
430 1.1 bouyer if (loc != NULL)
431 1.1 bouyer *loc = h.loc;
432 1.1 bouyer if (flags != NULL)
433 1.1 bouyer *flags = h.flags;
434 1.1 bouyer hid_end_parse(d);
435 1.1 bouyer return 1;
436 1.1 bouyer }
437 1.1 bouyer }
438 1.1 bouyer hid_end_parse(d);
439 1.1 bouyer if (loc != NULL)
440 1.1 bouyer loc->size = 0;
441 1.1 bouyer return 0;
442 1.1 bouyer }
443 1.1 bouyer
444 1.1 bouyer long
445 1.1 bouyer hid_get_data(const u_char *buf, const struct hid_location *loc)
446 1.1 bouyer {
447 1.1 bouyer u_int hsize = loc->size;
448 1.1 bouyer u_long data;
449 1.1 bouyer
450 1.1 bouyer if (hsize == 0)
451 1.1 bouyer return 0;
452 1.1 bouyer
453 1.1 bouyer data = hid_get_udata(buf, loc);
454 1.1 bouyer if (data < (1UL << (hsize - 1)) || hsize == sizeof(data) * NBBY)
455 1.1 bouyer return data;
456 1.1 bouyer return data - (1UL << hsize);
457 1.1 bouyer }
458 1.1 bouyer
459 1.1 bouyer u_long
460 1.1 bouyer hid_get_udata(const u_char *buf, const struct hid_location *loc)
461 1.1 bouyer {
462 1.1 bouyer u_int hpos = loc->pos;
463 1.1 bouyer u_int hsize = loc->size;
464 1.1 bouyer u_int i, num, off;
465 1.1 bouyer u_long data;
466 1.1 bouyer
467 1.1 bouyer if (hsize == 0)
468 1.1 bouyer return 0;
469 1.1 bouyer
470 1.1 bouyer data = 0;
471 1.1 bouyer off = hpos / 8;
472 1.1 bouyer num = (hpos + hsize + 7) / 8 - off;
473 1.1 bouyer
474 1.1 bouyer for (i = 0; i < num; i++)
475 1.1 bouyer data |= (unsigned long)buf[off + i] << (i * 8);
476 1.1 bouyer
477 1.1 bouyer data >>= hpos % 8;
478 1.1 bouyer if (hsize < sizeof(data) * NBBY)
479 1.1 bouyer data &= (1UL << hsize) - 1;
480 1.1 bouyer
481 1.1 bouyer DPRINTFN(10,("hid_get_udata: loc %d/%d = %lu\n", hpos, hsize, data));
482 1.1 bouyer return data;
483 1.1 bouyer }
484 1.1 bouyer
485 1.1 bouyer /*
486 1.1 bouyer * hid_is_collection(desc, size, id, usage)
487 1.1 bouyer *
488 1.1 bouyer * This function is broken in the following way.
489 1.1 bouyer *
490 1.1 bouyer * It is used to discover if the given 'id' is part of 'usage' collection
491 1.1 bouyer * in the descriptor in order to match report id against device type.
492 1.1 bouyer *
493 1.1 bouyer * The semantics of hid_start_parse() means though, that only a single
494 1.1 bouyer * kind of report is considered. The current HID code that uses this for
495 1.1 bouyer * matching is actually only looking for input reports, so this works
496 1.1 bouyer * for now.
497 1.1 bouyer *
498 1.1 bouyer * This function could try all report kinds (input, output and feature)
499 1.1 bouyer * consecutively if necessary, but it may be better to integrate the
500 1.1 bouyer * libusbhid code which can consider multiple report kinds simultaneously
501 1.1 bouyer *
502 1.1 bouyer * Needs some thought.
503 1.1 bouyer */
504 1.1 bouyer int
505 1.1 bouyer hid_is_collection(const void *desc, int size, uint8_t id, uint32_t usage)
506 1.1 bouyer {
507 1.1 bouyer struct hid_data *hd;
508 1.1 bouyer struct hid_item hi;
509 1.1 bouyer uint32_t coll_usage = ~0;
510 1.1 bouyer
511 1.1 bouyer hd = hid_start_parse(desc, size, hid_input);
512 1.1 bouyer if (hd == NULL)
513 1.1 bouyer return 0;
514 1.1 bouyer
515 1.1 bouyer DPRINTFN(2,("hid_is_collection: id=%d usage=0x%x\n", id, usage));
516 1.1 bouyer while (hid_get_item(hd, &hi)) {
517 1.1 bouyer DPRINTFN(2,("hid_is_collection: kind=%d id=%d usage=0x%x"
518 1.1 bouyer "(0x%x)\n",
519 1.1 bouyer hi.kind, hi.report_ID, hi.usage, coll_usage));
520 1.1 bouyer
521 1.1 bouyer if (hi.kind == hid_collection &&
522 1.6 nat (hi.collection == HCOLL_APPLICATION ||
523 1.6 nat hi.collection == HCOLL_PHYSICAL ||
524 1.6 nat hi.collection == HCOLL_LOGICAL))
525 1.1 bouyer coll_usage = hi.usage;
526 1.1 bouyer
527 1.8 jmcneill if ((hi.kind == hid_collection ||
528 1.8 jmcneill hi.kind == hid_endcollection) &&
529 1.1 bouyer coll_usage == usage &&
530 1.1 bouyer hi.report_ID == id) {
531 1.1 bouyer DPRINTFN(2,("hid_is_collection: found\n"));
532 1.1 bouyer hid_end_parse(hd);
533 1.1 bouyer return 1;
534 1.1 bouyer }
535 1.8 jmcneill
536 1.8 jmcneill if (hi.kind == hid_endcollection)
537 1.8 jmcneill coll_usage = ~0;
538 1.1 bouyer }
539 1.1 bouyer DPRINTFN(2,("hid_is_collection: not found\n"));
540 1.1 bouyer hid_end_parse(hd);
541 1.1 bouyer return 0;
542 1.1 bouyer }
543