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