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