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