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