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