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