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