Bug Summary

File:dev/hid/hid.c
Warning:line 290, column 4
Value stored to 'dval' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name hid.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/dev/hid/hid.c
1/* $OpenBSD: hid.c,v 1.3 2020/06/04 23:03:43 deraadt Exp $ */
2/* $NetBSD: hid.c,v 1.23 2002/07/11 21:14:25 augustss Exp $ */
3/* $FreeBSD: src/sys/dev/usb/hid.c,v 1.11 1999/11/17 22:33:39 n_hibma Exp $ */
4
5/*
6 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Lennart Augustsson (lennart@augustsson.net) at
11 * Carlstedt Research & Technology.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/malloc.h>
38
39#include <dev/hid/hid.h>
40
41#ifdef USBHID_DEBUG
42#define DPRINTF(x...) do { printf(x); } while (0)
43#else
44#define DPRINTF(x...)
45#endif
46
47#define MAXUSAGE64 64
48#define MAXPUSH4 4
49#define MAXID16 16
50
51struct hid_pos_data {
52 int32_t rid;
53 uint32_t pos;
54};
55
56struct hid_data {
57 const uint8_t *start;
58 const uint8_t *end;
59 const uint8_t *p;
60 struct hid_item cur[MAXPUSH4];
61 struct hid_pos_data last_pos[MAXID16];
62 int32_t usages_min[MAXUSAGE64];
63 int32_t usages_max[MAXUSAGE64];
64 int32_t usage_last; /* last seen usage */
65 uint32_t loc_size; /* last seen size */
66 uint32_t loc_count; /* last seen count */
67 enum hid_kind kind;
68 uint8_t pushlevel; /* current pushlevel */
69 uint8_t ncount; /* end usage item count */
70 uint8_t icount; /* current usage item count */
71 uint8_t nusage; /* end "usages_min/max" index */
72 uint8_t iusage; /* current "usages_min/max" index */
73 uint8_t ousage; /* current "usages_min/max" offset */
74 uint8_t susage; /* usage set flags */
75};
76
77static void
78hid_clear_local(struct hid_item *c)
79{
80 c->loc.count = 0;
81 c->loc.size = 0;
82 c->usage = 0;
83 c->usage_minimum = 0;
84 c->usage_maximum = 0;
85 c->designator_index = 0;
86 c->designator_minimum = 0;
87 c->designator_maximum = 0;
88 c->string_index = 0;
89 c->string_minimum = 0;
90 c->string_maximum = 0;
91 c->set_delimiter = 0;
92}
93
94static void
95hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t nextid)
96{
97 uint8_t i;
98
99 if (c->report_ID == nextid)
100 return;
101
102 /* save current position for current rID */
103 if (c->report_ID == 0) {
104 i = 0;
105 } else {
106 for (i = 1; i != MAXID16; i++) {
107 if (s->last_pos[i].rid == c->report_ID)
108 break;
109 if (s->last_pos[i].rid == 0)
110 break;
111 }
112 }
113 if (i != MAXID16) {
114 s->last_pos[i].rid = c->report_ID;
115 s->last_pos[i].pos = c->loc.pos;
116 }
117
118 /* store next report ID */
119 c->report_ID = nextid;
120
121 /* lookup last position for next rID */
122 if (nextid == 0) {
123 i = 0;
124 } else {
125 for (i = 1; i != MAXID16; i++) {
126 if (s->last_pos[i].rid == nextid)
127 break;
128 if (s->last_pos[i].rid == 0)
129 break;
130 }
131 }
132 if (i != MAXID16) {
133 s->last_pos[i].rid = nextid;
134 c->loc.pos = s->last_pos[i].pos;
135 } else {
136 DPRINTF("Out of RID entries, position is set to zero!\n");
137 c->loc.pos = 0;
138 }
139}
140
141struct hid_data *
142hid_start_parse(const void *d, int len, enum hid_kind kind)
143{
144 struct hid_data *s;
145
146 s = malloc(sizeof(*s), M_TEMP127, M_WAITOK0x0001 | M_ZERO0x0008);
147
148 s->start = s->p = d;
149 s->end = ((const uint8_t *)d) + len;
150 s->kind = kind;
151 return (s);
152}
153
154void
155hid_end_parse(struct hid_data *s)
156{
157 if (s == NULL((void *)0))
158 return;
159
160 free(s, M_TEMP127, 0);
161}
162
163static uint8_t
164hid_get_byte(struct hid_data *s, const uint16_t wSize)
165{
166 const uint8_t *ptr;
167 uint8_t retval;
168
169 ptr = s->p;
170
171 /* check if end is reached */
172 if (ptr == s->end)
173 return (0);
174
175 /* read out a byte */
176 retval = *ptr;
177
178 /* check if data pointer can be advanced by "wSize" bytes */
179 if ((s->end - ptr) < wSize)
180 ptr = s->end;
181 else
182 ptr += wSize;
183
184 /* update pointer */
185 s->p = ptr;
186
187 return (retval);
188}
189
190int
191hid_get_item(struct hid_data *s, struct hid_item *h)
192{
193 struct hid_item *c;
194 unsigned int bTag, bType, bSize;
195 uint32_t oldpos;
196 int32_t mask;
197 int32_t dval;
198
199 if (s == NULL((void *)0))
200 return (0);
201
202 if (s->pushlevel >= MAXPUSH4)
203 return (0);
204
205 c = &s->cur[s->pushlevel];
206
207 top:
208 /* check if there is an array of items */
209 DPRINTF("%s: icount=%d ncount=%d\n", __func__,
210 s->icount, s->ncount);
211 if (s->icount < s->ncount) {
212 /* get current usage */
213 if (s->iusage < s->nusage) {
214 dval = s->usages_min[s->iusage] + s->ousage;
215 c->usage = dval;
216 s->usage_last = dval;
217 if (dval == s->usages_max[s->iusage]) {
218 s->iusage ++;
219 s->ousage = 0;
220 } else {
221 s->ousage ++;
222 }
223 } else {
224 DPRINTF("Using last usage\n");
225 dval = s->usage_last;
226 }
227 s->icount ++;
228 /*
229 * Only copy HID item, increment position and return
230 * if correct kind!
231 */
232 if (s->kind == c->kind) {
233 *h = *c;
234 DPRINTF("%u,%u,%u\n", h->loc.pos,
235 h->loc.size, h->loc.count);
236 c->loc.pos += c->loc.size * c->loc.count;
237 return (1);
238 }
239 }
240
241 /* reset state variables */
242 s->icount = 0;
243 s->ncount = 0;
244 s->iusage = 0;
245 s->nusage = 0;
246 s->susage = 0;
247 s->ousage = 0;
248 hid_clear_local(c);
249
250 /* get next item */
251 while (s->p != s->end) {
252
253 bSize = hid_get_byte(s, 1);
254 if (bSize == 0xfe) {
255 /* long item */
256 bSize = hid_get_byte(s, 1);
257 bSize |= hid_get_byte(s, 1) << 8;
258 bTag = hid_get_byte(s, 1);
259 bType = 0xff; /* XXX what should it be */
260 } else {
261 /* short item */
262 bTag = bSize >> 4;
263 bType = (bSize >> 2) & 3;
264 bSize &= 3;
265 if (bSize == 3)
266 bSize = 4;
267 }
268 switch (bSize) {
269 case 0:
270 dval = 0;
271 mask = 0;
272 break;
273 case 1:
274 dval = hid_get_byte(s, 1);
275 mask = 0xFF;
276 break;
277 case 2:
278 dval = hid_get_byte(s, 1);
279 dval |= hid_get_byte(s, 1) << 8;
280 mask = 0xFFFF;
281 break;
282 case 4:
283 dval = hid_get_byte(s, 1);
284 dval |= hid_get_byte(s, 1) << 8;
285 dval |= hid_get_byte(s, 1) << 16;
286 dval |= hid_get_byte(s, 1) << 24;
287 mask = 0xFFFFFFFF;
288 break;
289 default:
290 dval = hid_get_byte(s, bSize);
Value stored to 'dval' is never read
291 DPRINTF("bad length %u (data=0x%02x)\n",
292 bSize, dval);
293 continue;
294 }
295
296 DPRINTF("%s: bType=%d bTag=%d dval=%d\n", __func__,
297 bType, bTag, dval);
298 switch (bType) {
299 case 0: /* Main */
300 switch (bTag) {
301 case 8: /* Input */
302 c->kind = hid_input;
303 c->flags = dval;
304 ret:
305 c->loc.count = s->loc_count;
306 c->loc.size = s->loc_size;
307
308 if (c->flags & HIO_VARIABLE0x002) {
309 /* range check usage count */
310 if (c->loc.count > 255) {
311 DPRINTF("Number of "
312 "items truncated to 255\n");
313 s->ncount = 255;
314 } else
315 s->ncount = c->loc.count;
316
317 /*
318 * The "top" loop will return
319 * one and one item:
320 */
321 c->loc.count = 1;
322 } else {
323 s->ncount = 1;
324 }
325 goto top;
326
327 case 9: /* Output */
328 c->kind = hid_output;
329 c->flags = dval;
330 goto ret;
331 case 10: /* Collection */
332 c->kind = hid_collection;
333 c->collection = dval;
334 c->collevel++;
335 c->usage = s->usage_last;
336 *h = *c;
337 return (1);
338 case 11: /* Feature */
339 c->kind = hid_feature;
340 c->flags = dval;
341 goto ret;
342 case 12: /* End collection */
343 c->kind = hid_endcollection;
344 if (c->collevel == 0) {
345 DPRINTF("invalid end collection\n");
346 return (0);
347 }
348 c->collevel--;
349 *h = *c;
350 return (1);
351 default:
352 DPRINTF("Main bTag=%d\n", bTag);
353 break;
354 }
355 break;
356 case 1: /* Global */
357 switch (bTag) {
358 case 0:
359 c->_usage_page = dval << 16;
360 break;
361 case 1:
362 c->logical_minimum = dval;
363 break;
364 case 2:
365 c->logical_maximum = dval;
366 break;
367 case 3:
368 c->physical_minimum = dval;
369 break;
370 case 4:
371 c->physical_maximum = dval;
372 break;
373 case 5:
374 c->unit_exponent = dval;
375 break;
376 case 6:
377 c->unit = dval;
378 break;
379 case 7:
380 /* mask because value is unsigned */
381 s->loc_size = dval & mask;
382 break;
383 case 8:
384 hid_switch_rid(s, c, dval & mask);
385 break;
386 case 9:
387 /* mask because value is unsigned */
388 s->loc_count = dval & mask;
389 break;
390 case 10: /* Push */
391 if (s->pushlevel < MAXPUSH4 - 1) {
392 s->pushlevel++;
393 s->cur[s->pushlevel] = *c;
394 /* store size and count */
395 c->loc.size = s->loc_size;
396 c->loc.count = s->loc_count;
397 /* update current item pointer */
398 c = &s->cur[s->pushlevel];
399 } else {
400 DPRINTF("Cannot push "
401 "item @ %d\n", s->pushlevel);
402 }
403 break;
404 case 11: /* Pop */
405 if (s->pushlevel > 0) {
406 s->pushlevel--;
407 /* preserve position */
408 oldpos = c->loc.pos;
409 c = &s->cur[s->pushlevel];
410 /* restore size and count */
411 s->loc_size = c->loc.size;
412 s->loc_count = c->loc.count;
413 /* set default item location */
414 c->loc.pos = oldpos;
415 c->loc.size = 0;
416 c->loc.count = 0;
417 } else {
418 DPRINTF("Cannot pop "
419 "item @ %d\n", s->pushlevel);
420 }
421 break;
422 default:
423 DPRINTF("Global bTag=%d\n", bTag);
424 break;
425 }
426 break;
427 case 2: /* Local */
428 switch (bTag) {
429 case 0:
430 if (bSize != 4)
431 dval = (dval & mask) | c->_usage_page;
432
433 /* set last usage, in case of a collection */
434 s->usage_last = dval;
435
436 if (s->nusage < MAXUSAGE64) {
437 s->usages_min[s->nusage] = dval;
438 s->usages_max[s->nusage] = dval;
439 s->nusage ++;
440 } else {
441 DPRINTF("max usage reached\n");
442 }
443
444 /* clear any pending usage sets */
445 s->susage = 0;
446 break;
447 case 1:
448 s->susage |= 1;
449
450 if (bSize != 4)
451 dval = (dval & mask) | c->_usage_page;
452 c->usage_minimum = dval;
453
454 goto check_set;
455 case 2:
456 s->susage |= 2;
457
458 if (bSize != 4)
459 dval = (dval & mask) | c->_usage_page;
460 c->usage_maximum = dval;
461
462 check_set:
463 if (s->susage != 3)
464 break;
465
466 /* sanity check */
467 if ((s->nusage < MAXUSAGE64) &&
468 (c->usage_minimum <= c->usage_maximum)) {
469 /* add usage range */
470 s->usages_min[s->nusage] =
471 c->usage_minimum;
472 s->usages_max[s->nusage] =
473 c->usage_maximum;
474 s->nusage ++;
475 } else {
476 DPRINTF("Usage set dropped\n");
477 }
478 s->susage = 0;
479 break;
480 case 3:
481 c->designator_index = dval;
482 break;
483 case 4:
484 c->designator_minimum = dval;
485 break;
486 case 5:
487 c->designator_maximum = dval;
488 break;
489 case 7:
490 c->string_index = dval;
491 break;
492 case 8:
493 c->string_minimum = dval;
494 break;
495 case 9:
496 c->string_maximum = dval;
497 break;
498 case 10:
499 c->set_delimiter = dval;
500 break;
501 default:
502 DPRINTF("Local bTag=%d\n", bTag);
503 break;
504 }
505 break;
506 default:
507 DPRINTF("default bType=%d\n", bType);
508 break;
509 }
510 }
511 return (0);
512}
513
514int
515hid_report_size(const void *buf, int len, enum hid_kind k, u_int8_t id)
516{
517 struct hid_data *d;
518 struct hid_item h;
519 int lo, hi;
520
521 h.report_ID = 0;
522 lo = hi = -1;
523 DPRINTF("hid_report_size: kind=%d id=%d\n", k, id);
524 for (d = hid_start_parse(buf, len, k); hid_get_item(d, &h); ) {
525 DPRINTF("hid_report_size: item kind=%d id=%d pos=%d "
526 "size=%d count=%d\n",
527 h.kind, h.report_ID, h.loc.pos, h.loc.size,
528 h.loc.count);
529 if (h.report_ID == id && h.kind == k) {
530 if (lo < 0) {
531 lo = h.loc.pos;
532#ifdef DIAGNOSTIC1
533 if (lo != 0) {
534 printf("hid_report_size: lo != 0\n");
535 }
536#endif
537 }
538 hi = h.loc.pos + h.loc.size * h.loc.count;
539 DPRINTF("hid_report_size: lo=%d hi=%d\n", lo, hi);
540
541 }
542 }
543 hid_end_parse(d);
544 return ((hi - lo + 7) / 8);
545}
546
547int
548hid_locate(const void *desc, int size, int32_t u, uint8_t id, enum hid_kind k,
549 struct hid_location *loc, uint32_t *flags)
550{
551 struct hid_data *d;
552 struct hid_item h;
553
554 h.report_ID = 0;
555 DPRINTF("hid_locate: enter usage=0x%x kind=%d id=%d\n", u, k, id);
556 for (d = hid_start_parse(desc, size, k); hid_get_item(d, &h); ) {
557 DPRINTF("hid_locate: usage=0x%x kind=%d id=%d flags=0x%x\n",
558 h.usage, h.kind, h.report_ID, h.flags);
559 if (h.kind == k && !(h.flags & HIO_CONST0x001) &&
560 h.usage == u && h.report_ID == id) {
561 if (loc != NULL((void *)0))
562 *loc = h.loc;
563 if (flags != NULL((void *)0))
564 *flags = h.flags;
565 hid_end_parse(d);
566 return (1);
567 }
568 }
569 hid_end_parse(d);
570 if (loc != NULL((void *)0))
571 loc->size = 0;
572 if (flags != NULL((void *)0))
573 *flags = 0;
574 return (0);
575}
576
577uint32_t
578hid_get_data_sub(const uint8_t *buf, int len, struct hid_location *loc,
579 int is_signed)
580{
581 uint32_t hpos = loc->pos;
582 uint32_t hsize = loc->size;
583 uint32_t data;
584 uint32_t rpos;
585 uint8_t n;
586
587 DPRINTF("hid_get_data_sub: loc %d/%d\n", hpos, hsize);
588
589 /* Range check and limit */
590 if (hsize == 0)
591 return (0);
592 if (hsize > 32)
593 hsize = 32;
594
595 /* Get data in a safe way */
596 data = 0;
597 rpos = (hpos / 8);
598 n = (hsize + 7) / 8;
599 rpos += n;
600 while (n--) {
601 rpos--;
602 if (rpos < len)
603 data |= buf[rpos] << (8 * n);
604 }
605
606 /* Correctly shift down data */
607 data = (data >> (hpos % 8));
608 n = 32 - hsize;
609
610 /* Mask and sign extend in one */
611 if (is_signed != 0)
612 data = (int32_t)((int32_t)data << n) >> n;
613 else
614 data = (uint32_t)((uint32_t)data << n) >> n;
615
616 DPRINTF("hid_get_data_sub: loc %d/%d = %lu\n",
617 loc->pos, loc->size, (long)data);
618 return (data);
619}
620
621int32_t
622hid_get_data(const uint8_t *buf, int len, struct hid_location *loc)
623{
624 return (hid_get_data_sub(buf, len, loc, 1));
625}
626
627uint32_t
628hid_get_udata(const uint8_t *buf, int len, struct hid_location *loc)
629{
630 return (hid_get_data_sub(buf, len, loc, 0));
631}
632
633int
634hid_is_collection(const void *desc, int size, uint8_t id, int32_t usage)
635{
636 struct hid_data *hd;
637 struct hid_item hi;
638 uint32_t coll_usage = ~0;
639
640 hd = hid_start_parse(desc, size, hid_none);
641
642 DPRINTF("%s: id=%d usage=0x%x\n", __func__, id, usage);
643 while (hid_get_item(hd, &hi)) {
644 DPRINTF("%s: kind=%d id=%d usage=0x%x(0x%x)\n", __func__,
645 hi.kind, hi.report_ID, hi.usage, coll_usage);
646 if (hi.kind == hid_collection &&
647 hi.collection == HCOLL_APPLICATION1)
648 coll_usage = hi.usage;
649 if (hi.kind == hid_endcollection &&
650 coll_usage == usage && hi.report_ID == id) {
651 DPRINTF("%s: found\n", __func__);
652 hid_end_parse(hd);
653 return (1);
654 }
655 }
656 DPRINTF("%s: not found\n", __func__);
657 hid_end_parse(hd);
658 return (0);
659}