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