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