1 /* $FreeBSD$ */
2 /* $NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $ */
3 /*-
4 * SPDX-License-Identifier: BSD-2-Clause-NetBSD
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 "implementation/global_implementation.h"
36 #include "input/usb_rdesc.h"
37
38 #ifndef nitems
39 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
40 #endif
41
42 #undef USB_DEBUG_VAR
43 #define USB_DEBUG_VAR usb_debug
44
45 static void hid_clear_local(struct hid_item *);
46 static uint8_t hid_get_byte(struct hid_data *s, const uint16_t wSize);
47
48 #define MAXUSAGE 64
49 #define MAXPUSH 4
50 #define MAXID 16
51 #define MAXLOCCNT 1024
52
53 struct hid_pos_data {
54 int32_t rid;
55 uint32_t pos;
56 };
57
58 struct hid_data {
59 const uint8_t *start;
60 const uint8_t *end;
61 const uint8_t *p;
62 struct hid_item cur[MAXPUSH];
63 struct hid_pos_data last_pos[MAXID];
64 int32_t usages_min[MAXUSAGE];
65 int32_t usages_max[MAXUSAGE];
66 int32_t usage_last; /* last seen usage */
67 uint32_t loc_size; /* last seen size */
68 uint32_t loc_count; /* last seen count */
69 uint32_t ncount; /* end usage item count */
70 uint32_t icount; /* current usage item count */
71 uint8_t kindset; /* we have 5 kinds so 8 bits are enough */
72 uint8_t pushlevel; /* current pushlevel */
73 uint8_t nusage; /* end "usages_min/max" index */
74 uint8_t iusage; /* current "usages_min/max" index */
75 uint8_t ousage; /* current "usages_min/max" offset */
76 uint8_t susage; /* usage set flags */
77 };
78
79 /*------------------------------------------------------------------------*
80 * hid_clear_local
81 *------------------------------------------------------------------------*/
82 static void
hid_clear_local(struct hid_item * c)83 hid_clear_local(struct hid_item *c)
84 {
85
86 c->loc.count = 0;
87 c->loc.size = 0;
88 c->usage = 0;
89 c->usage_minimum = 0;
90 c->usage_maximum = 0;
91 c->designator_index = 0;
92 c->designator_minimum = 0;
93 c->designator_maximum = 0;
94 c->string_index = 0;
95 c->string_minimum = 0;
96 c->string_maximum = 0;
97 c->set_delimiter = 0;
98 }
99
100 static void
hid_switch_rid(struct hid_data * s,struct hid_item * c,int32_t next_rID)101 hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID)
102 {
103 uint8_t i;
104
105 /* check for same report ID - optimise */
106
107 if (c->report_ID == next_rID)
108 return;
109
110 /* save current position for current rID */
111
112 if (c->report_ID == 0) {
113 i = 0;
114 } else {
115 for (i = 1; i != MAXID; i++) {
116 if (s->last_pos[i].rid == c->report_ID)
117 break;
118 if (s->last_pos[i].rid == 0)
119 break;
120 }
121 }
122 if (i != MAXID) {
123 s->last_pos[i].rid = c->report_ID;
124 s->last_pos[i].pos = c->loc.pos;
125 }
126
127 /* store next report ID */
128
129 c->report_ID = next_rID;
130
131 /* lookup last position for next rID */
132
133 if (next_rID == 0) {
134 i = 0;
135 } else {
136 for (i = 1; i != MAXID; i++) {
137 if (s->last_pos[i].rid == next_rID)
138 break;
139 if (s->last_pos[i].rid == 0)
140 break;
141 }
142 }
143 if (i != MAXID) {
144 s->last_pos[i].rid = next_rID;
145 c->loc.pos = s->last_pos[i].pos;
146 } else {
147 DPRINTF("Out of RID entries, position is set to zero!\n");
148 c->loc.pos = 0;
149 }
150 }
151
152 /*------------------------------------------------------------------------*
153 * hid_start_parse
154 *------------------------------------------------------------------------*/
155 struct hid_data *
hid_start_parse(const void * d,usb_size_t len,int kindset)156 hid_start_parse(const void *d, usb_size_t len, int kindset)
157 {
158 struct hid_data *s;
159
160 if ((kindset-1) & kindset) {
161 DPRINTFN(0, "Only one bit can be "
162 "set in the kindset\n");
163 return (NULL);
164 }
165
166 s = zalloc(sizeof *s);
167 if (s != NULL) {
168 s->start = s->p = d;
169 s->end = ((const uint8_t *)d) + len;
170 s->kindset = kindset;
171 }
172
173 return (s);
174 }
175
176 /*------------------------------------------------------------------------*
177 * hid_end_parse
178 *------------------------------------------------------------------------*/
179 void
hid_end_parse(struct hid_data * s)180 hid_end_parse(struct hid_data *s)
181 {
182 if (s == NULL)
183 return;
184
185 free(s);
186 }
187
188 /*------------------------------------------------------------------------*
189 * get byte from HID descriptor
190 *------------------------------------------------------------------------*/
191 static uint8_t
hid_get_byte(struct hid_data * s,const uint16_t wSize)192 hid_get_byte(struct hid_data *s, const uint16_t wSize)
193 {
194 const uint8_t *ptr;
195 uint8_t retval;
196
197 ptr = s->p;
198
199 /* check if end is reached */
200 if (ptr == s->end)
201 return (0);
202
203 /* read out a byte */
204 retval = *ptr;
205
206 /* check if data pointer can be advanced by "wSize" bytes */
207 if ((s->end - ptr) < wSize)
208 ptr = s->end;
209 else
210 ptr += wSize;
211
212 /* update pointer */
213 s->p = ptr;
214
215 return (retval);
216 }
217
218 /*------------------------------------------------------------------------*
219 * hid_get_item
220 *------------------------------------------------------------------------*/
221 int
hid_get_item(struct hid_data * s,struct hid_item * h)222 hid_get_item(struct hid_data *s, struct hid_item *h)
223 {
224 struct hid_item *c;
225 unsigned int bTag, bType, bSize;
226 uint32_t oldpos;
227 int32_t mask;
228 int32_t dval;
229
230 if (s == NULL)
231 return (0);
232
233 c = &s->cur[s->pushlevel];
234
235 top:
236 /* check if there is an array of items */
237 if (s->icount < s->ncount) {
238 /* get current usage */
239 if (s->iusage < s->nusage) {
240 dval = s->usages_min[s->iusage] + s->ousage;
241 c->usage = dval;
242 s->usage_last = dval;
243 if (dval == s->usages_max[s->iusage]) {
244 s->iusage ++;
245 s->ousage = 0;
246 } else {
247 s->ousage ++;
248 }
249 } else {
250 DPRINTFN(1, "Using last usage\n");
251 dval = s->usage_last;
252 }
253 s->icount ++;
254 /*
255 * Only copy HID item, increment position and return
256 * if correct kindset!
257 */
258 if (s->kindset & (1 << c->kind)) {
259 *h = *c;
260 DPRINTFN(1, "%u,%u,%u\n", h->loc.pos,
261 h->loc.size, h->loc.count);
262 c->loc.pos += c->loc.size * c->loc.count;
263 return (1);
264 }
265 }
266
267 /* reset state variables */
268 s->icount = 0;
269 s->ncount = 0;
270 s->iusage = 0;
271 s->nusage = 0;
272 s->susage = 0;
273 s->ousage = 0;
274 hid_clear_local(c);
275
276 /* get next item */
277 while (s->p != s->end) {
278
279 bSize = hid_get_byte(s, 1);
280 if (bSize == 0xfe) {
281 /* long item */
282 bSize = hid_get_byte(s, 1);
283 bSize |= hid_get_byte(s, 1) << 8;
284 bTag = hid_get_byte(s, 1);
285 bType = 0xff; /* XXX what should it be */
286 } else {
287 /* short item */
288 bTag = bSize >> 4;
289 bType = (bSize >> 2) & 3;
290 bSize &= 3;
291 if (bSize == 3)
292 bSize = 4;
293 }
294 switch (bSize) {
295 case 0:
296 dval = 0;
297 mask = 0;
298 break;
299 case 1:
300 dval = (int8_t)hid_get_byte(s, 1);
301 mask = 0xFF;
302 break;
303 case 2:
304 dval = hid_get_byte(s, 1);
305 dval |= hid_get_byte(s, 1) << 8;
306 dval = (int16_t)dval;
307 mask = 0xFFFF;
308 break;
309 case 4:
310 dval = hid_get_byte(s, 1);
311 dval |= hid_get_byte(s, 1) << 8;
312 dval |= hid_get_byte(s, 1) << 16;
313 dval |= hid_get_byte(s, 1) << 24;
314 mask = 0xFFFFFFFF;
315 break;
316 default:
317 dval = hid_get_byte(s, bSize);
318 DPRINTFN(0, "bad length %u (data=0x%02x)\n",
319 bSize, dval);
320 continue;
321 }
322
323 switch (bType) {
324 case 0: /* Main */
325 switch (bTag) {
326 case 8: /* Input */
327 c->kind = hid_input;
328 ret:
329 c->flags = dval;
330 c->loc.count = s->loc_count;
331 c->loc.size = s->loc_size;
332
333 if (c->flags & HIO_VARIABLE) {
334 /* range check usage count */
335 if (c->loc.count > MAXLOCCNT) {
336 DPRINTFN(0, "Number of "
337 "items(%u) truncated to %u\n",
338 (unsigned)(c->loc.count),
339 MAXLOCCNT);
340 s->ncount = MAXLOCCNT;
341 } else
342 s->ncount = c->loc.count;
343
344 /*
345 * The "top" loop will return
346 * one and one item:
347 */
348 c->loc.count = 1;
349 } else {
350 s->ncount = 1;
351 }
352 goto top;
353
354 case 9: /* Output */
355 c->kind = hid_output;
356 goto ret;
357 case 10: /* Collection */
358 c->kind = hid_collection;
359 c->collection = dval;
360 c->collevel++;
361 c->usage = s->usage_last;
362 *h = *c;
363 return (1);
364 case 11: /* Feature */
365 c->kind = hid_feature;
366 goto ret;
367 case 12: /* End collection */
368 c->kind = hid_endcollection;
369 if (c->collevel == 0) {
370 DPRINTFN(0, "invalid end collection\n");
371 return (0);
372 }
373 c->collevel--;
374 *h = *c;
375 return (1);
376 default:
377 DPRINTFN(0, "Main bTag=%d\n", bTag);
378 break;
379 }
380 break;
381 case 1: /* Global */
382 switch (bTag) {
383 case 0:
384 c->_usage_page = dval << 16;
385 break;
386 case 1:
387 c->logical_minimum = dval;
388 break;
389 case 2:
390 c->logical_maximum = dval;
391 break;
392 case 3:
393 c->physical_minimum = dval;
394 break;
395 case 4:
396 c->physical_maximum = dval;
397 break;
398 case 5:
399 c->unit_exponent = dval;
400 break;
401 case 6:
402 c->unit = dval;
403 break;
404 case 7:
405 /* mask because value is unsigned */
406 s->loc_size = dval & mask;
407 break;
408 case 8:
409 hid_switch_rid(s, c, dval & mask);
410 break;
411 case 9:
412 /* mask because value is unsigned */
413 s->loc_count = dval & mask;
414 break;
415 case 10: /* Push */
416 /* stop parsing, if invalid push level */
417 if ((s->pushlevel + 1) >= MAXPUSH) {
418 DPRINTFN(0, "Cannot push item @ %d\n", s->pushlevel);
419 return (0);
420 }
421 s->pushlevel ++;
422 s->cur[s->pushlevel] = *c;
423 /* store size and count */
424 c->loc.size = s->loc_size;
425 c->loc.count = s->loc_count;
426 /* update current item pointer */
427 c = &s->cur[s->pushlevel];
428 break;
429 case 11: /* Pop */
430 /* stop parsing, if invalid push level */
431 if (s->pushlevel == 0) {
432 DPRINTFN(0, "Cannot pop item @ 0\n");
433 return (0);
434 }
435 s->pushlevel --;
436 /* preserve position */
437 oldpos = c->loc.pos;
438 c = &s->cur[s->pushlevel];
439 /* restore size and count */
440 s->loc_size = c->loc.size;
441 s->loc_count = c->loc.count;
442 /* set default item location */
443 c->loc.pos = oldpos;
444 c->loc.size = 0;
445 c->loc.count = 0;
446 break;
447 default:
448 DPRINTFN(0, "Global bTag=%d\n", bTag);
449 break;
450 }
451 break;
452 case 2: /* Local */
453 switch (bTag) {
454 case 0:
455 if (bSize != 4)
456 dval = (dval & mask) | c->_usage_page;
457
458 /* set last usage, in case of a collection */
459 s->usage_last = dval;
460
461 if (s->nusage < MAXUSAGE) {
462 s->usages_min[s->nusage] = dval;
463 s->usages_max[s->nusage] = dval;
464 s->nusage ++;
465 } else {
466 DPRINTFN(0, "max usage reached\n");
467 }
468
469 /* clear any pending usage sets */
470 s->susage = 0;
471 break;
472 case 1:
473 s->susage |= 1;
474
475 if (bSize != 4)
476 dval = (dval & mask) | c->_usage_page;
477 c->usage_minimum = dval;
478
479 goto check_set;
480 case 2:
481 s->susage |= 2;
482
483 if (bSize != 4)
484 dval = (dval & mask) | c->_usage_page;
485 c->usage_maximum = dval;
486
487 check_set:
488 if (s->susage != 3)
489 break;
490
491 /* sanity check */
492 if ((s->nusage < MAXUSAGE) &&
493 (c->usage_minimum <= c->usage_maximum)) {
494 /* add usage range */
495 s->usages_min[s->nusage] =
496 c->usage_minimum;
497 s->usages_max[s->nusage] =
498 c->usage_maximum;
499 s->nusage ++;
500 } else {
501 DPRINTFN(0, "Usage set dropped\n");
502 }
503 s->susage = 0;
504 break;
505 case 3:
506 c->designator_index = dval;
507 break;
508 case 4:
509 c->designator_minimum = dval;
510 break;
511 case 5:
512 c->designator_maximum = dval;
513 break;
514 case 7:
515 c->string_index = dval;
516 break;
517 case 8:
518 c->string_minimum = dval;
519 break;
520 case 9:
521 c->string_maximum = dval;
522 break;
523 case 10:
524 c->set_delimiter = dval;
525 break;
526 default:
527 DPRINTFN(0, "Local bTag=%d\n", bTag);
528 break;
529 }
530 break;
531 default:
532 DPRINTFN(0, "default bType=%d\n", bType);
533 break;
534 }
535 }
536 return (0);
537 }
538
539 /*------------------------------------------------------------------------*
540 * hid_report_size
541 *------------------------------------------------------------------------*/
542 int
hid_report_size(const void * buf,usb_size_t len,enum hid_kind k,uint8_t * id)543 hid_report_size(const void *buf, usb_size_t len, enum hid_kind k, uint8_t *id)
544 {
545 struct hid_data *d;
546 struct hid_item h;
547 uint32_t temp;
548 uint32_t hpos;
549 uint32_t lpos;
550 uint8_t any_id;
551
552 any_id = 0;
553 hpos = 0;
554 lpos = 0xFFFFFFFF;
555
556 for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);) {
557 if (h.kind == k) {
558 /* check for ID-byte presence */
559 if ((h.report_ID != 0) && !any_id) {
560 if (id != NULL)
561 *id = h.report_ID;
562 any_id = 1;
563 }
564 /* compute minimum */
565 if (lpos > h.loc.pos)
566 lpos = h.loc.pos;
567 /* compute end position */
568 temp = h.loc.pos + (h.loc.size * h.loc.count);
569 /* compute maximum */
570 if (hpos < temp)
571 hpos = temp;
572 }
573 }
574 hid_end_parse(d);
575
576 /* safety check - can happen in case of currupt descriptors */
577 if (lpos > hpos)
578 temp = 0;
579 else
580 temp = hpos - lpos;
581
582 /* check for ID byte */
583 if (any_id)
584 temp += 8;
585 else if (id != NULL)
586 *id = 0;
587
588 /* return length in bytes rounded up */
589 return ((temp + 7) / 8);
590 }
591
592 /*------------------------------------------------------------------------*
593 * hid_locate
594 *------------------------------------------------------------------------*/
595 int
hid_locate(const void * desc,usb_size_t size,int32_t u,enum hid_kind k,uint8_t index,struct hid_location * loc,uint32_t * flags,uint8_t * id)596 hid_locate(const void *desc, usb_size_t size, int32_t u, enum hid_kind k,
597 uint8_t index, struct hid_location *loc, uint32_t *flags, uint8_t *id)
598 {
599 struct hid_data *d;
600 struct hid_item h;
601
602 for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) {
603 if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) {
604 if (index--)
605 continue;
606 if (loc != NULL)
607 *loc = h.loc;
608 if (flags != NULL)
609 *flags = h.flags;
610 if (id != NULL)
611 *id = h.report_ID;
612 hid_end_parse(d);
613 return (1);
614 }
615 }
616 if (loc != NULL)
617 loc->size = 0;
618 if (flags != NULL)
619 *flags = 0;
620 if (id != NULL)
621 *id = 0;
622 hid_end_parse(d);
623 return (0);
624 }
625
626 /*------------------------------------------------------------------------*
627 * hid_get_data
628 *------------------------------------------------------------------------*/
629 static uint32_t
hid_get_data_sub(const uint8_t * buf,usb_size_t len,struct hid_location * loc,int is_signed)630 hid_get_data_sub(const uint8_t *buf, usb_size_t len, struct hid_location *loc,
631 int is_signed)
632 {
633 uint32_t hpos = loc->pos;
634 uint32_t hsize = loc->size;
635 uint32_t data;
636 uint32_t rpos;
637 uint8_t n;
638
639 DPRINTFN(11, "hid_get_data: loc %d/%d\n", hpos, hsize);
640
641 /* Range check and limit */
642 if (hsize == 0)
643 return (0);
644 if (hsize > 32)
645 hsize = 32;
646
647 /* Get data in a safe way */
648 data = 0;
649 rpos = (hpos / 8);
650 n = (hsize + 7) / 8;
651 rpos += n;
652 while (n--) {
653 rpos--;
654 if (rpos < len)
655 data |= buf[rpos] << (8 * n);
656 }
657
658 /* Correctly shift down data */
659 data = (data >> (hpos % 8));
660 n = 32 - hsize;
661
662 /* Mask and sign extend in one */
663 if (is_signed != 0)
664 data = (int32_t)((int32_t)data << n) >> n;
665 else
666 data = (uint32_t)((uint32_t)data << n) >> n;
667
668 DPRINTFN(11, "hid_get_data: loc %d/%d = %lu\n",
669 loc->pos, loc->size, (long)data);
670 return (data);
671 }
672
673 int32_t
hid_get_data(const uint8_t * buf,usb_size_t len,struct hid_location * loc)674 hid_get_data(const uint8_t *buf, usb_size_t len, struct hid_location *loc)
675 {
676 return (hid_get_data_sub(buf, len, loc, 1));
677 }
678
679 uint32_t
hid_get_data_unsigned(const uint8_t * buf,usb_size_t len,struct hid_location * loc)680 hid_get_data_unsigned(const uint8_t *buf, usb_size_t len, struct hid_location *loc)
681 {
682 return (hid_get_data_sub(buf, len, loc, 0));
683 }
684
685 /*------------------------------------------------------------------------*
686 * hid_put_data
687 *------------------------------------------------------------------------*/
688 void
hid_put_data_unsigned(uint8_t * buf,usb_size_t len,struct hid_location * loc,unsigned int value)689 hid_put_data_unsigned(uint8_t *buf, usb_size_t len,
690 struct hid_location *loc, unsigned int value)
691 {
692 uint32_t hpos = loc->pos;
693 uint32_t hsize = loc->size;
694 uint64_t data;
695 uint64_t mask;
696 uint32_t rpos;
697 uint8_t n;
698
699 DPRINTFN(11, "hid_put_data: loc %d/%d = %u\n", hpos, hsize, value);
700
701 /* Range check and limit */
702 if (hsize == 0)
703 return;
704 if (hsize > 32)
705 hsize = 32;
706
707 /* Put data in a safe way */
708 rpos = (hpos / 8);
709 n = (hsize + 7) / 8;
710 data = ((uint64_t)value) << (hpos % 8);
711 mask = ((1ULL << hsize) - 1ULL) << (hpos % 8);
712 rpos += n;
713 while (n--) {
714 rpos--;
715 if (rpos < len) {
716 buf[rpos] &= ~(mask >> (8 * n));
717 buf[rpos] |= (data >> (8 * n));
718 }
719 }
720 }
721
722 /*------------------------------------------------------------------------*
723 * hid_is_collection
724 *------------------------------------------------------------------------*/
725 int
hid_is_collection(const void * desc,usb_size_t size,int32_t usage)726 hid_is_collection(const void *desc, usb_size_t size, int32_t usage)
727 {
728 struct hid_data *hd;
729 struct hid_item hi;
730 int err;
731
732 hd = hid_start_parse(desc, size, hid_input);
733 if (hd == NULL)
734 return (0);
735
736 while ((err = hid_get_item(hd, &hi))) {
737 if (hi.kind == hid_collection &&
738 hi.usage == usage)
739 break;
740 }
741 hid_end_parse(hd);
742 return (err);
743 }
744
745 /*------------------------------------------------------------------------*
746 * hid_get_descriptor_from_usb
747 *
748 * This function will search for a HID descriptor between two USB
749 * interface descriptors.
750 *
751 * Return values:
752 * NULL: No more HID descriptors.
753 * Else: Pointer to HID descriptor.
754 *------------------------------------------------------------------------*/
755 struct usb_hid_descriptor *
hid_get_descriptor_from_usb(struct usb_config_descriptor * cd,struct usb_interface_descriptor * id)756 hid_get_descriptor_from_usb(struct usb_config_descriptor *cd,
757 struct usb_interface_descriptor *id)
758 {
759 struct usb_descriptor *desc = (void *)id;
760
761 if (desc == NULL) {
762 return (NULL);
763 }
764 while ((desc = usb_desc_foreach(cd, desc))) {
765 if ((desc->bDescriptorType == UDESC_HID) &&
766 (desc->bLength >= USB_HID_DESCRIPTOR_SIZE(0))) {
767 return (void *)desc;
768 }
769 if (desc->bDescriptorType == UDESC_INTERFACE) {
770 break;
771 }
772 }
773 return (NULL);
774 }
775
776 /*------------------------------------------------------------------------*
777 * usbd_req_get_hid_desc
778 *
779 * This function will read out an USB report descriptor from the USB
780 * device.
781 *
782 * Return values:
783 * NULL: Failure.
784 * Else: Success. The pointer should eventually be passed to free().
785 *------------------------------------------------------------------------*/
786 usb_error_t
usbd_req_get_hid_desc(struct usb_device * udev,struct mtx * mtx,void ** descp,uint16_t * sizep,struct malloc_type * mem,uint8_t iface_index)787 usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx,
788 void **descp, uint16_t *sizep,
789 struct malloc_type *mem, uint8_t iface_index)
790 {
791 struct usb_interface *iface = usbd_get_iface(udev, iface_index);
792 struct usb_hid_descriptor *hid;
793 usb_error_t err;
794
795 if ((iface == NULL) || (iface->idesc == NULL)) {
796 return (USB_ERR_INVAL);
797 }
798 hid = hid_get_descriptor_from_usb
799 (usbd_get_config_descriptor(udev), iface->idesc);
800
801 if (hid == NULL) {
802 return (USB_ERR_IOERROR);
803 }
804 *sizep = UGETW(hid->descrs[0].wDescriptorLength);
805 if (*sizep == 0) {
806 return (USB_ERR_IOERROR);
807 }
808 if (mtx)
809 mtx_unlock(mtx);
810
811 *descp = zalloc(*sizep);
812
813 if (mtx)
814 mtx_lock(mtx);
815
816 if (*descp == NULL) {
817 return (USB_ERR_NOMEM);
818 }
819 err = usbd_req_get_report_descriptor
820 (udev, mtx, *descp, *sizep, iface_index);
821
822 if (err) {
823 free(*descp);
824 *descp = NULL;
825 return (err);
826 }
827 return (USB_ERR_NORMAL_COMPLETION);
828 }
829
830 /*------------------------------------------------------------------------*
831 * calculate HID item resolution. unit/mm for distances, unit/rad for angles
832 *------------------------------------------------------------------------*/
833 int32_t
hid_item_resolution(struct hid_item * hi)834 hid_item_resolution(struct hid_item *hi)
835 {
836 /*
837 * hid unit scaling table according to HID Usage Table Review
838 * Request 39 Tbl 17 http://www.usb.org/developers/hidpage/HUTRR39b.pdf
839 */
840 static const int64_t scale[0x10][2] = {
841 [0x00] = { 1, 1 },
842 [0x01] = { 1, 10 },
843 [0x02] = { 1, 100 },
844 [0x03] = { 1, 1000 },
845 [0x04] = { 1, 10000 },
846 [0x05] = { 1, 100000 },
847 [0x06] = { 1, 1000000 },
848 [0x07] = { 1, 10000000 },
849 [0x08] = { 100000000, 1 },
850 [0x09] = { 10000000, 1 },
851 [0x0A] = { 1000000, 1 },
852 [0x0B] = { 100000, 1 },
853 [0x0C] = { 10000, 1 },
854 [0x0D] = { 1000, 1 },
855 [0x0E] = { 100, 1 },
856 [0x0F] = { 10, 1 },
857 };
858 int64_t logical_size;
859 int64_t physical_size;
860 int64_t multiplier;
861 int64_t divisor;
862 int64_t resolution;
863
864 switch (hi->unit) {
865 case HUM_CENTIMETER:
866 multiplier = 1;
867 divisor = 10;
868 break;
869 case HUM_INCH:
870 multiplier = 10;
871 divisor = 254;
872 break;
873 case HUM_RADIAN:
874 multiplier = 1;
875 divisor = 1;
876 break;
877 case HUM_DEGREE:
878 multiplier = 573;
879 divisor = 10;
880 break;
881 default:
882 return (0);
883 }
884
885 if ((hi->logical_maximum <= hi->logical_minimum) ||
886 (hi->physical_maximum <= hi->physical_minimum) ||
887 (hi->unit_exponent < 0) || (hi->unit_exponent >= nitems(scale)))
888 return (0);
889
890 logical_size = (int64_t)hi->logical_maximum -
891 (int64_t)hi->logical_minimum;
892 physical_size = (int64_t)hi->physical_maximum -
893 (int64_t)hi->physical_minimum;
894 /* Round to ceiling */
895 resolution = logical_size * multiplier * scale[hi->unit_exponent][0] /
896 (physical_size * divisor * scale[hi->unit_exponent][1]);
897
898 if (resolution > INT32_MAX)
899 return (0);
900
901 return (resolution);
902 }
903
904 /*------------------------------------------------------------------------*
905 * hid_is_mouse
906 *
907 * This function will decide if a USB descriptor belongs to a USB mouse.
908 *
909 * Return values:
910 * Zero: Not a USB mouse.
911 * Else: Is a USB mouse.
912 *------------------------------------------------------------------------*/
913 int
hid_is_mouse(const void * d_ptr,uint16_t d_len)914 hid_is_mouse(const void *d_ptr, uint16_t d_len)
915 {
916 struct hid_data *hd;
917 struct hid_item hi;
918 int mdepth;
919 int found;
920
921 hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
922 if (hd == NULL)
923 return (0);
924
925 mdepth = 0;
926 found = 0;
927
928 while (hid_get_item(hd, &hi)) {
929 switch (hi.kind) {
930 case hid_collection:
931 if (mdepth != 0)
932 mdepth++;
933 else if (hi.collection == 1 &&
934 hi.usage ==
935 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
936 mdepth++;
937 break;
938 case hid_endcollection:
939 if (mdepth != 0)
940 mdepth--;
941 break;
942 case hid_input:
943 if (mdepth == 0)
944 break;
945 if (hi.usage ==
946 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
947 (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
948 found++;
949 if (hi.usage ==
950 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
951 (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
952 found++;
953 break;
954 default:
955 break;
956 }
957 }
958 hid_end_parse(hd);
959 return (found);
960 }
961
962 /*------------------------------------------------------------------------*
963 * hid_is_keyboard
964 *
965 * This function will decide if a USB descriptor belongs to a USB keyboard.
966 *
967 * Return values:
968 * Zero: Not a USB keyboard.
969 * Else: Is a USB keyboard.
970 *------------------------------------------------------------------------*/
971 int
hid_is_keyboard(const void * d_ptr,uint16_t d_len)972 hid_is_keyboard(const void *d_ptr, uint16_t d_len)
973 {
974 if (hid_is_collection(d_ptr, d_len,
975 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
976 return (1);
977 return (0);
978 }
979