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