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