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