1 /* 2 * PROJECT: ReactOS HID Parser Library 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: lib/drivers/hidparser/parser.c 5 * PURPOSE: HID Parser 6 * PROGRAMMERS: 7 * Michael Martin (michael.martin@reactos.org) 8 * Johannes Anderwald (johannes.anderwald@reactos.org) 9 */ 10 11 #include "parser.h" 12 13 #define NDEBUG 14 #include <debug.h> 15 16 static UCHAR ItemSize[4] = { 0, 1, 2, 4 }; 17 18 VOID 19 HidParser_DeleteReport( 20 IN PHID_REPORT Report) 21 { 22 // 23 // not implemented 24 // 25 } 26 27 VOID 28 HidParser_FreeCollection( 29 IN PHID_COLLECTION Collection) 30 { 31 // 32 // not implemented 33 // 34 } 35 36 NTSTATUS 37 HidParser_AllocateCollection( 38 IN PHID_COLLECTION ParentCollection, 39 IN UCHAR Type, 40 IN PLOCAL_ITEM_STATE LocalItemState, 41 OUT PHID_COLLECTION * OutCollection) 42 { 43 PHID_COLLECTION Collection; 44 USAGE_VALUE UsageValue; 45 46 // 47 // first allocate the collection 48 // 49 Collection = (PHID_COLLECTION)AllocFunction(sizeof(HID_COLLECTION)); 50 if (!Collection) 51 { 52 // 53 // no memory 54 // 55 return HIDP_STATUS_INTERNAL_ERROR; 56 } 57 58 // 59 // init collection 60 // 61 Collection->Root = ParentCollection; 62 Collection->Type = Type; 63 Collection->StringID = LocalItemState->StringIndex; 64 Collection->PhysicalID = LocalItemState->DesignatorIndex; 65 66 // 67 // set Usage 68 // 69 ASSERT(LocalItemState); 70 ASSERT(LocalItemState->UsageStack); 71 72 if (LocalItemState->UsageStackUsed > 0) 73 { 74 // 75 // usage value from first local stack item 76 // 77 UsageValue.u.Extended = LocalItemState->UsageStack[0].u.Extended; 78 } 79 else if (LocalItemState->UsageMinimumSet) 80 { 81 // 82 // use value from minimum 83 // 84 UsageValue.u.Extended = LocalItemState->UsageMinimum.u.Extended; 85 } 86 else if (LocalItemState->UsageMaximumSet) 87 { 88 // 89 // use value from maximum 90 // 91 UsageValue.u.Extended = LocalItemState->UsageMaximum.u.Extended; 92 } 93 else if (Type == COLLECTION_LOGICAL) 94 { 95 // 96 // root collection 97 // 98 UsageValue.u.Extended = 0; 99 } 100 else 101 { 102 // 103 // no usage set 104 // 105 DebugFunction("HIDPARSE] No usage set\n"); 106 UsageValue.u.Extended = 0; 107 } 108 109 // 110 // store usage 111 // 112 Collection->Usage = UsageValue.u.Extended; 113 114 // 115 // store result 116 // 117 *OutCollection = Collection; 118 119 // 120 // done 121 // 122 return HIDP_STATUS_SUCCESS; 123 } 124 125 NTSTATUS 126 HidParser_AddCollection( 127 IN PHID_COLLECTION CurrentCollection, 128 IN PHID_COLLECTION NewCollection) 129 { 130 PHID_COLLECTION * NewAllocCollection; 131 ULONG CollectionCount; 132 133 // 134 // increment collection array 135 // 136 CollectionCount = CurrentCollection->NodeCount + 1; 137 138 // 139 // allocate new collection 140 // 141 NewAllocCollection = (PHID_COLLECTION*)AllocFunction(sizeof(PHID_COLLECTION) * CollectionCount); 142 if (!NewAllocCollection) 143 { 144 // 145 // no memory 146 // 147 return HIDP_STATUS_INTERNAL_ERROR; 148 } 149 150 if (CurrentCollection->NodeCount) 151 { 152 // 153 // copy old array 154 // 155 CopyFunction(NewAllocCollection, CurrentCollection->Nodes, CurrentCollection->NodeCount * sizeof(PHID_COLLECTION)); 156 157 // 158 // delete old array 159 // 160 FreeFunction(CurrentCollection->Nodes); 161 } 162 163 // 164 // insert new item 165 // 166 NewAllocCollection[CurrentCollection->NodeCount] = (struct __HID_COLLECTION__*)NewCollection; 167 168 169 // 170 // store new array 171 // 172 CurrentCollection->Nodes = NewAllocCollection; 173 CurrentCollection->NodeCount++; 174 175 // 176 // done 177 // 178 return HIDP_STATUS_SUCCESS; 179 } 180 181 NTSTATUS 182 HidParser_FindReportInCollection( 183 IN PHID_COLLECTION Collection, 184 IN UCHAR ReportType, 185 IN UCHAR ReportID, 186 OUT PHID_REPORT *OutReport) 187 { 188 ULONG Index; 189 NTSTATUS Status; 190 191 // 192 // search in local list 193 // 194 for(Index = 0; Index < Collection->ReportCount; Index++) 195 { 196 if (Collection->Reports[Index]->Type == ReportType && Collection->Reports[Index]->ReportID == ReportID) 197 { 198 // 199 // found report 200 // 201 *OutReport = Collection->Reports[Index]; 202 return HIDP_STATUS_SUCCESS; 203 } 204 } 205 206 // 207 // search in sub collections 208 // 209 for(Index = 0; Index < Collection->NodeCount; Index++) 210 { 211 Status = HidParser_FindReportInCollection(Collection->Nodes[Index], ReportType, ReportID, OutReport); 212 if (Status == HIDP_STATUS_SUCCESS) 213 return Status; 214 } 215 216 // 217 // no such report found 218 // 219 *OutReport = NULL; 220 return HIDP_STATUS_REPORT_DOES_NOT_EXIST; 221 } 222 223 224 NTSTATUS 225 HidParser_FindReport( 226 IN PHID_PARSER_CONTEXT ParserContext, 227 IN UCHAR ReportType, 228 IN UCHAR ReportID, 229 OUT PHID_REPORT *OutReport) 230 { 231 // 232 // search in current top level collection 233 // 234 return HidParser_FindReportInCollection(ParserContext->RootCollection->Nodes[ParserContext->RootCollection->NodeCount-1], ReportType, ReportID, OutReport); 235 } 236 237 NTSTATUS 238 HidParser_AllocateReport( 239 IN UCHAR ReportType, 240 IN UCHAR ReportID, 241 OUT PHID_REPORT *OutReport) 242 { 243 PHID_REPORT Report; 244 245 // 246 // allocate report 247 // 248 Report = (PHID_REPORT)AllocFunction(sizeof(HID_REPORT)); 249 if (!Report) 250 { 251 // 252 // no memory 253 // 254 return HIDP_STATUS_INTERNAL_ERROR; 255 } 256 257 // 258 // init report 259 // 260 Report->ReportID = ReportID; 261 Report->Type = ReportType; 262 263 // 264 // done 265 // 266 *OutReport = Report; 267 return HIDP_STATUS_SUCCESS; 268 } 269 270 NTSTATUS 271 HidParser_AddReportToCollection( 272 IN PHID_PARSER_CONTEXT ParserContext, 273 IN PHID_COLLECTION CurrentCollection, 274 IN PHID_REPORT NewReport) 275 { 276 PHID_REPORT * NewReportArray; 277 278 // 279 // allocate new report array 280 // 281 NewReportArray = (PHID_REPORT*)AllocFunction(sizeof(PHID_REPORT) * (CurrentCollection->ReportCount + 1)); 282 if (!NewReportArray) 283 { 284 // 285 // no memory 286 // 287 return HIDP_STATUS_INTERNAL_ERROR; 288 } 289 290 if (CurrentCollection->ReportCount) 291 { 292 // 293 // copy old array contents 294 // 295 CopyFunction(NewReportArray, CurrentCollection->Reports, sizeof(PHID_REPORT) * CurrentCollection->ReportCount); 296 297 // 298 // free old array 299 // 300 FreeFunction(CurrentCollection->Reports); 301 } 302 303 // 304 // store result 305 // 306 NewReportArray[CurrentCollection->ReportCount] = NewReport; 307 CurrentCollection->Reports = NewReportArray; 308 CurrentCollection->ReportCount++; 309 310 // 311 // completed successfully 312 // 313 return HIDP_STATUS_SUCCESS; 314 } 315 316 NTSTATUS 317 HidParser_GetReport( 318 IN PHID_PARSER_CONTEXT ParserContext, 319 IN PHID_COLLECTION Collection, 320 IN UCHAR ReportType, 321 IN UCHAR ReportID, 322 IN UCHAR CreateIfNotExists, 323 OUT PHID_REPORT *OutReport) 324 { 325 NTSTATUS Status; 326 327 // 328 // try finding existing report 329 // 330 Status = HidParser_FindReport(ParserContext, ReportType, ReportID, OutReport); 331 if (Status == HIDP_STATUS_SUCCESS || CreateIfNotExists == FALSE) 332 { 333 // 334 // founed report 335 // 336 return Status; 337 } 338 339 // 340 // allocate new report 341 // 342 Status = HidParser_AllocateReport(ReportType, ReportID, OutReport); 343 if (Status != HIDP_STATUS_SUCCESS) 344 { 345 // 346 // failed to allocate report 347 // 348 return Status; 349 } 350 351 // 352 // add report 353 // 354 Status = HidParser_AddReportToCollection(ParserContext, Collection, *OutReport); 355 if (Status != HIDP_STATUS_SUCCESS) 356 { 357 // 358 // failed to allocate report 359 // 360 FreeFunction(*OutReport); 361 } 362 363 // 364 // done 365 // 366 return Status; 367 } 368 369 NTSTATUS 370 HidParser_ReserveReportItems( 371 IN PHID_REPORT Report, 372 IN ULONG ReportCount, 373 OUT PHID_REPORT *OutReport) 374 { 375 PHID_REPORT NewReport; 376 ULONG OldSize, Size; 377 378 if (Report->ItemCount + ReportCount <= Report->ItemAllocated) 379 { 380 // 381 // space is already allocated 382 // 383 *OutReport = Report; 384 return HIDP_STATUS_SUCCESS; 385 } 386 387 // 388 //calculate new size 389 // 390 OldSize = sizeof(HID_REPORT) + (Report->ItemCount) * sizeof(HID_REPORT_ITEM); 391 Size = ReportCount * sizeof(HID_REPORT_ITEM); 392 393 // 394 // allocate memory 395 // 396 NewReport = (PHID_REPORT)AllocFunction(Size + OldSize); 397 if (!NewReport) 398 { 399 // 400 // no memory 401 // 402 return HIDP_STATUS_INTERNAL_ERROR; 403 } 404 405 406 // 407 // copy old report 408 // 409 CopyFunction(NewReport, Report, OldSize); 410 411 // 412 // increase array size 413 // 414 NewReport->ItemAllocated += ReportCount; 415 416 // 417 // store result 418 // 419 *OutReport = NewReport; 420 421 // 422 // completed sucessfully 423 // 424 return HIDP_STATUS_SUCCESS; 425 } 426 427 VOID 428 HidParser_SignRange( 429 IN ULONG Minimum, 430 IN ULONG Maximum, 431 OUT PULONG NewMinimum, 432 OUT PULONG NewMaximum) 433 { 434 ULONG Mask = 0x80000000; 435 ULONG Index; 436 437 for (Index = 0; Index < 4; Index++) 438 { 439 if (Minimum & Mask) 440 { 441 Minimum |= Mask; 442 if (Maximum & Mask) 443 Maximum |= Mask; 444 return; 445 } 446 447 Mask >>= 8; 448 Mask |= 0xff000000; 449 } 450 451 *NewMinimum = Minimum; 452 *NewMaximum = Maximum; 453 } 454 455 NTSTATUS 456 HidParser_InitReportItem( 457 IN PHID_REPORT Report, 458 IN PHID_REPORT_ITEM ReportItem, 459 IN PGLOBAL_ITEM_STATE GlobalItemState, 460 IN PLOCAL_ITEM_STATE LocalItemState, 461 IN PMAIN_ITEM_DATA ItemData, 462 IN ULONG ReportItemIndex) 463 { 464 ULONG LogicalMinimum; 465 ULONG LogicalMaximum; 466 ULONG PhysicalMinimum; 467 ULONG PhysicalMaximum; 468 ULONG UsageMinimum; 469 ULONG UsageMaximum; 470 USAGE_VALUE UsageValue; 471 472 // 473 // get logical bounds 474 // 475 LogicalMinimum = GlobalItemState->LogicalMinimum; 476 LogicalMaximum = GlobalItemState->LogicialMaximum; 477 if (LogicalMinimum > LogicalMaximum) 478 { 479 // 480 // make them signed 481 // 482 HidParser_SignRange(LogicalMinimum, LogicalMaximum, &LogicalMinimum, &LogicalMaximum); 483 } 484 //ASSERT(LogicalMinimum <= LogicalMaximum); 485 486 // 487 // get physical bounds 488 // 489 PhysicalMinimum = GlobalItemState->PhysicalMinimum; 490 PhysicalMaximum = GlobalItemState->PhysicalMaximum; 491 if (PhysicalMinimum > PhysicalMaximum) 492 { 493 // 494 // make them signed 495 // 496 HidParser_SignRange(PhysicalMinimum, PhysicalMaximum, &PhysicalMinimum, &PhysicalMaximum); 497 } 498 //ASSERT(PhysicalMinimum <= PhysicalMaximum); 499 500 // 501 // get usage bounds 502 // 503 UsageMinimum = 0; 504 UsageMaximum = 0; 505 if (ItemData->ArrayVariable == FALSE) 506 { 507 // 508 // get usage bounds 509 // 510 UsageMinimum = LocalItemState->UsageMinimum.u.Extended; 511 UsageMaximum = LocalItemState->UsageMaximum.u.Extended; 512 } 513 else 514 { 515 // 516 // get usage value from stack 517 // 518 if (ReportItemIndex < LocalItemState->UsageStackUsed) 519 { 520 // 521 // use stack item 522 // 523 UsageValue = LocalItemState->UsageStack[ReportItemIndex]; 524 } 525 else 526 { 527 // 528 // get usage minimum from local state 529 // 530 UsageValue = LocalItemState->UsageMinimum; 531 532 // 533 // append item index 534 // 535 UsageValue.u.Extended += ReportItemIndex; 536 537 if (LocalItemState->UsageMaximumSet) 538 { 539 if (UsageValue.u.Extended > LocalItemState->UsageMaximum.u.Extended) 540 { 541 // 542 // maximum reached 543 // 544 UsageValue.u.Extended = LocalItemState->UsageMaximum.u.Extended; 545 } 546 } 547 } 548 549 // 550 // usage usage bounds 551 // 552 UsageMinimum = UsageMaximum = UsageValue.u.Extended; 553 } 554 555 // 556 // now store all values 557 // 558 ReportItem->ByteOffset = (Report->ReportSize / 8); 559 ReportItem->Shift = (Report->ReportSize % 8); 560 ReportItem->Mask = ~(0xFFFFFFFF << GlobalItemState->ReportSize); 561 ReportItem->BitCount = GlobalItemState->ReportSize; 562 ReportItem->HasData = (ItemData->DataConstant == FALSE); 563 ReportItem->Array = (ItemData->ArrayVariable == 0); 564 ReportItem->Relative = (ItemData->Relative != FALSE); 565 ReportItem->Minimum = LogicalMinimum; 566 ReportItem->Maximum = LogicalMaximum; 567 ReportItem->UsageMinimum = UsageMinimum; 568 ReportItem->UsageMaximum = UsageMaximum; 569 570 // 571 // increment report size 572 // 573 Report->ReportSize += GlobalItemState->ReportSize; 574 575 // 576 // completed successfully 577 // 578 return HIDP_STATUS_SUCCESS; 579 } 580 581 BOOLEAN 582 HidParser_UpdateCurrentCollectionReport( 583 IN PHID_COLLECTION Collection, 584 IN PHID_REPORT Report, 585 IN PHID_REPORT NewReport) 586 { 587 ULONG Index; 588 BOOLEAN Found = FALSE, TempFound; 589 590 // 591 // search in local list 592 // 593 for(Index = 0; Index < Collection->ReportCount; Index++) 594 { 595 if (Collection->Reports[Index] == Report) 596 { 597 // 598 // update report 599 // 600 Collection->Reports[Index] = NewReport; 601 Found = TRUE; 602 } 603 } 604 605 // 606 // search in sub collections 607 // 608 for(Index = 0; Index < Collection->NodeCount; Index++) 609 { 610 // 611 // was it found 612 // 613 TempFound = HidParser_UpdateCurrentCollectionReport(Collection->Nodes[Index], Report, NewReport); 614 if (TempFound) 615 { 616 // 617 // the same report should not be found in different collections 618 // 619 ASSERT(Found == FALSE); 620 Found = TRUE; 621 } 622 } 623 624 // 625 // done 626 // 627 return Found; 628 } 629 630 BOOLEAN 631 HidParser_UpdateCollectionReport( 632 IN PHID_PARSER_CONTEXT ParserContext, 633 IN PHID_REPORT Report, 634 IN PHID_REPORT NewReport) 635 { 636 // 637 // update in current collection 638 // 639 return HidParser_UpdateCurrentCollectionReport(ParserContext->RootCollection->Nodes[ParserContext->RootCollection->NodeCount-1], Report, NewReport); 640 } 641 642 643 NTSTATUS 644 HidParser_AddMainItem( 645 IN PHID_PARSER_CONTEXT ParserContext, 646 IN PHID_REPORT Report, 647 IN PGLOBAL_ITEM_STATE GlobalItemState, 648 IN PLOCAL_ITEM_STATE LocalItemState, 649 IN PMAIN_ITEM_DATA ItemData, 650 IN PHID_COLLECTION Collection) 651 { 652 NTSTATUS Status; 653 ULONG Index; 654 PHID_REPORT NewReport; 655 BOOLEAN Found; 656 657 // 658 // first grow report item array 659 // 660 Status = HidParser_ReserveReportItems(Report, GlobalItemState->ReportCount, &NewReport); 661 if (Status != HIDP_STATUS_SUCCESS) 662 { 663 // 664 // failed to allocate memory 665 // 666 return Status; 667 } 668 669 if (NewReport != Report) 670 { 671 // 672 // update current top level collection 673 // 674 Found = HidParser_UpdateCollectionReport(ParserContext, Report, NewReport); 675 ASSERT(Found); 676 } 677 678 // 679 // sanity check 680 // 681 ASSERT(NewReport->ItemCount + GlobalItemState->ReportCount <= NewReport->ItemAllocated); 682 683 for(Index = 0; Index < GlobalItemState->ReportCount; Index++) 684 { 685 Status = HidParser_InitReportItem(NewReport, &NewReport->Items[NewReport->ItemCount], GlobalItemState, LocalItemState, ItemData, Index); 686 if (Status != HIDP_STATUS_SUCCESS) 687 { 688 // 689 // failed to init report item 690 // 691 return Status; 692 } 693 694 // 695 // increment report item count 696 // 697 NewReport->ItemCount++; 698 } 699 700 // 701 // done 702 // 703 return HIDP_STATUS_SUCCESS; 704 } 705 706 NTSTATUS 707 HidParser_ParseReportDescriptor( 708 IN PUCHAR ReportDescriptor, 709 IN ULONG ReportLength, 710 OUT PVOID *OutParser) 711 { 712 PGLOBAL_ITEM_STATE LinkedGlobalItemState, NextLinkedGlobalItemState; 713 ULONG Index; 714 PUSAGE_VALUE NewUsageStack, UsageValue; 715 NTSTATUS Status; 716 PHID_COLLECTION CurrentCollection, NewCollection; 717 PUCHAR CurrentOffset, ReportEnd; 718 PITEM_PREFIX CurrentItem; 719 ULONG CurrentItemSize; 720 PLONG_ITEM CurrentLongItem; 721 PSHORT_ITEM CurrentShortItem; 722 ULONG Data; 723 UCHAR ReportType; 724 PHID_REPORT Report; 725 PMAIN_ITEM_DATA MainItemData; 726 PHID_PARSER_CONTEXT ParserContext; 727 728 CurrentOffset = ReportDescriptor; 729 ReportEnd = ReportDescriptor + ReportLength; 730 731 if (ReportDescriptor >= ReportEnd) 732 return HIDP_STATUS_USAGE_NOT_FOUND; 733 734 // 735 // allocate parser 736 // 737 ParserContext = AllocFunction(sizeof(HID_PARSER_CONTEXT)); 738 if (!ParserContext) 739 return HIDP_STATUS_INTERNAL_ERROR; 740 741 742 // 743 // allocate usage stack 744 // 745 ParserContext->LocalItemState.UsageStackAllocated = 10; 746 ParserContext->LocalItemState.UsageStack = (PUSAGE_VALUE)AllocFunction(ParserContext->LocalItemState.UsageStackAllocated * sizeof(USAGE_VALUE)); 747 if (!ParserContext->LocalItemState.UsageStack) 748 { 749 // 750 // no memory 751 // 752 FreeFunction(ParserContext); 753 return HIDP_STATUS_INTERNAL_ERROR; 754 } 755 756 // 757 // now allocate root collection 758 // 759 Status = HidParser_AllocateCollection(NULL, COLLECTION_LOGICAL, &ParserContext->LocalItemState, &ParserContext->RootCollection); 760 if (Status != HIDP_STATUS_SUCCESS) 761 { 762 // 763 // no memory 764 // 765 FreeFunction(ParserContext->LocalItemState.UsageStack); 766 ParserContext->LocalItemState.UsageStack = NULL; 767 FreeFunction(ParserContext); 768 return HIDP_STATUS_INTERNAL_ERROR; 769 } 770 771 // 772 // start parsing 773 // 774 CurrentCollection = ParserContext->RootCollection; 775 776 do 777 { 778 // 779 // get current item 780 // 781 CurrentItem = (PITEM_PREFIX)CurrentOffset; 782 783 // 784 // get item size 785 // 786 CurrentItemSize = ItemSize[CurrentItem->Size]; 787 Data = 0; 788 789 if (CurrentItem->Type == ITEM_TYPE_LONG) 790 { 791 // 792 // increment item size with size of data item 793 // 794 CurrentLongItem = (PLONG_ITEM)CurrentItem; 795 CurrentItemSize += CurrentLongItem->DataSize; 796 } 797 else 798 { 799 // 800 // get short item 801 // 802 CurrentShortItem = (PSHORT_ITEM)CurrentItem; 803 804 // 805 // get associated data 806 // 807 //ASSERT(CurrentItemSize == 1 || CurrentItemSize == 2 || CurrentItemSize == 4); 808 if (CurrentItemSize == 1) 809 Data = CurrentShortItem->Data.UData8[0]; 810 else if (CurrentItemSize == 2) 811 Data = CurrentShortItem->Data.UData16[0]; 812 else if (CurrentItemSize == 4) 813 Data = CurrentShortItem->Data.UData32; 814 else 815 { 816 // 817 // invalid item size 818 // 819 //DebugFunction("CurrentItem invalid item size %lu\n", CurrentItemSize); 820 } 821 822 } 823 DebugFunction("Tag %x Type %x Size %x Offset %lu Length %lu\n", CurrentItem->Tag, CurrentItem->Type, CurrentItem->Size, ((ULONG_PTR)CurrentItem - (ULONG_PTR)ReportDescriptor), ReportLength); 824 // 825 // handle items 826 // 827 ASSERT(CurrentItem->Type >= ITEM_TYPE_MAIN && CurrentItem->Type <= ITEM_TYPE_LONG); 828 switch(CurrentItem->Type) 829 { 830 case ITEM_TYPE_MAIN: 831 { 832 // preprocess the local state if relevant (usages for 833 // collections and report items) 834 if (CurrentItem->Tag != ITEM_TAG_MAIN_END_COLLECTION) 835 { 836 // make all usages extended for easier later processing 837 for (Index = 0; Index < ParserContext->LocalItemState.UsageStackUsed; Index++) 838 { 839 // 840 // is it already extended 841 // 842 if (ParserContext->LocalItemState.UsageStack[Index].IsExtended) 843 continue; 844 845 // 846 // extend usage item 847 // 848 ParserContext->LocalItemState.UsageStack[Index].u.s.UsagePage = ParserContext->GlobalItemState.UsagePage; 849 ParserContext->LocalItemState.UsageStack[Index].IsExtended = TRUE; 850 } 851 852 if (!ParserContext->LocalItemState.UsageMinimum.IsExtended) { 853 // the specs say if one of them is extended they must 854 // both be extended, so if the minimum isn't, the 855 // maximum mustn't either. 856 ParserContext->LocalItemState.UsageMinimum.u.s.UsagePage 857 = ParserContext->LocalItemState.UsageMaximum.u.s.UsagePage 858 = ParserContext->GlobalItemState.UsagePage; 859 ParserContext->LocalItemState.UsageMinimum.IsExtended 860 = ParserContext->LocalItemState.UsageMaximum.IsExtended = TRUE; 861 } 862 863 //LocalItemState.usage_stack = usageStack; 864 //ParserContext->LocalItemState.UsageStackUsed = UsageStackUsed; 865 } 866 867 if (CurrentItem->Tag == ITEM_TAG_MAIN_COLLECTION) { 868 869 // 870 // allocate new collection 871 // 872 Status = HidParser_AllocateCollection(CurrentCollection, (UCHAR)Data, &ParserContext->LocalItemState, &NewCollection); 873 ASSERT(Status == HIDP_STATUS_SUCCESS); 874 875 // 876 // add new collection to current collection 877 // 878 Status = HidParser_AddCollection(CurrentCollection, NewCollection); 879 ASSERT(Status == HIDP_STATUS_SUCCESS); 880 881 // 882 // make new collection current 883 // 884 CurrentCollection = NewCollection; 885 } 886 else if (CurrentItem->Tag == ITEM_TAG_MAIN_END_COLLECTION) 887 { 888 // 889 // assert on ending the root collection 890 // 891 ASSERT(CurrentCollection != ParserContext->RootCollection); 892 893 // 894 // use parent of current collection 895 // 896 CurrentCollection = CurrentCollection->Root; 897 ASSERT(CurrentCollection); 898 } 899 else 900 { 901 ReportType = HID_REPORT_TYPE_ANY; 902 903 switch (CurrentItem->Tag) { 904 case ITEM_TAG_MAIN_INPUT: 905 ReportType = HID_REPORT_TYPE_INPUT; 906 break; 907 908 case ITEM_TAG_MAIN_OUTPUT: 909 ReportType = HID_REPORT_TYPE_OUTPUT; 910 break; 911 912 case ITEM_TAG_MAIN_FEATURE: 913 ReportType = HID_REPORT_TYPE_FEATURE; 914 break; 915 916 default: 917 DebugFunction("[HIDPARSE] Unknown ReportType Tag %x Type %x Size %x CurrentItemSize %x\n", CurrentItem->Tag, CurrentItem->Type, CurrentItem->Size, CurrentItemSize); 918 ASSERT(FALSE); 919 break; 920 } 921 922 if (ReportType == HID_REPORT_TYPE_ANY) 923 break; 924 925 // 926 // get report 927 // 928 Status = HidParser_GetReport(ParserContext, CurrentCollection, ReportType, ParserContext->GlobalItemState.ReportId, TRUE, &Report); 929 ASSERT(Status == HIDP_STATUS_SUCCESS); 930 931 // fill in a sensible default if the index isn't set 932 if (!ParserContext->LocalItemState.DesignatorIndexSet) { 933 ParserContext->LocalItemState.DesignatorIndex 934 = ParserContext->LocalItemState.DesignatorMinimum; 935 } 936 937 if (!ParserContext->LocalItemState.StringIndexSet) 938 ParserContext->LocalItemState.StringIndex = ParserContext->LocalItemState.StringMinimum; 939 940 // 941 // get main item data 942 // 943 MainItemData = (PMAIN_ITEM_DATA)&Data; 944 945 // 946 // add states & data to the report 947 // 948 Status = HidParser_AddMainItem(ParserContext, Report, &ParserContext->GlobalItemState, &ParserContext->LocalItemState, MainItemData, CurrentCollection); 949 ASSERT(Status == HIDP_STATUS_SUCCESS); 950 } 951 952 // 953 // backup stack 954 // 955 Index = ParserContext->LocalItemState.UsageStackAllocated; 956 NewUsageStack = ParserContext->LocalItemState.UsageStack; 957 958 // 959 // reset the local item state and clear the usage stack 960 // 961 ZeroFunction(&ParserContext->LocalItemState, sizeof(LOCAL_ITEM_STATE)); 962 963 // 964 // restore stack 965 // 966 ParserContext->LocalItemState.UsageStack = NewUsageStack; 967 ParserContext->LocalItemState.UsageStackAllocated = Index; 968 break; 969 } 970 case ITEM_TYPE_GLOBAL: 971 { 972 switch (CurrentItem->Tag) { 973 case ITEM_TAG_GLOBAL_USAGE_PAGE: 974 DebugFunction("[HIDPARSE] ITEM_TAG_GLOBAL_USAGE_PAGE %x\n", Data); 975 ParserContext->GlobalItemState.UsagePage = Data; 976 break; 977 case ITEM_TAG_GLOBAL_LOGICAL_MINIMUM: 978 DebugFunction("[HIDPARSE] ITEM_TAG_GLOBAL_LOGICAL_MINIMUM %x\n", Data); 979 ParserContext->GlobalItemState.LogicalMinimum = Data; 980 break; 981 982 case ITEM_TAG_GLOBAL_LOGICAL_MAXIMUM: 983 DebugFunction("[HIDPARSE] ITEM_TAG_GLOBAL_LOCAL_MAXIMUM %x\n", Data); 984 ParserContext->GlobalItemState.LogicialMaximum = Data; 985 break; 986 987 case ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM: 988 DebugFunction("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM %x\n", Data); 989 ParserContext->GlobalItemState.PhysicalMinimum = Data; 990 break; 991 992 case ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM: 993 DebugFunction("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM %x\n", Data); 994 ParserContext->GlobalItemState.PhysicalMaximum = Data; 995 break; 996 997 case ITEM_TAG_GLOBAL_UNIT_EXPONENT: 998 DebugFunction("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT_EXPONENT %x\n", Data); 999 ParserContext->GlobalItemState.UnitExponent = Data; 1000 break; 1001 1002 case ITEM_TAG_GLOBAL_UNIT: 1003 DebugFunction("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT %x\n", Data); 1004 ParserContext->GlobalItemState.Unit = Data; 1005 break; 1006 1007 case ITEM_TAG_GLOBAL_REPORT_SIZE: 1008 DebugFunction("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_SIZE %x\n", Data); 1009 ParserContext->GlobalItemState.ReportSize = Data; 1010 break; 1011 1012 case ITEM_TAG_GLOBAL_REPORT_ID: 1013 DebugFunction("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_ID %x\n", Data); 1014 ParserContext->GlobalItemState.ReportId = Data; 1015 ParserContext->UseReportIDs = TRUE; 1016 break; 1017 1018 case ITEM_TAG_GLOBAL_REPORT_COUNT: 1019 DebugFunction("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_COUNT %x\n", Data); 1020 ParserContext->GlobalItemState.ReportCount = Data; 1021 break; 1022 1023 case ITEM_TAG_GLOBAL_PUSH: 1024 { 1025 DebugFunction("[HIDPARSE] ITEM_TAG_GLOBAL_PUSH\n"); 1026 // 1027 // allocate global item state 1028 // 1029 LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)AllocFunction(sizeof(GLOBAL_ITEM_STATE)); 1030 ASSERT(LinkedGlobalItemState); 1031 1032 // 1033 // copy global item state 1034 // 1035 CopyFunction(LinkedGlobalItemState, &ParserContext->GlobalItemState, sizeof(GLOBAL_ITEM_STATE)); 1036 1037 // 1038 // store pushed item in link member 1039 // 1040 ParserContext->GlobalItemState.Next = (struct __GLOBAL_ITEM_STATE__*)LinkedGlobalItemState; 1041 break; 1042 } 1043 case ITEM_TAG_GLOBAL_POP: 1044 { 1045 DebugFunction("[HIDPARSE] ITEM_TAG_GLOBAL_POP\n"); 1046 if (ParserContext->GlobalItemState.Next == NULL) 1047 { 1048 // 1049 // pop without push 1050 // 1051 ASSERT(FALSE); 1052 break; 1053 } 1054 1055 // 1056 // get link 1057 // 1058 LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)ParserContext->GlobalItemState.Next; 1059 1060 // 1061 // replace current item with linked one 1062 // 1063 CopyFunction(&ParserContext->GlobalItemState, LinkedGlobalItemState, sizeof(GLOBAL_ITEM_STATE)); 1064 1065 // 1066 // free item 1067 // 1068 FreeFunction(LinkedGlobalItemState); 1069 break; 1070 } 1071 1072 default: 1073 // 1074 // unknown / unsupported tag 1075 // 1076 ASSERT(FALSE); 1077 break; 1078 } 1079 1080 break; 1081 } 1082 case ITEM_TYPE_LOCAL: 1083 { 1084 switch (CurrentItem->Tag) 1085 { 1086 case ITEM_TAG_LOCAL_USAGE: 1087 { 1088 if (ParserContext->LocalItemState.UsageStackUsed >= ParserContext->LocalItemState.UsageStackAllocated) 1089 { 1090 // 1091 // increment stack size 1092 // 1093 ParserContext->LocalItemState.UsageStackAllocated += 10; 1094 1095 // 1096 // build new usage stack 1097 // 1098 NewUsageStack = (PUSAGE_VALUE)AllocFunction(sizeof(USAGE_VALUE) * ParserContext->LocalItemState.UsageStackAllocated); 1099 ASSERT(NewUsageStack); 1100 1101 // 1102 // copy old usage stack 1103 // 1104 CopyFunction(NewUsageStack, ParserContext->LocalItemState.UsageStack, sizeof(USAGE_VALUE) * (ParserContext->LocalItemState.UsageStackAllocated - 10)); 1105 1106 // 1107 // free old usage stack 1108 // 1109 FreeFunction(ParserContext->LocalItemState.UsageStack); 1110 1111 // 1112 // replace with new usage stack 1113 // 1114 ParserContext->LocalItemState.UsageStack = NewUsageStack; 1115 } 1116 1117 // 1118 // get fresh usage value 1119 // 1120 UsageValue = &ParserContext->LocalItemState.UsageStack[ParserContext->LocalItemState.UsageStackUsed]; 1121 1122 // 1123 // init usage stack 1124 // 1125 UsageValue->IsExtended = CurrentItemSize == sizeof(ULONG); 1126 UsageValue->u.Extended = Data; 1127 1128 // 1129 // increment usage stack usage count 1130 // 1131 ParserContext->LocalItemState.UsageStackUsed++; 1132 break; 1133 } 1134 1135 case ITEM_TAG_LOCAL_USAGE_MINIMUM: 1136 DebugFunction("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MINIMUM Data %x\n", Data); 1137 ParserContext->LocalItemState.UsageMinimum.u.Extended = Data; 1138 ParserContext->LocalItemState.UsageMinimum.IsExtended 1139 = CurrentItemSize == sizeof(ULONG); 1140 ParserContext->LocalItemState.UsageMinimumSet = TRUE; 1141 break; 1142 1143 case ITEM_TAG_LOCAL_USAGE_MAXIMUM: 1144 DebugFunction("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MAXIMUM Data %x ItemSize %x %x\n", Data, CurrentItemSize, CurrentItem->Size); 1145 ParserContext->LocalItemState.UsageMaximum.u.Extended = Data; 1146 ParserContext->LocalItemState.UsageMaximum.IsExtended 1147 = CurrentItemSize == sizeof(ULONG); 1148 ParserContext->LocalItemState.UsageMaximumSet = TRUE; 1149 break; 1150 1151 case ITEM_TAG_LOCAL_DESIGNATOR_INDEX: 1152 DebugFunction("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_INDEX Data %x\n", Data); 1153 ParserContext->LocalItemState.DesignatorIndex = Data; 1154 ParserContext->LocalItemState.DesignatorIndexSet = TRUE; 1155 break; 1156 1157 case ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM: 1158 DebugFunction("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM Data %x\n", Data); 1159 ParserContext->LocalItemState.DesignatorMinimum = Data; 1160 break; 1161 1162 case ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM: 1163 DebugFunction("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM Data %x\n", Data); 1164 ParserContext->LocalItemState.DesignatorMaximum = Data; 1165 break; 1166 1167 case ITEM_TAG_LOCAL_STRING_INDEX: 1168 DebugFunction("[HIDPARSE] ITEM_TAG_LOCAL_STRING_INDEX Data %x\n", Data); 1169 ParserContext->LocalItemState.StringIndex = Data; 1170 ParserContext->LocalItemState.StringIndexSet = TRUE; 1171 break; 1172 1173 case ITEM_TAG_LOCAL_STRING_MINIMUM: 1174 DebugFunction("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MINIMUM Data %x\n", Data); 1175 ParserContext->LocalItemState.StringMinimum = Data; 1176 break; 1177 1178 case ITEM_TAG_LOCAL_STRING_MAXIMUM: 1179 DebugFunction("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MAXIMUM Data %x\n", Data); 1180 ParserContext->LocalItemState.StringMaximum = Data; 1181 break; 1182 1183 default: 1184 DebugFunction("Unknown Local Item Tag %x\n", CurrentItem->Tag); 1185 ASSERT(FALSE); 1186 break; 1187 } 1188 break; 1189 } 1190 1191 case ITEM_TYPE_LONG: 1192 { 1193 CurrentLongItem = (PLONG_ITEM)CurrentItem; 1194 DebugFunction("Unsupported ITEM_TYPE_LONG Tag %x\n", CurrentLongItem->LongItemTag); 1195 break; 1196 } 1197 } 1198 1199 // 1200 // move to next item 1201 // 1202 CurrentOffset += CurrentItemSize + sizeof(ITEM_PREFIX); 1203 1204 }while (CurrentOffset < ReportEnd); 1205 1206 1207 // 1208 // cleanup global stack 1209 // 1210 LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)ParserContext->GlobalItemState.Next; 1211 while(LinkedGlobalItemState != NULL) 1212 { 1213 DebugFunction("[HIDPARSE] Freeing GlobalState %p\n", LinkedGlobalItemState); 1214 // 1215 // free global item state 1216 // 1217 NextLinkedGlobalItemState = (PGLOBAL_ITEM_STATE)LinkedGlobalItemState->Next; 1218 1219 // 1220 // free state 1221 // 1222 FreeFunction(LinkedGlobalItemState); 1223 1224 // 1225 // move to next global state 1226 // 1227 LinkedGlobalItemState = NextLinkedGlobalItemState; 1228 } 1229 1230 // 1231 // free usage stack 1232 // 1233 FreeFunction(ParserContext->LocalItemState.UsageStack); 1234 ParserContext->LocalItemState.UsageStack = NULL; 1235 1236 // 1237 // store result 1238 // 1239 *OutParser = ParserContext; 1240 1241 // 1242 // done 1243 // 1244 return HIDP_STATUS_SUCCESS; 1245 } 1246 1247 PHID_COLLECTION 1248 HidParser_GetCollection( 1249 PHID_PARSER_CONTEXT ParserContext, 1250 IN ULONG CollectionNumber) 1251 { 1252 // 1253 // sanity checks 1254 // 1255 ASSERT(ParserContext); 1256 ASSERT(ParserContext->RootCollection); 1257 ASSERT(ParserContext->RootCollection->NodeCount); 1258 1259 // 1260 // is collection index out of bounds 1261 // 1262 if (CollectionNumber < ParserContext->RootCollection->NodeCount) 1263 { 1264 // 1265 // valid collection 1266 // 1267 return ParserContext->RootCollection->Nodes[CollectionNumber]; 1268 } 1269 1270 // 1271 // no such collection 1272 // 1273 DebugFunction("HIDPARSE] No such collection %lu\n", CollectionNumber); 1274 return NULL; 1275 } 1276 1277 1278 ULONG 1279 HidParser_NumberOfTopCollections( 1280 IN PVOID ParserCtx) 1281 { 1282 PHID_PARSER_CONTEXT ParserContext; 1283 1284 // 1285 // get parser context 1286 // 1287 ParserContext = (PHID_PARSER_CONTEXT)ParserCtx; 1288 1289 // 1290 // sanity checks 1291 // 1292 ASSERT(ParserContext); 1293 ASSERT(ParserContext->RootCollection); 1294 ASSERT(ParserContext->RootCollection->NodeCount); 1295 1296 // 1297 // number of top collections 1298 // 1299 return ParserContext->RootCollection->NodeCount; 1300 } 1301 1302 NTSTATUS 1303 HidParser_BuildContext( 1304 IN PVOID ParserContext, 1305 IN ULONG CollectionIndex, 1306 IN ULONG ContextSize, 1307 OUT PVOID *CollectionContext) 1308 { 1309 PHID_COLLECTION Collection; 1310 PVOID Context; 1311 NTSTATUS Status; 1312 1313 // 1314 // lets get the collection 1315 // 1316 Collection = HidParser_GetCollection((PHID_PARSER_CONTEXT)ParserContext, CollectionIndex); 1317 ASSERT(Collection); 1318 1319 // 1320 // lets allocate the context 1321 // 1322 Context = AllocFunction(ContextSize); 1323 if (Context == NULL) 1324 { 1325 // 1326 // no memory 1327 // 1328 return HIDP_STATUS_INTERNAL_ERROR; 1329 } 1330 1331 // 1332 // lets build the context 1333 // 1334 Status = HidParser_BuildCollectionContext(Collection, Context, ContextSize); 1335 if (Status == HIDP_STATUS_SUCCESS) 1336 { 1337 // 1338 // store context 1339 // 1340 *CollectionContext = Context; 1341 } 1342 1343 // 1344 // done 1345 // 1346 return Status; 1347 } 1348 1349 1350 ULONG 1351 HidParser_GetContextSize( 1352 IN PVOID ParserContext, 1353 IN ULONG CollectionIndex) 1354 { 1355 PHID_COLLECTION Collection; 1356 ULONG Size; 1357 1358 // 1359 // lets get the collection 1360 // 1361 Collection = HidParser_GetCollection((PHID_PARSER_CONTEXT)ParserContext, CollectionIndex); 1362 1363 // 1364 // calculate size 1365 // 1366 Size = HidParser_CalculateContextSize(Collection); 1367 return Size; 1368 } 1369 1370