1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 #include <sys/usb/usba/usbai_version.h> 28 #include <sys/usb/usba.h> 29 #include <sys/usb/clients/hid/hid.h> 30 #include <sys/usb/clients/hidparser/hidparser.h> 31 #include <sys/usb/clients/hidparser/hid_parser_driver.h> 32 #include <sys/usb/clients/hidparser/hidparser_impl.h> 33 34 /* 35 * hidparser: Parser to generate parse tree for Report Descriptors 36 * in HID devices. 37 */ 38 39 uint_t hparser_errmask = (uint_t)PRINT_MASK_ALL; 40 uint_t hparser_errlevel = (uint_t)USB_LOG_L1; 41 static usb_log_handle_t hparser_log_handle; 42 43 /* 44 * Array used to store corresponding strings for the 45 * different item types for debugging. 46 */ 47 char *items[500]; /* Print items */ 48 49 /* 50 * modload support 51 */ 52 extern struct mod_ops mod_miscops; 53 54 static struct modlmisc modlmisc = { 55 &mod_miscops, /* Type of module */ 56 "HID Parser" 57 }; 58 59 static struct modlinkage modlinkage = { 60 MODREV_1, (void *)&modlmisc, NULL 61 }; 62 63 int 64 _init(void) 65 { 66 int rval = mod_install(&modlinkage); 67 68 if (rval == 0) { 69 hparser_log_handle = usb_alloc_log_hdl(NULL, "hidparser", 70 &hparser_errlevel, &hparser_errmask, NULL, 0); 71 } 72 73 return (rval); 74 } 75 76 int 77 _fini() 78 { 79 int rval = mod_remove(&modlinkage); 80 81 if (rval == 0) { 82 usb_free_log_hdl(hparser_log_handle); 83 } 84 85 return (rval); 86 } 87 88 int 89 _info(struct modinfo *modinfop) 90 { 91 92 return (mod_info(&modlinkage, modinfop)); 93 } 94 95 /* 96 * These functions are used internally in the parser. 97 * local declarations 98 */ 99 static void hidparser_scan(hidparser_tok_t *); 100 static int hidparser_Items(hidparser_tok_t *); 101 static int hidparser_LocalItem(hidparser_tok_t *); 102 static int hidparser_GlobalItem(hidparser_tok_t *); 103 static int hidparser_ItemList(entity_item_t **, 104 hidparser_tok_t *); 105 static int hidparser_ReportDescriptor(entity_item_t **, 106 hidparser_tok_t *); 107 static int hidparser_ReportDescriptorDash(entity_item_t **, 108 hidparser_tok_t *); 109 static int hidparser_MainItem(entity_item_t **, 110 hidparser_tok_t *); 111 static void hidparser_free_attribute_list( 112 entity_attribute_t *); 113 static entity_item_t *hidparser_allocate_entity(hidparser_tok_t *); 114 static void hidparser_add_attribute(hidparser_tok_t *); 115 static entity_attribute_t *hidparser_cp_attribute_list( 116 entity_attribute_t *); 117 static entity_attribute_t *hidparser_find_attribute_end( 118 entity_attribute_t *); 119 static entity_attribute_t *hidparser_alloc_attrib_list(int); 120 static entity_item_t *hidparser_find_item_end(entity_item_t *); 121 static void hidparser_report_err(int, int, 122 int, int, char *); 123 static int hidparser_isvalid_item(int); 124 static entity_attribute_t *hidparser_lookup_attribute(entity_item_t *, 125 int); 126 static void hidparser_global_err_check(entity_item_t *); 127 static void hidparser_local_err_check(entity_item_t *); 128 static void hidparser_mainitem_err_check(entity_item_t *); 129 static unsigned int hidparser_find_unsigned_val( 130 entity_attribute_t *); 131 static int hidparser_find_signed_val( 132 entity_attribute_t *); 133 static void hidparser_check_correspondence( 134 entity_item_t *, int, int, int, 135 int, char *, char *); 136 static void hidparser_check_minmax_val(entity_item_t *, 137 int, int, int, int); 138 static void hidparser_check_minmax_val_signed( 139 entity_item_t *, 140 int, int, int, int); 141 static void hidparser_error_delim(entity_item_t *, int); 142 static int hidparser_get_usage_attribute_report_des( 143 entity_item_t *, 144 uint32_t, uint32_t, uint32_t, 145 uint32_t, uint32_t, int32_t *); 146 static int hidparser_get_packet_size_report_des( 147 entity_item_t *, uint32_t, uint32_t, 148 uint32_t *); 149 static int hidparser_get_main_item_data_descr_main( 150 entity_item_t *, uint32_t, 151 uint32_t, uint32_t, uint32_t, 152 uint32_t *); 153 static void hidparser_print_entity( 154 entity_item_t *entity, 155 int indent_level); 156 static void hidparser_print_this_attribute( 157 entity_attribute_t *attribute, 158 char *ident_space); 159 static int hidparser_main(unsigned char *, size_t, 160 entity_item_t **); 161 static void hidparser_initialize_items(); 162 static void hidparser_free_report_descr_handle( 163 entity_item_t *); 164 static int hidparser_print_report_descr_handle( 165 entity_item_t *handle, 166 int indent_level); 167 static int hidparser_get_usage_list_in_order_internal( 168 entity_item_t *parse_handle, 169 uint_t collection_usage, 170 uint_t report_id, 171 uint_t main_item_type, 172 hidparser_rpt_t *rpt); 173 static void hidparser_fill_usage_info( 174 hidparser_usage_info_t *ui, 175 entity_attribute_t *attribute); 176 static int hidparser_get_report_id_list_internal( 177 entity_item_t *parser_handle, 178 uint_t main_item_type, 179 hidparser_report_id_list_t *id_lst); 180 181 /* 182 * The hidparser_lookup_first(N) of a non-terminal N is stored as an array of 183 * integer tokens, terminated by 0. Right now there is only one element. 184 */ 185 static hidparser_terminal_t first_Items[] = { 186 R_ITEM_USAGE_PAGE, R_ITEM_LOGICAL_MINIMUM, R_ITEM_LOGICAL_MAXIMUM, \ 187 R_ITEM_PHYSICAL_MINIMUM, R_ITEM_PHYSICAL_MAXIMUM, R_ITEM_UNIT, \ 188 R_ITEM_EXPONENT, R_ITEM_REPORT_SIZE, R_ITEM_REPORT_COUNT, \ 189 R_ITEM_REPORT_ID, \ 190 R_ITEM_USAGE, R_ITEM_USAGE_MIN, R_ITEM_USAGE_MAX, \ 191 R_ITEM_DESIGNATOR_INDEX, \ 192 R_ITEM_DESIGNATOR_MIN, R_ITEM_STRING_INDEX, R_ITEM_STRING_MIN, \ 193 R_ITEM_STRING_MAX, \ 194 R_ITEM_SET_DELIMITER, \ 195 0 196 }; 197 198 199 /* 200 * Each non-terminal is represented by a function. In a top-down parser, 201 * whenever a non-terminal is encountered on the state diagram, the 202 * corresponding function is called. Because of the grammar, there is NO 203 * backtracking. If there is an error in the middle, the parser returns 204 * HIDPARSER_FAILURE 205 */ 206 static hidparser_terminal_t *hid_first_list[] = { 207 first_Items 208 }; 209 210 211 /* 212 * hidparser_parse_report_descriptor: 213 * Calls the main parser routine 214 */ 215 int 216 hidparser_parse_report_descriptor( 217 unsigned char *descriptor, 218 size_t size, 219 usb_hid_descr_t *hid_descriptor, 220 hidparser_handle_t *parse_handle) 221 { 222 int error = 0; 223 entity_item_t *root; 224 225 hidparser_initialize_items(); 226 227 error = hidparser_main(descriptor, size, &root); 228 229 if (error != HIDPARSER_SUCCESS) { 230 231 return (HIDPARSER_FAILURE); 232 } else { 233 *parse_handle = kmem_zalloc( 234 sizeof (hidparser_handle), KM_SLEEP); 235 (*parse_handle)->hidparser_handle_hid_descr = hid_descriptor; 236 (*parse_handle)->hidparser_handle_parse_tree = root; 237 238 return (HIDPARSER_SUCCESS); 239 } 240 } 241 242 243 /* 244 * hidparser_free_report_descriptor_handle: 245 * Frees the parse_handle which consists of a pointer to the parse 246 * tree and a pointer to the Hid descriptor structure 247 */ 248 int 249 hidparser_free_report_descriptor_handle(hidparser_handle_t parse_handle) 250 { 251 if (parse_handle != NULL) { 252 hidparser_free_report_descr_handle( 253 parse_handle->hidparser_handle_parse_tree); 254 if (parse_handle != NULL) { 255 kmem_free(parse_handle, sizeof (hidparser_handle)); 256 } 257 } 258 259 return (HIDPARSER_SUCCESS); 260 } 261 262 263 /* 264 * hidparser_get_country_code: 265 * Return the bCountryCode from the Hid Descriptor 266 * to the hid module. 267 */ 268 int 269 hidparser_get_country_code(hidparser_handle_t parser_handle, 270 uint16_t *country_code) 271 { 272 if ((parser_handle == NULL) || 273 (parser_handle->hidparser_handle_hid_descr == NULL)) { 274 275 return (HIDPARSER_FAILURE); 276 } 277 278 *country_code = 279 parser_handle->hidparser_handle_hid_descr->bCountryCode; 280 281 return (HIDPARSER_SUCCESS); 282 } 283 284 285 /* 286 * hidparser_get_packet_size: 287 * Get the packet size(sum of REPORT_SIZE * REPORT_COUNT) 288 * corresponding to a report id and an item type 289 */ 290 int 291 hidparser_get_packet_size(hidparser_handle_t parser_handle, 292 uint_t report_id, 293 uint_t main_item_type, 294 uint_t *size) 295 { 296 if ((parser_handle == NULL) || (parser_handle-> 297 hidparser_handle_parse_tree == NULL)) { 298 299 return (HIDPARSER_FAILURE); 300 } 301 302 *size = 0; 303 304 return (hidparser_get_packet_size_report_des( 305 parser_handle->hidparser_handle_parse_tree, 306 report_id, main_item_type, size)); 307 } 308 309 310 /* 311 * hidparser_get_packet_size_report_des: 312 * Get the packet size(sum of REPORT_SIZE * REPORT_COUNT) 313 * corresponding to a report id and an item type 314 */ 315 int 316 hidparser_get_packet_size_report_des(entity_item_t *parser_handle, 317 uint32_t report_id, 318 uint32_t main_item_type, 319 uint32_t *size) 320 { 321 entity_item_t *current = parser_handle; 322 entity_attribute_t *attribute; 323 uint32_t temp; 324 uchar_t foundsize, foundcount, foundreportid, right_report_id; 325 326 foundsize = 0; 327 foundcount = 0; 328 right_report_id = 0; 329 330 while (current) { 331 if (current->entity_item_type == R_ITEM_COLLECTION) { 332 (void) hidparser_get_packet_size_report_des( 333 current->info.child, report_id, main_item_type, 334 size); 335 } else if (current->entity_item_type == main_item_type) { 336 temp = 1; 337 foundsize = 0; 338 foundcount = 0; 339 340 foundreportid = 0; 341 attribute = current->entity_item_attributes; 342 while (attribute != NULL) { 343 if (attribute->entity_attribute_tag == 344 R_ITEM_REPORT_ID) { 345 foundreportid = 1; 346 if ((attribute-> 347 entity_attribute_value[0]) == 348 report_id) { 349 right_report_id = 1; 350 } 351 } else if (attribute->entity_attribute_tag == 352 R_ITEM_REPORT_SIZE) { 353 foundsize = 1; 354 temp *= hidparser_find_unsigned_val( 355 attribute); 356 if (foundcount == 1) { 357 if (report_id && 358 right_report_id) { 359 break; 360 } 361 } 362 } else if (attribute->entity_attribute_tag == 363 R_ITEM_REPORT_COUNT) { 364 foundcount = 1; 365 temp *= hidparser_find_unsigned_val( 366 attribute); 367 if (foundsize == 1) { 368 if (report_id && 369 right_report_id) { 370 break; 371 } 372 } 373 } 374 attribute = attribute->entity_attribute_next; 375 } /* end while */ 376 377 if (foundreportid) { 378 if (right_report_id) { 379 *size = *size + temp; 380 } 381 } else if (report_id == HID_REPORT_ID_UNDEFINED) { 382 /* Just sanity checking */ 383 *size = *size + temp; 384 } 385 right_report_id = 0; 386 } /* end else if */ 387 388 current = current->entity_item_right_sibling; 389 } /* end while current */ 390 391 392 return (HIDPARSER_SUCCESS); 393 } 394 395 396 /* 397 * hidparser_get_usage_attribute: 398 * Get the attribute value corresponding to a particular 399 * report id, main item and usage 400 */ 401 int 402 hidparser_get_usage_attribute(hidparser_handle_t parser_handle, 403 uint_t report_id, 404 uint_t main_item_type, 405 uint_t usage_page, 406 uint_t usage_id, 407 uint_t usage_attribute, 408 int *usage_attribute_value) 409 { 410 411 return (hidparser_get_usage_attribute_report_des( 412 parser_handle->hidparser_handle_parse_tree, 413 report_id, main_item_type, usage_page, 414 usage_id, usage_attribute, usage_attribute_value)); 415 } 416 417 418 /* 419 * hidparser_get_usage_attribute_report_des: 420 * Called by the wrapper function hidparser_get_usage_attribute() 421 */ 422 static int 423 hidparser_get_usage_attribute_report_des(entity_item_t *parser_handle, 424 uint_t report_id, 425 uint_t main_item_type, 426 uint_t usage_page, 427 uint_t usage_id, 428 uint_t usage_attribute, 429 int *usage_attribute_value) 430 431 { 432 entity_item_t *current = parser_handle; 433 entity_attribute_t *attribute; 434 uchar_t found_page, found_ret_value, found_usage_id; 435 uchar_t foundreportid, right_report_id; 436 uint32_t usage; 437 short attvalue; 438 439 found_page = 0; 440 found_ret_value = 0; 441 found_usage_id = 0; 442 foundreportid = 0; 443 right_report_id = 0; 444 445 while (current) { 446 if (usage_id == HID_USAGE_UNDEFINED) { 447 found_usage_id = 1; 448 } 449 if (current->entity_item_type == R_ITEM_COLLECTION) { 450 451 if (hidparser_get_usage_attribute_report_des( 452 current->info.child, report_id, main_item_type, 453 usage_page, usage_id, usage_attribute, 454 usage_attribute_value) == 455 HIDPARSER_SUCCESS) { 456 457 return (HIDPARSER_SUCCESS); 458 } 459 460 } else if (current->entity_item_type == main_item_type) { 461 /* Match Item Type */ 462 attribute = current->entity_item_attributes; 463 464 while (attribute != NULL) { 465 if (attribute->entity_attribute_tag == 466 R_ITEM_USAGE) { 467 usage = hidparser_find_unsigned_val( 468 attribute); 469 if (usage_id == HID_USAGE_ID(usage)) { 470 471 found_usage_id = 1; 472 } else { 473 /* 474 * If we are trying to find out 475 * say, report size of usage = 476 * 0, a m.i with a valid usage 477 * will not contain that 478 */ 479 if (usage_id == 480 HID_USAGE_UNDEFINED) { 481 found_usage_id = 0; 482 } 483 } 484 485 if (found_usage_id && attribute-> 486 entity_attribute_length == 3) { 487 /* 488 * This is an extended usage ie. 489 * usage page in upper 16 bits 490 * or-ed with usage in the lower 491 * 16 bits. 492 */ 493 if (HID_USAGE_PAGE(usage) && 494 HID_USAGE_PAGE(usage) == 495 usage_page) { 496 497 found_page = 1; 498 } else { 499 500 found_usage_id = 0; 501 } 502 } 503 } else if (attribute->entity_attribute_tag == 504 R_ITEM_USAGE_PAGE) { 505 if (attribute-> 506 entity_attribute_value[0] == 507 usage_page) { 508 /* Match Usage Page */ 509 found_page = 1; 510 } 511 } else if (attribute->entity_attribute_tag == 512 R_ITEM_REPORT_ID) { 513 foundreportid = 1; 514 if (attribute-> 515 entity_attribute_value[0] == 516 report_id) { 517 right_report_id = 1; 518 } 519 } 520 if (attribute->entity_attribute_tag == 521 usage_attribute) { 522 /* Match attribute */ 523 found_ret_value = 1; 524 *usage_attribute_value = 525 attribute->entity_attribute_value[0]; 526 if (attribute-> 527 entity_attribute_length == 2) { 528 attvalue = 529 (attribute-> 530 entity_attribute_value[0] & 531 0xff) | 532 (attribute-> 533 entity_attribute_value[1] << 534 8); 535 *usage_attribute_value = 536 attvalue; 537 } 538 } 539 attribute = attribute->entity_attribute_next; 540 } 541 542 if (found_usage_id && found_page && found_ret_value) { 543 544 if (foundreportid) { 545 if (right_report_id) { 546 547 return (HIDPARSER_SUCCESS); 548 } else if (report_id == 549 HID_REPORT_ID_UNDEFINED) { 550 551 return (HIDPARSER_SUCCESS); 552 } 553 } else { 554 555 return (HIDPARSER_SUCCESS); 556 } 557 } 558 } 559 560 /* 561 * search the next main item, right sibling of this one 562 */ 563 if (current->entity_item_right_sibling != NULL) { 564 565 current = current->entity_item_right_sibling; 566 found_usage_id = found_page = found_ret_value = 0; 567 /* Don't change foundreportid */ 568 right_report_id = 0; 569 } else { 570 571 break; 572 } 573 } 574 /* Don't give junk result */ 575 *usage_attribute_value = 0; 576 577 return (HIDPARSER_NOT_FOUND); 578 } 579 580 581 /* 582 * hidparser_get_main_item_data_descr: 583 * Get the data value corresponding to a particular 584 * Main Item (Input, Output, Feature) 585 */ 586 int 587 hidparser_get_main_item_data_descr(hidparser_handle_t parser_handle, 588 uint_t report_id, 589 uint_t main_item_type, 590 uint_t usage_page, 591 uint_t usage_id, 592 uint_t *main_item_descr_value) 593 { 594 595 return hidparser_get_main_item_data_descr_main( 596 parser_handle->hidparser_handle_parse_tree, 597 report_id, main_item_type, usage_page, usage_id, 598 main_item_descr_value); 599 } 600 601 602 /* 603 * hidparser_get_main_item_data_descr_main: 604 * Called by the wrapper function hidparser_get_main_item_data_descr() 605 */ 606 static int 607 hidparser_get_main_item_data_descr_main(entity_item_t *parser_handle, 608 uint_t report_id, 609 uint_t main_item_type, 610 uint_t usage_page, 611 uint_t usage_id, 612 uint_t *main_item_descr_value) 613 { 614 entity_item_t *current = parser_handle; 615 entity_attribute_t *attribute; 616 617 uchar_t found_page, found_usage_id; 618 uchar_t foundreportid, right_report_id; 619 uint32_t usage; 620 621 found_page = 0; 622 found_usage_id = 0; 623 foundreportid = 0; 624 right_report_id = 0; 625 626 while (current) { 627 if (usage_id == HID_USAGE_UNDEFINED) { 628 found_usage_id = 1; 629 } 630 if (current->entity_item_type == R_ITEM_COLLECTION) { 631 632 if (hidparser_get_main_item_data_descr_main( 633 current->info.child, report_id, main_item_type, 634 usage_page, usage_id, main_item_descr_value) == 635 HIDPARSER_SUCCESS) { 636 637 return (HIDPARSER_SUCCESS); 638 } 639 } else if (current->entity_item_type == main_item_type) { 640 /* Match Item Type */ 641 attribute = current->entity_item_attributes; 642 643 if (report_id == HID_REPORT_ID_UNDEFINED) { 644 foundreportid = right_report_id = 1; 645 } 646 647 while (attribute != NULL) { 648 if (attribute->entity_attribute_tag == 649 R_ITEM_USAGE) { 650 usage = hidparser_find_unsigned_val( 651 attribute); 652 if (usage_id == HID_USAGE_ID(usage)) { 653 found_usage_id = 1; 654 if (attribute-> 655 entity_attribute_length == 656 3) { 657 if (HID_USAGE_PAGE( 658 usage) && 659 HID_USAGE_PAGE( 660 usage) == 661 usage_page) { 662 663 found_page = 1; 664 } else { 665 666 found_usage_id = 0; 667 } 668 } 669 670 if (found_usage_id && 671 found_page && 672 foundreportid && 673 right_report_id) { 674 *main_item_descr_value = 675 current-> 676 entity_item_params[0]; 677 break; 678 } 679 } 680 } else if ((attribute->entity_attribute_tag == 681 R_ITEM_USAGE_PAGE) && 682 (attribute->entity_attribute_value[0] == 683 usage_page)) { 684 685 /* Match Usage Page */ 686 found_page = 1; 687 if (found_usage_id && foundreportid && 688 right_report_id) { 689 *main_item_descr_value = 690 current-> 691 entity_item_params[0]; 692 break; 693 } 694 } else if (attribute->entity_attribute_tag == 695 R_ITEM_REPORT_ID) { 696 foundreportid = 1; 697 if (attribute-> 698 entity_attribute_value[0] == 699 report_id) { 700 right_report_id = 1; 701 } else { 702 break; 703 } 704 } 705 706 attribute = attribute->entity_attribute_next; 707 } 708 709 if (foundreportid) { 710 if (right_report_id) { 711 if (found_usage_id && found_page) { 712 713 return (HIDPARSER_SUCCESS); 714 } 715 } 716 } 717 } 718 719 /* 720 * search the next main item, right sibling of this one 721 */ 722 if (current->entity_item_right_sibling != NULL) { 723 724 current = current->entity_item_right_sibling; 725 found_page = found_usage_id = right_report_id = 0; 726 } else { 727 728 break; 729 } 730 } 731 732 *main_item_descr_value = (uint_t)NULL; 733 734 return (HIDPARSER_NOT_FOUND); 735 } 736 737 738 /* 739 * hidparser_get_top_level_collection_usage: 740 * Get the usage page and usage for the top level collection item 741 */ 742 int 743 hidparser_get_top_level_collection_usage(hidparser_handle_t parse_handle, 744 uint_t *usage_page, 745 uint_t *usage_id) 746 { 747 entity_item_t *current; 748 entity_attribute_t *attribute; 749 int found_usage_id = 0; 750 int found_page = 0; 751 uint32_t usage; 752 753 if ((parse_handle == NULL) || 754 (parse_handle->hidparser_handle_parse_tree == NULL)) 755 756 return (HIDPARSER_FAILURE); 757 758 current = parse_handle->hidparser_handle_parse_tree; 759 760 if (current->entity_item_type != R_ITEM_COLLECTION) { 761 762 return (HIDPARSER_FAILURE); 763 } 764 attribute = current->entity_item_attributes; 765 while (attribute != NULL) { 766 if (attribute->entity_attribute_tag == R_ITEM_USAGE) { 767 found_usage_id = 1; 768 usage = hidparser_find_unsigned_val(attribute); 769 *usage_id = HID_USAGE_ID(usage); 770 if (attribute->entity_attribute_length == 3) { 771 if (HID_USAGE_PAGE(usage)) { 772 found_page = 1; 773 *usage_page = HID_USAGE_PAGE(usage); 774 } 775 } 776 if (found_usage_id && found_page) { 777 778 return (HIDPARSER_SUCCESS); 779 } 780 } else if (attribute->entity_attribute_tag == 781 R_ITEM_USAGE_PAGE) { 782 found_page = 1; 783 *usage_page = attribute->entity_attribute_value[0]; 784 if (found_usage_id && found_page) { 785 786 return (HIDPARSER_SUCCESS); 787 } 788 } 789 attribute = attribute->entity_attribute_next; 790 } 791 792 return (HIDPARSER_FAILURE); 793 } 794 795 796 /* 797 * hidparser_get_usage_list_in_order: 798 * Find all the usages corresponding to a main item and report id. 799 * Note that only short items are supported. 800 * 801 * Arguments: 802 * parser_handle: 803 * hid parser handle 804 * report id: 805 * report id of the particular report where the usages belong to 806 * main_item_type: 807 * type of report, either Input, Output, or Feature 808 * usage_list: 809 * Filled in with the pointer to the first element of the 810 * usage list 811 * 812 * Return values: 813 * HIDPARSER_SUCCESS - returned success 814 * HIDPARSER_NOT_FOUND - usage specified by the parameters was not found 815 * HIDPARSER_FAILURE - unspecified failure 816 */ 817 int 818 hidparser_get_usage_list_in_order(hidparser_handle_t parser_handle, 819 uint_t report_id, 820 uint_t main_item_type, 821 hidparser_rpt_t *rpt) 822 { 823 824 if ((parser_handle == NULL) || 825 (parser_handle->hidparser_handle_parse_tree == NULL)) { 826 827 return (HIDPARSER_FAILURE); 828 } 829 830 rpt->no_of_usages = 0; 831 832 return (hidparser_get_usage_list_in_order_internal( 833 parser_handle->hidparser_handle_parse_tree, HID_USAGE_UNDEFINED, 834 report_id, main_item_type, rpt)); 835 } 836 837 838 static int 839 hidparser_get_usage_list_in_order_internal(entity_item_t *parser_handle, 840 uint_t collection_usage, 841 uint_t report_id, 842 uint_t main_item_type, 843 hidparser_rpt_t *rpt) 844 { 845 846 /* setup wrapper function */ 847 entity_item_t *current = parser_handle; 848 entity_attribute_t *attribute; 849 uchar_t foundreportid, right_report_id, valid_usage; 850 uchar_t found_usage_min, found_usage_max, found_usage; 851 int i, j; 852 int rval; 853 uint32_t usage, usage_min, usage_max, usage_id[USAGE_MAX]; 854 hidparser_usage_info_t *ui; 855 856 found_usage_min = 0; 857 found_usage_max = 0; 858 foundreportid = 0; 859 right_report_id = 0; 860 861 while (current) { 862 863 if (current->entity_item_type == R_ITEM_COLLECTION) { 864 865 /* 866 * find collection usage information for this 867 * collection 868 */ 869 valid_usage = 0; 870 871 attribute = current->entity_item_attributes; 872 873 while (attribute != NULL) { 874 if (attribute->entity_attribute_tag == 875 R_ITEM_USAGE) { 876 usage = hidparser_find_unsigned_val( 877 attribute); 878 valid_usage = 1; 879 } 880 attribute = attribute->entity_attribute_next; 881 } 882 883 if (!valid_usage) { 884 usage = HID_USAGE_UNDEFINED; 885 } 886 887 rval = hidparser_get_usage_list_in_order_internal( 888 current->info.child, usage, 889 report_id, main_item_type, rpt); 890 if (rval != HIDPARSER_SUCCESS) { 891 892 return (rval); 893 } 894 895 } else if (current->entity_item_type == main_item_type) { 896 /* Match Item Type */ 897 898 foundreportid = 0; 899 right_report_id = 0; 900 found_usage_min = 0; 901 found_usage_max = 0; 902 found_usage = 0; 903 valid_usage = 0; 904 905 attribute = current->entity_item_attributes; 906 907 while (attribute != NULL) { 908 switch (attribute->entity_attribute_tag) { 909 case R_ITEM_REPORT_ID: 910 foundreportid = 1; 911 912 if (attribute-> 913 entity_attribute_value[0] == 914 report_id) { 915 right_report_id = 1; 916 } else { 917 /* different report id */ 918 valid_usage = 1; 919 } 920 921 break; 922 case R_ITEM_USAGE: 923 if (found_usage >= USAGE_MAX) { 924 925 return (HIDPARSER_FAILURE); 926 } 927 usage = hidparser_find_unsigned_val( 928 attribute); 929 if (usage) { 930 usage_id[found_usage] = usage; 931 found_usage++; 932 } 933 934 break; 935 case R_ITEM_USAGE_MIN: 936 found_usage_min = 1; 937 usage_min = hidparser_find_unsigned_val( 938 attribute); 939 940 break; 941 case R_ITEM_USAGE_MAX: 942 found_usage_max = 1; 943 usage_max = hidparser_find_unsigned_val( 944 attribute); 945 946 break; 947 case R_ITEM_SET_DELIMITER: 948 /* skip over alternate usages */ 949 do { 950 attribute = attribute-> 951 entity_attribute_next; 952 } while (attribute-> 953 entity_attribute_tag != 954 R_ITEM_SET_DELIMITER); 955 956 break; 957 } 958 959 attribute = attribute->entity_attribute_next; 960 } 961 962 /* 963 * If we have a report id match (or report ids 964 * are not present), and have a usage item or 965 * usage min&max, put the usage item into the 966 * list. Don't put undefined usage items 967 * (HID_USAGE_UNDEFINED, 0) into the list; 968 * a 0 usage item is used to match padding 969 * fields that don't have an attached usage. 970 */ 971 if (!foundreportid || 972 (foundreportid && right_report_id)) { 973 974 for (j = 0; j < found_usage; j++) { 975 976 /* Put in usage list */ 977 if (rpt->no_of_usages >= USAGE_MAX) { 978 979 return (HIDPARSER_FAILURE); 980 } 981 982 i = rpt->no_of_usages++; 983 ui = &(rpt->usage_descr[i]); 984 985 hidparser_fill_usage_info(ui, 986 current->entity_item_attributes); 987 988 ui->rptcnt /= found_usage; 989 ui->collection_usage = collection_usage; 990 ui->usage_id = HID_USAGE_ID( 991 usage_id[j]); 992 993 /* 994 * This is an extended usage ie. 995 * usage page in upper 16 bits 996 * or-ed with usage in the lower 997 * 16 bits. 998 */ 999 if (usage_id[j] >> 16) { 1000 ui->usage_page = 1001 HID_USAGE_PAGE(usage_id[j]); 1002 } 1003 1004 rpt->report_id = report_id; 1005 valid_usage = 1; 1006 } 1007 1008 if (found_usage_min && found_usage_max) { 1009 1010 /* Put in usage list */ 1011 if (rpt->no_of_usages >= USAGE_MAX) { 1012 1013 return (HIDPARSER_FAILURE); 1014 } 1015 1016 if (found_usage) { 1017 1018 /* handle duplication */ 1019 ui->usage_min = HID_USAGE_ID( 1020 usage_min); 1021 ui->usage_max = HID_USAGE_ID( 1022 usage_max); 1023 } else { 1024 i = rpt->no_of_usages++; 1025 ui = &(rpt->usage_descr[i]); 1026 1027 hidparser_fill_usage_info(ui, 1028 current-> 1029 entity_item_attributes); 1030 1031 ui->collection_usage = 1032 collection_usage; 1033 ui->usage_min = HID_USAGE_ID( 1034 usage_min); 1035 ui->usage_max = HID_USAGE_ID( 1036 usage_max); 1037 1038 rpt->report_id = report_id; 1039 valid_usage = 1; 1040 } 1041 1042 /* 1043 * This is an extended usage ie. 1044 * usage page in upper 16 bits 1045 * or-ed with usage_max in the lower 1046 * 16 bits. 1047 */ 1048 if (usage_max >> 16) { 1049 ui->usage_page = 1050 HID_USAGE_PAGE(usage_max); 1051 } 1052 } 1053 } 1054 1055 /* 1056 * This main item contains no usage 1057 * Fill in with usage "UNDEFINED". 1058 * If report id is valid, only the 1059 * main item with matched report id 1060 * can be filled in. 1061 */ 1062 if (!valid_usage) { 1063 1064 if (rpt->no_of_usages >= USAGE_MAX) { 1065 1066 return (HIDPARSER_FAILURE); 1067 } 1068 1069 i = rpt->no_of_usages++; 1070 ui = &(rpt->usage_descr[i]); 1071 1072 hidparser_fill_usage_info(ui, 1073 current->entity_item_attributes); 1074 1075 ui->collection_usage = collection_usage; 1076 ui->usage_id = HID_USAGE_UNDEFINED; 1077 1078 rpt->report_id = report_id; 1079 } 1080 1081 } 1082 1083 current = current->entity_item_right_sibling; 1084 1085 } /* end while current */ 1086 1087 return (HIDPARSER_SUCCESS); 1088 } 1089 1090 1091 /* 1092 * hidparser_fill_usage_info(): 1093 * Fill in the mandatory item information for a main item. 1094 * See HID 6.2.2. 1095 */ 1096 static void 1097 hidparser_fill_usage_info(hidparser_usage_info_t *ui, 1098 entity_attribute_t *attribute) 1099 { 1100 bzero(ui, sizeof (*ui)); 1101 1102 while (attribute) { 1103 switch (attribute->entity_attribute_tag) { 1104 case R_ITEM_LOGICAL_MINIMUM: 1105 ui->lmin = hidparser_find_signed_val(attribute); 1106 1107 break; 1108 case R_ITEM_LOGICAL_MAXIMUM: 1109 ui->lmax = hidparser_find_signed_val(attribute); 1110 1111 break; 1112 case R_ITEM_REPORT_COUNT: 1113 ui->rptcnt = hidparser_find_unsigned_val(attribute); 1114 1115 break; 1116 case R_ITEM_REPORT_SIZE: 1117 ui->rptsz = hidparser_find_unsigned_val(attribute); 1118 1119 break; 1120 case R_ITEM_USAGE_PAGE: 1121 ui->usage_page = hidparser_find_unsigned_val(attribute) 1122 & 0xffff; 1123 1124 break; 1125 } 1126 1127 attribute = attribute->entity_attribute_next; 1128 } 1129 } 1130 1131 1132 /* 1133 * hidparser_get_report_id_list: 1134 * Return a list of all report ids used for descriptor items 1135 * corresponding to a main item. 1136 * 1137 * Arguments: 1138 * parser_handle: 1139 * hid parser handle 1140 * main_item_type: 1141 * type of report, either Input, Output, or Feature 1142 * report_id_list: 1143 * Filled in with a list of report ids found in the descriptor 1144 * 1145 * Return values: 1146 * HIDPARSER_SUCCESS - returned success 1147 * HIDPARSER_FAILURE - unspecified failure 1148 */ 1149 int 1150 hidparser_get_report_id_list(hidparser_handle_t parser_handle, 1151 uint_t main_item_type, 1152 hidparser_report_id_list_t *report_id_list) 1153 { 1154 1155 if ((parser_handle == NULL) || 1156 (parser_handle->hidparser_handle_parse_tree == NULL)) { 1157 1158 return (HIDPARSER_FAILURE); 1159 } 1160 1161 report_id_list->no_of_report_ids = 0; 1162 1163 return (hidparser_get_report_id_list_internal( 1164 parser_handle->hidparser_handle_parse_tree, 1165 main_item_type, report_id_list)); 1166 } 1167 1168 1169 /* 1170 * hidparser_get_report_id_list_internal: 1171 * internal function that generates list of all report ids 1172 */ 1173 int 1174 hidparser_get_report_id_list_internal( 1175 entity_item_t *parser_handle, 1176 uint_t main_item_type, 1177 hidparser_report_id_list_t *id_lst) 1178 { 1179 /* setup wrapper function */ 1180 entity_item_t *current = parser_handle; 1181 entity_attribute_t *attribute; 1182 uint_t report_id = 0; 1183 int i = 0; 1184 int rval; 1185 1186 while (current) { 1187 1188 if (current->entity_item_type == R_ITEM_COLLECTION) { 1189 1190 rval = hidparser_get_report_id_list_internal( 1191 current->info.child, main_item_type, id_lst); 1192 if (rval != HIDPARSER_SUCCESS) { 1193 1194 return (rval); 1195 } 1196 1197 } else if (current->entity_item_type == main_item_type) { 1198 /* Match Item Type */ 1199 attribute = current->entity_item_attributes; 1200 1201 while (attribute != NULL) { 1202 1203 if (attribute->entity_attribute_tag == 1204 R_ITEM_REPORT_ID) { 1205 1206 /* Found a Report ID */ 1207 report_id = attribute-> 1208 entity_attribute_value[0]; 1209 1210 /* Report ID already in list? */ 1211 for (i = 0; 1212 i < id_lst->no_of_report_ids; 1213 i++) { 1214 if (report_id == id_lst-> 1215 report_id[i]) { 1216 1217 break; 1218 } 1219 } 1220 1221 if (i >= id_lst->no_of_report_ids) { 1222 /* 1223 * New Report ID found, put 1224 * in list 1225 */ 1226 if (i >= REPORT_ID_MAX) { 1227 1228 return 1229 (HIDPARSER_FAILURE); 1230 } 1231 1232 id_lst->report_id[i] = 1233 report_id; 1234 id_lst->no_of_report_ids++; 1235 } 1236 } 1237 1238 attribute = attribute->entity_attribute_next; 1239 } 1240 } 1241 1242 current = current->entity_item_right_sibling; 1243 1244 } /* end while current */ 1245 1246 return (HIDPARSER_SUCCESS); 1247 } 1248 1249 1250 /* 1251 * hidparser_print_report_descr_handle: 1252 * Functions to print the parse tree. Currently not 1253 * being called. 1254 */ 1255 static int 1256 hidparser_print_report_descr_handle(entity_item_t *handle, 1257 int indent_level) 1258 { 1259 entity_item_t *current = handle; 1260 1261 while (current) { 1262 if (current->info.child) { 1263 hidparser_print_entity(current, indent_level); 1264 /* do children */ 1265 (void) hidparser_print_report_descr_handle( 1266 current->info.child, indent_level+1); 1267 } else /* just a regular entity */ { 1268 hidparser_print_entity(current, indent_level); 1269 } 1270 current = current->entity_item_right_sibling; 1271 } 1272 1273 return (HIDPARSER_SUCCESS); 1274 } 1275 1276 1277 #define SPACE_PER_LEVEL 5 1278 1279 /* 1280 * hidparser_print_entity ; 1281 * Prints the entity items recursively 1282 */ 1283 static void 1284 hidparser_print_entity(entity_item_t *entity, int indent_level) 1285 { 1286 char indent_space[256]; 1287 int count; 1288 entity_attribute_t *attr; 1289 1290 indent_level *= SPACE_PER_LEVEL; 1291 1292 for (count = 0; indent_level--; count++) 1293 indent_space[count] = ' '; 1294 1295 indent_space[count] = 0; 1296 1297 attr = entity->entity_item_attributes; 1298 while (attr) { 1299 hidparser_print_this_attribute(attr, indent_space); 1300 attr = attr->entity_attribute_next; 1301 } 1302 1303 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle, "%s%s(0x%x)", 1304 indent_space, items[entity->entity_item_type], 1305 (entity->entity_item_params_leng ? 1306 entity->entity_item_params[0] & 0xFF : 0x00)); 1307 } 1308 1309 1310 /* 1311 * hidparser_print_this_attribute: 1312 * Prints the attribute passed in the argument 1313 */ 1314 static void 1315 hidparser_print_this_attribute(entity_attribute_t *attribute, 1316 char *ident_space) 1317 { 1318 if (ident_space == NULL) { 1319 1320 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle, 1321 "%s(0x%X)", 1322 items[attribute->entity_attribute_tag], 1323 hidparser_find_unsigned_val(attribute)); 1324 } else { 1325 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle, 1326 "%s%s(0x%X)", ident_space, 1327 items[attribute->entity_attribute_tag], 1328 hidparser_find_unsigned_val(attribute)); 1329 1330 } 1331 } 1332 1333 1334 /* 1335 * The next few functions will be used for parsing using the 1336 * grammar: 1337 * 1338 * Start -> ReportDescriptor <EOF> 1339 * 1340 * ReportDescriptor -> ItemList 1341 * 1342 * ItemList -> Items MainItem ItemList 1343 * | epsilon 1344 * 1345 * MainItem -> BeginCollection ItemList EndCollection 1346 * | Input 1347 * | Output 1348 * | Feature 1349 * 1350 * Items -> GlobalItem Items 1351 * | LocalItem Items 1352 * | SetDelimiterOpen LocalItemList 1353 * SetDelimiterClose Items 1354 * | epsilon 1355 * 1356 * LocalItemList -> LocalItem Temp2 1357 * 1358 * Temp2 -> LocalItem Temp2 1359 * | epsilon 1360 * 1361 * GlobalItem -> UsagePage 1362 * | LogicalMinimum 1363 * | LogicalMaximum 1364 * | PhysicalMinimum 1365 * | PhysicalMaximum 1366 * | Unit 1367 * | Exponent 1368 * | ReportSize 1369 * | ReportCount 1370 * | ReportID 1371 * 1372 * LocalItem -> Usage 1373 * | UsageMinimum 1374 * | UsageMaximum 1375 * | DesignatorIndex 1376 * | DesignatorMinimum 1377 * | StringIndex 1378 * | StringMinimum 1379 * | StringMaximum 1380 * 1381 */ 1382 1383 1384 /* 1385 * hidparser_lookup_first: 1386 * Looks up if token belongs to the FIRST of the function tag 1387 * that is passed through the first argument 1388 */ 1389 static int 1390 hidparser_lookup_first(int func_index, 1391 int token) 1392 { 1393 int *itemp; 1394 1395 itemp = hid_first_list[func_index]; 1396 while (*itemp != 0) { 1397 /* get the next terminal on the list */ 1398 if (*itemp == token) { 1399 1400 return (HIDPARSER_SUCCESS); 1401 } 1402 itemp++; 1403 } 1404 1405 /* token is not on the FIRST list */ 1406 1407 return (HIDPARSER_FAILURE); 1408 } 1409 1410 1411 /* 1412 * hidparser_main: 1413 * Function called from hidparser_parse_report_descriptor() 1414 * to parse the Report Descriptor 1415 */ 1416 static int 1417 hidparser_main(unsigned char *descriptor, 1418 size_t size, 1419 entity_item_t **item_ptr) 1420 { 1421 hidparser_tok_t *scan_ifp; 1422 int retval; 1423 1424 scan_ifp = kmem_zalloc(sizeof (hidparser_tok_t), KM_SLEEP); 1425 scan_ifp->hidparser_tok_text = 1426 kmem_zalloc(HIDPARSER_TEXT_LENGTH, KM_SLEEP); 1427 scan_ifp->hidparser_tok_max_bsize = size; 1428 scan_ifp->hidparser_tok_entity_descriptor = descriptor; 1429 1430 *item_ptr = NULL; 1431 retval = hidparser_ReportDescriptorDash(item_ptr, scan_ifp); 1432 1433 /* 1434 * Free the Local & Global item list 1435 * It maybe the case that no tree has been built 1436 * up but there have been allocation in the attribute 1437 * & control lists 1438 */ 1439 if (scan_ifp->hidparser_tok_gitem_head) { 1440 hidparser_free_attribute_list( 1441 scan_ifp->hidparser_tok_gitem_head); 1442 } 1443 1444 if (scan_ifp->hidparser_tok_litem_head) { 1445 hidparser_free_attribute_list( 1446 scan_ifp->hidparser_tok_litem_head); 1447 } 1448 kmem_free(scan_ifp->hidparser_tok_text, HIDPARSER_TEXT_LENGTH); 1449 kmem_free(scan_ifp, sizeof (hidparser_tok_t)); 1450 1451 return (retval); 1452 } 1453 1454 1455 /* 1456 * hidparser_ReportDescriptorDash: 1457 * Synthetic start symbol, implements 1458 * hidparser_ReportDescriptor <EOF> 1459 */ 1460 static int 1461 hidparser_ReportDescriptorDash(entity_item_t ** item_ptr, 1462 hidparser_tok_t *scan_ifp) 1463 { 1464 1465 if ((hidparser_ReportDescriptor(item_ptr, scan_ifp) == 1466 HIDPARSER_SUCCESS) && (scan_ifp->hidparser_tok_token == 0)) { 1467 1468 return (HIDPARSER_SUCCESS); 1469 } 1470 1471 /* 1472 * In case of failure, free the kernel memory 1473 * allocated for partial building of the tree, 1474 * if any 1475 */ 1476 if (*item_ptr != NULL) { 1477 (void) hidparser_free_report_descr_handle(*item_ptr); 1478 } 1479 1480 *item_ptr = NULL; 1481 1482 return (HIDPARSER_FAILURE); 1483 } 1484 1485 1486 /* 1487 * hidparser_ReportDescriptor: 1488 * Implements the Rule: 1489 * ReportDescriptor -> ItemList 1490 */ 1491 static int 1492 hidparser_ReportDescriptor(entity_item_t ** item_ptr, 1493 hidparser_tok_t *scan_ifp) 1494 { 1495 hidparser_scan(scan_ifp); 1496 1497 /* 1498 * We do not search for the token in FIRST(ReportDescriptor) 1499 * since - 1500 * 1501 * FIRST(ReportDescriptor) == FIRST(ItemList) 1502 * ReportDescriptor ----> ItemList 1503 */ 1504 if (hidparser_ItemList(item_ptr, scan_ifp) == HIDPARSER_SUCCESS) { 1505 1506 return (HIDPARSER_SUCCESS); 1507 } 1508 1509 return (HIDPARSER_FAILURE); 1510 } 1511 1512 1513 /* 1514 * hidparser_ItemList: 1515 * Implements the Rule: 1516 * ItemList -> Items MainItem ItemList | epsilon 1517 * 1518 * This function constructs the tree on which depends the "hidparser" 1519 * consumer functions. Basically the structure of the tree is 1520 * 1521 * C--[RS]->EC--[RS]->C--[RS]->EC..(and so on) 1522 * | 1523 * [CH] <== This relationship is true for other "C's" 1524 * | also. 1525 * v 1526 * C/-------------/I/O/F <== [ Any of these ] 1527 * | ------ 1528 * | | 1529 * v v 1530 * [CH | RS] [ RS ] 1531 * C/I/O/F | EC I/O/F 1532 * | 1533 * | 1534 * and so on... 1535 * 1536 * where C = Collection 1537 * EC = EndCollection 1538 * I = Input 1539 * O = Output 1540 * F = Feature "Main" Items. 1541 * 1542 * and the relationships are [RS] for right sibling and [CH] for 1543 * child. [CH | RS ] stands for "child or right sibling" with the 1544 * possible values below it. 1545 */ 1546 static int 1547 hidparser_ItemList(entity_item_t ** item_ptr, hidparser_tok_t *scan_ifp) 1548 { 1549 entity_item_t *curr_ei, *cache_ei, *prev_ei, *tmp_ei; 1550 boolean_t root_coll = B_FALSE; 1551 1552 curr_ei = cache_ei = prev_ei = tmp_ei = NULL; 1553 1554 while (scan_ifp->hidparser_tok_token != 0) { 1555 if (hidparser_Items(scan_ifp) == HIDPARSER_FAILURE) { 1556 1557 return (HIDPARSER_FAILURE); 1558 } 1559 1560 if (hidparser_MainItem(&curr_ei, scan_ifp) == 1561 HIDPARSER_FAILURE) { 1562 USB_DPRINTF_L2(PRINT_MASK_ALL, 1563 hparser_log_handle, 1564 "Invalid MAIN item 0x%x in input stream", 1565 scan_ifp->hidparser_tok_token); 1566 1567 return (HIDPARSER_FAILURE); 1568 } 1569 if (curr_ei->entity_item_type == R_ITEM_COLLECTION) { 1570 if (root_coll == B_FALSE) { 1571 *item_ptr = curr_ei; 1572 root_coll = B_TRUE; 1573 } 1574 curr_ei->prev_coll = cache_ei; 1575 cache_ei = curr_ei; 1576 1577 USB_DPRINTF_L3(PRINT_MASK_ALL, 1578 hparser_log_handle, 1579 "Start Collection:cache_ei = 0x%p," 1580 " curr_ei = 0x%p", 1581 (void *)cache_ei, (void *)curr_ei); 1582 1583 if (prev_ei == NULL) { 1584 prev_ei = curr_ei; 1585 1586 continue; 1587 } 1588 if (prev_ei->entity_item_type == 1589 R_ITEM_COLLECTION) { 1590 prev_ei->info.child = curr_ei; 1591 } else { 1592 prev_ei->entity_item_right_sibling = 1593 curr_ei; 1594 } 1595 } else if (curr_ei->entity_item_type == 1596 R_ITEM_END_COLLECTION) { 1597 tmp_ei = cache_ei->prev_coll; 1598 cache_ei->entity_item_right_sibling = curr_ei; 1599 USB_DPRINTF_L3(PRINT_MASK_ALL, 1600 hparser_log_handle, 1601 "End Collection: cache_ei = 0x%p, " 1602 "curr_ei = 0x%p", 1603 (void *)cache_ei, (void *)curr_ei); 1604 if (tmp_ei != NULL) { 1605 /* 1606 * As will be the case for final end 1607 * collection. 1608 */ 1609 cache_ei = tmp_ei; 1610 } 1611 tmp_ei = NULL; 1612 } else { 1613 if (prev_ei == NULL) { 1614 USB_DPRINTF_L2(PRINT_MASK_ALL, 1615 hparser_log_handle, 1616 "Invalid First MAIN item 0x%x", 1617 scan_ifp->hidparser_tok_token); 1618 1619 return (HIDPARSER_FAILURE); 1620 } 1621 if (prev_ei->entity_item_type == 1622 R_ITEM_COLLECTION) { 1623 USB_DPRINTF_L3(PRINT_MASK_ALL, 1624 hparser_log_handle, 1625 "Main Item: token = 0x%x, " 1626 "curr_ei = 0x%p " 1627 "will be the child of prev_ei " 1628 "= 0x%p, " 1629 "cache_ei being 0x%p", 1630 curr_ei->entity_item_type, 1631 (void *)curr_ei, (void *)prev_ei, 1632 (void *)cache_ei); 1633 prev_ei->info.child = curr_ei; 1634 } else { 1635 USB_DPRINTF_L3(PRINT_MASK_ALL, 1636 hparser_log_handle, 1637 "Main Item: token = 0x%x, " 1638 "curr_ei = 0x%p " 1639 "will be the right sibling of " 1640 "prev_ei = 0x%p, " 1641 "cache_ei being 0x%p", 1642 curr_ei->entity_item_type, 1643 (void *)curr_ei, (void *)prev_ei, 1644 (void *)cache_ei); 1645 prev_ei->entity_item_right_sibling = 1646 curr_ei; 1647 } 1648 } 1649 prev_ei = curr_ei; 1650 } 1651 if (*item_ptr != cache_ei) { 1652 /* Something wrong happened */ 1653 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 1654 "Failed to parse report descriptor"); 1655 1656 return (HIDPARSER_FAILURE); 1657 } 1658 (void) hidparser_print_report_descr_handle(cache_ei, 0); 1659 1660 return (HIDPARSER_SUCCESS); 1661 } 1662 1663 1664 /* 1665 * hidparser_MainItem: 1666 * Implements the Rule: 1667 * MainItem -> BeginCollection ItemList EndCollection 1668 * | Input 1669 * | Output 1670 * | Feature 1671 */ 1672 static int 1673 hidparser_MainItem(entity_item_t ** item_ptr, 1674 hidparser_tok_t *scan_ifp) 1675 { 1676 switch (scan_ifp->hidparser_tok_token) { 1677 case R_ITEM_INPUT: 1678 /* FALLTHRU */ 1679 case R_ITEM_OUTPUT: 1680 /* FALLTHRU */ 1681 case R_ITEM_FEATURE: 1682 case R_ITEM_COLLECTION: 1683 case R_ITEM_END_COLLECTION: 1684 *item_ptr = hidparser_allocate_entity(scan_ifp); 1685 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle, 1686 "hidparser_MainItem:index = 0x%lx token = 0x%x", 1687 scan_ifp->hidparser_tok_index - 1688 (*item_ptr)->entity_item_params_leng - 1, 1689 scan_ifp->hidparser_tok_token); 1690 hidparser_scan(scan_ifp); 1691 hidparser_global_err_check(*item_ptr); 1692 hidparser_local_err_check(*item_ptr); 1693 hidparser_mainitem_err_check(*item_ptr); 1694 1695 return (HIDPARSER_SUCCESS); 1696 1697 default: 1698 break; 1699 } 1700 1701 *item_ptr = NULL; 1702 1703 return (HIDPARSER_FAILURE); 1704 } 1705 1706 1707 /* 1708 * hidparser_Items: 1709 * Implements the Rule: 1710 * Items -> GlobalItem Items 1711 * | LocalItem Items 1712 * | SetDelimiterOpen LocalItemList 1713 * SetDelimiterClose Items 1714 * | epsilon 1715 */ 1716 static int 1717 hidparser_Items(hidparser_tok_t *scan_ifp) 1718 { 1719 boolean_t delim_pre = B_FALSE; 1720 1721 int token = scan_ifp->hidparser_tok_token; 1722 1723 while (hidparser_lookup_first(HIDPARSER_ITEMS, token) == 1724 HIDPARSER_SUCCESS) { 1725 if (token == R_ITEM_SET_DELIMITER) { 1726 if (delim_pre == B_FALSE) { 1727 if (scan_ifp->hidparser_tok_text[0] != 1) { 1728 hidparser_error_delim(NULL, 1729 HIDPARSER_DELIM_ERR1); 1730 } else { 1731 delim_pre = B_TRUE; 1732 } 1733 } else { 1734 if (scan_ifp->hidparser_tok_text[0] != 1735 0) { 1736 hidparser_error_delim(NULL, 1737 HIDPARSER_DELIM_ERR2); 1738 } else { 1739 delim_pre = B_FALSE; 1740 } 1741 } 1742 (void) hidparser_LocalItem(scan_ifp); 1743 token = scan_ifp->hidparser_tok_token; 1744 } else if (hidparser_GlobalItem(scan_ifp) == 1745 HIDPARSER_SUCCESS) { 1746 token = scan_ifp->hidparser_tok_token; 1747 } else if (hidparser_LocalItem(scan_ifp) == HIDPARSER_SUCCESS) { 1748 token = scan_ifp->hidparser_tok_token; 1749 } 1750 } 1751 1752 return (HIDPARSER_SUCCESS); /* epsilon */ 1753 } 1754 1755 1756 /* 1757 * hidparser_GlobalItem: 1758 * Implements the Rule: 1759 * GlobalItem -> UsagePage 1760 * | LogicalMinimum 1761 * | LocgicalMaximum 1762 * | PhysicalMinimum 1763 * | PhysicalMaximum 1764 * | Unit 1765 * | Exponent 1766 * | ReportSize 1767 * | ReportCount 1768 * | ReportID 1769 */ 1770 static int 1771 hidparser_GlobalItem(hidparser_tok_t *scan_ifp) 1772 { 1773 1774 int i; 1775 entity_attribute_stack_t *elem; 1776 1777 switch (scan_ifp->hidparser_tok_token) { 1778 case R_ITEM_USAGE_PAGE: 1779 /* Error check */ 1780 for (i = 0; i < scan_ifp->hidparser_tok_leng; i++) { 1781 /* Undefined data value: 0 */ 1782 if (scan_ifp->hidparser_tok_text[i] == 0) { 1783 hidparser_report_err( 1784 HIDPARSER_ERR_WARN, 1785 HIDPARSER_ERR_STANDARD, 1786 R_ITEM_USAGE_PAGE, 1787 0, 1788 "Data field should be non-Zero"); 1789 } 1790 /* Reserved values 0x0A-0xFE */ 1791 else if ((scan_ifp->hidparser_tok_text[i] >= 1792 0x0a) && 1793 (scan_ifp->hidparser_tok_text[i] <= 1794 0xFE)) { 1795 hidparser_report_err( 1796 HIDPARSER_ERR_WARN, 1797 HIDPARSER_ERR_STANDARD, 1798 R_ITEM_USAGE_PAGE, 1799 1, 1800 "Data field should not use " 1801 "reserved values"); 1802 } 1803 } 1804 break; 1805 case R_ITEM_UNIT: 1806 /* FALLTHRU */ 1807 case R_ITEM_EXPONENT: 1808 /* 1809 * Error check: 1810 * Nibble 7 should be zero 1811 */ 1812 if (scan_ifp->hidparser_tok_leng == 4) { 1813 if ((scan_ifp->hidparser_tok_text[3] & 1814 0xf0) != 0) { 1815 hidparser_report_err( 1816 HIDPARSER_ERR_WARN, 1817 HIDPARSER_ERR_STANDARD, 1818 scan_ifp->hidparser_tok_token, 1819 0, 1820 "Data field reserved bits should " 1821 "be Zero"); 1822 } 1823 } 1824 break; 1825 case R_ITEM_REPORT_COUNT: 1826 /* 1827 * Error Check: 1828 * Report Count should be nonzero 1829 */ 1830 for (i = 0; i < scan_ifp->hidparser_tok_leng; i++) { 1831 if (scan_ifp->hidparser_tok_text[i]) 1832 break; 1833 } 1834 if (i == scan_ifp->hidparser_tok_leng) { 1835 hidparser_report_err( 1836 HIDPARSER_ERR_ERROR, 1837 HIDPARSER_ERR_STANDARD, 1838 R_ITEM_REPORT_COUNT, 1839 0, 1840 "Report Count = 0"); 1841 } 1842 break; 1843 case R_ITEM_REPORT_ID: 1844 /* 1845 * Error check: 1846 * Report Id should be nonzero & <= 255 1847 */ 1848 if (scan_ifp->hidparser_tok_leng != 1) { 1849 hidparser_report_err( 1850 HIDPARSER_ERR_ERROR, 1851 HIDPARSER_ERR_STANDARD, 1852 R_ITEM_REPORT_ID, 1853 1, 1854 "Must be contained in a byte"); 1855 } 1856 if (!scan_ifp->hidparser_tok_text[0]) { 1857 hidparser_report_err( 1858 HIDPARSER_ERR_ERROR, 1859 HIDPARSER_ERR_STANDARD, 1860 R_ITEM_REPORT_ID, 1861 0, 1862 "Report Id must be non-zero"); 1863 } 1864 break; 1865 case R_ITEM_LOGICAL_MINIMUM: 1866 break; 1867 case R_ITEM_LOGICAL_MAXIMUM: 1868 break; 1869 case R_ITEM_PHYSICAL_MINIMUM: 1870 break; 1871 case R_ITEM_PHYSICAL_MAXIMUM: 1872 break; 1873 case R_ITEM_REPORT_SIZE: 1874 break; 1875 case R_ITEM_PUSH: 1876 if (scan_ifp->hidparser_tok_leng != 0) { 1877 hidparser_report_err( 1878 HIDPARSER_ERR_ERROR, 1879 HIDPARSER_ERR_STANDARD, 1880 scan_ifp->hidparser_tok_token, 1881 0, 1882 "Data Field size should be zero"); 1883 } else { 1884 elem = (entity_attribute_stack_t *)kmem_zalloc( 1885 sizeof (entity_attribute_stack_t), 1886 KM_SLEEP); 1887 1888 elem->list = hidparser_cp_attribute_list( 1889 scan_ifp->hidparser_tok_gitem_head); 1890 if (scan_ifp->hidparser_head) { 1891 elem->next = scan_ifp->hidparser_head; 1892 } 1893 scan_ifp->hidparser_head = elem; 1894 } 1895 1896 break; 1897 case R_ITEM_POP: 1898 if (scan_ifp->hidparser_tok_leng != 0) { 1899 hidparser_report_err( 1900 HIDPARSER_ERR_ERROR, 1901 HIDPARSER_ERR_STANDARD, 1902 scan_ifp->hidparser_tok_token, 1903 0, 1904 "Data Field size should be zero"); 1905 } else { 1906 /* Free the current global list */ 1907 hidparser_free_attribute_list(scan_ifp-> 1908 hidparser_tok_gitem_head); 1909 scan_ifp->hidparser_tok_gitem_head = 1910 scan_ifp->hidparser_head->list; 1911 scan_ifp->hidparser_head->list = NULL; 1912 elem = scan_ifp->hidparser_head; 1913 scan_ifp->hidparser_head = elem->next; 1914 kmem_free(elem, 1915 sizeof (entity_attribute_stack_t)); 1916 } 1917 1918 break; 1919 default: 1920 1921 return (HIDPARSER_FAILURE); 1922 1923 /*NOTREACHED*/ 1924 } 1925 1926 hidparser_add_attribute(scan_ifp); 1927 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle, 1928 "hidparser_GlobalItem:index = 0x%lx token = 0x%x", 1929 scan_ifp->hidparser_tok_index - 1930 scan_ifp->hidparser_tok_leng - 1, 1931 scan_ifp->hidparser_tok_token); 1932 hidparser_scan(scan_ifp); 1933 1934 return (HIDPARSER_SUCCESS); 1935 } 1936 1937 1938 /* 1939 * hidparser_LocalItem: 1940 * Implements the Rule: 1941 * LocalItem -> Usage 1942 * | UsageMinimum 1943 * | UsageMaximum 1944 * | DesignatorIndex 1945 * | DesignatorMinimum 1946 * | StringIndex 1947 * | StringMinimum 1948 * | StringMaximum 1949 */ 1950 static int 1951 hidparser_LocalItem(hidparser_tok_t *scan_ifp) 1952 { 1953 int i; 1954 1955 switch (scan_ifp->hidparser_tok_token) { 1956 case R_ITEM_USAGE: 1957 /* 1958 * Error Check: 1959 * Data Field should be nonzero 1960 */ 1961 for (i = 0; i < scan_ifp->hidparser_tok_leng; i++) { 1962 if (scan_ifp->hidparser_tok_text[i]) 1963 break; 1964 } 1965 if (i == scan_ifp->hidparser_tok_leng) { 1966 hidparser_report_err( 1967 HIDPARSER_ERR_WARN, 1968 HIDPARSER_ERR_STANDARD, 1969 R_ITEM_USAGE, 1970 0, 1971 "Data Field should be non-zero"); 1972 } 1973 /* FALLTHRU */ 1974 case R_ITEM_USAGE_MIN: 1975 /* FALLTHRU */ 1976 case R_ITEM_USAGE_MAX: 1977 /* FALLTHRU */ 1978 case R_ITEM_DESIGNATOR_INDEX: 1979 /* FALLTHRU */ 1980 case R_ITEM_DESIGNATOR_MIN: 1981 /* FALLTHRU */ 1982 case R_ITEM_STRING_INDEX: 1983 /* FALLTHRU */ 1984 case R_ITEM_STRING_MIN: 1985 /* FALLTHRU */ 1986 case R_ITEM_STRING_MAX: 1987 /* FALLTHRU */ 1988 case R_ITEM_SET_DELIMITER: 1989 hidparser_add_attribute(scan_ifp); 1990 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle, 1991 "hidparser_LocalItem:index = 0x%lx token = 0x%x", 1992 scan_ifp->hidparser_tok_index - 1993 scan_ifp->hidparser_tok_leng - 1, 1994 scan_ifp->hidparser_tok_token); 1995 hidparser_scan(scan_ifp); 1996 1997 return (HIDPARSER_SUCCESS); 1998 1999 /*NOTREACHED*/ 2000 default: 2001 break; 2002 } 2003 2004 return (HIDPARSER_FAILURE); 2005 } 2006 2007 2008 /* 2009 * hidparser_allocate_entity: 2010 * Allocate Item of type 'type', length 'leng' and 2011 * params 'text'. Fill in the attributes allocated 2012 * so far from both the local and global item lists. 2013 * Make the child and sibling of the item NULL. 2014 */ 2015 static entity_item_t * 2016 hidparser_allocate_entity(hidparser_tok_t *scan_ifp) 2017 { 2018 entity_item_t *entity; 2019 entity_attribute_t *aend; 2020 2021 int entity_type = scan_ifp->hidparser_tok_token; 2022 unsigned char *text = scan_ifp->hidparser_tok_text; 2023 int len = scan_ifp->hidparser_tok_leng; 2024 2025 entity = kmem_zalloc(sizeof (entity_item_t), KM_SLEEP); 2026 entity->entity_item_type = entity_type; 2027 entity->entity_item_params_leng = len; 2028 2029 if (len != 0) { 2030 entity->entity_item_params = kmem_zalloc(len, KM_SLEEP); 2031 (void) bcopy(text, entity->entity_item_params, len); 2032 } 2033 2034 /* 2035 * Copy attributes from entity attribute state table if not 2036 * end collection. 2037 */ 2038 if (entity_type != R_ITEM_END_COLLECTION) { 2039 entity->entity_item_attributes = hidparser_cp_attribute_list( 2040 scan_ifp->hidparser_tok_gitem_head); 2041 2042 /* 2043 * append the control attributes, then clear out the control 2044 * attribute state table list 2045 */ 2046 if (entity->entity_item_attributes) { 2047 aend = hidparser_find_attribute_end( 2048 entity->entity_item_attributes); 2049 aend->entity_attribute_next = 2050 scan_ifp->hidparser_tok_litem_head; 2051 scan_ifp->hidparser_tok_litem_head = NULL; 2052 } else { 2053 entity->entity_item_attributes = 2054 scan_ifp->hidparser_tok_litem_head; 2055 scan_ifp->hidparser_tok_litem_head = NULL; 2056 } 2057 } 2058 2059 entity->info.child = entity->entity_item_right_sibling = 0; 2060 2061 return (entity); 2062 } 2063 2064 2065 /* 2066 * hidparser_add_attribute: 2067 * Add an attribute to the global or local item list 2068 * If the last 4th bit from right is 1, add to the local item list 2069 * Else add to the global item list 2070 */ 2071 static void 2072 hidparser_add_attribute(hidparser_tok_t *scan_ifp) 2073 { 2074 entity_attribute_t *newattrib, **previous, *elem; 2075 int entity = scan_ifp->hidparser_tok_token; 2076 unsigned char *text = scan_ifp->hidparser_tok_text; 2077 int len = scan_ifp->hidparser_tok_leng; 2078 2079 if (len == 0) { 2080 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 2081 "hidparser_add_attribute: len = 0 for item = 0x%x", 2082 entity); 2083 2084 return; 2085 } 2086 2087 if (entity & HIDPARSER_ISLOCAL_MASK) { 2088 previous = &scan_ifp->hidparser_tok_litem_head; 2089 } else { 2090 previous = &scan_ifp->hidparser_tok_gitem_head; 2091 } 2092 2093 elem = *previous; 2094 2095 /* 2096 * remove attribute if it is already on list, except 2097 * for control attributes(local items), as we could have 2098 * multiple usages... 2099 * unless we want to hassle with checking for unique parameters. 2100 */ 2101 while (elem) { 2102 if (elem->entity_attribute_tag == entity && 2103 !(entity & HIDPARSER_ISLOCAL_MASK)) { 2104 *previous = elem->entity_attribute_next; 2105 kmem_free(elem->entity_attribute_value, 2106 elem->entity_attribute_length); 2107 kmem_free(elem, sizeof (entity_attribute_t)); 2108 elem = *previous; 2109 } else { 2110 previous = &elem->entity_attribute_next; 2111 elem = elem->entity_attribute_next; 2112 } 2113 } 2114 2115 /* create new attribute for this entry */ 2116 newattrib = hidparser_alloc_attrib_list(1); 2117 newattrib->entity_attribute_tag = entity; 2118 newattrib->entity_attribute_value = kmem_zalloc(len, KM_SLEEP); 2119 (void) bcopy(text, newattrib->entity_attribute_value, len); 2120 newattrib->entity_attribute_length = len; 2121 2122 /* attach to end of list */ 2123 *previous = newattrib; 2124 } 2125 2126 2127 /* 2128 * hidparser_alloc_attrib_list: 2129 * Allocate space for n attributes , create a linked list and 2130 * return the head 2131 */ 2132 static entity_attribute_t * 2133 hidparser_alloc_attrib_list(int count) 2134 { 2135 entity_attribute_t *head, *current; 2136 2137 if (count <= 0) { 2138 2139 return (NULL); 2140 } 2141 2142 head = kmem_zalloc(sizeof (entity_attribute_t), KM_SLEEP); 2143 count--; 2144 current = head; 2145 while (count--) { 2146 current->entity_attribute_next = kmem_zalloc( 2147 sizeof (entity_attribute_t), KM_SLEEP); 2148 current = current->entity_attribute_next; 2149 } 2150 current->entity_attribute_next = NULL; 2151 2152 return (head); 2153 } 2154 2155 2156 /* 2157 * hidparser_cp_attribute_list: 2158 * Copies the Global item list pointed to by head 2159 * We create a clone of the global item list here 2160 * because we want to retain the Global items to 2161 * the next Main Item. 2162 */ 2163 static entity_attribute_t * 2164 hidparser_cp_attribute_list(entity_attribute_t *head) 2165 { 2166 entity_attribute_t *return_value, *current_src, *current_dst; 2167 2168 if (!head) { 2169 2170 return (NULL); 2171 } 2172 2173 current_src = head; 2174 current_dst = return_value = hidparser_alloc_attrib_list(1); 2175 2176 while (current_src) { 2177 current_dst->entity_attribute_tag = 2178 current_src->entity_attribute_tag; 2179 current_dst->entity_attribute_length = 2180 current_src->entity_attribute_length; 2181 current_dst->entity_attribute_value = kmem_zalloc( 2182 current_dst->entity_attribute_length, KM_SLEEP); 2183 (void) bcopy(current_src->entity_attribute_value, 2184 current_dst->entity_attribute_value, 2185 current_src->entity_attribute_length); 2186 if (current_src->entity_attribute_next) { 2187 current_dst->entity_attribute_next = 2188 hidparser_alloc_attrib_list(1); 2189 } else { 2190 current_dst->entity_attribute_next = NULL; 2191 } 2192 current_src = current_src->entity_attribute_next; 2193 current_dst = current_dst->entity_attribute_next; 2194 } 2195 2196 return (return_value); 2197 } 2198 2199 2200 /* 2201 * hidparser_find_attribute_end: 2202 * Find the last item in the attribute list pointed to by head 2203 */ 2204 static entity_attribute_t * 2205 hidparser_find_attribute_end(entity_attribute_t *head) 2206 { 2207 if (head == NULL) { 2208 2209 return (NULL); 2210 } 2211 while (head->entity_attribute_next != NULL) { 2212 head = head->entity_attribute_next; 2213 } 2214 2215 return (head); 2216 } 2217 2218 2219 /* 2220 * hidparser_find_item_end: 2221 * Search the siblings of items and find the last item in the list 2222 */ 2223 static entity_item_t * 2224 hidparser_find_item_end(entity_item_t *head) 2225 { 2226 if (!head) { 2227 2228 return (NULL); 2229 } 2230 2231 while (head->entity_item_right_sibling) { 2232 head = head->entity_item_right_sibling; 2233 } 2234 2235 return (head); 2236 } 2237 2238 2239 /* 2240 * hidparser_free_report_descr_handle: 2241 * Free the parse tree pointed to by handle 2242 */ 2243 static void 2244 hidparser_free_report_descr_handle(entity_item_t *handle) 2245 { 2246 entity_item_t *next, *current, *child; 2247 2248 current = handle; 2249 2250 while (current) { 2251 child = current->info.child; 2252 next = current->entity_item_right_sibling; 2253 if (current->entity_item_type == R_ITEM_COLLECTION) { 2254 if (current->entity_item_params != NULL) 2255 kmem_free(current->entity_item_params, 2256 current->entity_item_params_leng); 2257 if (current->entity_item_attributes != NULL) 2258 hidparser_free_attribute_list( 2259 current->entity_item_attributes); 2260 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle, 2261 "FREE 1: %s", 2262 items[current->entity_item_type]); 2263 kmem_free(current, sizeof (entity_item_t)); 2264 (void) hidparser_free_report_descr_handle(child); 2265 } else { 2266 if (current->entity_item_params != NULL) { 2267 kmem_free(current->entity_item_params, 2268 current->entity_item_params_leng); 2269 } 2270 if (current->entity_item_attributes != NULL) { 2271 hidparser_free_attribute_list( 2272 current->entity_item_attributes); 2273 } 2274 USB_DPRINTF_L4(PRINT_MASK_ALL, 2275 hparser_log_handle, "FREE 2: %s", 2276 items[current->entity_item_type]); 2277 kmem_free(current, sizeof (entity_item_t)); 2278 } 2279 current = next; 2280 } 2281 2282 } 2283 2284 2285 /* 2286 * hidparser_free_attribute_list: 2287 * Free the attribute list pointed to by head 2288 */ 2289 static void 2290 hidparser_free_attribute_list(entity_attribute_t *head) 2291 { 2292 entity_attribute_t *next, *current; 2293 2294 current = head; 2295 2296 while (current) { 2297 next = current->entity_attribute_next; 2298 USB_DPRINTF_L4(PRINT_MASK_ALL, 2299 hparser_log_handle, "FREE: %s value_length = %d", 2300 items[current->entity_attribute_tag], 2301 current->entity_attribute_length); 2302 2303 if (current->entity_attribute_value != NULL) { 2304 USB_DPRINTF_L4(PRINT_MASK_ALL, 2305 hparser_log_handle, 2306 "\tvalue = 0x%x", 2307 current->entity_attribute_value[0]); 2308 kmem_free(current->entity_attribute_value, 2309 current->entity_attribute_length); 2310 } 2311 2312 kmem_free(current, sizeof (entity_attribute_t)); 2313 current = next; 2314 } 2315 } 2316 2317 2318 /* 2319 * hidparser_initialize_items: 2320 * Initialize items array before start scanning and parsing. 2321 * This array of strings are used for printing purpose. 2322 */ 2323 static void 2324 hidparser_initialize_items(void) 2325 { 2326 items[R_ITEM_USAGE] = "Usage"; 2327 items[R_ITEM_USAGE_MIN] = "Usage Minimum"; 2328 items[R_ITEM_USAGE_MAX] = "Usage Maximum"; 2329 items[R_ITEM_DESIGNATOR_INDEX] = "Designator Index"; 2330 items[R_ITEM_DESIGNATOR_MIN] = "Designator Minimum"; 2331 items[R_ITEM_DESIGNATOR_MAX] = "Designator Maximum"; 2332 items[R_ITEM_STRING_INDEX] = "String Index"; 2333 items[R_ITEM_STRING_MIN] = "String Minimum"; 2334 items[R_ITEM_STRING_MAX] = "String Maximum"; 2335 2336 2337 items[R_ITEM_USAGE_PAGE] = "Usage Page"; 2338 items[R_ITEM_LOGICAL_MINIMUM] = "Logical Minimum"; 2339 items[R_ITEM_LOGICAL_MAXIMUM] = "Logical Maximum"; 2340 items[R_ITEM_PHYSICAL_MINIMUM] = "Physical Minimum"; 2341 items[R_ITEM_PHYSICAL_MAXIMUM] = "Physical Maximum"; 2342 items[R_ITEM_EXPONENT] = "Exponent"; 2343 items[R_ITEM_UNIT] = "Unit"; 2344 items[R_ITEM_REPORT_SIZE] = "Report Size"; 2345 items[R_ITEM_REPORT_ID] = "Report Id"; 2346 items[R_ITEM_REPORT_COUNT] = "Report Count"; 2347 items[R_ITEM_PUSH] = "Push"; 2348 items[R_ITEM_POP] = "Pop"; 2349 2350 2351 items[R_ITEM_INPUT] = "Input"; 2352 items[R_ITEM_OUTPUT] = "Output"; 2353 items[R_ITEM_COLLECTION] = "Collection"; 2354 items[R_ITEM_FEATURE] = "Feature"; 2355 items[R_ITEM_END_COLLECTION] = "End Collection"; 2356 2357 items[R_ITEM_SET_DELIMITER] = "Delimiter"; 2358 } 2359 2360 2361 /* 2362 * hidparser_scan: 2363 * This function scans the input entity descriptor, sees the data 2364 * length, returns the next token, data bytes and length in the 2365 * scan_ifp structure. 2366 */ 2367 static void 2368 hidparser_scan(hidparser_tok_t *scan_ifp) 2369 { 2370 int count; 2371 int ch; 2372 int parsed_length; 2373 unsigned char *parsed_text; 2374 unsigned char *entity_descriptor; 2375 char err_str[32]; 2376 size_t entity_buffer_size, index; 2377 2378 index = scan_ifp->hidparser_tok_index; 2379 entity_buffer_size = scan_ifp->hidparser_tok_max_bsize; 2380 parsed_length = 0; 2381 parsed_text = scan_ifp->hidparser_tok_text; 2382 entity_descriptor = scan_ifp->hidparser_tok_entity_descriptor; 2383 2384 next_item: 2385 if (index <= entity_buffer_size -1) { 2386 2387 ch = 0xFF & entity_descriptor[index]; 2388 USB_DPRINTF_L4(PRINT_MASK_ALL, 2389 hparser_log_handle, "scanner: index = 0x%lx ch = 0x%x", 2390 index, ch); 2391 2392 index++; 2393 2394 /* 2395 * Error checking: 2396 * Unrecognized items should be passed over 2397 * by the parser. 2398 * Section 5.4 2399 */ 2400 if (!(hidparser_isvalid_item(ch))) { 2401 (void) sprintf(err_str, "%s: 0x%2x", 2402 "Unknown or reserved item", ch); 2403 hidparser_report_err(HIDPARSER_ERR_ERROR, 2404 HIDPARSER_ERR_STANDARD, 0, 0x3F, err_str); 2405 goto next_item; 2406 } 2407 2408 if (ch == EXTENDED_ITEM) { 2409 parsed_length = entity_descriptor[index++]; 2410 ch = entity_descriptor[index++]; 2411 hidparser_report_err(HIDPARSER_ERR_WARN, 2412 HIDPARSER_ERR_STANDARD, 2413 0, 2414 0x3E, 2415 "Long item defined"); 2416 } else { 2417 parsed_length = ch & 0x03; 2418 USB_DPRINTF_L4(PRINT_MASK_ALL, 2419 hparser_log_handle, 2420 "scanner: parsed_length = %x", parsed_length); 2421 /* 3 really means 4.. see p.21 HID */ 2422 if (parsed_length == 3) 2423 parsed_length++; 2424 } 2425 for (count = 0; count < parsed_length; count++) { 2426 parsed_text[count] = entity_descriptor[index]; 2427 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle, 2428 "scanner: parsed_text[%d] = 0x%x," 2429 "index = 0x%lx", 2430 count, parsed_text[count], index); 2431 index++; 2432 } 2433 2434 USB_DPRINTF_L4(PRINT_MASK_ALL, 2435 hparser_log_handle, "scanner: lexical analyzer found 0x%x " 2436 "before translation", ch); 2437 2438 scan_ifp->hidparser_tok_index = index; 2439 scan_ifp->hidparser_tok_leng = parsed_length; 2440 scan_ifp->hidparser_tok_token = ch & 0xFC; 2441 USB_DPRINTF_L4(PRINT_MASK_ALL, 2442 hparser_log_handle, "scanner: aindex = 0x%lx", index); 2443 } else { 2444 USB_DPRINTF_L4(PRINT_MASK_ALL, 2445 hparser_log_handle, "scanner: eindex = 0x%lx", index); 2446 scan_ifp->hidparser_tok_leng = 0; 2447 scan_ifp->hidparser_tok_token = 0; /* EOF */ 2448 } 2449 } 2450 2451 2452 /* 2453 * hidparser_report_err: 2454 * Construct and print the error code 2455 * Ref: Hidview error check list 2456 */ 2457 static void 2458 hidparser_report_err(int err_level, 2459 int err_type, 2460 int tag, 2461 int subcode, 2462 char *msg) 2463 { 2464 unsigned int BmParserErrorCode = 0; 2465 2466 if (err_level) { 2467 BmParserErrorCode |= HIDPARSER_ERR_ERROR; 2468 } 2469 if (err_type) { 2470 BmParserErrorCode |= HIDPARSER_ERR_STANDARD; 2471 } 2472 BmParserErrorCode |= (tag << 8) & HIDPARSER_ERR_TAG_MASK; 2473 BmParserErrorCode |= subcode & HIDPARSER_ERR_SUBCODE_MASK; 2474 2475 if (err_level) { 2476 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 2477 "err code = 0x%4x, err str = %s", 2478 BmParserErrorCode, msg); 2479 2480 } else { 2481 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 2482 "wrn code = 0x%4x, wrn str = %s", 2483 BmParserErrorCode, msg); 2484 } 2485 } 2486 2487 2488 /* 2489 * hidparser_isvalid_item: 2490 * Find if the item tag is a valid one 2491 */ 2492 static int 2493 hidparser_isvalid_item(int tag) 2494 { 2495 if (tag == EXTENDED_ITEM) { 2496 2497 return (1); 2498 } 2499 2500 tag &= 0xFC; 2501 if ((tag == R_ITEM_INPUT) || 2502 (tag == R_ITEM_OUTPUT) || 2503 (tag == R_ITEM_COLLECTION) || 2504 (tag == R_ITEM_FEATURE) || 2505 (tag == R_ITEM_END_COLLECTION) || 2506 (tag == R_ITEM_USAGE_PAGE) || 2507 (tag == R_ITEM_LOGICAL_MINIMUM) || 2508 (tag == R_ITEM_LOGICAL_MAXIMUM) || 2509 (tag == R_ITEM_PHYSICAL_MINIMUM) || 2510 (tag == R_ITEM_PHYSICAL_MAXIMUM) || 2511 (tag == R_ITEM_EXPONENT) || 2512 (tag == R_ITEM_UNIT) || 2513 (tag == R_ITEM_REPORT_SIZE) || 2514 (tag == R_ITEM_REPORT_ID) || 2515 (tag == R_ITEM_REPORT_COUNT) || 2516 (tag == R_ITEM_PUSH) || 2517 (tag == R_ITEM_POP) || 2518 (tag == R_ITEM_USAGE) || 2519 (tag == R_ITEM_USAGE_MIN) || 2520 (tag == R_ITEM_USAGE_MAX) || 2521 (tag == R_ITEM_DESIGNATOR_INDEX) || 2522 (tag == R_ITEM_DESIGNATOR_MIN) || 2523 (tag == R_ITEM_DESIGNATOR_MAX) || 2524 (tag == R_ITEM_STRING_INDEX) || 2525 (tag == R_ITEM_STRING_MIN) || 2526 (tag == R_ITEM_STRING_MAX) || 2527 (tag == R_ITEM_SET_DELIMITER)) { 2528 2529 return (1); 2530 } else { 2531 2532 return (0); 2533 } 2534 } 2535 2536 2537 /* 2538 * hidparser_lookup_attribute: 2539 * Takes an item pointer(report structure) and a tag(e.g Logical 2540 * Min) as input. Returns the corresponding attribute structure. 2541 * Presently used for error checking only. 2542 */ 2543 static entity_attribute_t * 2544 hidparser_lookup_attribute(entity_item_t *item, int attr_tag) 2545 { 2546 entity_attribute_t *temp; 2547 2548 if (item == NULL) { 2549 2550 return (NULL); 2551 } 2552 2553 temp = item->entity_item_attributes; 2554 while (temp != NULL) { 2555 if (temp->entity_attribute_tag == attr_tag) { 2556 2557 return (temp); 2558 } 2559 2560 temp = temp->entity_attribute_next; 2561 } 2562 2563 return (NULL); 2564 } 2565 2566 2567 /* 2568 * hidparser_global_err_check: 2569 * Error checking for Global Items that need to be 2570 * performed in MainItem 2571 */ 2572 static void 2573 hidparser_global_err_check(entity_item_t *mainitem) 2574 { 2575 hidparser_check_minmax_val_signed(mainitem, R_ITEM_LOGICAL_MINIMUM, 2576 R_ITEM_LOGICAL_MAXIMUM, 0, 0); 2577 hidparser_check_minmax_val_signed(mainitem, R_ITEM_PHYSICAL_MINIMUM, 2578 R_ITEM_PHYSICAL_MAXIMUM, 0, 0); 2579 hidparser_check_correspondence(mainitem, R_ITEM_PHYSICAL_MINIMUM, 2580 R_ITEM_PHYSICAL_MAXIMUM, 0, 0, 2581 "Must have a corresponding Physical min", 2582 "Must have a corresponding Physical max"); 2583 hidparser_check_correspondence(mainitem, R_ITEM_PUSH, R_ITEM_POP, 2584 1, 0, "Should have a corresponding Pop", 2585 "Must have a corresponding Push"); 2586 2587 } 2588 2589 2590 /* 2591 * hidparser_mainitem_err_check: 2592 * Error checking for Main Items 2593 */ 2594 static void 2595 hidparser_mainitem_err_check(entity_item_t *mainitem) 2596 { 2597 int itemmask = 0; 2598 entity_attribute_t *attr; 2599 2600 attr = mainitem->entity_item_attributes; 2601 2602 if (attr != NULL) { 2603 while (attr) { 2604 switch (attr->entity_attribute_tag) { 2605 case R_ITEM_LOGICAL_MINIMUM: 2606 itemmask |= 0x01; 2607 break; 2608 case R_ITEM_LOGICAL_MAXIMUM: 2609 itemmask |= 0x02; 2610 break; 2611 case R_ITEM_REPORT_SIZE: 2612 itemmask |= 0x04; 2613 break; 2614 case R_ITEM_REPORT_COUNT: 2615 itemmask |= 0x08; 2616 break; 2617 case R_ITEM_USAGE_PAGE: 2618 itemmask |= 0x10; 2619 break; 2620 default: 2621 break; 2622 } /* switch */ 2623 attr = attr->entity_attribute_next; 2624 } /* while */ 2625 } /* if */ 2626 2627 if ((mainitem->entity_item_type == R_ITEM_COLLECTION) || 2628 (mainitem->entity_item_type == R_ITEM_END_COLLECTION)) { 2629 2630 return; 2631 } 2632 if (itemmask != 0x1f) { 2633 hidparser_report_err( 2634 HIDPARSER_ERR_ERROR, 2635 HIDPARSER_ERR_STANDARD, 2636 mainitem->entity_item_type, 2637 0, 2638 "Required Global/Local items must be defined"); 2639 } 2640 } 2641 2642 2643 /* 2644 * hidparser_local_err_check: 2645 * Error checking for Local items that is done when a MainItem 2646 * is encountered 2647 */ 2648 static void 2649 hidparser_local_err_check(entity_item_t *mainitem) 2650 { 2651 hidparser_check_correspondence(mainitem, R_ITEM_USAGE_MIN, 2652 R_ITEM_USAGE_MAX, 0, 0, 2653 "Must have a corresponding Usage Min", 2654 "Must have a corresponding Usage Max"); 2655 hidparser_check_minmax_val(mainitem, R_ITEM_USAGE_MIN, 2656 R_ITEM_USAGE_MAX, 1, 1); 2657 hidparser_check_correspondence(mainitem, R_ITEM_DESIGNATOR_MIN, 2658 R_ITEM_DESIGNATOR_MAX, 0, 0, 2659 "Must have a corresponding Designator min", 2660 "Must have a corresponding Designator Max"); 2661 hidparser_check_minmax_val(mainitem, R_ITEM_DESIGNATOR_MIN, 2662 R_ITEM_DESIGNATOR_MAX, 1, 1); 2663 hidparser_check_correspondence(mainitem, R_ITEM_STRING_MIN, 2664 R_ITEM_STRING_MAX, 0, 0, 2665 "Must have a corresponding String min", 2666 "Must have a corresponding String Max"); 2667 hidparser_check_minmax_val(mainitem, R_ITEM_STRING_MIN, 2668 R_ITEM_STRING_MAX, 1, 1); 2669 } 2670 2671 2672 /* 2673 * hidparser_find_unsigned_val: 2674 * Find the value for multibyte data 2675 * Ref: Section 5.8 of HID Spec 1.0 2676 */ 2677 static unsigned int 2678 hidparser_find_unsigned_val(entity_attribute_t *attr) 2679 { 2680 char *text; 2681 int len, i; 2682 unsigned int ret = 0; 2683 2684 text = attr->entity_attribute_value; 2685 len = attr->entity_attribute_length; 2686 for (i = 0; i < len; i++) { 2687 ret |= ((text[i] & 0xff) << (8*i)); 2688 } 2689 2690 return (ret); 2691 } 2692 2693 2694 /* 2695 * hidparser_find_signed_val: 2696 * Find the value for signed multibyte data 2697 * Ref: Section 5.8 of HID Spec 1.0 2698 */ 2699 static signed int 2700 hidparser_find_signed_val(entity_attribute_t *attr) 2701 { 2702 char *text; 2703 int len, i; 2704 int ret = 0; 2705 2706 text = attr->entity_attribute_value; 2707 len = attr->entity_attribute_length; 2708 2709 for (i = 0; i < len - 1; i++) { 2710 ret |= ((text[i] & 0xff) << (8 * i)); 2711 } 2712 2713 if (len > 0) { 2714 ret |= (text[i] << (8 * i)); 2715 } 2716 2717 return (ret); 2718 } 2719 2720 2721 /* 2722 * hidparser_check_correspondence: 2723 * Check if the item item2 corresponding to item1 exists and vice versa 2724 * If not report the appropriate error 2725 */ 2726 static void 2727 hidparser_check_correspondence(entity_item_t *mainitem, 2728 int item_tag1, 2729 int item_tag2, 2730 int val1, 2731 int val2, 2732 char *str1, 2733 char *str2) 2734 { 2735 entity_attribute_t *temp1, *temp2; 2736 2737 temp1 = hidparser_lookup_attribute(mainitem, item_tag1); 2738 temp2 = hidparser_lookup_attribute(mainitem, item_tag2); 2739 if ((temp1 != NULL) && (temp2 == NULL)) { 2740 hidparser_report_err( 2741 HIDPARSER_ERR_ERROR, 2742 HIDPARSER_ERR_STANDARD, 2743 item_tag1, 2744 val1, 2745 str1); 2746 } 2747 if ((temp2 != NULL) && (temp1 == NULL)) { 2748 hidparser_report_err( 2749 HIDPARSER_ERR_ERROR, 2750 HIDPARSER_ERR_STANDARD, 2751 item_tag2, 2752 val2, 2753 str2); 2754 } 2755 } 2756 2757 2758 /* 2759 * hidparser_check_minmax_val: 2760 * Check if the Min value <= Max and vice versa 2761 * Print for warnings and errors have been taken care separately. 2762 */ 2763 static void 2764 hidparser_check_minmax_val(entity_item_t *mainitem, 2765 int item_tag1, 2766 int item_tag2, 2767 int val1, 2768 int val2) 2769 { 2770 entity_attribute_t *temp1, *temp2; 2771 2772 temp1 = hidparser_lookup_attribute(mainitem, item_tag1); 2773 temp2 = hidparser_lookup_attribute(mainitem, item_tag2); 2774 if ((temp1 != NULL) && (temp2 != NULL)) { 2775 if (hidparser_find_unsigned_val(temp1) > 2776 hidparser_find_unsigned_val(temp2)) { 2777 if ((item_tag1 == R_ITEM_LOGICAL_MINIMUM) || 2778 (item_tag1 == R_ITEM_PHYSICAL_MINIMUM)) { 2779 hidparser_report_err( 2780 HIDPARSER_ERR_WARN, 2781 HIDPARSER_ERR_STANDARD, 2782 item_tag1, 2783 val1, 2784 "unsigned: Min should be <= to Max"); 2785 } else { 2786 hidparser_report_err( 2787 HIDPARSER_ERR_ERROR, 2788 HIDPARSER_ERR_STANDARD, 2789 item_tag1, 2790 val1, 2791 "Min must be <= to Max"); 2792 } 2793 } 2794 if (hidparser_find_unsigned_val(temp2) < 2795 hidparser_find_unsigned_val(temp1)) { 2796 if ((item_tag2 == R_ITEM_LOGICAL_MAXIMUM) || 2797 (item_tag2 == R_ITEM_PHYSICAL_MAXIMUM)) { 2798 hidparser_report_err( 2799 HIDPARSER_ERR_ERROR, 2800 HIDPARSER_ERR_STANDARD, 2801 item_tag2, 2802 val2, 2803 "unsigned: Max should be >= to Min"); 2804 } else { 2805 hidparser_report_err( 2806 HIDPARSER_ERR_ERROR, 2807 HIDPARSER_ERR_STANDARD, 2808 item_tag2, 2809 val2, 2810 "Max must be >= to Min"); 2811 } 2812 } 2813 } /* if (temp1 != NULL) && (temp2 != NULL) */ 2814 } 2815 2816 2817 /* 2818 * hidparser_check_minmax_val_signed: 2819 * Check if the Min value <= Max and vice versa 2820 * Print for warnings and errors have been taken care separately. 2821 */ 2822 static void 2823 hidparser_check_minmax_val_signed(entity_item_t *mainitem, 2824 int item_tag1, 2825 int item_tag2, 2826 int val1, 2827 int val2) 2828 { 2829 entity_attribute_t *temp1, *temp2; 2830 2831 temp1 = hidparser_lookup_attribute(mainitem, item_tag1); 2832 temp2 = hidparser_lookup_attribute(mainitem, item_tag2); 2833 if ((temp1 != NULL) && (temp2 != NULL)) { 2834 if (hidparser_find_signed_val(temp1) > 2835 hidparser_find_signed_val(temp2)) { 2836 if ((item_tag1 == R_ITEM_LOGICAL_MINIMUM) || 2837 (item_tag1 == R_ITEM_PHYSICAL_MINIMUM)) { 2838 hidparser_report_err( 2839 HIDPARSER_ERR_WARN, 2840 HIDPARSER_ERR_STANDARD, 2841 item_tag1, 2842 val1, 2843 "signed: Min should be <= to Max"); 2844 } else { 2845 hidparser_report_err( 2846 HIDPARSER_ERR_ERROR, 2847 HIDPARSER_ERR_STANDARD, 2848 item_tag1, 2849 val1, 2850 "Min must be <= to Max"); 2851 } 2852 } 2853 if (hidparser_find_signed_val(temp2) < 2854 hidparser_find_signed_val(temp1)) { 2855 if ((item_tag2 == R_ITEM_LOGICAL_MAXIMUM) || 2856 (item_tag2 == R_ITEM_PHYSICAL_MAXIMUM)) { 2857 hidparser_report_err( 2858 HIDPARSER_ERR_ERROR, 2859 HIDPARSER_ERR_STANDARD, 2860 item_tag2, 2861 val2, 2862 "signed: Max should be >= to Min"); 2863 } else { 2864 hidparser_report_err( 2865 HIDPARSER_ERR_ERROR, 2866 HIDPARSER_ERR_STANDARD, 2867 item_tag2, 2868 val2, 2869 "Max must be >= to Min"); 2870 } 2871 } 2872 } /* if (temp1 != NULL) && (temp2 != NULL) */ 2873 } 2874 2875 2876 /* 2877 * hidparser_error_delim: 2878 * Error check for Delimiter Sets 2879 */ 2880 static void 2881 hidparser_error_delim(entity_item_t *item, int err) 2882 { 2883 entity_attribute_t *attr; 2884 switch (err) { 2885 case HIDPARSER_DELIM_ERR1: 2886 hidparser_report_err( 2887 HIDPARSER_ERR_ERROR, 2888 HIDPARSER_ERR_STANDARD, 2889 R_ITEM_SET_DELIMITER, 2890 0, 2891 "Must be Delimiter Open"); 2892 2893 break; 2894 case HIDPARSER_DELIM_ERR2: 2895 hidparser_report_err( 2896 HIDPARSER_ERR_ERROR, 2897 HIDPARSER_ERR_STANDARD, 2898 R_ITEM_SET_DELIMITER, 2899 0, 2900 "Must be Delimiter Close"); 2901 2902 break; 2903 case HIDPARSER_DELIM_ERR3: 2904 attr = item->entity_item_attributes; 2905 while (attr != NULL) { 2906 if ((attr->entity_attribute_tag != 2907 R_ITEM_USAGE) && 2908 (attr->entity_attribute_tag != 2909 R_ITEM_USAGE_MIN) && 2910 (attr->entity_attribute_tag != 2911 R_ITEM_USAGE_MAX)) { 2912 hidparser_report_err( 2913 HIDPARSER_ERR_ERROR, 2914 HIDPARSER_ERR_STANDARD, 2915 R_ITEM_SET_DELIMITER, 2916 3, 2917 "May only contain Usage, " 2918 "Usage Min and Usage Max"); 2919 } 2920 attr = attr->entity_attribute_next; 2921 } 2922 2923 break; 2924 default: 2925 2926 break; 2927 } 2928 } 2929 2930 2931 /* 2932 * hidparser_find_max_packet_size_from_report_descriptor: 2933 * find packet size of the largest report in the report descriptor 2934 */ 2935 void 2936 hidparser_find_max_packet_size_from_report_descriptor( 2937 hidparser_handle_t hparser_handle, 2938 hidparser_packet_info_t *hpack) 2939 { 2940 2941 int rval, i; 2942 uint_t packet_size; 2943 uint_t max_packet_size; 2944 uint_t max_report_id; 2945 hidparser_report_id_list_t report_id_list; 2946 2947 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle, 2948 "hidparser_find_max_packet_size_from_report_descriptor"); 2949 2950 /* get a list of input reports */ 2951 rval = hidparser_get_report_id_list(hparser_handle, 2952 R_ITEM_INPUT, &report_id_list); 2953 if (rval != HIDPARSER_SUCCESS) { 2954 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 2955 "No report id used"); 2956 } else { 2957 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle, 2958 "%d unique report IDs found in hid report descriptor", 2959 report_id_list.no_of_report_ids); 2960 2961 for (i = 0; i < (report_id_list.no_of_report_ids); i++) { 2962 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle, 2963 "report_id: %d", report_id_list.report_id[i]); 2964 } 2965 } 2966 2967 if ((rval != HIDPARSER_SUCCESS) || 2968 (report_id_list.no_of_report_ids == 0)) { 2969 /* 2970 * since no report id is used, get the packet size 2971 * for the only report available 2972 */ 2973 (void) hidparser_get_packet_size(hparser_handle, 2974 0, R_ITEM_INPUT, &packet_size); 2975 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 2976 "Not using report id prefix. HID packet size = %d", 2977 packet_size); 2978 2979 hpack->max_packet_size = packet_size; 2980 hpack->report_id = HID_REPORT_ID_UNDEFINED; 2981 } else { 2982 /* 2983 * hid device uses multiple reports with report id prefix byte. 2984 * Find the longest input report. 2985 * See HID 8.4. 2986 */ 2987 max_packet_size = 0; 2988 max_report_id = 0; 2989 2990 for (i = 0; i < (report_id_list.no_of_report_ids); i++) { 2991 (void) hidparser_get_packet_size(hparser_handle, 2992 report_id_list.report_id[i], R_ITEM_INPUT, 2993 &packet_size); 2994 if (packet_size > max_packet_size) { 2995 max_packet_size = packet_size; 2996 max_report_id = report_id_list.report_id[i]; 2997 } 2998 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 2999 "Report ID %d has a packet size of %d", 3000 report_id_list.report_id[i], packet_size); 3001 } 3002 3003 hpack->max_packet_size = max_packet_size; 3004 hpack->report_id = max_report_id; 3005 3006 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 3007 "Report ID %d has the maximum packet size of %d", 3008 max_report_id, max_packet_size); 3009 } 3010 } 3011