Merge illumos-gate
[unleashed.git] / usr / src / uts / common / io / usb / clients / hidparser / hidparser.c
blobc95edad885db96c7849a2ec713d1aabe681761f0
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Copyright (c) 2018, Joyent, Inc.
30 #include <sys/usb/usba/usbai_version.h>
31 #include <sys/usb/usba.h>
32 #include <sys/usb/clients/hid/hid.h>
33 #include <sys/usb/clients/hidparser/hidparser.h>
34 #include <sys/usb/clients/hidparser/hid_parser_driver.h>
35 #include <sys/usb/clients/hidparser/hidparser_impl.h>
38 * hidparser: Parser to generate parse tree for Report Descriptors
39 * in HID devices.
42 uint_t hparser_errmask = (uint_t)PRINT_MASK_ALL;
43 uint_t hparser_errlevel = (uint_t)USB_LOG_L1;
44 static usb_log_handle_t hparser_log_handle;
47 * Array used to store corresponding strings for the
48 * different item types for debugging.
50 char *items[500]; /* Print items */
53 * modload support
55 extern struct mod_ops mod_miscops;
57 static struct modlmisc modlmisc = {
58 &mod_miscops, /* Type of module */
59 "HID Parser"
62 static struct modlinkage modlinkage = {
63 MODREV_1, (void *)&modlmisc, NULL
66 int
67 _init(void)
69 int rval = mod_install(&modlinkage);
71 if (rval == 0) {
72 hparser_log_handle = usb_alloc_log_hdl(NULL, "hidparser",
73 &hparser_errlevel, &hparser_errmask, NULL, 0);
76 return (rval);
79 int
80 _fini()
82 int rval = mod_remove(&modlinkage);
84 if (rval == 0) {
85 usb_free_log_hdl(hparser_log_handle);
88 return (rval);
91 int
92 _info(struct modinfo *modinfop)
95 return (mod_info(&modlinkage, modinfop));
99 * These functions are used internally in the parser.
100 * local declarations
102 static void hidparser_scan(hidparser_tok_t *);
103 static int hidparser_Items(hidparser_tok_t *);
104 static int hidparser_LocalItem(hidparser_tok_t *);
105 static int hidparser_GlobalItem(hidparser_tok_t *);
106 static int hidparser_ItemList(entity_item_t **,
107 hidparser_tok_t *);
108 static int hidparser_ReportDescriptor(entity_item_t **,
109 hidparser_tok_t *);
110 static int hidparser_ReportDescriptorDash(entity_item_t **,
111 hidparser_tok_t *);
112 static int hidparser_MainItem(entity_item_t **,
113 hidparser_tok_t *);
114 static void hidparser_free_attribute_list(
115 entity_attribute_t *);
116 static entity_item_t *hidparser_allocate_entity(hidparser_tok_t *);
117 static void hidparser_add_attribute(hidparser_tok_t *);
118 static entity_attribute_t *hidparser_cp_attribute_list(
119 entity_attribute_t *);
120 static entity_attribute_t *hidparser_find_attribute_end(
121 entity_attribute_t *);
122 static entity_attribute_t *hidparser_alloc_attrib_list(int);
123 static void hidparser_report_err(int, int,
124 int, int, char *);
125 static int hidparser_isvalid_item(int);
126 static entity_attribute_t *hidparser_lookup_attribute(entity_item_t *,
127 int);
128 static void hidparser_global_err_check(entity_item_t *);
129 static void hidparser_local_err_check(entity_item_t *);
130 static void hidparser_mainitem_err_check(entity_item_t *);
131 static unsigned int hidparser_find_unsigned_val(
132 entity_attribute_t *);
133 static int hidparser_find_signed_val(
134 entity_attribute_t *);
135 static void hidparser_check_correspondence(
136 entity_item_t *, int, int, int,
137 int, char *, char *);
138 static void hidparser_check_minmax_val(entity_item_t *,
139 int, int, int, int);
140 static void hidparser_check_minmax_val_signed(
141 entity_item_t *,
142 int, int, int, int);
143 static void hidparser_error_delim(entity_item_t *, int);
144 static int hidparser_get_usage_attribute_report_des(
145 entity_item_t *,
146 uint32_t, uint32_t, uint32_t,
147 uint32_t, uint32_t, int32_t *);
148 static int hidparser_get_packet_size_report_des(
149 entity_item_t *, uint32_t, uint32_t,
150 uint32_t *);
151 static int hidparser_get_main_item_data_descr_main(
152 entity_item_t *, uint32_t,
153 uint32_t, uint32_t, uint32_t,
154 uint32_t *);
155 static void hidparser_print_entity(
156 entity_item_t *entity,
157 int indent_level);
158 static void hidparser_print_this_attribute(
159 entity_attribute_t *attribute,
160 char *ident_space);
161 static int hidparser_main(unsigned char *, size_t,
162 entity_item_t **);
163 static void hidparser_initialize_items();
164 static void hidparser_free_report_descr_handle(
165 entity_item_t *);
166 static int hidparser_print_report_descr_handle(
167 entity_item_t *handle,
168 int indent_level);
169 static int hidparser_get_usage_list_in_order_internal(
170 entity_item_t *parse_handle,
171 uint_t collection_usage,
172 uint_t report_id,
173 uint_t main_item_type,
174 hidparser_rpt_t *rpt);
175 static void hidparser_fill_usage_info(
176 hidparser_usage_info_t *ui,
177 entity_attribute_t *attribute);
178 static int hidparser_get_report_id_list_internal(
179 entity_item_t *parser_handle,
180 uint_t main_item_type,
181 hidparser_report_id_list_t *id_lst);
184 * The hidparser_lookup_first(N) of a non-terminal N is stored as an array of
185 * integer tokens, terminated by 0. Right now there is only one element.
187 static hidparser_terminal_t first_Items[] = {
188 R_ITEM_USAGE_PAGE, R_ITEM_LOGICAL_MINIMUM, R_ITEM_LOGICAL_MAXIMUM, \
189 R_ITEM_PHYSICAL_MINIMUM, R_ITEM_PHYSICAL_MAXIMUM, R_ITEM_UNIT, \
190 R_ITEM_EXPONENT, R_ITEM_REPORT_SIZE, R_ITEM_REPORT_COUNT, \
191 R_ITEM_REPORT_ID, \
192 R_ITEM_USAGE, R_ITEM_USAGE_MIN, R_ITEM_USAGE_MAX, \
193 R_ITEM_DESIGNATOR_INDEX, \
194 R_ITEM_DESIGNATOR_MIN, R_ITEM_STRING_INDEX, R_ITEM_STRING_MIN, \
195 R_ITEM_STRING_MAX, \
196 R_ITEM_SET_DELIMITER, \
202 * Each non-terminal is represented by a function. In a top-down parser,
203 * whenever a non-terminal is encountered on the state diagram, the
204 * corresponding function is called. Because of the grammar, there is NO
205 * backtracking. If there is an error in the middle, the parser returns
206 * HIDPARSER_FAILURE
208 static hidparser_terminal_t *hid_first_list[] = {
209 first_Items
214 * hidparser_parse_report_descriptor:
215 * Calls the main parser routine
218 hidparser_parse_report_descriptor(
219 unsigned char *descriptor,
220 size_t size,
221 usb_hid_descr_t *hid_descriptor,
222 hidparser_handle_t *parse_handle)
224 int error = 0;
225 entity_item_t *root;
227 hidparser_initialize_items();
229 error = hidparser_main(descriptor, size, &root);
231 if (error != HIDPARSER_SUCCESS) {
233 return (HIDPARSER_FAILURE);
234 } else {
235 *parse_handle = kmem_zalloc(
236 sizeof (hidparser_handle), KM_SLEEP);
237 (*parse_handle)->hidparser_handle_hid_descr = hid_descriptor;
238 (*parse_handle)->hidparser_handle_parse_tree = root;
240 return (HIDPARSER_SUCCESS);
246 * hidparser_free_report_descriptor_handle:
247 * Frees the parse_handle which consists of a pointer to the parse
248 * tree and a pointer to the Hid descriptor structure
251 hidparser_free_report_descriptor_handle(hidparser_handle_t parse_handle)
253 if (parse_handle != NULL) {
254 hidparser_free_report_descr_handle(
255 parse_handle->hidparser_handle_parse_tree);
256 if (parse_handle != NULL) {
257 kmem_free(parse_handle, sizeof (hidparser_handle));
261 return (HIDPARSER_SUCCESS);
266 * hidparser_get_country_code:
267 * Return the bCountryCode from the Hid Descriptor
268 * to the hid module.
271 hidparser_get_country_code(hidparser_handle_t parser_handle,
272 uint16_t *country_code)
274 if ((parser_handle == NULL) ||
275 (parser_handle->hidparser_handle_hid_descr == NULL)) {
277 return (HIDPARSER_FAILURE);
280 *country_code =
281 parser_handle->hidparser_handle_hid_descr->bCountryCode;
283 return (HIDPARSER_SUCCESS);
288 * hidparser_get_packet_size:
289 * Get the packet size(sum of REPORT_SIZE * REPORT_COUNT)
290 * corresponding to a report id and an item type
293 hidparser_get_packet_size(hidparser_handle_t parser_handle,
294 uint_t report_id,
295 uint_t main_item_type,
296 uint_t *size)
298 if ((parser_handle == NULL) || (parser_handle->
299 hidparser_handle_parse_tree == NULL)) {
301 return (HIDPARSER_FAILURE);
304 *size = 0;
306 return (hidparser_get_packet_size_report_des(
307 parser_handle->hidparser_handle_parse_tree,
308 report_id, main_item_type, size));
313 * hidparser_get_packet_size_report_des:
314 * Get the packet size(sum of REPORT_SIZE * REPORT_COUNT)
315 * corresponding to a report id and an item type
318 hidparser_get_packet_size_report_des(entity_item_t *parser_handle,
319 uint32_t report_id,
320 uint32_t main_item_type,
321 uint32_t *size)
323 entity_item_t *current = parser_handle;
324 entity_attribute_t *attribute;
325 uint32_t temp;
326 uchar_t foundsize, foundcount, foundreportid, right_report_id;
328 foundsize = 0;
329 foundcount = 0;
330 right_report_id = 0;
332 while (current) {
333 if (current->entity_item_type == R_ITEM_COLLECTION) {
334 (void) hidparser_get_packet_size_report_des(
335 current->info.child, report_id, main_item_type,
336 size);
337 } else if (current->entity_item_type == main_item_type) {
338 temp = 1;
339 foundsize = 0;
340 foundcount = 0;
342 foundreportid = 0;
343 attribute = current->entity_item_attributes;
344 while (attribute != NULL) {
345 if (attribute->entity_attribute_tag ==
346 R_ITEM_REPORT_ID) {
347 foundreportid = 1;
348 if ((attribute->
349 entity_attribute_value[0]) ==
350 report_id) {
351 right_report_id = 1;
353 } else if (attribute->entity_attribute_tag ==
354 R_ITEM_REPORT_SIZE) {
355 foundsize = 1;
356 temp *= hidparser_find_unsigned_val(
357 attribute);
358 if (foundcount == 1) {
359 if (report_id &&
360 right_report_id) {
361 break;
364 } else if (attribute->entity_attribute_tag ==
365 R_ITEM_REPORT_COUNT) {
366 foundcount = 1;
367 temp *= hidparser_find_unsigned_val(
368 attribute);
369 if (foundsize == 1) {
370 if (report_id &&
371 right_report_id) {
372 break;
376 attribute = attribute->entity_attribute_next;
377 } /* end while */
379 if (foundreportid) {
380 if (right_report_id) {
381 *size = *size + temp;
383 } else if (report_id == HID_REPORT_ID_UNDEFINED) {
384 /* Just sanity checking */
385 *size = *size + temp;
387 right_report_id = 0;
388 } /* end else if */
390 current = current->entity_item_right_sibling;
391 } /* end while current */
394 return (HIDPARSER_SUCCESS);
399 * hidparser_get_usage_attribute:
400 * Get the attribute value corresponding to a particular
401 * report id, main item and usage
404 hidparser_get_usage_attribute(hidparser_handle_t parser_handle,
405 uint_t report_id,
406 uint_t main_item_type,
407 uint_t usage_page,
408 uint_t usage_id,
409 uint_t usage_attribute,
410 int *usage_attribute_value)
413 return (hidparser_get_usage_attribute_report_des(
414 parser_handle->hidparser_handle_parse_tree,
415 report_id, main_item_type, usage_page,
416 usage_id, usage_attribute, usage_attribute_value));
421 * hidparser_get_usage_attribute_report_des:
422 * Called by the wrapper function hidparser_get_usage_attribute()
424 static int
425 hidparser_get_usage_attribute_report_des(entity_item_t *parser_handle,
426 uint_t report_id,
427 uint_t main_item_type,
428 uint_t usage_page,
429 uint_t usage_id,
430 uint_t usage_attribute,
431 int *usage_attribute_value)
433 entity_item_t *current = parser_handle;
434 entity_attribute_t *attribute;
435 uchar_t found_page, found_ret_value, found_usage_id;
436 uchar_t foundreportid, right_report_id;
437 uint32_t usage;
438 short attvalue;
440 found_page = 0;
441 found_ret_value = 0;
442 found_usage_id = 0;
443 foundreportid = 0;
444 right_report_id = 0;
446 while (current) {
447 if (usage_id == HID_USAGE_UNDEFINED) {
448 found_usage_id = 1;
450 if (current->entity_item_type == R_ITEM_COLLECTION) {
452 if (hidparser_get_usage_attribute_report_des(
453 current->info.child, report_id, main_item_type,
454 usage_page, usage_id, usage_attribute,
455 usage_attribute_value) ==
456 HIDPARSER_SUCCESS) {
458 return (HIDPARSER_SUCCESS);
461 } else if (current->entity_item_type == main_item_type) {
462 /* Match Item Type */
463 attribute = current->entity_item_attributes;
465 while (attribute != NULL) {
466 if (attribute->entity_attribute_tag ==
467 R_ITEM_USAGE) {
468 usage = hidparser_find_unsigned_val(
469 attribute);
470 if (usage_id == HID_USAGE_ID(usage)) {
472 found_usage_id = 1;
473 } else {
475 * If we are trying to find out
476 * say, report size of usage =
477 * 0, a m.i with a valid usage
478 * will not contain that
480 if (usage_id ==
481 HID_USAGE_UNDEFINED) {
482 found_usage_id = 0;
486 if (found_usage_id && attribute->
487 entity_attribute_length == 3) {
489 * This is an extended usage ie.
490 * usage page in upper 16 bits
491 * or-ed with usage in the lower
492 * 16 bits.
494 if (HID_USAGE_PAGE(usage) &&
495 HID_USAGE_PAGE(usage) ==
496 usage_page) {
498 found_page = 1;
499 } else {
501 found_usage_id = 0;
504 } else if (attribute->entity_attribute_tag ==
505 R_ITEM_USAGE_PAGE) {
506 if (attribute->
507 entity_attribute_value[0] ==
508 usage_page) {
509 /* Match Usage Page */
510 found_page = 1;
512 } else if (attribute->entity_attribute_tag ==
513 R_ITEM_REPORT_ID) {
514 foundreportid = 1;
515 if (attribute->
516 entity_attribute_value[0] ==
517 report_id) {
518 right_report_id = 1;
521 if (attribute->entity_attribute_tag ==
522 usage_attribute) {
523 /* Match attribute */
524 found_ret_value = 1;
525 *usage_attribute_value = attribute->
526 entity_attribute_value[0];
527 if (attribute->
528 entity_attribute_length == 2) {
529 attvalue =
530 (attribute->
531 entity_attribute_value[0] &
532 0xff) |
533 (attribute->
534 entity_attribute_value[1] <<
536 *usage_attribute_value =
537 attvalue;
540 attribute = attribute->entity_attribute_next;
543 if (found_usage_id && found_page && found_ret_value) {
545 if (foundreportid) {
546 if (right_report_id) {
548 return (HIDPARSER_SUCCESS);
549 } else if (report_id ==
550 HID_REPORT_ID_UNDEFINED) {
552 return (HIDPARSER_SUCCESS);
554 } else {
556 return (HIDPARSER_SUCCESS);
562 * search the next main item, right sibling of this one
564 if (current->entity_item_right_sibling != NULL) {
566 current = current->entity_item_right_sibling;
567 found_usage_id = found_page = found_ret_value = 0;
568 /* Don't change foundreportid */
569 right_report_id = 0;
570 } else {
572 break;
575 /* Don't give junk result */
576 *usage_attribute_value = 0;
578 return (HIDPARSER_NOT_FOUND);
583 * hidparser_get_main_item_data_descr:
584 * Get the data value corresponding to a particular
585 * Main Item (Input, Output, Feature)
588 hidparser_get_main_item_data_descr(hidparser_handle_t parser_handle,
589 uint_t report_id,
590 uint_t main_item_type,
591 uint_t usage_page,
592 uint_t usage_id,
593 uint_t *main_item_descr_value)
596 return hidparser_get_main_item_data_descr_main(
597 parser_handle->hidparser_handle_parse_tree,
598 report_id, main_item_type, usage_page, usage_id,
599 main_item_descr_value);
604 * hidparser_get_main_item_data_descr_main:
605 * Called by the wrapper function hidparser_get_main_item_data_descr()
607 static int
608 hidparser_get_main_item_data_descr_main(entity_item_t *parser_handle,
609 uint_t report_id,
610 uint_t main_item_type,
611 uint_t usage_page,
612 uint_t usage_id,
613 uint_t *main_item_descr_value)
615 entity_item_t *current = parser_handle;
616 entity_attribute_t *attribute;
618 uchar_t found_page, found_usage_id;
619 uchar_t foundreportid, right_report_id;
620 uint32_t usage;
622 found_page = 0;
623 found_usage_id = 0;
624 foundreportid = 0;
625 right_report_id = 0;
627 while (current) {
628 if (usage_id == HID_USAGE_UNDEFINED) {
629 found_usage_id = 1;
631 if (current->entity_item_type == R_ITEM_COLLECTION) {
633 if (hidparser_get_main_item_data_descr_main(
634 current->info.child, report_id, main_item_type,
635 usage_page, usage_id, main_item_descr_value) ==
636 HIDPARSER_SUCCESS) {
638 return (HIDPARSER_SUCCESS);
640 } else if (current->entity_item_type == main_item_type) {
641 /* Match Item Type */
642 attribute = current->entity_item_attributes;
644 if (report_id == HID_REPORT_ID_UNDEFINED) {
645 foundreportid = right_report_id = 1;
648 while (attribute != NULL) {
649 if (attribute->entity_attribute_tag ==
650 R_ITEM_USAGE) {
651 usage = hidparser_find_unsigned_val(
652 attribute);
653 if (usage_id == HID_USAGE_ID(usage)) {
654 found_usage_id = 1;
655 if (attribute->
656 entity_attribute_length ==
657 3) {
658 if (HID_USAGE_PAGE(
659 usage) &&
660 HID_USAGE_PAGE(
661 usage) ==
662 usage_page) {
664 found_page = 1;
665 } else {
667 found_usage_id = 0;
671 if (found_usage_id &&
672 found_page &&
673 foundreportid &&
674 right_report_id) {
675 *main_item_descr_value =
676 current->
677 entity_item_params[0];
678 break;
681 } else if ((attribute->entity_attribute_tag ==
682 R_ITEM_USAGE_PAGE) &&
683 (attribute->entity_attribute_value[0] ==
684 usage_page)) {
686 /* Match Usage Page */
687 found_page = 1;
688 if (found_usage_id && foundreportid &&
689 right_report_id) {
690 *main_item_descr_value =
691 current->
692 entity_item_params[0];
693 break;
695 } else if (attribute->entity_attribute_tag ==
696 R_ITEM_REPORT_ID) {
697 foundreportid = 1;
698 if (attribute->
699 entity_attribute_value[0] ==
700 report_id) {
701 right_report_id = 1;
702 } else {
703 break;
707 attribute = attribute->entity_attribute_next;
710 if (foundreportid) {
711 if (right_report_id) {
712 if (found_usage_id && found_page) {
714 return (HIDPARSER_SUCCESS);
721 * search the next main item, right sibling of this one
723 if (current->entity_item_right_sibling != NULL) {
725 current = current->entity_item_right_sibling;
726 found_page = found_usage_id = right_report_id = 0;
727 } else {
729 break;
733 *main_item_descr_value = 0;
735 return (HIDPARSER_NOT_FOUND);
739 * hidparser_lookup_usage_collection:
740 * Look up the collection specified by the usage page and usage id
743 hidparser_lookup_usage_collection(hidparser_handle_t parse_handle,
744 uint_t lusage_page,
745 uint_t lusage_id)
747 entity_item_t *current;
748 entity_attribute_t *attribute;
749 int found_usage_id = 0;
750 int found_page = 0;
751 uint32_t usage;
752 uint_t usage_page;
753 uint_t usage_id;
755 if ((parse_handle == NULL) ||
756 (parse_handle->hidparser_handle_parse_tree == NULL))
757 return (HIDPARSER_FAILURE);
759 current = parse_handle->hidparser_handle_parse_tree;
760 while (current != NULL) {
762 if (current->entity_item_type != R_ITEM_COLLECTION) {
763 current = current->entity_item_right_sibling;
764 continue;
767 attribute = current->entity_item_attributes;
768 found_usage_id = 0;
769 found_page = 0;
771 while (attribute != NULL) {
772 if (attribute->entity_attribute_tag == R_ITEM_USAGE) {
773 found_usage_id = 1;
774 usage = hidparser_find_unsigned_val(attribute);
775 usage_id = HID_USAGE_ID(usage);
776 if (attribute->entity_attribute_length == 3) {
777 if (HID_USAGE_PAGE(usage)) {
778 found_page = 1;
779 usage_page =
780 HID_USAGE_PAGE(usage);
783 if (found_page) {
784 goto check_usage;
786 } else if (attribute->entity_attribute_tag ==
787 R_ITEM_USAGE_PAGE) {
788 found_page = 1;
789 usage_page =
790 attribute->entity_attribute_value[0];
791 if (found_usage_id) {
792 goto check_usage;
795 attribute = attribute->entity_attribute_next;
797 check_usage:
798 if ((usage_page == lusage_page) && (usage_id == lusage_id))
799 return (HIDPARSER_SUCCESS);
800 else
801 current = current->entity_item_right_sibling;
804 return (HIDPARSER_FAILURE);
809 * hidparser_get_top_level_collection_usage:
810 * Get the usage page and usage for the top level collection item
813 hidparser_get_top_level_collection_usage(hidparser_handle_t parse_handle,
814 uint_t *usage_page,
815 uint_t *usage_id)
817 entity_item_t *current;
818 entity_attribute_t *attribute;
819 int found_usage_id = 0;
820 int found_page = 0;
821 uint32_t usage;
823 if ((parse_handle == NULL) ||
824 (parse_handle->hidparser_handle_parse_tree == NULL))
826 return (HIDPARSER_FAILURE);
828 current = parse_handle->hidparser_handle_parse_tree;
830 if (current->entity_item_type != R_ITEM_COLLECTION) {
832 return (HIDPARSER_FAILURE);
834 attribute = current->entity_item_attributes;
835 while (attribute != NULL) {
836 if (attribute->entity_attribute_tag == R_ITEM_USAGE) {
837 found_usage_id = 1;
838 usage = hidparser_find_unsigned_val(attribute);
839 *usage_id = HID_USAGE_ID(usage);
840 if (attribute->entity_attribute_length == 3) {
841 if (HID_USAGE_PAGE(usage)) {
842 found_page = 1;
843 *usage_page = HID_USAGE_PAGE(usage);
846 if (found_usage_id && found_page) {
848 return (HIDPARSER_SUCCESS);
850 } else if (attribute->entity_attribute_tag ==
851 R_ITEM_USAGE_PAGE) {
852 found_page = 1;
853 *usage_page = attribute->entity_attribute_value[0];
854 if (found_usage_id && found_page) {
856 return (HIDPARSER_SUCCESS);
859 attribute = attribute->entity_attribute_next;
862 return (HIDPARSER_FAILURE);
867 * hidparser_get_usage_list_in_order:
868 * Find all the usages corresponding to a main item and report id.
869 * Note that only short items are supported.
871 * Arguments:
872 * parser_handle:
873 * hid parser handle
874 * report id:
875 * report id of the particular report where the usages belong to
876 * main_item_type:
877 * type of report, either Input, Output, or Feature
878 * usage_list:
879 * Filled in with the pointer to the first element of the
880 * usage list
882 * Return values:
883 * HIDPARSER_SUCCESS - returned success
884 * HIDPARSER_NOT_FOUND - usage specified by the parameters was not found
885 * HIDPARSER_FAILURE - unspecified failure
888 hidparser_get_usage_list_in_order(hidparser_handle_t parser_handle,
889 uint_t report_id,
890 uint_t main_item_type,
891 hidparser_rpt_t *rpt)
894 if ((parser_handle == NULL) ||
895 (parser_handle->hidparser_handle_parse_tree == NULL)) {
897 return (HIDPARSER_FAILURE);
900 rpt->no_of_usages = 0;
902 return (hidparser_get_usage_list_in_order_internal(
903 parser_handle->hidparser_handle_parse_tree, HID_USAGE_UNDEFINED,
904 report_id, main_item_type, rpt));
908 static int
909 hidparser_get_usage_list_in_order_internal(entity_item_t *parser_handle,
910 uint_t collection_usage,
911 uint_t report_id,
912 uint_t main_item_type,
913 hidparser_rpt_t *rpt)
916 /* setup wrapper function */
917 entity_item_t *current = parser_handle;
918 entity_attribute_t *attribute;
919 uchar_t foundreportid, right_report_id, valid_usage;
920 uchar_t found_usage_min, found_usage_max, found_usage;
921 int i, j;
922 int rval;
923 uint32_t usage, usage_min, usage_max, usage_id[USAGE_MAX];
924 hidparser_usage_info_t *ui;
926 found_usage_min = 0;
927 found_usage_max = 0;
928 foundreportid = 0;
929 right_report_id = 0;
931 while (current) {
933 if (current->entity_item_type == R_ITEM_COLLECTION) {
936 * find collection usage information for this
937 * collection
939 valid_usage = 0;
941 attribute = current->entity_item_attributes;
943 while (attribute != NULL) {
944 if (attribute->entity_attribute_tag ==
945 R_ITEM_USAGE) {
946 usage = hidparser_find_unsigned_val(
947 attribute);
948 valid_usage = 1;
950 attribute = attribute->entity_attribute_next;
953 if (!valid_usage) {
954 usage = HID_USAGE_UNDEFINED;
957 rval = hidparser_get_usage_list_in_order_internal(
958 current->info.child, usage,
959 report_id, main_item_type, rpt);
960 if (rval != HIDPARSER_SUCCESS) {
962 return (rval);
965 } else if (current->entity_item_type == main_item_type) {
966 /* Match Item Type */
968 foundreportid = 0;
969 right_report_id = 0;
970 found_usage_min = 0;
971 found_usage_max = 0;
972 found_usage = 0;
973 valid_usage = 0;
975 attribute = current->entity_item_attributes;
977 while (attribute != NULL) {
978 switch (attribute->entity_attribute_tag) {
979 case R_ITEM_REPORT_ID:
980 foundreportid = 1;
982 if (attribute->
983 entity_attribute_value[0] ==
984 report_id) {
985 right_report_id = 1;
986 } else {
987 /* different report id */
988 valid_usage = 1;
991 break;
992 case R_ITEM_USAGE:
993 if (found_usage >= USAGE_MAX) {
995 return (HIDPARSER_FAILURE);
997 usage = hidparser_find_unsigned_val(
998 attribute);
999 if (usage) {
1000 usage_id[found_usage] = usage;
1001 found_usage++;
1004 break;
1005 case R_ITEM_USAGE_MIN:
1006 found_usage_min = 1;
1007 usage_min = hidparser_find_unsigned_val(
1008 attribute);
1010 break;
1011 case R_ITEM_USAGE_MAX:
1012 found_usage_max = 1;
1013 usage_max = hidparser_find_unsigned_val(
1014 attribute);
1016 break;
1017 case R_ITEM_SET_DELIMITER:
1018 /* skip over alternate usages */
1019 do {
1020 attribute = attribute->
1021 entity_attribute_next;
1022 } while (attribute->
1023 entity_attribute_tag !=
1024 R_ITEM_SET_DELIMITER);
1026 break;
1029 attribute = attribute->entity_attribute_next;
1033 * If we have a report id match (or report ids
1034 * are not present), and have a usage item or
1035 * usage min&max, put the usage item into the
1036 * list. Don't put undefined usage items
1037 * (HID_USAGE_UNDEFINED, 0) into the list;
1038 * a 0 usage item is used to match padding
1039 * fields that don't have an attached usage.
1041 if (!foundreportid ||
1042 (foundreportid && right_report_id)) {
1044 for (j = 0; j < found_usage; j++) {
1046 /* Put in usage list */
1047 if (rpt->no_of_usages >= USAGE_MAX) {
1049 return (HIDPARSER_FAILURE);
1052 i = rpt->no_of_usages++;
1053 ui = &(rpt->usage_descr[i]);
1055 hidparser_fill_usage_info(ui,
1056 current->entity_item_attributes);
1058 ui->rptcnt /= found_usage;
1059 ui->collection_usage = collection_usage;
1060 ui->usage_id = HID_USAGE_ID(
1061 usage_id[j]);
1064 * This is an extended usage ie.
1065 * usage page in upper 16 bits
1066 * or-ed with usage in the lower
1067 * 16 bits.
1069 if (usage_id[j] >> 16) {
1070 ui->usage_page =
1071 HID_USAGE_PAGE(usage_id[j]);
1074 rpt->report_id = report_id;
1075 valid_usage = 1;
1078 if (found_usage_min && found_usage_max) {
1080 /* Put in usage list */
1081 if (rpt->no_of_usages >= USAGE_MAX) {
1083 return (HIDPARSER_FAILURE);
1086 if (found_usage) {
1088 /* handle duplication */
1089 ui->usage_min = HID_USAGE_ID(
1090 usage_min);
1091 ui->usage_max = HID_USAGE_ID(
1092 usage_max);
1093 } else {
1094 i = rpt->no_of_usages++;
1095 ui = &(rpt->usage_descr[i]);
1097 hidparser_fill_usage_info(ui,
1098 current->
1099 entity_item_attributes);
1101 ui->collection_usage =
1102 collection_usage;
1103 ui->usage_min = HID_USAGE_ID(
1104 usage_min);
1105 ui->usage_max = HID_USAGE_ID(
1106 usage_max);
1108 rpt->report_id = report_id;
1109 valid_usage = 1;
1113 * This is an extended usage ie.
1114 * usage page in upper 16 bits
1115 * or-ed with usage_max in the lower
1116 * 16 bits.
1118 if (usage_max >> 16) {
1119 ui->usage_page =
1120 HID_USAGE_PAGE(usage_max);
1126 * This main item contains no usage
1127 * Fill in with usage "UNDEFINED".
1128 * If report id is valid, only the
1129 * main item with matched report id
1130 * can be filled in.
1132 if (!valid_usage) {
1134 if (rpt->no_of_usages >= USAGE_MAX) {
1136 return (HIDPARSER_FAILURE);
1139 i = rpt->no_of_usages++;
1140 ui = &(rpt->usage_descr[i]);
1142 hidparser_fill_usage_info(ui,
1143 current->entity_item_attributes);
1145 ui->collection_usage = collection_usage;
1146 ui->usage_id = HID_USAGE_UNDEFINED;
1148 rpt->report_id = report_id;
1153 current = current->entity_item_right_sibling;
1155 } /* end while current */
1157 return (HIDPARSER_SUCCESS);
1162 * hidparser_fill_usage_info():
1163 * Fill in the mandatory item information for a main item.
1164 * See HID 6.2.2.
1166 static void
1167 hidparser_fill_usage_info(hidparser_usage_info_t *ui,
1168 entity_attribute_t *attribute)
1170 bzero(ui, sizeof (*ui));
1172 while (attribute) {
1173 switch (attribute->entity_attribute_tag) {
1174 case R_ITEM_LOGICAL_MINIMUM:
1175 ui->lmin = hidparser_find_signed_val(attribute);
1177 break;
1178 case R_ITEM_LOGICAL_MAXIMUM:
1179 ui->lmax = hidparser_find_signed_val(attribute);
1181 break;
1182 case R_ITEM_REPORT_COUNT:
1183 ui->rptcnt = hidparser_find_unsigned_val(attribute);
1185 break;
1186 case R_ITEM_REPORT_SIZE:
1187 ui->rptsz = hidparser_find_unsigned_val(attribute);
1189 break;
1190 case R_ITEM_USAGE_PAGE:
1191 ui->usage_page = hidparser_find_unsigned_val(attribute)
1192 & 0xffff;
1194 break;
1197 attribute = attribute->entity_attribute_next;
1203 * hidparser_get_report_id_list:
1204 * Return a list of all report ids used for descriptor items
1205 * corresponding to a main item.
1207 * Arguments:
1208 * parser_handle:
1209 * hid parser handle
1210 * main_item_type:
1211 * type of report, either Input, Output, or Feature
1212 * report_id_list:
1213 * Filled in with a list of report ids found in the descriptor
1215 * Return values:
1216 * HIDPARSER_SUCCESS - returned success
1217 * HIDPARSER_FAILURE - unspecified failure
1220 hidparser_get_report_id_list(hidparser_handle_t parser_handle,
1221 uint_t main_item_type,
1222 hidparser_report_id_list_t *report_id_list)
1225 if ((parser_handle == NULL) ||
1226 (parser_handle->hidparser_handle_parse_tree == NULL)) {
1228 return (HIDPARSER_FAILURE);
1231 report_id_list->no_of_report_ids = 0;
1233 return (hidparser_get_report_id_list_internal(
1234 parser_handle->hidparser_handle_parse_tree,
1235 main_item_type, report_id_list));
1240 * hidparser_get_report_id_list_internal:
1241 * internal function that generates list of all report ids
1244 hidparser_get_report_id_list_internal(
1245 entity_item_t *parser_handle,
1246 uint_t main_item_type,
1247 hidparser_report_id_list_t *id_lst)
1249 /* setup wrapper function */
1250 entity_item_t *current = parser_handle;
1251 entity_attribute_t *attribute;
1252 uint_t report_id = 0;
1253 int i = 0;
1254 int rval;
1256 while (current) {
1258 if (current->entity_item_type == R_ITEM_COLLECTION) {
1260 rval = hidparser_get_report_id_list_internal(
1261 current->info.child, main_item_type, id_lst);
1262 if (rval != HIDPARSER_SUCCESS) {
1264 return (rval);
1267 } else if (current->entity_item_type == main_item_type) {
1268 /* Match Item Type */
1269 attribute = current->entity_item_attributes;
1271 while (attribute != NULL) {
1273 if (attribute->entity_attribute_tag ==
1274 R_ITEM_REPORT_ID) {
1276 /* Found a Report ID */
1277 report_id = attribute->
1278 entity_attribute_value[0];
1280 /* Report ID already in list? */
1281 for (i = 0;
1282 i < id_lst->no_of_report_ids;
1283 i++) {
1284 if (report_id == id_lst->
1285 report_id[i]) {
1287 break;
1291 if (i >= id_lst->no_of_report_ids) {
1293 * New Report ID found, put
1294 * in list
1296 if (i >= REPORT_ID_MAX) {
1298 return
1299 (HIDPARSER_FAILURE);
1302 id_lst->report_id[i] =
1303 report_id;
1304 id_lst->no_of_report_ids++;
1308 attribute = attribute->entity_attribute_next;
1312 current = current->entity_item_right_sibling;
1314 } /* end while current */
1316 return (HIDPARSER_SUCCESS);
1321 * hidparser_print_report_descr_handle:
1322 * Functions to print the parse tree. Currently not
1323 * being called.
1325 static int
1326 hidparser_print_report_descr_handle(entity_item_t *handle,
1327 int indent_level)
1329 entity_item_t *current = handle;
1331 while (current) {
1332 if (current->info.child) {
1333 hidparser_print_entity(current, indent_level);
1334 /* do children */
1335 (void) hidparser_print_report_descr_handle(
1336 current->info.child, indent_level+1);
1337 } else /* just a regular entity */ {
1338 hidparser_print_entity(current, indent_level);
1340 current = current->entity_item_right_sibling;
1343 return (HIDPARSER_SUCCESS);
1347 #define SPACE_PER_LEVEL 5
1350 * hidparser_print_entity ;
1351 * Prints the entity items recursively
1353 static void
1354 hidparser_print_entity(entity_item_t *entity, int indent_level)
1356 char indent_space[256];
1357 int count;
1358 entity_attribute_t *attr;
1360 indent_level *= SPACE_PER_LEVEL;
1362 for (count = 0; indent_level--; count++)
1363 indent_space[count] = ' ';
1365 indent_space[count] = 0;
1367 attr = entity->entity_item_attributes;
1368 while (attr) {
1369 hidparser_print_this_attribute(attr, indent_space);
1370 attr = attr->entity_attribute_next;
1373 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle, "%s%s(0x%x)",
1374 indent_space, items[entity->entity_item_type],
1375 (entity->entity_item_params_leng ?
1376 entity->entity_item_params[0] & 0xFF : 0x00));
1381 * hidparser_print_this_attribute:
1382 * Prints the attribute passed in the argument
1384 static void
1385 hidparser_print_this_attribute(entity_attribute_t *attribute,
1386 char *ident_space)
1388 if (ident_space == NULL) {
1390 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle,
1391 "%s(0x%X)",
1392 items[attribute->entity_attribute_tag],
1393 hidparser_find_unsigned_val(attribute));
1394 } else {
1395 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle,
1396 "%s%s(0x%X)", ident_space,
1397 items[attribute->entity_attribute_tag],
1398 hidparser_find_unsigned_val(attribute));
1405 * The next few functions will be used for parsing using the
1406 * grammar:
1408 * Start -> ReportDescriptor <EOF>
1410 * ReportDescriptor -> ItemList
1412 * ItemList -> Items MainItem ItemList
1413 * | epsilon
1415 * MainItem -> BeginCollection ItemList EndCollection
1416 * | Input
1417 * | Output
1418 * | Feature
1420 * Items -> GlobalItem Items
1421 * | LocalItem Items
1422 * | SetDelimiterOpen LocalItemList
1423 * SetDelimiterClose Items
1424 * | epsilon
1426 * LocalItemList -> LocalItem Temp2
1428 * Temp2 -> LocalItem Temp2
1429 * | epsilon
1431 * GlobalItem -> UsagePage
1432 * | LogicalMinimum
1433 * | LogicalMaximum
1434 * | PhysicalMinimum
1435 * | PhysicalMaximum
1436 * | Unit
1437 * | Exponent
1438 * | ReportSize
1439 * | ReportCount
1440 * | ReportID
1442 * LocalItem -> Usage
1443 * | UsageMinimum
1444 * | UsageMaximum
1445 * | DesignatorIndex
1446 * | DesignatorMinimum
1447 * | StringIndex
1448 * | StringMinimum
1449 * | StringMaximum
1455 * hidparser_lookup_first:
1456 * Looks up if token belongs to the FIRST of the function tag
1457 * that is passed through the first argument
1459 static int
1460 hidparser_lookup_first(int func_index,
1461 int token)
1463 int *itemp;
1465 itemp = hid_first_list[func_index];
1466 while (*itemp != 0) {
1467 /* get the next terminal on the list */
1468 if (*itemp == token) {
1470 return (HIDPARSER_SUCCESS);
1472 itemp++;
1475 /* token is not on the FIRST list */
1477 return (HIDPARSER_FAILURE);
1482 * hidparser_main:
1483 * Function called from hidparser_parse_report_descriptor()
1484 * to parse the Report Descriptor
1486 static int
1487 hidparser_main(unsigned char *descriptor,
1488 size_t size,
1489 entity_item_t **item_ptr)
1491 hidparser_tok_t *scan_ifp;
1492 int retval;
1494 scan_ifp = kmem_zalloc(sizeof (hidparser_tok_t), KM_SLEEP);
1495 scan_ifp->hidparser_tok_text =
1496 kmem_zalloc(HIDPARSER_TEXT_LENGTH, KM_SLEEP);
1497 scan_ifp->hidparser_tok_max_bsize = size;
1498 scan_ifp->hidparser_tok_entity_descriptor = descriptor;
1500 *item_ptr = NULL;
1501 retval = hidparser_ReportDescriptorDash(item_ptr, scan_ifp);
1504 * Free the Local & Global item list
1505 * It maybe the case that no tree has been built
1506 * up but there have been allocation in the attribute
1507 * & control lists
1509 if (scan_ifp->hidparser_tok_gitem_head) {
1510 hidparser_free_attribute_list(
1511 scan_ifp->hidparser_tok_gitem_head);
1514 if (scan_ifp->hidparser_tok_litem_head) {
1515 hidparser_free_attribute_list(
1516 scan_ifp->hidparser_tok_litem_head);
1518 kmem_free(scan_ifp->hidparser_tok_text, HIDPARSER_TEXT_LENGTH);
1519 kmem_free(scan_ifp, sizeof (hidparser_tok_t));
1521 return (retval);
1526 * hidparser_ReportDescriptorDash:
1527 * Synthetic start symbol, implements
1528 * hidparser_ReportDescriptor <EOF>
1530 static int
1531 hidparser_ReportDescriptorDash(entity_item_t ** item_ptr,
1532 hidparser_tok_t *scan_ifp)
1535 if ((hidparser_ReportDescriptor(item_ptr, scan_ifp) ==
1536 HIDPARSER_SUCCESS) && (scan_ifp->hidparser_tok_token == 0)) {
1538 return (HIDPARSER_SUCCESS);
1542 * In case of failure, free the kernel memory
1543 * allocated for partial building of the tree,
1544 * if any
1546 if (*item_ptr != NULL) {
1547 (void) hidparser_free_report_descr_handle(*item_ptr);
1550 *item_ptr = NULL;
1552 return (HIDPARSER_FAILURE);
1557 * hidparser_ReportDescriptor:
1558 * Implements the Rule:
1559 * ReportDescriptor -> ItemList
1561 static int
1562 hidparser_ReportDescriptor(entity_item_t ** item_ptr,
1563 hidparser_tok_t *scan_ifp)
1565 hidparser_scan(scan_ifp);
1568 * We do not search for the token in FIRST(ReportDescriptor)
1569 * since -
1571 * FIRST(ReportDescriptor) == FIRST(ItemList)
1572 * ReportDescriptor ----> ItemList
1574 if (hidparser_ItemList(item_ptr, scan_ifp) == HIDPARSER_SUCCESS) {
1576 return (HIDPARSER_SUCCESS);
1579 return (HIDPARSER_FAILURE);
1584 * hidparser_ItemList:
1585 * Implements the Rule:
1586 * ItemList -> Items MainItem ItemList | epsilon
1588 * This function constructs the tree on which depends the "hidparser"
1589 * consumer functions. Basically the structure of the tree is
1591 * C--[RS]->EC--[RS]->C--[RS]->EC..(and so on)
1593 * [CH] <== This relationship is true for other "C's"
1594 * | also.
1596 * C/-------------/I/O/F <== [ Any of these ]
1597 * | ------
1598 * | |
1599 * v v
1600 * [CH | RS] [ RS ]
1601 * C/I/O/F | EC I/O/F
1604 * and so on...
1606 * where C = Collection
1607 * EC = EndCollection
1608 * I = Input
1609 * O = Output
1610 * F = Feature "Main" Items.
1612 * and the relationships are [RS] for right sibling and [CH] for
1613 * child. [CH | RS ] stands for "child or right sibling" with the
1614 * possible values below it.
1616 static int
1617 hidparser_ItemList(entity_item_t ** item_ptr, hidparser_tok_t *scan_ifp)
1619 entity_item_t *curr_ei, *cache_ei, *prev_ei, *tmp_ei;
1620 boolean_t root_coll = B_FALSE;
1622 curr_ei = cache_ei = prev_ei = tmp_ei = NULL;
1624 while (scan_ifp->hidparser_tok_token != 0) {
1625 if (hidparser_Items(scan_ifp) == HIDPARSER_FAILURE) {
1627 return (HIDPARSER_FAILURE);
1630 if (hidparser_MainItem(&curr_ei, scan_ifp) ==
1631 HIDPARSER_FAILURE) {
1632 USB_DPRINTF_L2(PRINT_MASK_ALL,
1633 hparser_log_handle,
1634 "Invalid MAIN item 0x%x in input stream",
1635 scan_ifp->hidparser_tok_token);
1637 return (HIDPARSER_FAILURE);
1639 if (curr_ei->entity_item_type == R_ITEM_COLLECTION) {
1640 if (root_coll == B_FALSE) {
1641 *item_ptr = curr_ei;
1642 root_coll = B_TRUE;
1644 curr_ei->prev_coll = cache_ei;
1645 cache_ei = curr_ei;
1647 USB_DPRINTF_L3(PRINT_MASK_ALL,
1648 hparser_log_handle,
1649 "Start Collection:cache_ei = 0x%p,"
1650 " curr_ei = 0x%p",
1651 (void *)cache_ei, (void *)curr_ei);
1653 if (prev_ei == NULL) {
1654 prev_ei = curr_ei;
1656 continue;
1658 if (prev_ei->entity_item_type ==
1659 R_ITEM_COLLECTION) {
1660 prev_ei->info.child = curr_ei;
1661 } else {
1662 prev_ei->entity_item_right_sibling =
1663 curr_ei;
1665 } else if (curr_ei->entity_item_type ==
1666 R_ITEM_END_COLLECTION) {
1667 tmp_ei = cache_ei->prev_coll;
1668 cache_ei->entity_item_right_sibling = curr_ei;
1669 USB_DPRINTF_L3(PRINT_MASK_ALL,
1670 hparser_log_handle,
1671 "End Collection: cache_ei = 0x%p, "
1672 "curr_ei = 0x%p",
1673 (void *)cache_ei, (void *)curr_ei);
1674 if (tmp_ei != NULL) {
1676 * As will be the case for final end
1677 * collection.
1679 cache_ei = tmp_ei;
1681 tmp_ei = NULL;
1682 } else {
1683 if (prev_ei == NULL) {
1684 USB_DPRINTF_L2(PRINT_MASK_ALL,
1685 hparser_log_handle,
1686 "Invalid First MAIN item 0x%x",
1687 scan_ifp->hidparser_tok_token);
1689 return (HIDPARSER_FAILURE);
1691 if (prev_ei->entity_item_type ==
1692 R_ITEM_COLLECTION) {
1693 USB_DPRINTF_L3(PRINT_MASK_ALL,
1694 hparser_log_handle,
1695 "Main Item: token = 0x%x, "
1696 "curr_ei = 0x%p "
1697 "will be the child of prev_ei "
1698 "= 0x%p, "
1699 "cache_ei being 0x%p",
1700 curr_ei->entity_item_type,
1701 (void *)curr_ei, (void *)prev_ei,
1702 (void *)cache_ei);
1703 prev_ei->info.child = curr_ei;
1704 } else {
1705 USB_DPRINTF_L3(PRINT_MASK_ALL,
1706 hparser_log_handle,
1707 "Main Item: token = 0x%x, "
1708 "curr_ei = 0x%p "
1709 "will be the right sibling of "
1710 "prev_ei = 0x%p, "
1711 "cache_ei being 0x%p",
1712 curr_ei->entity_item_type,
1713 (void *)curr_ei, (void *)prev_ei,
1714 (void *)cache_ei);
1715 prev_ei->entity_item_right_sibling =
1716 curr_ei;
1719 prev_ei = curr_ei;
1721 if (*item_ptr != cache_ei) {
1722 /* Something wrong happened */
1723 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle,
1724 "Failed to parse report descriptor");
1726 return (HIDPARSER_FAILURE);
1728 (void) hidparser_print_report_descr_handle(cache_ei, 0);
1730 return (HIDPARSER_SUCCESS);
1735 * hidparser_MainItem:
1736 * Implements the Rule:
1737 * MainItem -> BeginCollection ItemList EndCollection
1738 * | Input
1739 * | Output
1740 * | Feature
1742 static int
1743 hidparser_MainItem(entity_item_t ** item_ptr,
1744 hidparser_tok_t *scan_ifp)
1746 switch (scan_ifp->hidparser_tok_token) {
1747 case R_ITEM_INPUT:
1748 /* FALLTHRU */
1749 case R_ITEM_OUTPUT:
1750 /* FALLTHRU */
1751 case R_ITEM_FEATURE:
1752 case R_ITEM_COLLECTION:
1753 case R_ITEM_END_COLLECTION:
1754 *item_ptr = hidparser_allocate_entity(scan_ifp);
1755 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle,
1756 "hidparser_MainItem:index = 0x%lx token = 0x%x",
1757 scan_ifp->hidparser_tok_index -
1758 (*item_ptr)->entity_item_params_leng - 1,
1759 scan_ifp->hidparser_tok_token);
1760 hidparser_scan(scan_ifp);
1761 hidparser_global_err_check(*item_ptr);
1762 hidparser_local_err_check(*item_ptr);
1763 hidparser_mainitem_err_check(*item_ptr);
1765 return (HIDPARSER_SUCCESS);
1767 default:
1768 break;
1771 *item_ptr = NULL;
1773 return (HIDPARSER_FAILURE);
1778 * hidparser_Items:
1779 * Implements the Rule:
1780 * Items -> GlobalItem Items
1781 * | LocalItem Items
1782 * | SetDelimiterOpen LocalItemList
1783 * SetDelimiterClose Items
1784 * | epsilon
1786 static int
1787 hidparser_Items(hidparser_tok_t *scan_ifp)
1789 boolean_t delim_pre = B_FALSE;
1791 int token = scan_ifp->hidparser_tok_token;
1793 while (hidparser_lookup_first(HIDPARSER_ITEMS, token) ==
1794 HIDPARSER_SUCCESS) {
1795 if (token == R_ITEM_SET_DELIMITER) {
1796 if (delim_pre == B_FALSE) {
1797 if (scan_ifp->hidparser_tok_text[0] != 1) {
1798 hidparser_error_delim(NULL,
1799 HIDPARSER_DELIM_ERR1);
1800 } else {
1801 delim_pre = B_TRUE;
1803 } else {
1804 if (scan_ifp->hidparser_tok_text[0] !=
1805 0) {
1806 hidparser_error_delim(NULL,
1807 HIDPARSER_DELIM_ERR2);
1808 } else {
1809 delim_pre = B_FALSE;
1812 (void) hidparser_LocalItem(scan_ifp);
1813 token = scan_ifp->hidparser_tok_token;
1814 } else if (hidparser_GlobalItem(scan_ifp) ==
1815 HIDPARSER_SUCCESS) {
1816 token = scan_ifp->hidparser_tok_token;
1817 } else if (hidparser_LocalItem(scan_ifp) == HIDPARSER_SUCCESS) {
1818 token = scan_ifp->hidparser_tok_token;
1822 return (HIDPARSER_SUCCESS); /* epsilon */
1827 * hidparser_GlobalItem:
1828 * Implements the Rule:
1829 * GlobalItem -> UsagePage
1830 * | LogicalMinimum
1831 * | LocgicalMaximum
1832 * | PhysicalMinimum
1833 * | PhysicalMaximum
1834 * | Unit
1835 * | Exponent
1836 * | ReportSize
1837 * | ReportCount
1838 * | ReportID
1840 static int
1841 hidparser_GlobalItem(hidparser_tok_t *scan_ifp)
1844 int i;
1845 entity_attribute_stack_t *elem;
1847 switch (scan_ifp->hidparser_tok_token) {
1848 case R_ITEM_USAGE_PAGE:
1849 /* Error check */
1850 for (i = 0; i < scan_ifp->hidparser_tok_leng; i++) {
1851 /* Undefined data value: 0 */
1852 if (scan_ifp->hidparser_tok_text[i] == 0) {
1853 hidparser_report_err(
1854 HIDPARSER_ERR_WARN,
1855 HIDPARSER_ERR_STANDARD,
1856 R_ITEM_USAGE_PAGE,
1858 "Data field should be non-Zero");
1860 /* Reserved values 0x0A-0xFE */
1861 else if ((scan_ifp->hidparser_tok_text[i] >=
1862 0x0a) &&
1863 (scan_ifp->hidparser_tok_text[i] <=
1864 0xFE)) {
1865 hidparser_report_err(
1866 HIDPARSER_ERR_WARN,
1867 HIDPARSER_ERR_STANDARD,
1868 R_ITEM_USAGE_PAGE,
1870 "Data field should not use "
1871 "reserved values");
1874 break;
1875 case R_ITEM_UNIT:
1876 /* FALLTHRU */
1877 case R_ITEM_EXPONENT:
1879 * Error check:
1880 * Nibble 7 should be zero
1882 if (scan_ifp->hidparser_tok_leng == 4) {
1883 if ((scan_ifp->hidparser_tok_text[3] &
1884 0xf0) != 0) {
1885 hidparser_report_err(
1886 HIDPARSER_ERR_WARN,
1887 HIDPARSER_ERR_STANDARD,
1888 scan_ifp->hidparser_tok_token,
1890 "Data field reserved bits should "
1891 "be Zero");
1894 break;
1895 case R_ITEM_REPORT_COUNT:
1897 * Error Check:
1898 * Report Count should be nonzero
1900 for (i = 0; i < scan_ifp->hidparser_tok_leng; i++) {
1901 if (scan_ifp->hidparser_tok_text[i])
1902 break;
1904 if (i == scan_ifp->hidparser_tok_leng) {
1905 hidparser_report_err(
1906 HIDPARSER_ERR_ERROR,
1907 HIDPARSER_ERR_STANDARD,
1908 R_ITEM_REPORT_COUNT,
1910 "Report Count = 0");
1912 break;
1913 case R_ITEM_REPORT_ID:
1915 * Error check:
1916 * Report Id should be nonzero & <= 255
1918 if (scan_ifp->hidparser_tok_leng != 1) {
1919 hidparser_report_err(
1920 HIDPARSER_ERR_ERROR,
1921 HIDPARSER_ERR_STANDARD,
1922 R_ITEM_REPORT_ID,
1924 "Must be contained in a byte");
1926 if (!scan_ifp->hidparser_tok_text[0]) {
1927 hidparser_report_err(
1928 HIDPARSER_ERR_ERROR,
1929 HIDPARSER_ERR_STANDARD,
1930 R_ITEM_REPORT_ID,
1932 "Report Id must be non-zero");
1934 break;
1935 case R_ITEM_LOGICAL_MINIMUM:
1936 break;
1937 case R_ITEM_LOGICAL_MAXIMUM:
1938 break;
1939 case R_ITEM_PHYSICAL_MINIMUM:
1940 break;
1941 case R_ITEM_PHYSICAL_MAXIMUM:
1942 break;
1943 case R_ITEM_REPORT_SIZE:
1944 break;
1945 case R_ITEM_PUSH:
1946 if (scan_ifp->hidparser_tok_leng != 0) {
1947 hidparser_report_err(
1948 HIDPARSER_ERR_ERROR,
1949 HIDPARSER_ERR_STANDARD,
1950 scan_ifp->hidparser_tok_token,
1952 "Data Field size should be zero");
1953 } else {
1954 elem = (entity_attribute_stack_t *)kmem_zalloc(
1955 sizeof (entity_attribute_stack_t),
1956 KM_SLEEP);
1958 elem->list = hidparser_cp_attribute_list(
1959 scan_ifp->hidparser_tok_gitem_head);
1960 if (scan_ifp->hidparser_head) {
1961 elem->next = scan_ifp->hidparser_head;
1963 scan_ifp->hidparser_head = elem;
1966 break;
1967 case R_ITEM_POP:
1968 if (scan_ifp->hidparser_tok_leng != 0) {
1969 hidparser_report_err(
1970 HIDPARSER_ERR_ERROR,
1971 HIDPARSER_ERR_STANDARD,
1972 scan_ifp->hidparser_tok_token,
1974 "Data Field size should be zero");
1975 } else {
1976 /* Free the current global list */
1977 hidparser_free_attribute_list(scan_ifp->
1978 hidparser_tok_gitem_head);
1979 scan_ifp->hidparser_tok_gitem_head =
1980 scan_ifp->hidparser_head->list;
1981 scan_ifp->hidparser_head->list = NULL;
1982 elem = scan_ifp->hidparser_head;
1983 scan_ifp->hidparser_head = elem->next;
1984 kmem_free(elem,
1985 sizeof (entity_attribute_stack_t));
1988 break;
1989 default:
1991 return (HIDPARSER_FAILURE);
1993 /*NOTREACHED*/
1996 hidparser_add_attribute(scan_ifp);
1997 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle,
1998 "hidparser_GlobalItem:index = 0x%lx token = 0x%x",
1999 scan_ifp->hidparser_tok_index -
2000 scan_ifp->hidparser_tok_leng - 1,
2001 scan_ifp->hidparser_tok_token);
2002 hidparser_scan(scan_ifp);
2004 return (HIDPARSER_SUCCESS);
2009 * hidparser_LocalItem:
2010 * Implements the Rule:
2011 * LocalItem -> Usage
2012 * | UsageMinimum
2013 * | UsageMaximum
2014 * | DesignatorIndex
2015 * | DesignatorMinimum
2016 * | StringIndex
2017 * | StringMinimum
2018 * | StringMaximum
2020 static int
2021 hidparser_LocalItem(hidparser_tok_t *scan_ifp)
2023 int i;
2025 switch (scan_ifp->hidparser_tok_token) {
2026 case R_ITEM_USAGE:
2028 * Error Check:
2029 * Data Field should be nonzero
2031 for (i = 0; i < scan_ifp->hidparser_tok_leng; i++) {
2032 if (scan_ifp->hidparser_tok_text[i])
2033 break;
2035 if (i == scan_ifp->hidparser_tok_leng) {
2036 hidparser_report_err(
2037 HIDPARSER_ERR_WARN,
2038 HIDPARSER_ERR_STANDARD,
2039 R_ITEM_USAGE,
2041 "Data Field should be non-zero");
2043 /* FALLTHRU */
2044 case R_ITEM_USAGE_MIN:
2045 /* FALLTHRU */
2046 case R_ITEM_USAGE_MAX:
2047 /* FALLTHRU */
2048 case R_ITEM_DESIGNATOR_INDEX:
2049 /* FALLTHRU */
2050 case R_ITEM_DESIGNATOR_MIN:
2051 /* FALLTHRU */
2052 case R_ITEM_STRING_INDEX:
2053 /* FALLTHRU */
2054 case R_ITEM_STRING_MIN:
2055 /* FALLTHRU */
2056 case R_ITEM_STRING_MAX:
2057 /* FALLTHRU */
2058 case R_ITEM_SET_DELIMITER:
2059 hidparser_add_attribute(scan_ifp);
2060 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle,
2061 "hidparser_LocalItem:index = 0x%lx token = 0x%x",
2062 scan_ifp->hidparser_tok_index -
2063 scan_ifp->hidparser_tok_leng - 1,
2064 scan_ifp->hidparser_tok_token);
2065 hidparser_scan(scan_ifp);
2067 return (HIDPARSER_SUCCESS);
2069 /*NOTREACHED*/
2070 default:
2071 break;
2074 return (HIDPARSER_FAILURE);
2079 * hidparser_allocate_entity:
2080 * Allocate Item of type 'type', length 'leng' and
2081 * params 'text'. Fill in the attributes allocated
2082 * so far from both the local and global item lists.
2083 * Make the child and sibling of the item NULL.
2085 static entity_item_t *
2086 hidparser_allocate_entity(hidparser_tok_t *scan_ifp)
2088 entity_item_t *entity;
2089 entity_attribute_t *aend;
2091 int entity_type = scan_ifp->hidparser_tok_token;
2092 unsigned char *text = scan_ifp->hidparser_tok_text;
2093 int len = scan_ifp->hidparser_tok_leng;
2095 entity = kmem_zalloc(sizeof (entity_item_t), KM_SLEEP);
2096 entity->entity_item_type = entity_type;
2097 entity->entity_item_params_leng = len;
2099 if (len != 0) {
2100 entity->entity_item_params = kmem_zalloc(len, KM_SLEEP);
2101 (void) bcopy(text, entity->entity_item_params, len);
2105 * Copy attributes from entity attribute state table if not
2106 * end collection.
2108 if (entity_type != R_ITEM_END_COLLECTION) {
2109 entity->entity_item_attributes = hidparser_cp_attribute_list(
2110 scan_ifp->hidparser_tok_gitem_head);
2113 * append the control attributes, then clear out the control
2114 * attribute state table list
2116 if (entity->entity_item_attributes) {
2117 aend = hidparser_find_attribute_end(
2118 entity->entity_item_attributes);
2119 aend->entity_attribute_next =
2120 scan_ifp->hidparser_tok_litem_head;
2121 scan_ifp->hidparser_tok_litem_head = NULL;
2122 } else {
2123 entity->entity_item_attributes =
2124 scan_ifp->hidparser_tok_litem_head;
2125 scan_ifp->hidparser_tok_litem_head = NULL;
2129 entity->info.child = entity->entity_item_right_sibling = 0;
2131 return (entity);
2136 * hidparser_add_attribute:
2137 * Add an attribute to the global or local item list
2138 * If the last 4th bit from right is 1, add to the local item list
2139 * Else add to the global item list
2141 static void
2142 hidparser_add_attribute(hidparser_tok_t *scan_ifp)
2144 entity_attribute_t *newattrib, **previous, *elem;
2145 int entity = scan_ifp->hidparser_tok_token;
2146 unsigned char *text = scan_ifp->hidparser_tok_text;
2147 int len = scan_ifp->hidparser_tok_leng;
2149 if (len == 0) {
2150 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle,
2151 "hidparser_add_attribute: len = 0 for item = 0x%x",
2152 entity);
2154 return;
2157 if (entity & HIDPARSER_ISLOCAL_MASK) {
2158 previous = &scan_ifp->hidparser_tok_litem_head;
2159 } else {
2160 previous = &scan_ifp->hidparser_tok_gitem_head;
2163 elem = *previous;
2166 * remove attribute if it is already on list, except
2167 * for control attributes(local items), as we could have
2168 * multiple usages...
2169 * unless we want to hassle with checking for unique parameters.
2171 while (elem) {
2172 if (elem->entity_attribute_tag == entity &&
2173 !(entity & HIDPARSER_ISLOCAL_MASK)) {
2174 *previous = elem->entity_attribute_next;
2175 kmem_free(elem->entity_attribute_value,
2176 elem->entity_attribute_length);
2177 kmem_free(elem, sizeof (entity_attribute_t));
2178 elem = *previous;
2179 } else {
2180 previous = &elem->entity_attribute_next;
2181 elem = elem->entity_attribute_next;
2185 /* create new attribute for this entry */
2186 newattrib = hidparser_alloc_attrib_list(1);
2187 newattrib->entity_attribute_tag = entity;
2188 newattrib->entity_attribute_value = kmem_zalloc(len, KM_SLEEP);
2189 (void) bcopy(text, newattrib->entity_attribute_value, len);
2190 newattrib->entity_attribute_length = len;
2192 /* attach to end of list */
2193 *previous = newattrib;
2198 * hidparser_alloc_attrib_list:
2199 * Allocate space for n attributes , create a linked list and
2200 * return the head
2202 static entity_attribute_t *
2203 hidparser_alloc_attrib_list(int count)
2205 entity_attribute_t *head, *current;
2207 if (count <= 0) {
2209 return (NULL);
2212 head = kmem_zalloc(sizeof (entity_attribute_t), KM_SLEEP);
2213 count--;
2214 current = head;
2215 while (count--) {
2216 current->entity_attribute_next = kmem_zalloc(
2217 sizeof (entity_attribute_t), KM_SLEEP);
2218 current = current->entity_attribute_next;
2220 current->entity_attribute_next = NULL;
2222 return (head);
2227 * hidparser_cp_attribute_list:
2228 * Copies the Global item list pointed to by head
2229 * We create a clone of the global item list here
2230 * because we want to retain the Global items to
2231 * the next Main Item.
2233 static entity_attribute_t *
2234 hidparser_cp_attribute_list(entity_attribute_t *head)
2236 entity_attribute_t *return_value, *current_src, *current_dst;
2238 if (!head) {
2240 return (NULL);
2243 current_src = head;
2244 current_dst = return_value = hidparser_alloc_attrib_list(1);
2246 while (current_src) {
2247 current_dst->entity_attribute_tag =
2248 current_src->entity_attribute_tag;
2249 current_dst->entity_attribute_length =
2250 current_src->entity_attribute_length;
2251 current_dst->entity_attribute_value = kmem_zalloc(
2252 current_dst->entity_attribute_length, KM_SLEEP);
2253 (void) bcopy(current_src->entity_attribute_value,
2254 current_dst->entity_attribute_value,
2255 current_src->entity_attribute_length);
2256 if (current_src->entity_attribute_next) {
2257 current_dst->entity_attribute_next =
2258 hidparser_alloc_attrib_list(1);
2259 } else {
2260 current_dst->entity_attribute_next = NULL;
2262 current_src = current_src->entity_attribute_next;
2263 current_dst = current_dst->entity_attribute_next;
2266 return (return_value);
2271 * hidparser_find_attribute_end:
2272 * Find the last item in the attribute list pointed to by head
2274 static entity_attribute_t *
2275 hidparser_find_attribute_end(entity_attribute_t *head)
2277 if (head == NULL) {
2279 return (NULL);
2281 while (head->entity_attribute_next != NULL) {
2282 head = head->entity_attribute_next;
2285 return (head);
2290 * hidparser_free_report_descr_handle:
2291 * Free the parse tree pointed to by handle
2293 static void
2294 hidparser_free_report_descr_handle(entity_item_t *handle)
2296 entity_item_t *next, *current, *child;
2298 current = handle;
2300 while (current) {
2301 child = current->info.child;
2302 next = current->entity_item_right_sibling;
2303 if (current->entity_item_type == R_ITEM_COLLECTION) {
2304 if (current->entity_item_params != NULL)
2305 kmem_free(current->entity_item_params,
2306 current->entity_item_params_leng);
2307 if (current->entity_item_attributes != NULL)
2308 hidparser_free_attribute_list(
2309 current->entity_item_attributes);
2310 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle,
2311 "FREE 1: %s",
2312 items[current->entity_item_type]);
2313 kmem_free(current, sizeof (entity_item_t));
2314 (void) hidparser_free_report_descr_handle(child);
2315 } else {
2316 if (current->entity_item_params != NULL) {
2317 kmem_free(current->entity_item_params,
2318 current->entity_item_params_leng);
2320 if (current->entity_item_attributes != NULL) {
2321 hidparser_free_attribute_list(
2322 current->entity_item_attributes);
2324 USB_DPRINTF_L4(PRINT_MASK_ALL,
2325 hparser_log_handle, "FREE 2: %s",
2326 items[current->entity_item_type]);
2327 kmem_free(current, sizeof (entity_item_t));
2329 current = next;
2336 * hidparser_free_attribute_list:
2337 * Free the attribute list pointed to by head
2339 static void
2340 hidparser_free_attribute_list(entity_attribute_t *head)
2342 entity_attribute_t *next, *current;
2344 current = head;
2346 while (current) {
2347 next = current->entity_attribute_next;
2348 USB_DPRINTF_L4(PRINT_MASK_ALL,
2349 hparser_log_handle, "FREE: %s value_length = %d",
2350 items[current->entity_attribute_tag],
2351 current->entity_attribute_length);
2353 if (current->entity_attribute_value != NULL) {
2354 USB_DPRINTF_L4(PRINT_MASK_ALL,
2355 hparser_log_handle,
2356 "\tvalue = 0x%x",
2357 current->entity_attribute_value[0]);
2358 kmem_free(current->entity_attribute_value,
2359 current->entity_attribute_length);
2362 kmem_free(current, sizeof (entity_attribute_t));
2363 current = next;
2369 * hidparser_initialize_items:
2370 * Initialize items array before start scanning and parsing.
2371 * This array of strings are used for printing purpose.
2373 static void
2374 hidparser_initialize_items(void)
2376 items[R_ITEM_USAGE] = "Usage";
2377 items[R_ITEM_USAGE_MIN] = "Usage Minimum";
2378 items[R_ITEM_USAGE_MAX] = "Usage Maximum";
2379 items[R_ITEM_DESIGNATOR_INDEX] = "Designator Index";
2380 items[R_ITEM_DESIGNATOR_MIN] = "Designator Minimum";
2381 items[R_ITEM_DESIGNATOR_MAX] = "Designator Maximum";
2382 items[R_ITEM_STRING_INDEX] = "String Index";
2383 items[R_ITEM_STRING_MIN] = "String Minimum";
2384 items[R_ITEM_STRING_MAX] = "String Maximum";
2387 items[R_ITEM_USAGE_PAGE] = "Usage Page";
2388 items[R_ITEM_LOGICAL_MINIMUM] = "Logical Minimum";
2389 items[R_ITEM_LOGICAL_MAXIMUM] = "Logical Maximum";
2390 items[R_ITEM_PHYSICAL_MINIMUM] = "Physical Minimum";
2391 items[R_ITEM_PHYSICAL_MAXIMUM] = "Physical Maximum";
2392 items[R_ITEM_EXPONENT] = "Exponent";
2393 items[R_ITEM_UNIT] = "Unit";
2394 items[R_ITEM_REPORT_SIZE] = "Report Size";
2395 items[R_ITEM_REPORT_ID] = "Report Id";
2396 items[R_ITEM_REPORT_COUNT] = "Report Count";
2397 items[R_ITEM_PUSH] = "Push";
2398 items[R_ITEM_POP] = "Pop";
2401 items[R_ITEM_INPUT] = "Input";
2402 items[R_ITEM_OUTPUT] = "Output";
2403 items[R_ITEM_COLLECTION] = "Collection";
2404 items[R_ITEM_FEATURE] = "Feature";
2405 items[R_ITEM_END_COLLECTION] = "End Collection";
2407 items[R_ITEM_SET_DELIMITER] = "Delimiter";
2412 * hidparser_scan:
2413 * This function scans the input entity descriptor, sees the data
2414 * length, returns the next token, data bytes and length in the
2415 * scan_ifp structure.
2417 static void
2418 hidparser_scan(hidparser_tok_t *scan_ifp)
2420 int count;
2421 int ch;
2422 int parsed_length;
2423 unsigned char *parsed_text;
2424 unsigned char *entity_descriptor;
2425 char err_str[32];
2426 size_t entity_buffer_size, index;
2428 index = scan_ifp->hidparser_tok_index;
2429 entity_buffer_size = scan_ifp->hidparser_tok_max_bsize;
2430 parsed_length = 0;
2431 parsed_text = scan_ifp->hidparser_tok_text;
2432 entity_descriptor = scan_ifp->hidparser_tok_entity_descriptor;
2434 next_item:
2435 if (index <= entity_buffer_size -1) {
2437 ch = 0xFF & entity_descriptor[index];
2438 USB_DPRINTF_L4(PRINT_MASK_ALL,
2439 hparser_log_handle, "scanner: index = 0x%lx ch = 0x%x",
2440 index, ch);
2442 index++;
2445 * Error checking:
2446 * Unrecognized items should be passed over
2447 * by the parser.
2448 * Section 5.4
2450 if (!(hidparser_isvalid_item(ch))) {
2451 (void) sprintf(err_str, "%s: 0x%2x",
2452 "Unknown or reserved item", ch);
2453 hidparser_report_err(HIDPARSER_ERR_ERROR,
2454 HIDPARSER_ERR_STANDARD, 0, 0x3F, err_str);
2455 goto next_item;
2458 if (ch == EXTENDED_ITEM) {
2459 parsed_length = entity_descriptor[index++];
2460 ch = entity_descriptor[index++];
2461 hidparser_report_err(HIDPARSER_ERR_WARN,
2462 HIDPARSER_ERR_STANDARD,
2464 0x3E,
2465 "Long item defined");
2466 } else {
2467 parsed_length = ch & 0x03;
2468 USB_DPRINTF_L4(PRINT_MASK_ALL,
2469 hparser_log_handle,
2470 "scanner: parsed_length = %x", parsed_length);
2471 /* 3 really means 4.. see p.21 HID */
2472 if (parsed_length == 3)
2473 parsed_length++;
2475 for (count = 0; count < parsed_length; count++) {
2476 parsed_text[count] = entity_descriptor[index];
2477 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle,
2478 "scanner: parsed_text[%d] = 0x%x,"
2479 "index = 0x%lx",
2480 count, parsed_text[count], index);
2481 index++;
2484 USB_DPRINTF_L4(PRINT_MASK_ALL,
2485 hparser_log_handle, "scanner: lexical analyzer found 0x%x "
2486 "before translation", ch);
2488 scan_ifp->hidparser_tok_index = index;
2489 scan_ifp->hidparser_tok_leng = parsed_length;
2490 scan_ifp->hidparser_tok_token = ch & 0xFC;
2491 USB_DPRINTF_L4(PRINT_MASK_ALL,
2492 hparser_log_handle, "scanner: aindex = 0x%lx", index);
2493 } else {
2494 USB_DPRINTF_L4(PRINT_MASK_ALL,
2495 hparser_log_handle, "scanner: eindex = 0x%lx", index);
2496 scan_ifp->hidparser_tok_leng = 0;
2497 scan_ifp->hidparser_tok_token = 0; /* EOF */
2503 * hidparser_report_err:
2504 * Construct and print the error code
2505 * Ref: Hidview error check list
2507 static void
2508 hidparser_report_err(int err_level,
2509 int err_type,
2510 int tag,
2511 int subcode,
2512 char *msg)
2514 unsigned int BmParserErrorCode = 0;
2516 if (err_level) {
2517 BmParserErrorCode |= HIDPARSER_ERR_ERROR;
2519 if (err_type) {
2520 BmParserErrorCode |= HIDPARSER_ERR_STANDARD;
2522 BmParserErrorCode |= (tag << 8) & HIDPARSER_ERR_TAG_MASK;
2523 BmParserErrorCode |= subcode & HIDPARSER_ERR_SUBCODE_MASK;
2525 if (err_level) {
2526 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle,
2527 "err code = 0x%4x, err str = %s",
2528 BmParserErrorCode, msg);
2530 } else {
2531 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle,
2532 "wrn code = 0x%4x, wrn str = %s",
2533 BmParserErrorCode, msg);
2539 * hidparser_isvalid_item:
2540 * Find if the item tag is a valid one
2542 static int
2543 hidparser_isvalid_item(int tag)
2545 if (tag == EXTENDED_ITEM) {
2547 return (1);
2550 tag &= 0xFC;
2551 if ((tag == R_ITEM_INPUT) ||
2552 (tag == R_ITEM_OUTPUT) ||
2553 (tag == R_ITEM_COLLECTION) ||
2554 (tag == R_ITEM_FEATURE) ||
2555 (tag == R_ITEM_END_COLLECTION) ||
2556 (tag == R_ITEM_USAGE_PAGE) ||
2557 (tag == R_ITEM_LOGICAL_MINIMUM) ||
2558 (tag == R_ITEM_LOGICAL_MAXIMUM) ||
2559 (tag == R_ITEM_PHYSICAL_MINIMUM) ||
2560 (tag == R_ITEM_PHYSICAL_MAXIMUM) ||
2561 (tag == R_ITEM_EXPONENT) ||
2562 (tag == R_ITEM_UNIT) ||
2563 (tag == R_ITEM_REPORT_SIZE) ||
2564 (tag == R_ITEM_REPORT_ID) ||
2565 (tag == R_ITEM_REPORT_COUNT) ||
2566 (tag == R_ITEM_PUSH) ||
2567 (tag == R_ITEM_POP) ||
2568 (tag == R_ITEM_USAGE) ||
2569 (tag == R_ITEM_USAGE_MIN) ||
2570 (tag == R_ITEM_USAGE_MAX) ||
2571 (tag == R_ITEM_DESIGNATOR_INDEX) ||
2572 (tag == R_ITEM_DESIGNATOR_MIN) ||
2573 (tag == R_ITEM_DESIGNATOR_MAX) ||
2574 (tag == R_ITEM_STRING_INDEX) ||
2575 (tag == R_ITEM_STRING_MIN) ||
2576 (tag == R_ITEM_STRING_MAX) ||
2577 (tag == R_ITEM_SET_DELIMITER)) {
2579 return (1);
2580 } else {
2582 return (0);
2588 * hidparser_lookup_attribute:
2589 * Takes an item pointer(report structure) and a tag(e.g Logical
2590 * Min) as input. Returns the corresponding attribute structure.
2591 * Presently used for error checking only.
2593 static entity_attribute_t *
2594 hidparser_lookup_attribute(entity_item_t *item, int attr_tag)
2596 entity_attribute_t *temp;
2598 if (item == NULL) {
2600 return (NULL);
2603 temp = item->entity_item_attributes;
2604 while (temp != NULL) {
2605 if (temp->entity_attribute_tag == attr_tag) {
2607 return (temp);
2610 temp = temp->entity_attribute_next;
2613 return (NULL);
2618 * hidparser_global_err_check:
2619 * Error checking for Global Items that need to be
2620 * performed in MainItem
2622 static void
2623 hidparser_global_err_check(entity_item_t *mainitem)
2625 hidparser_check_minmax_val_signed(mainitem, R_ITEM_LOGICAL_MINIMUM,
2626 R_ITEM_LOGICAL_MAXIMUM, 0, 0);
2627 hidparser_check_minmax_val_signed(mainitem, R_ITEM_PHYSICAL_MINIMUM,
2628 R_ITEM_PHYSICAL_MAXIMUM, 0, 0);
2629 hidparser_check_correspondence(mainitem, R_ITEM_PHYSICAL_MINIMUM,
2630 R_ITEM_PHYSICAL_MAXIMUM, 0, 0,
2631 "Must have a corresponding Physical min",
2632 "Must have a corresponding Physical max");
2633 hidparser_check_correspondence(mainitem, R_ITEM_PUSH, R_ITEM_POP,
2634 1, 0, "Should have a corresponding Pop",
2635 "Must have a corresponding Push");
2641 * hidparser_mainitem_err_check:
2642 * Error checking for Main Items
2644 static void
2645 hidparser_mainitem_err_check(entity_item_t *mainitem)
2647 int itemmask = 0;
2648 entity_attribute_t *attr;
2650 attr = mainitem->entity_item_attributes;
2652 if (attr != NULL) {
2653 while (attr) {
2654 switch (attr->entity_attribute_tag) {
2655 case R_ITEM_LOGICAL_MINIMUM:
2656 itemmask |= 0x01;
2657 break;
2658 case R_ITEM_LOGICAL_MAXIMUM:
2659 itemmask |= 0x02;
2660 break;
2661 case R_ITEM_REPORT_SIZE:
2662 itemmask |= 0x04;
2663 break;
2664 case R_ITEM_REPORT_COUNT:
2665 itemmask |= 0x08;
2666 break;
2667 case R_ITEM_USAGE_PAGE:
2668 itemmask |= 0x10;
2669 break;
2670 default:
2671 break;
2672 } /* switch */
2673 attr = attr->entity_attribute_next;
2674 } /* while */
2675 } /* if */
2677 if ((mainitem->entity_item_type == R_ITEM_COLLECTION) ||
2678 (mainitem->entity_item_type == R_ITEM_END_COLLECTION)) {
2680 return;
2682 if (itemmask != 0x1f) {
2683 hidparser_report_err(
2684 HIDPARSER_ERR_ERROR,
2685 HIDPARSER_ERR_STANDARD,
2686 mainitem->entity_item_type,
2688 "Required Global/Local items must be defined");
2694 * hidparser_local_err_check:
2695 * Error checking for Local items that is done when a MainItem
2696 * is encountered
2698 static void
2699 hidparser_local_err_check(entity_item_t *mainitem)
2701 hidparser_check_correspondence(mainitem, R_ITEM_USAGE_MIN,
2702 R_ITEM_USAGE_MAX, 0, 0,
2703 "Must have a corresponding Usage Min",
2704 "Must have a corresponding Usage Max");
2705 hidparser_check_minmax_val(mainitem, R_ITEM_USAGE_MIN,
2706 R_ITEM_USAGE_MAX, 1, 1);
2707 hidparser_check_correspondence(mainitem, R_ITEM_DESIGNATOR_MIN,
2708 R_ITEM_DESIGNATOR_MAX, 0, 0,
2709 "Must have a corresponding Designator min",
2710 "Must have a corresponding Designator Max");
2711 hidparser_check_minmax_val(mainitem, R_ITEM_DESIGNATOR_MIN,
2712 R_ITEM_DESIGNATOR_MAX, 1, 1);
2713 hidparser_check_correspondence(mainitem, R_ITEM_STRING_MIN,
2714 R_ITEM_STRING_MAX, 0, 0,
2715 "Must have a corresponding String min",
2716 "Must have a corresponding String Max");
2717 hidparser_check_minmax_val(mainitem, R_ITEM_STRING_MIN,
2718 R_ITEM_STRING_MAX, 1, 1);
2723 * hidparser_find_unsigned_val:
2724 * Find the value for multibyte data
2725 * Ref: Section 5.8 of HID Spec 1.0
2727 static unsigned int
2728 hidparser_find_unsigned_val(entity_attribute_t *attr)
2730 char *text;
2731 int len, i;
2732 unsigned int ret = 0;
2734 text = attr->entity_attribute_value;
2735 len = attr->entity_attribute_length;
2736 for (i = 0; i < len; i++) {
2737 ret |= ((text[i] & 0xff) << (8*i));
2740 return (ret);
2745 * hidparser_find_signed_val:
2746 * Find the value for signed multibyte data
2747 * Ref: Section 5.8 of HID Spec 1.0
2749 static signed int
2750 hidparser_find_signed_val(entity_attribute_t *attr)
2752 char *text;
2753 int len, i;
2754 int ret = 0;
2756 text = attr->entity_attribute_value;
2757 len = attr->entity_attribute_length;
2759 for (i = 0; i < len - 1; i++) {
2760 ret |= ((text[i] & 0xff) << (8 * i));
2763 if (len > 0) {
2764 ret |= (text[i] << (8 * i));
2767 return (ret);
2772 * hidparser_check_correspondence:
2773 * Check if the item item2 corresponding to item1 exists and vice versa
2774 * If not report the appropriate error
2776 static void
2777 hidparser_check_correspondence(entity_item_t *mainitem,
2778 int item_tag1,
2779 int item_tag2,
2780 int val1,
2781 int val2,
2782 char *str1,
2783 char *str2)
2785 entity_attribute_t *temp1, *temp2;
2787 temp1 = hidparser_lookup_attribute(mainitem, item_tag1);
2788 temp2 = hidparser_lookup_attribute(mainitem, item_tag2);
2789 if ((temp1 != NULL) && (temp2 == NULL)) {
2790 hidparser_report_err(
2791 HIDPARSER_ERR_ERROR,
2792 HIDPARSER_ERR_STANDARD,
2793 item_tag1,
2794 val1,
2795 str1);
2797 if ((temp2 != NULL) && (temp1 == NULL)) {
2798 hidparser_report_err(
2799 HIDPARSER_ERR_ERROR,
2800 HIDPARSER_ERR_STANDARD,
2801 item_tag2,
2802 val2,
2803 str2);
2809 * hidparser_check_minmax_val:
2810 * Check if the Min value <= Max and vice versa
2811 * Print for warnings and errors have been taken care separately.
2813 static void
2814 hidparser_check_minmax_val(entity_item_t *mainitem,
2815 int item_tag1,
2816 int item_tag2,
2817 int val1,
2818 int val2)
2820 entity_attribute_t *temp1, *temp2;
2822 temp1 = hidparser_lookup_attribute(mainitem, item_tag1);
2823 temp2 = hidparser_lookup_attribute(mainitem, item_tag2);
2824 if ((temp1 != NULL) && (temp2 != NULL)) {
2825 if (hidparser_find_unsigned_val(temp1) >
2826 hidparser_find_unsigned_val(temp2)) {
2827 if ((item_tag1 == R_ITEM_LOGICAL_MINIMUM) ||
2828 (item_tag1 == R_ITEM_PHYSICAL_MINIMUM)) {
2829 hidparser_report_err(
2830 HIDPARSER_ERR_WARN,
2831 HIDPARSER_ERR_STANDARD,
2832 item_tag1,
2833 val1,
2834 "unsigned: Min should be <= to Max");
2835 } else {
2836 hidparser_report_err(
2837 HIDPARSER_ERR_ERROR,
2838 HIDPARSER_ERR_STANDARD,
2839 item_tag1,
2840 val1,
2841 "Min must be <= to Max");
2844 if (hidparser_find_unsigned_val(temp2) <
2845 hidparser_find_unsigned_val(temp1)) {
2846 if ((item_tag2 == R_ITEM_LOGICAL_MAXIMUM) ||
2847 (item_tag2 == R_ITEM_PHYSICAL_MAXIMUM)) {
2848 hidparser_report_err(
2849 HIDPARSER_ERR_ERROR,
2850 HIDPARSER_ERR_STANDARD,
2851 item_tag2,
2852 val2,
2853 "unsigned: Max should be >= to Min");
2854 } else {
2855 hidparser_report_err(
2856 HIDPARSER_ERR_ERROR,
2857 HIDPARSER_ERR_STANDARD,
2858 item_tag2,
2859 val2,
2860 "Max must be >= to Min");
2863 } /* if (temp1 != NULL) && (temp2 != NULL) */
2868 * hidparser_check_minmax_val_signed:
2869 * Check if the Min value <= Max and vice versa
2870 * Print for warnings and errors have been taken care separately.
2872 static void
2873 hidparser_check_minmax_val_signed(entity_item_t *mainitem,
2874 int item_tag1,
2875 int item_tag2,
2876 int val1,
2877 int val2)
2879 entity_attribute_t *temp1, *temp2;
2881 temp1 = hidparser_lookup_attribute(mainitem, item_tag1);
2882 temp2 = hidparser_lookup_attribute(mainitem, item_tag2);
2883 if ((temp1 != NULL) && (temp2 != NULL)) {
2884 if (hidparser_find_signed_val(temp1) >
2885 hidparser_find_signed_val(temp2)) {
2886 if ((item_tag1 == R_ITEM_LOGICAL_MINIMUM) ||
2887 (item_tag1 == R_ITEM_PHYSICAL_MINIMUM)) {
2888 hidparser_report_err(
2889 HIDPARSER_ERR_WARN,
2890 HIDPARSER_ERR_STANDARD,
2891 item_tag1,
2892 val1,
2893 "signed: Min should be <= to Max");
2894 } else {
2895 hidparser_report_err(
2896 HIDPARSER_ERR_ERROR,
2897 HIDPARSER_ERR_STANDARD,
2898 item_tag1,
2899 val1,
2900 "Min must be <= to Max");
2903 if (hidparser_find_signed_val(temp2) <
2904 hidparser_find_signed_val(temp1)) {
2905 if ((item_tag2 == R_ITEM_LOGICAL_MAXIMUM) ||
2906 (item_tag2 == R_ITEM_PHYSICAL_MAXIMUM)) {
2907 hidparser_report_err(
2908 HIDPARSER_ERR_ERROR,
2909 HIDPARSER_ERR_STANDARD,
2910 item_tag2,
2911 val2,
2912 "signed: Max should be >= to Min");
2913 } else {
2914 hidparser_report_err(
2915 HIDPARSER_ERR_ERROR,
2916 HIDPARSER_ERR_STANDARD,
2917 item_tag2,
2918 val2,
2919 "Max must be >= to Min");
2922 } /* if (temp1 != NULL) && (temp2 != NULL) */
2927 * hidparser_error_delim:
2928 * Error check for Delimiter Sets
2930 static void
2931 hidparser_error_delim(entity_item_t *item, int err)
2933 entity_attribute_t *attr;
2934 switch (err) {
2935 case HIDPARSER_DELIM_ERR1:
2936 hidparser_report_err(
2937 HIDPARSER_ERR_ERROR,
2938 HIDPARSER_ERR_STANDARD,
2939 R_ITEM_SET_DELIMITER,
2941 "Must be Delimiter Open");
2943 break;
2944 case HIDPARSER_DELIM_ERR2:
2945 hidparser_report_err(
2946 HIDPARSER_ERR_ERROR,
2947 HIDPARSER_ERR_STANDARD,
2948 R_ITEM_SET_DELIMITER,
2950 "Must be Delimiter Close");
2952 break;
2953 case HIDPARSER_DELIM_ERR3:
2954 attr = item->entity_item_attributes;
2955 while (attr != NULL) {
2956 if ((attr->entity_attribute_tag !=
2957 R_ITEM_USAGE) &&
2958 (attr->entity_attribute_tag !=
2959 R_ITEM_USAGE_MIN) &&
2960 (attr->entity_attribute_tag !=
2961 R_ITEM_USAGE_MAX)) {
2962 hidparser_report_err(
2963 HIDPARSER_ERR_ERROR,
2964 HIDPARSER_ERR_STANDARD,
2965 R_ITEM_SET_DELIMITER,
2967 "May only contain Usage, "
2968 "Usage Min and Usage Max");
2970 attr = attr->entity_attribute_next;
2973 break;
2974 default:
2976 break;
2982 * hidparser_find_max_packet_size_from_report_descriptor:
2983 * find packet size of the largest report in the report descriptor
2985 void
2986 hidparser_find_max_packet_size_from_report_descriptor(
2987 hidparser_handle_t hparser_handle,
2988 hidparser_packet_info_t *hpack)
2991 int rval, i;
2992 uint_t packet_size;
2993 uint_t max_packet_size;
2994 uint_t max_report_id;
2995 hidparser_report_id_list_t report_id_list;
2997 USB_DPRINTF_L4(PRINT_MASK_ALL, hparser_log_handle,
2998 "hidparser_find_max_packet_size_from_report_descriptor");
3000 /* get a list of input reports */
3001 rval = hidparser_get_report_id_list(hparser_handle,
3002 R_ITEM_INPUT, &report_id_list);
3003 if (rval != HIDPARSER_SUCCESS) {
3004 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle,
3005 "No report id used");
3006 } else {
3007 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle,
3008 "%d unique report IDs found in hid report descriptor",
3009 report_id_list.no_of_report_ids);
3011 for (i = 0; i < (report_id_list.no_of_report_ids); i++) {
3012 USB_DPRINTF_L3(PRINT_MASK_ALL, hparser_log_handle,
3013 "report_id: %d", report_id_list.report_id[i]);
3017 if ((rval != HIDPARSER_SUCCESS) ||
3018 (report_id_list.no_of_report_ids == 0)) {
3020 * since no report id is used, get the packet size
3021 * for the only report available
3023 (void) hidparser_get_packet_size(hparser_handle,
3024 0, R_ITEM_INPUT, &packet_size);
3025 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle,
3026 "Not using report id prefix. HID packet size = %d",
3027 packet_size);
3029 hpack->max_packet_size = packet_size;
3030 hpack->report_id = HID_REPORT_ID_UNDEFINED;
3031 } else {
3033 * hid device uses multiple reports with report id prefix byte.
3034 * Find the longest input report.
3035 * See HID 8.4.
3037 max_packet_size = 0;
3038 max_report_id = 0;
3040 for (i = 0; i < (report_id_list.no_of_report_ids); i++) {
3041 (void) hidparser_get_packet_size(hparser_handle,
3042 report_id_list.report_id[i], R_ITEM_INPUT,
3043 &packet_size);
3044 if (packet_size > max_packet_size) {
3045 max_packet_size = packet_size;
3046 max_report_id = report_id_list.report_id[i];
3048 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle,
3049 "Report ID %d has a packet size of %d",
3050 report_id_list.report_id[i], packet_size);
3053 hpack->max_packet_size = max_packet_size;
3054 hpack->report_id = max_report_id;
3056 USB_DPRINTF_L2(PRINT_MASK_ALL, hparser_log_handle,
3057 "Report ID %d has the maximum packet size of %d",
3058 max_report_id, max_packet_size);