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