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