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