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