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