1 /* $NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $ */ 2 3 4 #include <sys/cdefs.h> 5 __FBSDID("$FreeBSD$"); 6 /*- 7 * Copyright (c) 1998 The NetBSD Foundation, Inc. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to The NetBSD Foundation 11 * by Lennart Augustsson (lennart@augustsson.net) at 12 * Carlstedt Research & Technology. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the NetBSD 25 * Foundation, Inc. and its contributors. 26 * 4. Neither the name of The NetBSD Foundation nor the names of its 27 * contributors may be used to endorse or promote products derived 28 * from this software without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 32 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 34 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 40 * POSSIBILITY OF SUCH DAMAGE. 41 */ 42 43 #include <dev/usb/usb.h> 44 #include <dev/usb/usb_mfunc.h> 45 #include <dev/usb/usb_error.h> 46 #include <dev/usb/usbhid.h> 47 48 #define USB_DEBUG_VAR usb2_debug 49 50 #include <dev/usb/usb_core.h> 51 #include <dev/usb/usb_debug.h> 52 #include <dev/usb/usb_parse.h> 53 #include <dev/usb/usb_process.h> 54 #include <dev/usb/usb_device.h> 55 #include <dev/usb/usb_request.h> 56 #include <dev/usb/usb_hid.h> 57 58 static void hid_clear_local(struct hid_item *); 59 static uint8_t hid_get_byte(struct hid_data *s, const uint16_t wSize); 60 61 #define MAXUSAGE 64 62 #define MAXPUSH 4 63 struct hid_data { 64 const uint8_t *start; 65 const uint8_t *end; 66 const uint8_t *p; 67 struct hid_item cur[MAXPUSH]; 68 int32_t usages_min[MAXUSAGE]; 69 int32_t usages_max[MAXUSAGE]; 70 int32_t usage_last; /* last seen usage */ 71 uint32_t loc_size; /* last seen size */ 72 uint32_t loc_count; /* last seen count */ 73 uint8_t kindset; /* we have 5 kinds so 8 bits are enough */ 74 uint8_t pushlevel; /* current pushlevel */ 75 uint8_t ncount; /* end usage item count */ 76 uint8_t icount; /* current usage item count */ 77 uint8_t nusage; /* end "usages_min/max" index */ 78 uint8_t iusage; /* current "usages_min/max" index */ 79 uint8_t ousage; /* current "usages_min/max" offset */ 80 uint8_t susage; /* usage set flags */ 81 }; 82 83 /*------------------------------------------------------------------------* 84 * hid_clear_local 85 *------------------------------------------------------------------------*/ 86 static void 87 hid_clear_local(struct hid_item *c) 88 { 89 90 c->loc.count = 0; 91 c->loc.size = 0; 92 c->usage = 0; 93 c->usage_minimum = 0; 94 c->usage_maximum = 0; 95 c->designator_index = 0; 96 c->designator_minimum = 0; 97 c->designator_maximum = 0; 98 c->string_index = 0; 99 c->string_minimum = 0; 100 c->string_maximum = 0; 101 c->set_delimiter = 0; 102 } 103 104 /*------------------------------------------------------------------------* 105 * hid_start_parse 106 *------------------------------------------------------------------------*/ 107 struct hid_data * 108 hid_start_parse(const void *d, usb2_size_t len, int kindset) 109 { 110 struct hid_data *s; 111 112 if ((kindset-1) & kindset) { 113 DPRINTFN(0, "Only one bit can be " 114 "set in the kindset\n"); 115 return (NULL); 116 } 117 118 s = malloc(sizeof *s, M_TEMP, M_WAITOK | M_ZERO); 119 s->start = s->p = d; 120 s->end = ((const uint8_t *)d) + len; 121 s->kindset = kindset; 122 return (s); 123 } 124 125 /*------------------------------------------------------------------------* 126 * hid_end_parse 127 *------------------------------------------------------------------------*/ 128 void 129 hid_end_parse(struct hid_data *s) 130 { 131 if (s == NULL) 132 return; 133 134 free(s, M_TEMP); 135 } 136 137 /*------------------------------------------------------------------------* 138 * get byte from HID descriptor 139 *------------------------------------------------------------------------*/ 140 static uint8_t 141 hid_get_byte(struct hid_data *s, const uint16_t wSize) 142 { 143 const uint8_t *ptr; 144 uint8_t retval; 145 146 ptr = s->p; 147 148 /* check if end is reached */ 149 if (ptr == s->end) 150 return (0); 151 152 /* read out a byte */ 153 retval = *ptr; 154 155 /* check if data pointer can be advanced by "wSize" bytes */ 156 if ((s->end - ptr) < wSize) 157 ptr = s->end; 158 else 159 ptr += wSize; 160 161 /* update pointer */ 162 s->p = ptr; 163 164 return (retval); 165 } 166 167 /*------------------------------------------------------------------------* 168 * hid_get_item 169 *------------------------------------------------------------------------*/ 170 int 171 hid_get_item(struct hid_data *s, struct hid_item *h) 172 { 173 struct hid_item *c; 174 unsigned int bTag, bType, bSize; 175 uint32_t oldpos; 176 int32_t mask; 177 int32_t dval; 178 179 if (s == NULL) 180 return (0); 181 182 c = &s->cur[s->pushlevel]; 183 184 top: 185 /* check if there is an array of items */ 186 if (s->icount < s->ncount) { 187 /* get current usage */ 188 if (s->iusage < s->nusage) { 189 dval = s->usages_min[s->iusage] + s->ousage; 190 c->usage = dval; 191 s->usage_last = dval; 192 if (dval == s->usages_max[s->iusage]) { 193 s->iusage ++; 194 s->ousage = 0; 195 } else { 196 s->ousage ++; 197 } 198 } else { 199 DPRINTFN(1, "Using last usage\n"); 200 dval = s->usage_last; 201 } 202 s->icount ++; 203 /* 204 * Only copy HID item, increment position and return 205 * if correct kindset! 206 */ 207 if (s->kindset & (1 << c->kind)) { 208 *h = *c; 209 DPRINTFN(1, "%u,%u,%u\n", h->loc.pos, 210 h->loc.size, h->loc.count); 211 c->loc.pos += c->loc.size * c->loc.count; 212 return (1); 213 } 214 } 215 216 /* reset state variables */ 217 s->icount = 0; 218 s->ncount = 0; 219 s->iusage = 0; 220 s->nusage = 0; 221 s->susage = 0; 222 s->ousage = 0; 223 hid_clear_local(c); 224 225 /* get next item */ 226 while (s->p != s->end) { 227 228 bSize = hid_get_byte(s, 1); 229 if (bSize == 0xfe) { 230 /* long item */ 231 bSize = hid_get_byte(s, 1); 232 bSize |= hid_get_byte(s, 1) << 8; 233 bTag = hid_get_byte(s, 1); 234 bType = 0xff; /* XXX what should it be */ 235 } else { 236 /* short item */ 237 bTag = bSize >> 4; 238 bType = (bSize >> 2) & 3; 239 bSize &= 3; 240 if (bSize == 3) 241 bSize = 4; 242 } 243 switch (bSize) { 244 case 0: 245 dval = 0; 246 mask = 0; 247 break; 248 case 1: 249 dval = (int8_t)hid_get_byte(s, 1); 250 mask = 0xFF; 251 break; 252 case 2: 253 dval = hid_get_byte(s, 1); 254 dval |= hid_get_byte(s, 1) << 8; 255 dval = (int16_t)dval; 256 mask = 0xFFFF; 257 break; 258 case 4: 259 dval = hid_get_byte(s, 1); 260 dval |= hid_get_byte(s, 1) << 8; 261 dval |= hid_get_byte(s, 1) << 16; 262 dval |= hid_get_byte(s, 1) << 24; 263 mask = 0xFFFFFFFF; 264 break; 265 default: 266 dval = hid_get_byte(s, bSize); 267 DPRINTFN(0, "bad length %u (data=0x%02x)\n", 268 bSize, dval); 269 continue; 270 } 271 272 switch (bType) { 273 case 0: /* Main */ 274 switch (bTag) { 275 case 8: /* Input */ 276 c->kind = hid_input; 277 c->flags = dval; 278 ret: 279 c->loc.count = s->loc_count; 280 c->loc.size = s->loc_size; 281 282 if (c->flags & HIO_VARIABLE) { 283 /* range check usage count */ 284 if (c->loc.count > 255) { 285 DPRINTFN(0, "Number of " 286 "items truncated to 255\n"); 287 s->ncount = 255; 288 } else 289 s->ncount = c->loc.count; 290 291 /* 292 * The "top" loop will return 293 * one and one item: 294 */ 295 c->loc.count = 1; 296 } else { 297 s->ncount = 1; 298 } 299 /* set default usage */ 300 /* use the undefined HID PAGE */ 301 s->usage_last = 0; 302 goto top; 303 304 case 9: /* Output */ 305 c->kind = hid_output; 306 c->flags = dval; 307 goto ret; 308 case 10: /* Collection */ 309 c->kind = hid_collection; 310 c->collection = dval; 311 c->collevel++; 312 *h = *c; 313 return (1); 314 case 11: /* Feature */ 315 c->kind = hid_feature; 316 c->flags = dval; 317 goto ret; 318 case 12: /* End collection */ 319 c->kind = hid_endcollection; 320 if (c->collevel == 0) { 321 DPRINTFN(0, "invalid end collection\n"); 322 return (0); 323 } 324 c->collevel--; 325 *h = *c; 326 return (1); 327 default: 328 DPRINTFN(0, "Main bTag=%d\n", bTag); 329 break; 330 } 331 break; 332 case 1: /* Global */ 333 switch (bTag) { 334 case 0: 335 c->_usage_page = dval << 16; 336 break; 337 case 1: 338 c->logical_minimum = dval; 339 break; 340 case 2: 341 c->logical_maximum = dval; 342 break; 343 case 3: 344 c->physical_minimum = dval; 345 break; 346 case 4: 347 c->physical_maximum = dval; 348 break; 349 case 5: 350 c->unit_exponent = dval; 351 break; 352 case 6: 353 c->unit = dval; 354 break; 355 case 7: 356 /* mask because value is unsigned */ 357 s->loc_size = dval & mask; 358 break; 359 case 8: 360 c->report_ID = dval; 361 /* new report - reset position */ 362 c->loc.pos = 0; 363 break; 364 case 9: 365 /* mask because value is unsigned */ 366 s->loc_count = dval & mask; 367 break; 368 case 10: /* Push */ 369 s->pushlevel ++; 370 if (s->pushlevel < MAXPUSH) { 371 s->cur[s->pushlevel] = *c; 372 /* store size and count */ 373 c->loc.size = s->loc_size; 374 c->loc.count = s->loc_count; 375 /* update current item pointer */ 376 c = &s->cur[s->pushlevel]; 377 } else { 378 DPRINTFN(0, "Cannot push " 379 "item @ %d!\n", s->pushlevel); 380 } 381 break; 382 case 11: /* Pop */ 383 s->pushlevel --; 384 if (s->pushlevel < MAXPUSH) { 385 /* preserve position */ 386 oldpos = c->loc.pos; 387 c = &s->cur[s->pushlevel]; 388 /* restore size and count */ 389 s->loc_size = c->loc.size; 390 s->loc_count = c->loc.count; 391 /* set default item location */ 392 c->loc.pos = oldpos; 393 c->loc.size = 0; 394 c->loc.count = 0; 395 } else { 396 DPRINTFN(0, "Cannot pop " 397 "item @ %d!\n", s->pushlevel); 398 } 399 break; 400 default: 401 DPRINTFN(0, "Global bTag=%d\n", bTag); 402 break; 403 } 404 break; 405 case 2: /* Local */ 406 switch (bTag) { 407 case 0: 408 if (bSize != 4) 409 dval = (dval & mask) | c->_usage_page; 410 411 if (s->nusage < MAXUSAGE) { 412 s->usages_min[s->nusage] = dval; 413 s->usages_max[s->nusage] = dval; 414 s->nusage ++; 415 } else { 416 DPRINTFN(0, "max usage reached!\n"); 417 } 418 419 /* clear any pending usage sets */ 420 s->susage = 0; 421 break; 422 case 1: 423 s->susage |= 1; 424 425 if (bSize != 4) 426 dval = (dval & mask) | c->_usage_page; 427 c->usage_minimum = dval; 428 429 goto check_set; 430 case 2: 431 s->susage |= 2; 432 433 if (bSize != 4) 434 dval = (dval & mask) | c->_usage_page; 435 c->usage_maximum = dval; 436 437 check_set: 438 if (s->susage != 3) 439 break; 440 441 /* sanity check */ 442 if ((s->nusage < MAXUSAGE) && 443 (c->usage_minimum <= c->usage_maximum)) { 444 /* add usage range */ 445 s->usages_min[s->nusage] = 446 c->usage_minimum; 447 s->usages_max[s->nusage] = 448 c->usage_maximum; 449 s->nusage ++; 450 } else { 451 DPRINTFN(0, "Usage set dropped!\n"); 452 } 453 s->susage = 0; 454 break; 455 case 3: 456 c->designator_index = dval; 457 break; 458 case 4: 459 c->designator_minimum = dval; 460 break; 461 case 5: 462 c->designator_maximum = dval; 463 break; 464 case 7: 465 c->string_index = dval; 466 break; 467 case 8: 468 c->string_minimum = dval; 469 break; 470 case 9: 471 c->string_maximum = dval; 472 break; 473 case 10: 474 c->set_delimiter = dval; 475 break; 476 default: 477 DPRINTFN(0, "Local bTag=%d\n", bTag); 478 break; 479 } 480 break; 481 default: 482 DPRINTFN(0, "default bType=%d\n", bType); 483 break; 484 } 485 } 486 return (0); 487 } 488 489 /*------------------------------------------------------------------------* 490 * hid_report_size 491 *------------------------------------------------------------------------*/ 492 int 493 hid_report_size(const void *buf, usb2_size_t len, enum hid_kind k, uint8_t *id) 494 { 495 struct hid_data *d; 496 struct hid_item h; 497 uint32_t temp; 498 uint32_t hpos; 499 uint32_t lpos; 500 uint8_t any_id; 501 502 any_id = 0; 503 hpos = 0; 504 lpos = 0xFFFFFFFF; 505 506 for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);) { 507 if (h.kind == k) { 508 /* check for ID-byte presense */ 509 if ((h.report_ID != 0) && !any_id) { 510 if (id != NULL) 511 *id = h.report_ID; 512 any_id = 1; 513 } 514 /* compute minimum */ 515 if (lpos > h.loc.pos) 516 lpos = h.loc.pos; 517 /* compute end position */ 518 temp = h.loc.pos + (h.loc.size * h.loc.count); 519 /* compute maximum */ 520 if (hpos < temp) 521 hpos = temp; 522 } 523 } 524 hid_end_parse(d); 525 526 /* safety check - can happen in case of currupt descriptors */ 527 if (lpos > hpos) 528 temp = 0; 529 else 530 temp = hpos - lpos; 531 532 /* check for ID byte */ 533 if (any_id) 534 temp += 8; 535 else if (id != NULL) 536 *id = 0; 537 538 /* return length in bytes rounded up */ 539 return ((temp + 7) / 8); 540 } 541 542 /*------------------------------------------------------------------------* 543 * hid_locate 544 *------------------------------------------------------------------------*/ 545 int 546 hid_locate(const void *desc, usb2_size_t size, uint32_t u, enum hid_kind k, 547 uint8_t index, struct hid_location *loc, uint32_t *flags, uint8_t *id) 548 { 549 struct hid_data *d; 550 struct hid_item h; 551 552 for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) { 553 if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) { 554 if (index--) 555 continue; 556 if (loc != NULL) 557 *loc = h.loc; 558 if (flags != NULL) 559 *flags = h.flags; 560 if (id != NULL) 561 *id = h.report_ID; 562 hid_end_parse(d); 563 return (1); 564 } 565 } 566 if (loc != NULL) 567 loc->size = 0; 568 if (flags != NULL) 569 *flags = 0; 570 if (id != NULL) 571 *id = 0; 572 hid_end_parse(d); 573 return (0); 574 } 575 576 /*------------------------------------------------------------------------* 577 * hid_get_data 578 *------------------------------------------------------------------------*/ 579 uint32_t 580 hid_get_data(const uint8_t *buf, usb2_size_t len, struct hid_location *loc) 581 { 582 uint32_t hpos = loc->pos; 583 uint32_t hsize = loc->size; 584 uint32_t data; 585 uint32_t rpos; 586 uint8_t n; 587 588 DPRINTFN(11, "hid_get_data: loc %d/%d\n", hpos, hsize); 589 590 /* Range check and limit */ 591 if (hsize == 0) 592 return (0); 593 if (hsize > 32) 594 hsize = 32; 595 596 /* Get data in a safe way */ 597 data = 0; 598 rpos = (hpos / 8); 599 n = (hsize + 7) / 8; 600 rpos += n; 601 while (n--) { 602 rpos--; 603 if (rpos < len) 604 data |= buf[rpos] << (8 * n); 605 } 606 607 /* Correctly shift down data */ 608 data = (data >> (hpos % 8)); 609 610 /* Mask and sign extend in one */ 611 n = 32 - hsize; 612 data = ((int32_t)data << n) >> n; 613 614 DPRINTFN(11, "hid_get_data: loc %d/%d = %lu\n", 615 loc->pos, loc->size, (long)data); 616 return (data); 617 } 618 619 /*------------------------------------------------------------------------* 620 * hid_is_collection 621 *------------------------------------------------------------------------*/ 622 int 623 hid_is_collection(const void *desc, usb2_size_t size, uint32_t usage) 624 { 625 struct hid_data *hd; 626 struct hid_item hi; 627 int err; 628 629 hd = hid_start_parse(desc, size, hid_input); 630 if (hd == NULL) 631 return (0); 632 633 err = hid_get_item(hd, &hi) && 634 hi.kind == hid_collection && 635 hi.usage == usage; 636 hid_end_parse(hd); 637 return (err); 638 } 639 640 /*------------------------------------------------------------------------* 641 * hid_get_descriptor_from_usb 642 * 643 * This function will search for a HID descriptor between two USB 644 * interface descriptors. 645 * 646 * Return values: 647 * NULL: No more HID descriptors. 648 * Else: Pointer to HID descriptor. 649 *------------------------------------------------------------------------*/ 650 struct usb2_hid_descriptor * 651 hid_get_descriptor_from_usb(struct usb2_config_descriptor *cd, 652 struct usb2_interface_descriptor *id) 653 { 654 struct usb2_descriptor *desc = (void *)id; 655 656 if (desc == NULL) { 657 return (NULL); 658 } 659 while ((desc = usb2_desc_foreach(cd, desc))) { 660 if ((desc->bDescriptorType == UDESC_HID) && 661 (desc->bLength >= USB_HID_DESCRIPTOR_SIZE(0))) { 662 return (void *)desc; 663 } 664 if (desc->bDescriptorType == UDESC_INTERFACE) { 665 break; 666 } 667 } 668 return (NULL); 669 } 670 671 /*------------------------------------------------------------------------* 672 * usb2_req_get_hid_desc 673 * 674 * This function will read out an USB report descriptor from the USB 675 * device. 676 * 677 * Return values: 678 * NULL: Failure. 679 * Else: Success. The pointer should eventually be passed to free(). 680 *------------------------------------------------------------------------*/ 681 usb2_error_t 682 usb2_req_get_hid_desc(struct usb2_device *udev, struct mtx *mtx, 683 void **descp, uint16_t *sizep, 684 usb2_malloc_type mem, uint8_t iface_index) 685 { 686 struct usb2_interface *iface = usb2_get_iface(udev, iface_index); 687 struct usb2_hid_descriptor *hid; 688 usb2_error_t err; 689 690 if ((iface == NULL) || (iface->idesc == NULL)) { 691 return (USB_ERR_INVAL); 692 } 693 hid = hid_get_descriptor_from_usb 694 (usb2_get_config_descriptor(udev), iface->idesc); 695 696 if (hid == NULL) { 697 return (USB_ERR_IOERROR); 698 } 699 *sizep = UGETW(hid->descrs[0].wDescriptorLength); 700 if (*sizep == 0) { 701 return (USB_ERR_IOERROR); 702 } 703 if (mtx) 704 mtx_unlock(mtx); 705 706 *descp = malloc(*sizep, mem, M_ZERO | M_WAITOK); 707 708 if (mtx) 709 mtx_lock(mtx); 710 711 if (*descp == NULL) { 712 return (USB_ERR_NOMEM); 713 } 714 err = usb2_req_get_report_descriptor 715 (udev, mtx, *descp, *sizep, iface_index); 716 717 if (err) { 718 free(*descp, mem); 719 *descp = NULL; 720 return (err); 721 } 722 return (USB_ERR_NORMAL_COMPLETION); 723 } 724