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