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