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