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