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 #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--; count++) 1294 indent_space[count] = ' '; 1295 1296 indent_space[count] = 0; 1297 1298 attr = entity->entity_item_attributes; 1299 while (attr) { 1300 hidparser_print_this_attribute(attr, indent_space); 1301 attr = attr->entity_attribute_next; 1302 } 1303 1304 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle, "%s%s(0x%x)", 1305 indent_space, items[entity->entity_item_type], 1306 (entity->entity_item_params_leng ? 1307 entity->entity_item_params[0] & 0xFF : 0x00)); 1308 } 1309 1310 1311 /* 1312 * hidparser_print_this_attribute: 1313 * Prints the attribute passed in the argument 1314 */ 1315 static void 1316 hidparser_print_this_attribute(entity_attribute_t *attribute, 1317 char *ident_space) 1318 { 1319 if (ident_space == NULL) { 1320 1321 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle, 1322 "%s(0x%X)", 1323 items[attribute->entity_attribute_tag], 1324 hidparser_find_unsigned_val(attribute)); 1325 } else { 1326 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle, 1327 "%s%s(0x%X)", ident_space, 1328 items[attribute->entity_attribute_tag], 1329 hidparser_find_unsigned_val(attribute)); 1330 1331 } 1332 } 1333 1334 1335 /* 1336 * The next few functions will be used for parsing using the 1337 * grammar: 1338 * 1339 * Start -> ReportDescriptor <EOF> 1340 * 1341 * ReportDescriptor -> ItemList 1342 * 1343 * ItemList -> Items MainItem ItemList 1344 * | epsilon 1345 * 1346 * MainItem -> BeginCollection ItemList EndCollection 1347 * | Input 1348 * | Output 1349 * | Feature 1350 * 1351 * Items -> GlobalItem Items 1352 * | LocalItem Items 1353 * | SetDelimiterOpen LocalItemList 1354 * SetDelimiterClose Items 1355 * | epsilon 1356 * 1357 * LocalItemList -> LocalItem Temp2 1358 * 1359 * Temp2 -> LocalItem Temp2 1360 * | epsilon 1361 * 1362 * GlobalItem -> UsagePage 1363 * | LogicalMinimum 1364 * | LogicalMaximum 1365 * | PhysicalMinimum 1366 * | PhysicalMaximum 1367 * | Unit 1368 * | Exponent 1369 * | ReportSize 1370 * | ReportCount 1371 * | ReportID 1372 * 1373 * LocalItem -> Usage 1374 * | UsageMinimum 1375 * | UsageMaximum 1376 * | DesignatorIndex 1377 * | DesignatorMinimum 1378 * | StringIndex 1379 * | StringMinimum 1380 * | StringMaximum 1381 * 1382 */ 1383 1384 1385 /* 1386 * hidparser_lookup_first: 1387 * Looks up if token belongs to the FIRST of the function tag 1388 * that is passed through the first argument 1389 */ 1390 static int 1391 hidparser_lookup_first(int func_index, 1392 int token) 1393 { 1394 int *itemp; 1395 1396 itemp = hid_first_list[func_index]; 1397 while (*itemp != 0) { 1398 /* get the next terminal on the list */ 1399 if (*itemp == token) { 1400 1401 return (HIDPARSER_SUCCESS); 1402 } 1403 itemp++; 1404 } 1405 1406 /* token is not on the FIRST list */ 1407 1408 return (HIDPARSER_FAILURE); 1409 } 1410 1411 1412 /* 1413 * hidparser_main: 1414 * Function called from hidparser_parse_report_descriptor() 1415 * to parse the Report Descriptor 1416 */ 1417 static int 1418 hidparser_main(unsigned char *descriptor, 1419 size_t size, 1420 entity_item_t **item_ptr) 1421 { 1422 hidparser_tok_t *scan_ifp; 1423 int retval; 1424 1425 scan_ifp = kmem_zalloc(sizeof (hidparser_tok_t), KM_SLEEP); 1426 scan_ifp->hidparser_tok_text = 1427 kmem_zalloc(HIDPARSER_TEXT_LENGTH, KM_SLEEP); 1428 scan_ifp->hidparser_tok_max_bsize = size; 1429 scan_ifp->hidparser_tok_entity_descriptor = descriptor; 1430 1431 *item_ptr = NULL; 1432 retval = hidparser_ReportDescriptorDash(item_ptr, scan_ifp); 1433 1434 /* 1435 * Free the Local & Global item list 1436 * It maybe the case that no tree has been built 1437 * up but there have been allocation in the attribute 1438 * & control lists 1439 */ 1440 if (scan_ifp->hidparser_tok_gitem_head) { 1441 hidparser_free_attribute_list( 1442 scan_ifp->hidparser_tok_gitem_head); 1443 } 1444 1445 if (scan_ifp->hidparser_tok_litem_head) { 1446 hidparser_free_attribute_list( 1447 scan_ifp->hidparser_tok_litem_head); 1448 } 1449 kmem_free(scan_ifp->hidparser_tok_text, HIDPARSER_TEXT_LENGTH); 1450 kmem_free(scan_ifp, sizeof (hidparser_tok_t)); 1451 1452 return (retval); 1453 } 1454 1455 1456 /* 1457 * hidparser_ReportDescriptorDash: 1458 * Synthetic start symbol, implements 1459 * hidparser_ReportDescriptor <EOF> 1460 */ 1461 static int 1462 hidparser_ReportDescriptorDash(entity_item_t ** item_ptr, 1463 hidparser_tok_t *scan_ifp) 1464 { 1465 1466 if ((hidparser_ReportDescriptor(item_ptr, scan_ifp) == 1467 HIDPARSER_SUCCESS) && (scan_ifp->hidparser_tok_token == 0)) { 1468 1469 return (HIDPARSER_SUCCESS); 1470 } 1471 1472 /* 1473 * In case of failure, free the kernel memory 1474 * allocated for partial building of the tree, 1475 * if any 1476 */ 1477 if (*item_ptr != NULL) { 1478 (void) hidparser_free_report_descr_handle(*item_ptr); 1479 } 1480 1481 *item_ptr = NULL; 1482 1483 return (HIDPARSER_FAILURE); 1484 } 1485 1486 1487 /* 1488 * hidparser_ReportDescriptor: 1489 * Implements the Rule: 1490 * ReportDescriptor -> ItemList 1491 */ 1492 static int 1493 hidparser_ReportDescriptor(entity_item_t ** item_ptr, 1494 hidparser_tok_t *scan_ifp) 1495 { 1496 hidparser_scan(scan_ifp); 1497 1498 /* 1499 * We do not search for the token in FIRST(ReportDescriptor) 1500 * since - 1501 * 1502 * FIRST(ReportDescriptor) == FIRST(ItemList) 1503 * ReportDescriptor ----> ItemList 1504 */ 1505 if (hidparser_ItemList(item_ptr, scan_ifp) == HIDPARSER_SUCCESS) { 1506 1507 return (HIDPARSER_SUCCESS); 1508 } 1509 1510 return (HIDPARSER_FAILURE); 1511 } 1512 1513 1514 /* 1515 * hidparser_ItemList: 1516 * Implements the Rule: 1517 * ItemList -> Items MainItem ItemList | epsilon 1518 * 1519 * This function constructs the tree on which depends the "hidparser" 1520 * consumer functions. Basically the structure of the tree is 1521 * 1522 * C--[RS]->EC--[RS]->C--[RS]->EC..(and so on) 1523 * | 1524 * [CH] <== This relationship is true for other "C's" 1525 * | also. 1526 * v 1527 * C/-------------/I/O/F <== [ Any of these ] 1528 * | ------ 1529 * | | 1530 * v v 1531 * [CH | RS] [ RS ] 1532 * C/I/O/F | EC I/O/F 1533 * | 1534 * | 1535 * and so on... 1536 * 1537 * where C = Collection 1538 * EC = EndCollection 1539 * I = Input 1540 * O = Output 1541 * F = Feature "Main" Items. 1542 * 1543 * and the relationships are [RS] for right sibling and [CH] for 1544 * child. [CH | RS ] stands for "child or right sibling" with the 1545 * possible values below it. 1546 */ 1547 static int 1548 hidparser_ItemList(entity_item_t ** item_ptr, hidparser_tok_t *scan_ifp) 1549 { 1550 entity_item_t *curr_ei, *cache_ei, *prev_ei, *tmp_ei; 1551 boolean_t root_coll = B_FALSE; 1552 1553 curr_ei = cache_ei = prev_ei = tmp_ei = NULL; 1554 1555 while (scan_ifp->hidparser_tok_token != 0) { 1556 if (hidparser_Items(scan_ifp) == HIDPARSER_FAILURE) { 1557 1558 return (HIDPARSER_FAILURE); 1559 } 1560 1561 if (hidparser_MainItem(&curr_ei, scan_ifp) == 1562 HIDPARSER_FAILURE) { 1563 USB_DPRINTF_L2(PRINT_MASK_ALL, 1564 hparser_log_handle, 1565 "Invalid MAIN item 0x%x in input stream", 1566 scan_ifp->hidparser_tok_token); 1567 1568 return (HIDPARSER_FAILURE); 1569 } 1570 if (curr_ei->entity_item_type == R_ITEM_COLLECTION) { 1571 if (root_coll == B_FALSE) { 1572 *item_ptr = curr_ei; 1573 root_coll = B_TRUE; 1574 } 1575 curr_ei->prev_coll = cache_ei; 1576 cache_ei = curr_ei; 1577 1578 USB_DPRINTF_L3(PRINT_MASK_ALL, 1579 hparser_log_handle, 1580 "Start Collection:cache_ei = 0x%p," 1581 " curr_ei = 0x%p", 1582 (void *)cache_ei, (void *)curr_ei); 1583 1584 if (prev_ei == NULL) { 1585 prev_ei = curr_ei; 1586 1587 continue; 1588 } 1589 if (prev_ei->entity_item_type == 1590 R_ITEM_COLLECTION) { 1591 prev_ei->info.child = curr_ei; 1592 } else { 1593 prev_ei->entity_item_right_sibling = 1594 curr_ei; 1595 } 1596 } else if (curr_ei->entity_item_type == 1597 R_ITEM_END_COLLECTION) { 1598 tmp_ei = cache_ei->prev_coll; 1599 cache_ei->entity_item_right_sibling = curr_ei; 1600 USB_DPRINTF_L3(PRINT_MASK_ALL, 1601 hparser_log_handle, 1602 "End Collection: cache_ei = 0x%p, " 1603 "curr_ei = 0x%p", 1604 (void *)cache_ei, (void *)curr_ei); 1605 if (tmp_ei != NULL) { 1606 /* 1607 * As will be the case for final end 1608 * collection. 1609 */ 1610 cache_ei = tmp_ei; 1611 } 1612 tmp_ei = NULL; 1613 } else { 1614 if (prev_ei->entity_item_type == 1615 R_ITEM_COLLECTION) { 1616 USB_DPRINTF_L3(PRINT_MASK_ALL, 1617 hparser_log_handle, 1618 "Main Item: token = 0x%x, " 1619 "curr_ei = 0x%p " 1620 "will be the child of prev_ei " 1621 "= 0x%p, " 1622 "cache_ei being 0x%p", 1623 curr_ei->entity_item_type, 1624 (void *)curr_ei, (void *)prev_ei, 1625 (void *)cache_ei); 1626 prev_ei->info.child = curr_ei; 1627 } else { 1628 USB_DPRINTF_L3(PRINT_MASK_ALL, 1629 hparser_log_handle, 1630 "Main Item: token = 0x%x, " 1631 "curr_ei = 0x%p " 1632 "will be the right sibling of " 1633 "prev_ei = 0x%p, " 1634 "cache_ei being 0x%p", 1635 curr_ei->entity_item_type, 1636 (void *)curr_ei, (void *)prev_ei, 1637 (void *)cache_ei); 1638 prev_ei->entity_item_right_sibling = 1639 curr_ei; 1640 } 1641 } 1642 prev_ei = curr_ei; 1643 } 1644 if (*item_ptr != cache_ei) { 1645 /* Something wrong happened */ 1646 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 1647 "Failed to parse report descriptor"); 1648 1649 return (HIDPARSER_FAILURE); 1650 } 1651 (void) hidparser_print_report_descr_handle(cache_ei, 0); 1652 1653 return (HIDPARSER_SUCCESS); 1654 } 1655 1656 1657 /* 1658 * hidparser_MainItem: 1659 * Implements the Rule: 1660 * MainItem -> BeginCollection ItemList EndCollection 1661 * | Input 1662 * | Output 1663 * | Feature 1664 */ 1665 static int 1666 hidparser_MainItem(entity_item_t ** item_ptr, 1667 hidparser_tok_t *scan_ifp) 1668 { 1669 switch (scan_ifp->hidparser_tok_token) { 1670 case R_ITEM_INPUT: 1671 /* FALLTHRU */ 1672 case R_ITEM_OUTPUT: 1673 /* FALLTHRU */ 1674 case R_ITEM_FEATURE: 1675 case R_ITEM_COLLECTION: 1676 case R_ITEM_END_COLLECTION: 1677 *item_ptr = hidparser_allocate_entity(scan_ifp); 1678 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle, 1679 "hidparser_MainItem:index = 0x%lx token = 0x%x", 1680 scan_ifp->hidparser_tok_index - 1681 (*item_ptr)->entity_item_params_leng - 1, 1682 scan_ifp->hidparser_tok_token); 1683 hidparser_scan(scan_ifp); 1684 hidparser_global_err_check(*item_ptr); 1685 hidparser_local_err_check(*item_ptr); 1686 hidparser_mainitem_err_check(*item_ptr); 1687 1688 return (HIDPARSER_SUCCESS); 1689 1690 default: 1691 break; 1692 } 1693 1694 *item_ptr = NULL; 1695 1696 return (HIDPARSER_FAILURE); 1697 } 1698 1699 1700 /* 1701 * hidparser_Items: 1702 * Implements the Rule: 1703 * Items -> GlobalItem Items 1704 * | LocalItem Items 1705 * | SetDelimiterOpen LocalItemList 1706 * SetDelimiterClose Items 1707 * | epsilon 1708 */ 1709 static int 1710 hidparser_Items(hidparser_tok_t *scan_ifp) 1711 { 1712 boolean_t delim_pre = B_FALSE; 1713 1714 int token = scan_ifp->hidparser_tok_token; 1715 1716 while (hidparser_lookup_first(HIDPARSER_ITEMS, token) == 1717 HIDPARSER_SUCCESS) { 1718 if (token == R_ITEM_SET_DELIMITER) { 1719 if (delim_pre == B_FALSE) { 1720 if (scan_ifp->hidparser_tok_text[0] != 1) { 1721 hidparser_error_delim(NULL, 1722 HIDPARSER_DELIM_ERR1); 1723 } else { 1724 delim_pre = B_TRUE; 1725 } 1726 } else { 1727 if (scan_ifp->hidparser_tok_text[0] != 1728 0) { 1729 hidparser_error_delim(NULL, 1730 HIDPARSER_DELIM_ERR2); 1731 } else { 1732 delim_pre = B_FALSE; 1733 } 1734 } 1735 (void) hidparser_LocalItem(scan_ifp); 1736 token = scan_ifp->hidparser_tok_token; 1737 } else if (hidparser_GlobalItem(scan_ifp) == 1738 HIDPARSER_SUCCESS) { 1739 token = scan_ifp->hidparser_tok_token; 1740 } else if (hidparser_LocalItem(scan_ifp) == HIDPARSER_SUCCESS) { 1741 token = scan_ifp->hidparser_tok_token; 1742 } 1743 } 1744 1745 return (HIDPARSER_SUCCESS); /* epsilon */ 1746 } 1747 1748 1749 /* 1750 * hidparser_GlobalItem: 1751 * Implements the Rule: 1752 * GlobalItem -> UsagePage 1753 * | LogicalMinimum 1754 * | LocgicalMaximum 1755 * | PhysicalMinimum 1756 * | PhysicalMaximum 1757 * | Unit 1758 * | Exponent 1759 * | ReportSize 1760 * | ReportCount 1761 * | ReportID 1762 */ 1763 static int 1764 hidparser_GlobalItem(hidparser_tok_t *scan_ifp) 1765 { 1766 1767 int i; 1768 entity_attribute_stack_t *elem; 1769 1770 switch (scan_ifp->hidparser_tok_token) { 1771 case R_ITEM_USAGE_PAGE: 1772 /* Error check */ 1773 for (i = 0; i < scan_ifp->hidparser_tok_leng; i++) { 1774 /* Undefined data value: 0 */ 1775 if (scan_ifp->hidparser_tok_text[i] == 0) { 1776 hidparser_report_err( 1777 HIDPARSER_ERR_WARN, 1778 HIDPARSER_ERR_STANDARD, 1779 R_ITEM_USAGE_PAGE, 1780 0, 1781 "Data field should be non-Zero"); 1782 } 1783 /* Reserved values 0x0A-0xFE */ 1784 else if ((scan_ifp->hidparser_tok_text[i] >= 1785 0x0a) && 1786 (scan_ifp->hidparser_tok_text[i] <= 1787 0xFE)) { 1788 hidparser_report_err( 1789 HIDPARSER_ERR_WARN, 1790 HIDPARSER_ERR_STANDARD, 1791 R_ITEM_USAGE_PAGE, 1792 1, 1793 "Data field should not use " 1794 "reserved values"); 1795 } 1796 } 1797 break; 1798 case R_ITEM_UNIT: 1799 /* FALLTHRU */ 1800 case R_ITEM_EXPONENT: 1801 /* 1802 * Error check: 1803 * Nibble 7 should be zero 1804 */ 1805 if (scan_ifp->hidparser_tok_leng == 4) { 1806 if ((scan_ifp->hidparser_tok_text[3] & 1807 0xf0) != 0) { 1808 hidparser_report_err( 1809 HIDPARSER_ERR_WARN, 1810 HIDPARSER_ERR_STANDARD, 1811 scan_ifp->hidparser_tok_token, 1812 0, 1813 "Data field reserved bits should " 1814 "be Zero"); 1815 } 1816 } 1817 break; 1818 case R_ITEM_REPORT_COUNT: 1819 /* 1820 * Error Check: 1821 * Report Count should be nonzero 1822 */ 1823 for (i = 0; i < scan_ifp->hidparser_tok_leng; i++) { 1824 if (scan_ifp->hidparser_tok_text[i]) 1825 break; 1826 } 1827 if (i == scan_ifp->hidparser_tok_leng) { 1828 hidparser_report_err( 1829 HIDPARSER_ERR_ERROR, 1830 HIDPARSER_ERR_STANDARD, 1831 R_ITEM_REPORT_COUNT, 1832 0, 1833 "Report Count = 0"); 1834 } 1835 break; 1836 case R_ITEM_REPORT_ID: 1837 /* 1838 * Error check: 1839 * Report Id should be nonzero & <= 255 1840 */ 1841 if (scan_ifp->hidparser_tok_leng != 1) { 1842 hidparser_report_err( 1843 HIDPARSER_ERR_ERROR, 1844 HIDPARSER_ERR_STANDARD, 1845 R_ITEM_REPORT_ID, 1846 1, 1847 "Must be contained in a byte"); 1848 } 1849 if (!scan_ifp->hidparser_tok_text[0]) { 1850 hidparser_report_err( 1851 HIDPARSER_ERR_ERROR, 1852 HIDPARSER_ERR_STANDARD, 1853 R_ITEM_REPORT_ID, 1854 0, 1855 "Report Id must be non-zero"); 1856 } 1857 break; 1858 case R_ITEM_LOGICAL_MINIMUM: 1859 break; 1860 case R_ITEM_LOGICAL_MAXIMUM: 1861 break; 1862 case R_ITEM_PHYSICAL_MINIMUM: 1863 break; 1864 case R_ITEM_PHYSICAL_MAXIMUM: 1865 break; 1866 case R_ITEM_REPORT_SIZE: 1867 break; 1868 case R_ITEM_PUSH: 1869 if (scan_ifp->hidparser_tok_leng != 0) { 1870 hidparser_report_err( 1871 HIDPARSER_ERR_ERROR, 1872 HIDPARSER_ERR_STANDARD, 1873 scan_ifp->hidparser_tok_token, 1874 0, 1875 "Data Field size should be zero"); 1876 } else { 1877 elem = (entity_attribute_stack_t *)kmem_zalloc( 1878 sizeof (entity_attribute_stack_t), 1879 KM_SLEEP); 1880 1881 elem->list = hidparser_cp_attribute_list( 1882 scan_ifp->hidparser_tok_gitem_head); 1883 if (scan_ifp->hidparser_head) { 1884 elem->next = scan_ifp->hidparser_head; 1885 } 1886 scan_ifp->hidparser_head = elem; 1887 } 1888 1889 break; 1890 case R_ITEM_POP: 1891 if (scan_ifp->hidparser_tok_leng != 0) { 1892 hidparser_report_err( 1893 HIDPARSER_ERR_ERROR, 1894 HIDPARSER_ERR_STANDARD, 1895 scan_ifp->hidparser_tok_token, 1896 0, 1897 "Data Field size should be zero"); 1898 } else { 1899 /* Free the current global list */ 1900 hidparser_free_attribute_list(scan_ifp-> 1901 hidparser_tok_gitem_head); 1902 scan_ifp->hidparser_tok_gitem_head = 1903 scan_ifp->hidparser_head->list; 1904 scan_ifp->hidparser_head->list = NULL; 1905 elem = scan_ifp->hidparser_head; 1906 scan_ifp->hidparser_head = elem->next; 1907 kmem_free(elem, 1908 sizeof (entity_attribute_stack_t)); 1909 } 1910 1911 break; 1912 default: 1913 1914 return (HIDPARSER_FAILURE); 1915 1916 /*NOTREACHED*/ 1917 } 1918 1919 hidparser_add_attribute(scan_ifp); 1920 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle, 1921 "hidparser_GlobalItem:index = 0x%lx token = 0x%x", 1922 scan_ifp->hidparser_tok_index - 1923 scan_ifp->hidparser_tok_leng - 1, 1924 scan_ifp->hidparser_tok_token); 1925 hidparser_scan(scan_ifp); 1926 1927 return (HIDPARSER_SUCCESS); 1928 } 1929 1930 1931 /* 1932 * hidparser_LocalItem: 1933 * Implements the Rule: 1934 * LocalItem -> Usage 1935 * | UsageMinimum 1936 * | UsageMaximum 1937 * | DesignatorIndex 1938 * | DesignatorMinimum 1939 * | StringIndex 1940 * | StringMinimum 1941 * | StringMaximum 1942 */ 1943 static int 1944 hidparser_LocalItem(hidparser_tok_t *scan_ifp) 1945 { 1946 int i; 1947 1948 switch (scan_ifp->hidparser_tok_token) { 1949 case R_ITEM_USAGE: 1950 /* 1951 * Error Check: 1952 * Data Field should be nonzero 1953 */ 1954 for (i = 0; i < scan_ifp->hidparser_tok_leng; i++) { 1955 if (scan_ifp->hidparser_tok_text[i]) 1956 break; 1957 } 1958 if (i == scan_ifp->hidparser_tok_leng) { 1959 hidparser_report_err( 1960 HIDPARSER_ERR_WARN, 1961 HIDPARSER_ERR_STANDARD, 1962 R_ITEM_USAGE, 1963 0, 1964 "Data Field should be non-zero"); 1965 } 1966 /* FALLTHRU */ 1967 case R_ITEM_USAGE_MIN: 1968 /* FALLTHRU */ 1969 case R_ITEM_USAGE_MAX: 1970 /* FALLTHRU */ 1971 case R_ITEM_DESIGNATOR_INDEX: 1972 /* FALLTHRU */ 1973 case R_ITEM_DESIGNATOR_MIN: 1974 /* FALLTHRU */ 1975 case R_ITEM_STRING_INDEX: 1976 /* FALLTHRU */ 1977 case R_ITEM_STRING_MIN: 1978 /* FALLTHRU */ 1979 case R_ITEM_STRING_MAX: 1980 /* FALLTHRU */ 1981 case R_ITEM_SET_DELIMITER: 1982 hidparser_add_attribute(scan_ifp); 1983 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle, 1984 "hidparser_LocalItem:index = 0x%lx token = 0x%x", 1985 scan_ifp->hidparser_tok_index - 1986 scan_ifp->hidparser_tok_leng - 1, 1987 scan_ifp->hidparser_tok_token); 1988 hidparser_scan(scan_ifp); 1989 1990 return (HIDPARSER_SUCCESS); 1991 1992 /*NOTREACHED*/ 1993 default: 1994 break; 1995 } 1996 1997 return (HIDPARSER_FAILURE); 1998 } 1999 2000 2001 /* 2002 * hidparser_allocate_entity: 2003 * Allocate Item of type 'type', length 'leng' and 2004 * params 'text'. Fill in the attributes allocated 2005 * so far from both the local and global item lists. 2006 * Make the child and sibling of the item NULL. 2007 */ 2008 static entity_item_t * 2009 hidparser_allocate_entity(hidparser_tok_t *scan_ifp) 2010 { 2011 entity_item_t *entity; 2012 entity_attribute_t *aend; 2013 2014 int entity_type = scan_ifp->hidparser_tok_token; 2015 unsigned char *text = scan_ifp->hidparser_tok_text; 2016 int len = scan_ifp->hidparser_tok_leng; 2017 2018 entity = kmem_zalloc(sizeof (entity_item_t), KM_SLEEP); 2019 entity->entity_item_type = entity_type; 2020 entity->entity_item_params_leng = len; 2021 2022 if (len != 0) { 2023 entity->entity_item_params = kmem_zalloc(len, KM_SLEEP); 2024 (void) bcopy(text, entity->entity_item_params, len); 2025 } 2026 2027 /* 2028 * Copy attributes from entity attribute state table if not 2029 * end collection. 2030 */ 2031 if (entity_type != R_ITEM_END_COLLECTION) { 2032 entity->entity_item_attributes = hidparser_cp_attribute_list( 2033 scan_ifp->hidparser_tok_gitem_head); 2034 2035 /* 2036 * append the control attributes, then clear out the control 2037 * attribute state table list 2038 */ 2039 if (entity->entity_item_attributes) { 2040 aend = hidparser_find_attribute_end( 2041 entity->entity_item_attributes); 2042 aend->entity_attribute_next = 2043 scan_ifp->hidparser_tok_litem_head; 2044 scan_ifp->hidparser_tok_litem_head = NULL; 2045 } else { 2046 entity->entity_item_attributes = 2047 scan_ifp->hidparser_tok_litem_head; 2048 scan_ifp->hidparser_tok_litem_head = NULL; 2049 } 2050 } 2051 2052 entity->info.child = entity->entity_item_right_sibling = 0; 2053 2054 return (entity); 2055 } 2056 2057 2058 /* 2059 * hidparser_add_attribute: 2060 * Add an attribute to the global or local item list 2061 * If the last 4th bit from right is 1, add to the local item list 2062 * Else add to the global item list 2063 */ 2064 static void 2065 hidparser_add_attribute(hidparser_tok_t *scan_ifp) 2066 { 2067 entity_attribute_t *newattrib, **previous, *elem; 2068 int entity = scan_ifp->hidparser_tok_token; 2069 unsigned char *text = scan_ifp->hidparser_tok_text; 2070 int len = scan_ifp->hidparser_tok_leng; 2071 2072 if (len == 0) { 2073 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 2074 "hidparser_add_attribute: len = 0 for item = 0x%x", 2075 entity); 2076 2077 return; 2078 } 2079 2080 if (entity & HIDPARSER_ISLOCAL_MASK) { 2081 previous = &scan_ifp->hidparser_tok_litem_head; 2082 } else { 2083 previous = &scan_ifp->hidparser_tok_gitem_head; 2084 } 2085 2086 elem = *previous; 2087 2088 /* 2089 * remove attribute if it is already on list, except 2090 * for control attributes(local items), as we could have 2091 * multiple usages... 2092 * unless we want to hassle with checking for unique parameters. 2093 */ 2094 while (elem) { 2095 if (elem->entity_attribute_tag == entity && 2096 !(entity & HIDPARSER_ISLOCAL_MASK)) { 2097 *previous = elem->entity_attribute_next; 2098 kmem_free(elem->entity_attribute_value, 2099 elem->entity_attribute_length); 2100 kmem_free(elem, sizeof (entity_attribute_t)); 2101 elem = *previous; 2102 } else { 2103 previous = &elem->entity_attribute_next; 2104 elem = elem->entity_attribute_next; 2105 } 2106 } 2107 2108 /* create new attribute for this entry */ 2109 newattrib = hidparser_alloc_attrib_list(1); 2110 newattrib->entity_attribute_tag = entity; 2111 newattrib->entity_attribute_value = kmem_zalloc(len, KM_SLEEP); 2112 (void) bcopy(text, newattrib->entity_attribute_value, len); 2113 newattrib->entity_attribute_length = len; 2114 2115 /* attach to end of list */ 2116 *previous = newattrib; 2117 } 2118 2119 2120 /* 2121 * hidparser_alloc_attrib_list: 2122 * Allocate space for n attributes , create a linked list and 2123 * return the head 2124 */ 2125 static entity_attribute_t * 2126 hidparser_alloc_attrib_list(int count) 2127 { 2128 entity_attribute_t *head, *current; 2129 2130 if (count <= 0) { 2131 2132 return (NULL); 2133 } 2134 2135 head = kmem_zalloc(sizeof (entity_attribute_t), KM_SLEEP); 2136 count--; 2137 current = head; 2138 while (count--) { 2139 current->entity_attribute_next = kmem_zalloc( 2140 sizeof (entity_attribute_t), KM_SLEEP); 2141 current = current->entity_attribute_next; 2142 } 2143 current->entity_attribute_next = NULL; 2144 2145 return (head); 2146 } 2147 2148 2149 /* 2150 * hidparser_cp_attribute_list: 2151 * Copies the Global item list pointed to by head 2152 * We create a clone of the global item list here 2153 * because we want to retain the Global items to 2154 * the next Main Item. 2155 */ 2156 static entity_attribute_t * 2157 hidparser_cp_attribute_list(entity_attribute_t *head) 2158 { 2159 entity_attribute_t *return_value, *current_src, *current_dst; 2160 2161 if (!head) { 2162 2163 return (NULL); 2164 } 2165 2166 current_src = head; 2167 current_dst = return_value = hidparser_alloc_attrib_list(1); 2168 2169 while (current_src) { 2170 current_dst->entity_attribute_tag = 2171 current_src->entity_attribute_tag; 2172 current_dst->entity_attribute_length = 2173 current_src->entity_attribute_length; 2174 current_dst->entity_attribute_value = kmem_zalloc( 2175 current_dst->entity_attribute_length, KM_SLEEP); 2176 (void) bcopy(current_src->entity_attribute_value, 2177 current_dst->entity_attribute_value, 2178 current_src->entity_attribute_length); 2179 if (current_src->entity_attribute_next) { 2180 current_dst->entity_attribute_next = 2181 hidparser_alloc_attrib_list(1); 2182 } else { 2183 current_dst->entity_attribute_next = NULL; 2184 } 2185 current_src = current_src->entity_attribute_next; 2186 current_dst = current_dst->entity_attribute_next; 2187 } 2188 2189 return (return_value); 2190 } 2191 2192 2193 /* 2194 * hidparser_find_attribute_end: 2195 * Find the last item in the attribute list pointed to by head 2196 */ 2197 static entity_attribute_t * 2198 hidparser_find_attribute_end(entity_attribute_t *head) 2199 { 2200 if (head == NULL) { 2201 2202 return (NULL); 2203 } 2204 while (head->entity_attribute_next != NULL) { 2205 head = head->entity_attribute_next; 2206 } 2207 2208 return (head); 2209 } 2210 2211 2212 /* 2213 * hidparser_find_item_end: 2214 * Search the siblings of items and find the last item in the list 2215 */ 2216 static entity_item_t * 2217 hidparser_find_item_end(entity_item_t *head) 2218 { 2219 if (!head) { 2220 2221 return (NULL); 2222 } 2223 2224 while (head->entity_item_right_sibling) { 2225 head = head->entity_item_right_sibling; 2226 } 2227 2228 return (head); 2229 } 2230 2231 2232 /* 2233 * hidparser_free_report_descr_handle: 2234 * Free the parse tree pointed to by handle 2235 */ 2236 static void 2237 hidparser_free_report_descr_handle(entity_item_t *handle) 2238 { 2239 entity_item_t *next, *current, *child; 2240 2241 current = handle; 2242 2243 while (current) { 2244 child = current->info.child; 2245 next = current->entity_item_right_sibling; 2246 if (current->entity_item_type == R_ITEM_COLLECTION) { 2247 if (current->entity_item_params != NULL) 2248 kmem_free(current->entity_item_params, 2249 current->entity_item_params_leng); 2250 if (current->entity_item_attributes != NULL) 2251 hidparser_free_attribute_list( 2252 current->entity_item_attributes); 2253 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle, 2254 "FREE 1: %s", 2255 items[current->entity_item_type]); 2256 kmem_free(current, sizeof (entity_item_t)); 2257 (void) hidparser_free_report_descr_handle(child); 2258 } else { 2259 if (current->entity_item_params != NULL) { 2260 kmem_free(current->entity_item_params, 2261 current->entity_item_params_leng); 2262 } 2263 if (current->entity_item_attributes != NULL) { 2264 hidparser_free_attribute_list( 2265 current->entity_item_attributes); 2266 } 2267 USB_DPRINTF_L4(PRINT_MASK_ALL, 2268 hparser_log_handle, "FREE 2: %s", 2269 items[current->entity_item_type]); 2270 kmem_free(current, sizeof (entity_item_t)); 2271 } 2272 current = next; 2273 } 2274 2275 } 2276 2277 2278 /* 2279 * hidparser_free_attribute_list: 2280 * Free the attribute list pointed to by head 2281 */ 2282 static void 2283 hidparser_free_attribute_list(entity_attribute_t *head) 2284 { 2285 entity_attribute_t *next, *current; 2286 2287 current = head; 2288 2289 while (current) { 2290 next = current->entity_attribute_next; 2291 USB_DPRINTF_L4(PRINT_MASK_ALL, 2292 hparser_log_handle, "FREE: %s value_length = %d", 2293 items[current->entity_attribute_tag], 2294 current->entity_attribute_length); 2295 2296 if (current->entity_attribute_value != NULL) { 2297 USB_DPRINTF_L4(PRINT_MASK_ALL, 2298 hparser_log_handle, 2299 "\tvalue = 0x%x", 2300 current->entity_attribute_value[0]); 2301 kmem_free(current->entity_attribute_value, 2302 current->entity_attribute_length); 2303 } 2304 2305 kmem_free(current, sizeof (entity_attribute_t)); 2306 current = next; 2307 } 2308 } 2309 2310 2311 /* 2312 * hidparser_initialize_items: 2313 * Initialize items array before start scanning and parsing. 2314 * This array of strings are used for printing purpose. 2315 */ 2316 static void 2317 hidparser_initialize_items(void) 2318 { 2319 items[R_ITEM_USAGE] = "Usage"; 2320 items[R_ITEM_USAGE_MIN] = "Usage Minimum"; 2321 items[R_ITEM_USAGE_MAX] = "Usage Maximum"; 2322 items[R_ITEM_DESIGNATOR_INDEX] = "Designator Index"; 2323 items[R_ITEM_DESIGNATOR_MIN] = "Designator Minimum"; 2324 items[R_ITEM_DESIGNATOR_MAX] = "Designator Maximum"; 2325 items[R_ITEM_STRING_INDEX] = "String Index"; 2326 items[R_ITEM_STRING_MIN] = "String Minimum"; 2327 items[R_ITEM_STRING_MAX] = "String Maximum"; 2328 2329 2330 items[R_ITEM_USAGE_PAGE] = "Usage Page"; 2331 items[R_ITEM_LOGICAL_MINIMUM] = "Logical Minimum"; 2332 items[R_ITEM_LOGICAL_MAXIMUM] = "Logical Maximum"; 2333 items[R_ITEM_PHYSICAL_MINIMUM] = "Physical Minimum"; 2334 items[R_ITEM_PHYSICAL_MAXIMUM] = "Physical Maximum"; 2335 items[R_ITEM_EXPONENT] = "Exponent"; 2336 items[R_ITEM_UNIT] = "Unit"; 2337 items[R_ITEM_REPORT_SIZE] = "Report Size"; 2338 items[R_ITEM_REPORT_ID] = "Report Id"; 2339 items[R_ITEM_REPORT_COUNT] = "Report Count"; 2340 items[R_ITEM_PUSH] = "Push"; 2341 items[R_ITEM_POP] = "Pop"; 2342 2343 2344 items[R_ITEM_INPUT] = "Input"; 2345 items[R_ITEM_OUTPUT] = "Output"; 2346 items[R_ITEM_COLLECTION] = "Collection"; 2347 items[R_ITEM_FEATURE] = "Feature"; 2348 items[R_ITEM_END_COLLECTION] = "End Collection"; 2349 2350 items[R_ITEM_SET_DELIMITER] = "Delimiter"; 2351 } 2352 2353 2354 /* 2355 * hidparser_scan: 2356 * This function scans the input entity descriptor, sees the data 2357 * length, returns the next token, data bytes and length in the 2358 * scan_ifp structure. 2359 */ 2360 static void 2361 hidparser_scan(hidparser_tok_t *scan_ifp) 2362 { 2363 int count; 2364 int ch; 2365 int parsed_length; 2366 unsigned char *parsed_text; 2367 unsigned char *entity_descriptor; 2368 char err_str[32]; 2369 size_t entity_buffer_size, index; 2370 2371 index = scan_ifp->hidparser_tok_index; 2372 entity_buffer_size = scan_ifp->hidparser_tok_max_bsize; 2373 parsed_length = 0; 2374 parsed_text = scan_ifp->hidparser_tok_text; 2375 entity_descriptor = scan_ifp->hidparser_tok_entity_descriptor; 2376 2377 next_item: 2378 if (index <= entity_buffer_size -1) { 2379 2380 ch = 0xFF & entity_descriptor[index]; 2381 USB_DPRINTF_L4(PRINT_MASK_ALL, 2382 hparser_log_handle, "scanner: index = 0x%lx ch = 0x%x", 2383 index, ch); 2384 2385 index++; 2386 2387 /* 2388 * Error checking: 2389 * Unrecognized items should be passed over 2390 * by the parser. 2391 * Section 5.4 2392 */ 2393 if (!(hidparser_isvalid_item(ch))) { 2394 (void) sprintf(err_str, "%s: 0x%2x", 2395 "Unknown or reserved item", ch); 2396 hidparser_report_err(HIDPARSER_ERR_ERROR, 2397 HIDPARSER_ERR_STANDARD, 0, 0x3F, err_str); 2398 goto next_item; 2399 } 2400 2401 if (ch == EXTENDED_ITEM) { 2402 parsed_length = entity_descriptor[index++]; 2403 ch = entity_descriptor[index++]; 2404 hidparser_report_err(HIDPARSER_ERR_WARN, 2405 HIDPARSER_ERR_STANDARD, 2406 0, 2407 0x3E, 2408 "Long item defined"); 2409 } else { 2410 parsed_length = ch & 0x03; 2411 USB_DPRINTF_L4(PRINT_MASK_ALL, 2412 hparser_log_handle, 2413 "scanner: parsed_length = %x", parsed_length); 2414 /* 3 really means 4.. see p.21 HID */ 2415 if (parsed_length == 3) 2416 parsed_length++; 2417 } 2418 for (count = 0; count < parsed_length; count++) { 2419 parsed_text[count] = entity_descriptor[index]; 2420 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle, 2421 "scanner: parsed_text[%d] = 0x%x," 2422 "index = 0x%lx", 2423 count, parsed_text[count], index); 2424 index++; 2425 } 2426 2427 USB_DPRINTF_L4(PRINT_MASK_ALL, 2428 hparser_log_handle, "scanner: lexical analyzer found 0x%x " 2429 "before translation", ch); 2430 2431 scan_ifp->hidparser_tok_index = index; 2432 scan_ifp->hidparser_tok_leng = parsed_length; 2433 scan_ifp->hidparser_tok_token = ch & 0xFC; 2434 USB_DPRINTF_L4(PRINT_MASK_ALL, 2435 hparser_log_handle, "scanner: aindex = 0x%lx", index); 2436 } else { 2437 USB_DPRINTF_L4(PRINT_MASK_ALL, 2438 hparser_log_handle, "scanner: eindex = 0x%lx", index); 2439 scan_ifp->hidparser_tok_leng = 0; 2440 scan_ifp->hidparser_tok_token = 0; /* EOF */ 2441 } 2442 } 2443 2444 2445 /* 2446 * hidparser_report_err: 2447 * Construct and print the error code 2448 * Ref: Hidview error check list 2449 */ 2450 static void 2451 hidparser_report_err(int err_level, 2452 int err_type, 2453 int tag, 2454 int subcode, 2455 char *msg) 2456 { 2457 unsigned int BmParserErrorCode = 0; 2458 2459 if (err_level) { 2460 BmParserErrorCode |= HIDPARSER_ERR_ERROR; 2461 } 2462 if (err_type) { 2463 BmParserErrorCode |= HIDPARSER_ERR_STANDARD; 2464 } 2465 BmParserErrorCode |= (tag << 8) & HIDPARSER_ERR_TAG_MASK; 2466 BmParserErrorCode |= subcode & HIDPARSER_ERR_SUBCODE_MASK; 2467 2468 if (err_level) { 2469 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 2470 "err code = 0x%4x, err str = %s", 2471 BmParserErrorCode, msg); 2472 2473 } else { 2474 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 2475 "wrn code = 0x%4x, wrn str = %s", 2476 BmParserErrorCode, msg); 2477 } 2478 } 2479 2480 2481 /* 2482 * hidparser_isvalid_item: 2483 * Find if the item tag is a valid one 2484 */ 2485 static int 2486 hidparser_isvalid_item(int tag) 2487 { 2488 if (tag == EXTENDED_ITEM) { 2489 2490 return (1); 2491 } 2492 2493 tag &= 0xFC; 2494 if ((tag == R_ITEM_INPUT) || 2495 (tag == R_ITEM_OUTPUT) || 2496 (tag == R_ITEM_COLLECTION) || 2497 (tag == R_ITEM_FEATURE) || 2498 (tag == R_ITEM_END_COLLECTION) || 2499 (tag == R_ITEM_USAGE_PAGE) || 2500 (tag == R_ITEM_LOGICAL_MINIMUM) || 2501 (tag == R_ITEM_LOGICAL_MAXIMUM) || 2502 (tag == R_ITEM_PHYSICAL_MINIMUM) || 2503 (tag == R_ITEM_PHYSICAL_MAXIMUM) || 2504 (tag == R_ITEM_EXPONENT) || 2505 (tag == R_ITEM_UNIT) || 2506 (tag == R_ITEM_REPORT_SIZE) || 2507 (tag == R_ITEM_REPORT_ID) || 2508 (tag == R_ITEM_REPORT_COUNT) || 2509 (tag == R_ITEM_PUSH) || 2510 (tag == R_ITEM_POP) || 2511 (tag == R_ITEM_USAGE) || 2512 (tag == R_ITEM_USAGE_MIN) || 2513 (tag == R_ITEM_USAGE_MAX) || 2514 (tag == R_ITEM_DESIGNATOR_INDEX) || 2515 (tag == R_ITEM_DESIGNATOR_MIN) || 2516 (tag == R_ITEM_DESIGNATOR_MAX) || 2517 (tag == R_ITEM_STRING_INDEX) || 2518 (tag == R_ITEM_STRING_MIN) || 2519 (tag == R_ITEM_STRING_MAX) || 2520 (tag == R_ITEM_SET_DELIMITER)) { 2521 2522 return (1); 2523 } else { 2524 2525 return (0); 2526 } 2527 } 2528 2529 2530 /* 2531 * hidparser_lookup_attribute: 2532 * Takes an item pointer(report structure) and a tag(e.g Logical 2533 * Min) as input. Returns the corresponding attribute structure. 2534 * Presently used for error checking only. 2535 */ 2536 static entity_attribute_t * 2537 hidparser_lookup_attribute(entity_item_t *item, int attr_tag) 2538 { 2539 entity_attribute_t *temp; 2540 2541 if (item == NULL) { 2542 2543 return (NULL); 2544 } 2545 2546 temp = item->entity_item_attributes; 2547 while (temp != NULL) { 2548 if (temp->entity_attribute_tag == attr_tag) { 2549 2550 return (temp); 2551 } 2552 2553 temp = temp->entity_attribute_next; 2554 } 2555 2556 return (NULL); 2557 } 2558 2559 2560 /* 2561 * hidparser_global_err_check: 2562 * Error checking for Global Items that need to be 2563 * performed in MainItem 2564 */ 2565 static void 2566 hidparser_global_err_check(entity_item_t *mainitem) 2567 { 2568 hidparser_check_minmax_val_signed(mainitem, R_ITEM_LOGICAL_MINIMUM, 2569 R_ITEM_LOGICAL_MAXIMUM, 0, 0); 2570 hidparser_check_minmax_val_signed(mainitem, R_ITEM_PHYSICAL_MINIMUM, 2571 R_ITEM_PHYSICAL_MAXIMUM, 0, 0); 2572 hidparser_check_correspondence(mainitem, R_ITEM_PHYSICAL_MINIMUM, 2573 R_ITEM_PHYSICAL_MAXIMUM, 0, 0, 2574 "Must have a corresponding Physical min", 2575 "Must have a corresponding Physical max"); 2576 hidparser_check_correspondence(mainitem, R_ITEM_PUSH, R_ITEM_POP, 2577 1, 0, "Should have a corresponding Pop", 2578 "Must have a corresponding Push"); 2579 2580 } 2581 2582 2583 /* 2584 * hidparser_mainitem_err_check: 2585 * Error checking for Main Items 2586 */ 2587 static void 2588 hidparser_mainitem_err_check(entity_item_t *mainitem) 2589 { 2590 int itemmask = 0; 2591 entity_attribute_t *attr; 2592 2593 attr = mainitem->entity_item_attributes; 2594 2595 if (attr != NULL) { 2596 while (attr) { 2597 switch (attr->entity_attribute_tag) { 2598 case R_ITEM_LOGICAL_MINIMUM: 2599 itemmask |= 0x01; 2600 break; 2601 case R_ITEM_LOGICAL_MAXIMUM: 2602 itemmask |= 0x02; 2603 break; 2604 case R_ITEM_REPORT_SIZE: 2605 itemmask |= 0x04; 2606 break; 2607 case R_ITEM_REPORT_COUNT: 2608 itemmask |= 0x08; 2609 break; 2610 case R_ITEM_USAGE_PAGE: 2611 itemmask |= 0x10; 2612 break; 2613 default: 2614 break; 2615 } /* switch */ 2616 attr = attr->entity_attribute_next; 2617 } /* while */ 2618 } /* if */ 2619 2620 if ((mainitem->entity_item_type == R_ITEM_COLLECTION) || 2621 (mainitem->entity_item_type == R_ITEM_END_COLLECTION)) { 2622 2623 return; 2624 } 2625 if (itemmask != 0x1f) { 2626 hidparser_report_err( 2627 HIDPARSER_ERR_ERROR, 2628 HIDPARSER_ERR_STANDARD, 2629 mainitem->entity_item_type, 2630 0, 2631 "Required Global/Local items must be defined"); 2632 } 2633 } 2634 2635 2636 /* 2637 * hidparser_local_err_check: 2638 * Error checking for Local items that is done when a MainItem 2639 * is encountered 2640 */ 2641 static void 2642 hidparser_local_err_check(entity_item_t *mainitem) 2643 { 2644 hidparser_check_correspondence(mainitem, R_ITEM_USAGE_MIN, 2645 R_ITEM_USAGE_MAX, 0, 0, 2646 "Must have a corresponding Usage Min", 2647 "Must have a corresponding Usage Max"); 2648 hidparser_check_minmax_val(mainitem, R_ITEM_USAGE_MIN, 2649 R_ITEM_USAGE_MAX, 1, 1); 2650 hidparser_check_correspondence(mainitem, R_ITEM_DESIGNATOR_MIN, 2651 R_ITEM_DESIGNATOR_MAX, 0, 0, 2652 "Must have a corresponding Designator min", 2653 "Must have a corresponding Designator Max"); 2654 hidparser_check_minmax_val(mainitem, R_ITEM_DESIGNATOR_MIN, 2655 R_ITEM_DESIGNATOR_MAX, 1, 1); 2656 hidparser_check_correspondence(mainitem, R_ITEM_STRING_MIN, 2657 R_ITEM_STRING_MAX, 0, 0, 2658 "Must have a corresponding String min", 2659 "Must have a corresponding String Max"); 2660 hidparser_check_minmax_val(mainitem, R_ITEM_STRING_MIN, 2661 R_ITEM_STRING_MAX, 1, 1); 2662 } 2663 2664 2665 /* 2666 * hidparser_find_unsigned_val: 2667 * Find the value for multibyte data 2668 * Ref: Section 5.8 of HID Spec 1.0 2669 */ 2670 static unsigned int 2671 hidparser_find_unsigned_val(entity_attribute_t *attr) 2672 { 2673 char *text; 2674 int len, i; 2675 unsigned int ret = 0; 2676 2677 text = attr->entity_attribute_value; 2678 len = attr->entity_attribute_length; 2679 for (i = 0; i < len; i++) { 2680 ret |= ((text[i] & 0xff) << (8*i)); 2681 } 2682 2683 return (ret); 2684 } 2685 2686 2687 /* 2688 * hidparser_find_signed_val: 2689 * Find the value for signed multibyte data 2690 * Ref: Section 5.8 of HID Spec 1.0 2691 */ 2692 static signed int 2693 hidparser_find_signed_val(entity_attribute_t *attr) 2694 { 2695 char *text; 2696 int len, i; 2697 int ret = 0; 2698 2699 text = attr->entity_attribute_value; 2700 len = attr->entity_attribute_length; 2701 2702 for (i = 0; i < len - 1; i++) { 2703 ret |= ((text[i] & 0xff) << (8 * i)); 2704 } 2705 2706 if (len > 0) { 2707 ret |= (text[i] << (8 * i)); 2708 } 2709 2710 return (ret); 2711 } 2712 2713 2714 /* 2715 * hidparser_check_correspondence: 2716 * Check if the item item2 corresponding to item1 exists and vice versa 2717 * If not report the appropriate error 2718 */ 2719 static void 2720 hidparser_check_correspondence(entity_item_t *mainitem, 2721 int item_tag1, 2722 int item_tag2, 2723 int val1, 2724 int val2, 2725 char *str1, 2726 char *str2) 2727 { 2728 entity_attribute_t *temp1, *temp2; 2729 2730 temp1 = hidparser_lookup_attribute(mainitem, item_tag1); 2731 temp2 = hidparser_lookup_attribute(mainitem, item_tag2); 2732 if ((temp1 != NULL) && (temp2 == NULL)) { 2733 hidparser_report_err( 2734 HIDPARSER_ERR_ERROR, 2735 HIDPARSER_ERR_STANDARD, 2736 item_tag1, 2737 val1, 2738 str1); 2739 } 2740 if ((temp2 != NULL) && (temp1 == NULL)) { 2741 hidparser_report_err( 2742 HIDPARSER_ERR_ERROR, 2743 HIDPARSER_ERR_STANDARD, 2744 item_tag2, 2745 val2, 2746 str2); 2747 } 2748 } 2749 2750 2751 /* 2752 * hidparser_check_minmax_val: 2753 * Check if the Min value <= Max and vice versa 2754 * Print for warnings and errors have been taken care separately. 2755 */ 2756 static void 2757 hidparser_check_minmax_val(entity_item_t *mainitem, 2758 int item_tag1, 2759 int item_tag2, 2760 int val1, 2761 int val2) 2762 { 2763 entity_attribute_t *temp1, *temp2; 2764 2765 temp1 = hidparser_lookup_attribute(mainitem, item_tag1); 2766 temp2 = hidparser_lookup_attribute(mainitem, item_tag2); 2767 if ((temp1 != NULL) && (temp2 != NULL)) { 2768 if (hidparser_find_unsigned_val(temp1) > 2769 hidparser_find_unsigned_val(temp2)) { 2770 if ((item_tag1 == R_ITEM_LOGICAL_MINIMUM) || 2771 (item_tag1 == R_ITEM_PHYSICAL_MINIMUM)) { 2772 hidparser_report_err( 2773 HIDPARSER_ERR_WARN, 2774 HIDPARSER_ERR_STANDARD, 2775 item_tag1, 2776 val1, 2777 "unsigned: Min should be <= to Max"); 2778 } else { 2779 hidparser_report_err( 2780 HIDPARSER_ERR_ERROR, 2781 HIDPARSER_ERR_STANDARD, 2782 item_tag1, 2783 val1, 2784 "Min must be <= to Max"); 2785 } 2786 } 2787 if (hidparser_find_unsigned_val(temp2) < 2788 hidparser_find_unsigned_val(temp1)) { 2789 if ((item_tag2 == R_ITEM_LOGICAL_MAXIMUM) || 2790 (item_tag2 == R_ITEM_PHYSICAL_MAXIMUM)) { 2791 hidparser_report_err( 2792 HIDPARSER_ERR_ERROR, 2793 HIDPARSER_ERR_STANDARD, 2794 item_tag2, 2795 val2, 2796 "unsigned: Max should be >= to Min"); 2797 } else { 2798 hidparser_report_err( 2799 HIDPARSER_ERR_ERROR, 2800 HIDPARSER_ERR_STANDARD, 2801 item_tag2, 2802 val2, 2803 "Max must be >= to Min"); 2804 } 2805 } 2806 } /* if (temp1 != NULL) && (temp2 != NULL) */ 2807 } 2808 2809 2810 /* 2811 * hidparser_check_minmax_val_signed: 2812 * Check if the Min value <= Max and vice versa 2813 * Print for warnings and errors have been taken care separately. 2814 */ 2815 static void 2816 hidparser_check_minmax_val_signed(entity_item_t *mainitem, 2817 int item_tag1, 2818 int item_tag2, 2819 int val1, 2820 int val2) 2821 { 2822 entity_attribute_t *temp1, *temp2; 2823 2824 temp1 = hidparser_lookup_attribute(mainitem, item_tag1); 2825 temp2 = hidparser_lookup_attribute(mainitem, item_tag2); 2826 if ((temp1 != NULL) && (temp2 != NULL)) { 2827 if (hidparser_find_signed_val(temp1) > 2828 hidparser_find_signed_val(temp2)) { 2829 if ((item_tag1 == R_ITEM_LOGICAL_MINIMUM) || 2830 (item_tag1 == R_ITEM_PHYSICAL_MINIMUM)) { 2831 hidparser_report_err( 2832 HIDPARSER_ERR_WARN, 2833 HIDPARSER_ERR_STANDARD, 2834 item_tag1, 2835 val1, 2836 "signed: Min should be <= to Max"); 2837 } else { 2838 hidparser_report_err( 2839 HIDPARSER_ERR_ERROR, 2840 HIDPARSER_ERR_STANDARD, 2841 item_tag1, 2842 val1, 2843 "Min must be <= to Max"); 2844 } 2845 } 2846 if (hidparser_find_signed_val(temp2) < 2847 hidparser_find_signed_val(temp1)) { 2848 if ((item_tag2 == R_ITEM_LOGICAL_MAXIMUM) || 2849 (item_tag2 == R_ITEM_PHYSICAL_MAXIMUM)) { 2850 hidparser_report_err( 2851 HIDPARSER_ERR_ERROR, 2852 HIDPARSER_ERR_STANDARD, 2853 item_tag2, 2854 val2, 2855 "signed: Max should be >= to Min"); 2856 } else { 2857 hidparser_report_err( 2858 HIDPARSER_ERR_ERROR, 2859 HIDPARSER_ERR_STANDARD, 2860 item_tag2, 2861 val2, 2862 "Max must be >= to Min"); 2863 } 2864 } 2865 } /* if (temp1 != NULL) && (temp2 != NULL) */ 2866 } 2867 2868 2869 /* 2870 * hidparser_error_delim: 2871 * Error check for Delimiter Sets 2872 */ 2873 static void 2874 hidparser_error_delim(entity_item_t *item, int err) 2875 { 2876 entity_attribute_t *attr; 2877 switch (err) { 2878 case HIDPARSER_DELIM_ERR1: 2879 hidparser_report_err( 2880 HIDPARSER_ERR_ERROR, 2881 HIDPARSER_ERR_STANDARD, 2882 R_ITEM_SET_DELIMITER, 2883 0, 2884 "Must be Delimiter Open"); 2885 2886 break; 2887 case HIDPARSER_DELIM_ERR2: 2888 hidparser_report_err( 2889 HIDPARSER_ERR_ERROR, 2890 HIDPARSER_ERR_STANDARD, 2891 R_ITEM_SET_DELIMITER, 2892 0, 2893 "Must be Delimiter Close"); 2894 2895 break; 2896 case HIDPARSER_DELIM_ERR3: 2897 attr = item->entity_item_attributes; 2898 while (attr != NULL) { 2899 if ((attr->entity_attribute_tag != 2900 R_ITEM_USAGE) && 2901 (attr->entity_attribute_tag != 2902 R_ITEM_USAGE_MIN) && 2903 (attr->entity_attribute_tag != 2904 R_ITEM_USAGE_MAX)) { 2905 hidparser_report_err( 2906 HIDPARSER_ERR_ERROR, 2907 HIDPARSER_ERR_STANDARD, 2908 R_ITEM_SET_DELIMITER, 2909 3, 2910 "May only contain Usage, " 2911 "Usage Min and Usage Max"); 2912 } 2913 attr = attr->entity_attribute_next; 2914 } 2915 2916 break; 2917 default: 2918 2919 break; 2920 } 2921 } 2922 2923 2924 /* 2925 * hidparser_find_max_packet_size_from_report_descriptor: 2926 * find packet size of the largest report in the report descriptor 2927 */ 2928 void 2929 hidparser_find_max_packet_size_from_report_descriptor( 2930 hidparser_handle_t hparser_handle, 2931 hidparser_packet_info_t *hpack) 2932 { 2933 2934 int rval, i; 2935 uint_t packet_size; 2936 uint_t max_packet_size; 2937 uint_t max_report_id; 2938 hidparser_report_id_list_t report_id_list; 2939 2940 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle, 2941 "hidparser_find_max_packet_size_from_report_descriptor"); 2942 2943 /* get a list of input reports */ 2944 rval = hidparser_get_report_id_list(hparser_handle, 2945 R_ITEM_INPUT, &report_id_list); 2946 if (rval != HIDPARSER_SUCCESS) { 2947 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 2948 "No report id used"); 2949 } else { 2950 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle, 2951 "%d unique report IDs found in hid report descriptor", 2952 report_id_list.no_of_report_ids); 2953 2954 for (i = 0; i < (report_id_list.no_of_report_ids); i++) { 2955 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle, 2956 "report_id: %d", report_id_list.report_id[i]); 2957 } 2958 } 2959 2960 if ((rval != HIDPARSER_SUCCESS) || 2961 (report_id_list.no_of_report_ids == 0)) { 2962 /* 2963 * since no report id is used, get the packet size 2964 * for the only report available 2965 */ 2966 (void) hidparser_get_packet_size(hparser_handle, 2967 0, R_ITEM_INPUT, &packet_size); 2968 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 2969 "Not using report id prefix. HID packet size = %d", 2970 packet_size); 2971 2972 hpack->max_packet_size = packet_size; 2973 hpack->report_id = HID_REPORT_ID_UNDEFINED; 2974 } else { 2975 /* 2976 * hid device uses multiple reports with report id prefix byte. 2977 * Find the longest input report. 2978 * See HID 8.4. 2979 */ 2980 max_packet_size = 0; 2981 max_report_id = 0; 2982 2983 for (i = 0; i < (report_id_list.no_of_report_ids); i++) { 2984 (void) hidparser_get_packet_size(hparser_handle, 2985 report_id_list.report_id[i], R_ITEM_INPUT, 2986 &packet_size); 2987 if (packet_size > max_packet_size) { 2988 max_packet_size = packet_size; 2989 max_report_id = report_id_list.report_id[i]; 2990 } 2991 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 2992 "Report ID %d has a packet size of %d", 2993 report_id_list.report_id[i], packet_size); 2994 } 2995 2996 hpack->max_packet_size = max_packet_size; 2997 hpack->report_id = max_report_id; 2998 2999 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle, 3000 "Report ID %d has the maximum packet size of %d", 3001 max_report_id, max_packet_size); 3002 } 3003 } 3004