2 * PROJECT: ReactOS HID Parser Library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: lib/drivers/hidparser/parser.c
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
16 static UCHAR ItemSize
[4] = { 0, 1, 2, 4 };
19 HidParser_DeleteReport(
20 IN PHID_PARSER Parser
,
21 IN PHID_REPORT Report
)
29 HidParser_FreeCollection(
30 IN PHID_PARSER Parser
,
31 IN PHID_COLLECTION Collection
)
39 HidParser_AllocateCollection(
40 IN PHID_PARSER Parser
,
41 IN PHID_COLLECTION ParentCollection
,
43 IN PLOCAL_ITEM_STATE LocalItemState
,
44 OUT PHID_COLLECTION
* OutCollection
)
46 PHID_COLLECTION Collection
;
47 USAGE_VALUE UsageValue
;
50 // first allocate the collection
52 Collection
= (PHID_COLLECTION
)Parser
->Alloc(sizeof(HID_COLLECTION
));
58 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES
;
64 Collection
->Root
= ParentCollection
;
65 Collection
->Type
= Type
;
66 Collection
->StringID
= LocalItemState
->StringIndex
;
67 Collection
->PhysicalID
= LocalItemState
->DesignatorIndex
;
72 ASSERT(LocalItemState
);
73 ASSERT(LocalItemState
->UsageStack
);
75 if (LocalItemState
->UsageStackUsed
> 0)
78 // usage value from first local stack item
80 UsageValue
.u
.Extended
= LocalItemState
->UsageStack
[0].u
.Extended
;
82 else if (LocalItemState
->UsageMinimumSet
)
85 // use value from minimum
87 UsageValue
.u
.Extended
= LocalItemState
->UsageMinimum
.u
.Extended
;
89 else if (LocalItemState
->UsageMaximumSet
)
92 // use value from maximum
94 UsageValue
.u
.Extended
= LocalItemState
->UsageMaximum
.u
.Extended
;
96 else if (Type
== COLLECTION_LOGICAL
)
101 UsageValue
.u
.Extended
= 0;
108 Parser
->Debug("HIDPARSE] No usage set\n");
109 UsageValue
.u
.Extended
= 0;
115 Collection
->Usage
= UsageValue
.u
.Extended
;
120 *OutCollection
= Collection
;
125 return HIDPARSER_STATUS_SUCCESS
;
129 HidParser_AddCollection(
130 IN PHID_PARSER Parser
,
131 IN PHID_COLLECTION CurrentCollection
,
132 IN PHID_COLLECTION NewCollection
)
134 PHID_COLLECTION
* NewAllocCollection
;
135 ULONG CollectionCount
;
138 // increment collection array
140 CollectionCount
= CurrentCollection
->NodeCount
+ 1;
143 // allocate new collection
145 NewAllocCollection
= (PHID_COLLECTION
*)Parser
->Alloc(sizeof(PHID_COLLECTION
) * CollectionCount
);
146 if (!NewAllocCollection
)
151 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES
;
154 if (CurrentCollection
->NodeCount
)
159 Parser
->Copy(NewAllocCollection
, CurrentCollection
->Nodes
, CurrentCollection
->NodeCount
* sizeof(PHID_COLLECTION
));
164 Parser
->Free(CurrentCollection
->Nodes
);
170 NewAllocCollection
[CurrentCollection
->NodeCount
] = (struct __HID_COLLECTION__
*)NewCollection
;
176 CurrentCollection
->Nodes
= NewAllocCollection
;
177 CurrentCollection
->NodeCount
++;
182 return HIDPARSER_STATUS_SUCCESS
;
186 HidParser_FindReportInCollection(
187 IN PHID_COLLECTION Collection
,
190 OUT PHID_REPORT
*OutReport
)
193 HIDPARSER_STATUS Status
;
196 // search in local list
198 for(Index
= 0; Index
< Collection
->ReportCount
; Index
++)
200 if (Collection
->Reports
[Index
]->Type
== ReportType
&& Collection
->Reports
[Index
]->ReportID
== ReportID
)
205 *OutReport
= Collection
->Reports
[Index
];
206 return HIDPARSER_STATUS_SUCCESS
;
211 // search in sub collections
213 for(Index
= 0; Index
< Collection
->NodeCount
; Index
++)
215 Status
= HidParser_FindReportInCollection(Collection
->Nodes
[Index
], ReportType
, ReportID
, OutReport
);
216 if (Status
== HIDPARSER_STATUS_SUCCESS
)
221 // no such report found
224 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
229 HidParser_FindReport(
230 IN PHID_PARSER Parser
,
231 IN PHID_PARSER_CONTEXT ParserContext
,
234 OUT PHID_REPORT
*OutReport
)
237 // search in current top level collection
239 return HidParser_FindReportInCollection(ParserContext
->RootCollection
->Nodes
[ParserContext
->RootCollection
->NodeCount
-1], ReportType
, ReportID
, OutReport
);
243 HidParser_AllocateReport(
244 IN PHID_PARSER Parser
,
247 OUT PHID_REPORT
*OutReport
)
254 Report
= (PHID_REPORT
)Parser
->Alloc(sizeof(HID_REPORT
));
260 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES
;
266 Report
->ReportID
= ReportID
;
267 Report
->Type
= ReportType
;
273 return HIDPARSER_STATUS_SUCCESS
;
277 HidParser_AddReportToCollection(
278 IN PHID_PARSER Parser
,
279 IN PHID_PARSER_CONTEXT ParserContext
,
280 IN PHID_COLLECTION CurrentCollection
,
281 IN PHID_REPORT NewReport
)
283 PHID_REPORT
* NewReportArray
;
286 // allocate new report array
288 NewReportArray
= (PHID_REPORT
*)Parser
->Alloc(sizeof(PHID_REPORT
) * (CurrentCollection
->ReportCount
+ 1));
294 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES
;
297 if (CurrentCollection
->ReportCount
)
300 // copy old array contents
302 Parser
->Copy(NewReportArray
, CurrentCollection
->Reports
, sizeof(PHID_REPORT
) * CurrentCollection
->ReportCount
);
307 Parser
->Free(CurrentCollection
->Reports
);
313 NewReportArray
[CurrentCollection
->ReportCount
] = NewReport
;
314 CurrentCollection
->Reports
= NewReportArray
;
315 CurrentCollection
->ReportCount
++;
318 // completed successfully
320 return HIDPARSER_STATUS_SUCCESS
;
325 IN PHID_PARSER Parser
,
326 IN PHID_PARSER_CONTEXT ParserContext
,
327 IN PHID_COLLECTION Collection
,
330 IN UCHAR CreateIfNotExists
,
331 OUT PHID_REPORT
*OutReport
)
333 HIDPARSER_STATUS Status
;
336 // try finding existing report
338 Status
= HidParser_FindReport(Parser
, ParserContext
, ReportType
, ReportID
, OutReport
);
339 if (Status
== HIDPARSER_STATUS_SUCCESS
|| CreateIfNotExists
== FALSE
)
348 // allocate new report
350 Status
= HidParser_AllocateReport(Parser
, ReportType
, ReportID
, OutReport
);
351 if (Status
!= HIDPARSER_STATUS_SUCCESS
)
354 // failed to allocate report
362 Status
= HidParser_AddReportToCollection(Parser
, ParserContext
, Collection
, *OutReport
);
363 if (Status
!= HIDPARSER_STATUS_SUCCESS
)
366 // failed to allocate report
368 Parser
->Free(*OutReport
);
378 HidParser_ReserveReportItems(
379 IN PHID_PARSER Parser
,
380 IN PHID_REPORT Report
,
381 IN ULONG ReportCount
,
382 OUT PHID_REPORT
*OutReport
)
384 PHID_REPORT NewReport
;
387 if (Report
->ItemCount
+ ReportCount
<= Report
->ItemAllocated
)
390 // space is already allocated
393 return HIDPARSER_STATUS_SUCCESS
;
399 OldSize
= sizeof(HID_REPORT
) + (Report
->ItemCount
) * sizeof(HID_REPORT_ITEM
);
400 Size
= ReportCount
* sizeof(HID_REPORT_ITEM
);
405 NewReport
= (PHID_REPORT
)Parser
->Alloc(Size
+ OldSize
);
411 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES
;
418 Parser
->Copy(NewReport
, Report
, OldSize
);
421 // increase array size
423 NewReport
->ItemAllocated
+= ReportCount
;
428 *OutReport
= NewReport
;
431 // completed sucessfully
433 return HIDPARSER_STATUS_SUCCESS
;
440 OUT PULONG NewMinimum
,
441 OUT PULONG NewMaximum
)
443 ULONG Mask
= 0x80000000;
446 for (Index
= 0; Index
< 4; Index
++)
460 *NewMinimum
= Minimum
;
461 *NewMaximum
= Maximum
;
465 HidParser_InitReportItem(
466 IN PHID_REPORT Report
,
467 IN PHID_REPORT_ITEM ReportItem
,
468 IN PGLOBAL_ITEM_STATE GlobalItemState
,
469 IN PLOCAL_ITEM_STATE LocalItemState
,
470 IN PMAIN_ITEM_DATA ItemData
,
471 IN ULONG ReportItemIndex
)
473 ULONG LogicalMinimum
;
474 ULONG LogicalMaximum
;
475 ULONG PhysicalMinimum
;
476 ULONG PhysicalMaximum
;
479 USAGE_VALUE UsageValue
;
482 // get logical bounds
484 LogicalMinimum
= GlobalItemState
->LogicalMinimum
;
485 LogicalMaximum
= GlobalItemState
->LogicialMaximum
;
486 if (LogicalMinimum
> LogicalMaximum
)
491 HidParser_SignRange(LogicalMinimum
, LogicalMaximum
, &LogicalMinimum
, &LogicalMaximum
);
493 //ASSERT(LogicalMinimum <= LogicalMaximum);
496 // get physical bounds
498 PhysicalMinimum
= GlobalItemState
->PhysicalMinimum
;
499 PhysicalMaximum
= GlobalItemState
->PhysicalMaximum
;
500 if (PhysicalMinimum
> PhysicalMaximum
)
505 HidParser_SignRange(PhysicalMinimum
, PhysicalMaximum
, &PhysicalMinimum
, &PhysicalMaximum
);
507 //ASSERT(PhysicalMinimum <= PhysicalMaximum);
514 if (ItemData
->ArrayVariable
== FALSE
)
519 UsageMinimum
= LocalItemState
->UsageMinimum
.u
.Extended
;
520 UsageMaximum
= LocalItemState
->UsageMaximum
.u
.Extended
;
525 // get usage value from stack
527 if (ReportItemIndex
< LocalItemState
->UsageStackUsed
)
532 UsageValue
= LocalItemState
->UsageStack
[ReportItemIndex
];
537 // get usage minimum from local state
539 UsageValue
= LocalItemState
->UsageMinimum
;
544 UsageValue
.u
.Extended
+= ReportItemIndex
;
546 if (LocalItemState
->UsageMaximumSet
)
548 if (UsageValue
.u
.Extended
> LocalItemState
->UsageMaximum
.u
.Extended
)
553 UsageValue
.u
.Extended
= LocalItemState
->UsageMaximum
.u
.Extended
;
559 // usage usage bounds
561 UsageMinimum
= UsageMaximum
= UsageValue
.u
.Extended
;
565 // now store all values
567 ReportItem
->ByteOffset
= (Report
->ReportSize
/ 8);
568 ReportItem
->Shift
= (Report
->ReportSize
% 8);
569 ReportItem
->Mask
= ~(0xFFFFFFFF << GlobalItemState
->ReportSize
);
570 ReportItem
->BitCount
= GlobalItemState
->ReportSize
;
571 ReportItem
->HasData
= (ItemData
->DataConstant
== FALSE
);
572 ReportItem
->Array
= (ItemData
->ArrayVariable
== 0);
573 ReportItem
->Relative
= (ItemData
->Relative
!= FALSE
);
574 ReportItem
->Minimum
= LogicalMinimum
;
575 ReportItem
->Maximum
= LogicalMaximum
;
576 ReportItem
->UsageMinimum
= UsageMinimum
;
577 ReportItem
->UsageMaximum
= UsageMaximum
;
580 // increment report size
582 Report
->ReportSize
+= GlobalItemState
->ReportSize
;
585 // completed successfully
587 return HIDPARSER_STATUS_SUCCESS
;
591 HidParser_UpdateCurrentCollectionReport(
592 IN PHID_COLLECTION Collection
,
593 IN PHID_REPORT Report
,
594 IN PHID_REPORT NewReport
)
597 BOOLEAN Found
= FALSE
, TempFound
;
600 // search in local list
602 for(Index
= 0; Index
< Collection
->ReportCount
; Index
++)
604 if (Collection
->Reports
[Index
] == Report
)
609 Collection
->Reports
[Index
] = NewReport
;
615 // search in sub collections
617 for(Index
= 0; Index
< Collection
->NodeCount
; Index
++)
622 TempFound
= HidParser_UpdateCurrentCollectionReport(Collection
->Nodes
[Index
], Report
, NewReport
);
626 // the same report should not be found in different collections
628 ASSERT(Found
== FALSE
);
640 HidParser_UpdateCollectionReport(
641 IN PHID_PARSER_CONTEXT ParserContext
,
642 IN PHID_REPORT Report
,
643 IN PHID_REPORT NewReport
)
646 // update in current collection
648 return HidParser_UpdateCurrentCollectionReport(ParserContext
->RootCollection
->Nodes
[ParserContext
->RootCollection
->NodeCount
-1], Report
, NewReport
);
653 HidParser_AddMainItem(
654 IN PHID_PARSER Parser
,
655 IN PHID_PARSER_CONTEXT ParserContext
,
656 IN PHID_REPORT Report
,
657 IN PGLOBAL_ITEM_STATE GlobalItemState
,
658 IN PLOCAL_ITEM_STATE LocalItemState
,
659 IN PMAIN_ITEM_DATA ItemData
,
660 IN PHID_COLLECTION Collection
)
662 HIDPARSER_STATUS Status
;
664 PHID_REPORT NewReport
;
668 // first grow report item array
670 Status
= HidParser_ReserveReportItems(Parser
, Report
, GlobalItemState
->ReportCount
, &NewReport
);
671 if (Status
!= HIDPARSER_STATUS_SUCCESS
)
674 // failed to allocate memory
679 if (NewReport
!= Report
)
682 // update current top level collection
684 Found
= HidParser_UpdateCollectionReport(ParserContext
, Report
, NewReport
);
691 ASSERT(NewReport
->ItemCount
+ GlobalItemState
->ReportCount
<= NewReport
->ItemAllocated
);
693 for(Index
= 0; Index
< GlobalItemState
->ReportCount
; Index
++)
695 Status
= HidParser_InitReportItem(NewReport
, &NewReport
->Items
[NewReport
->ItemCount
], GlobalItemState
, LocalItemState
, ItemData
, Index
);
696 if (Status
!= HIDPARSER_STATUS_SUCCESS
)
699 // failed to init report item
705 // increment report item count
707 NewReport
->ItemCount
++;
713 return HIDPARSER_STATUS_SUCCESS
;
717 HidParser_ParseReportDescriptor(
718 IN PHID_PARSER Parser
,
719 IN PUCHAR ReportDescriptor
,
720 IN ULONG ReportLength
,
721 OUT PVOID
*OutParser
)
723 PGLOBAL_ITEM_STATE LinkedGlobalItemState
, NextLinkedGlobalItemState
;
725 PUSAGE_VALUE NewUsageStack
, UsageValue
;
726 HIDPARSER_STATUS Status
;
727 PHID_COLLECTION CurrentCollection
, NewCollection
;
728 PUCHAR CurrentOffset
, ReportEnd
;
729 PITEM_PREFIX CurrentItem
;
730 ULONG CurrentItemSize
;
731 PLONG_ITEM CurrentLongItem
;
732 PSHORT_ITEM CurrentShortItem
;
736 PMAIN_ITEM_DATA MainItemData
;
737 PHID_PARSER_CONTEXT ParserContext
;
739 CurrentOffset
= ReportDescriptor
;
740 ReportEnd
= ReportDescriptor
+ ReportLength
;
742 if (ReportDescriptor
>= ReportEnd
)
743 return HIDPARSER_STATUS_COLLECTION_NOT_FOUND
;
748 ParserContext
= Parser
->Alloc(sizeof(HID_PARSER_CONTEXT
));;
750 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES
;
754 // allocate usage stack
756 ParserContext
->LocalItemState
.UsageStackAllocated
= 10;
757 ParserContext
->LocalItemState
.UsageStack
= (PUSAGE_VALUE
)Parser
->Alloc(ParserContext
->LocalItemState
.UsageStackAllocated
* sizeof(USAGE_VALUE
));
758 if (!ParserContext
->LocalItemState
.UsageStack
)
763 Parser
->Free(ParserContext
);
764 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES
;
768 // now allocate root collection
770 Status
= HidParser_AllocateCollection(Parser
, NULL
, COLLECTION_LOGICAL
, &ParserContext
->LocalItemState
, &ParserContext
->RootCollection
);
771 if (Status
!= HIDPARSER_STATUS_SUCCESS
)
776 Parser
->Free(ParserContext
->LocalItemState
.UsageStack
);
777 ParserContext
->LocalItemState
.UsageStack
= NULL
;
778 Parser
->Free(ParserContext
);
779 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES
;
785 CurrentCollection
= ParserContext
->RootCollection
;
792 CurrentItem
= (PITEM_PREFIX
)CurrentOffset
;
797 CurrentItemSize
= ItemSize
[CurrentItem
->Size
];
800 if (CurrentItem
->Type
== ITEM_TYPE_LONG
)
803 // increment item size with size of data item
805 CurrentLongItem
= (PLONG_ITEM
)CurrentItem
;
806 CurrentItemSize
+= CurrentLongItem
->DataSize
;
813 CurrentShortItem
= (PSHORT_ITEM
)CurrentItem
;
816 // get associated data
818 //ASSERT(CurrentItemSize == 1 || CurrentItemSize == 2 || CurrentItemSize == 4);
819 if (CurrentItemSize
== 1)
820 Data
= CurrentShortItem
->Data
.UData8
[0];
821 else if (CurrentItemSize
== 2)
822 Data
= CurrentShortItem
->Data
.UData16
[0];
823 else if (CurrentItemSize
== 4)
824 Data
= CurrentShortItem
->Data
.UData32
;
830 //Parser->Debug("CurrentItem invalid item size %lu\n", CurrentItemSize);
834 Parser
->Debug("Tag %x Type %x Size %x Offset %lu Length %lu\n", CurrentItem
->Tag
, CurrentItem
->Type
, CurrentItem
->Size
, ((ULONG_PTR
)CurrentItem
- (ULONG_PTR
)ReportDescriptor
), ReportLength
);
838 ASSERT(CurrentItem
->Type
>= ITEM_TYPE_MAIN
&& CurrentItem
->Type
<= ITEM_TYPE_LONG
);
839 switch(CurrentItem
->Type
)
843 // preprocess the local state if relevant (usages for
844 // collections and report items)
845 if (CurrentItem
->Tag
!= ITEM_TAG_MAIN_END_COLLECTION
)
847 // make all usages extended for easier later processing
848 for (Index
= 0; Index
< ParserContext
->LocalItemState
.UsageStackUsed
; Index
++)
851 // is it already extended
853 if (ParserContext
->LocalItemState
.UsageStack
[Index
].IsExtended
)
859 ParserContext
->LocalItemState
.UsageStack
[Index
].u
.s
.UsagePage
= ParserContext
->GlobalItemState
.UsagePage
;
860 ParserContext
->LocalItemState
.UsageStack
[Index
].IsExtended
= TRUE
;
863 if (!ParserContext
->LocalItemState
.UsageMinimum
.IsExtended
) {
864 // the specs say if one of them is extended they must
865 // both be extended, so if the minimum isn't, the
866 // maximum mustn't either.
867 ParserContext
->LocalItemState
.UsageMinimum
.u
.s
.UsagePage
868 = ParserContext
->LocalItemState
.UsageMaximum
.u
.s
.UsagePage
869 = ParserContext
->GlobalItemState
.UsagePage
;
870 ParserContext
->LocalItemState
.UsageMinimum
.IsExtended
871 = ParserContext
->LocalItemState
.UsageMaximum
.IsExtended
= TRUE
;
874 //LocalItemState.usage_stack = usageStack;
875 //ParserContext->LocalItemState.UsageStackUsed = UsageStackUsed;
878 if (CurrentItem
->Tag
== ITEM_TAG_MAIN_COLLECTION
) {
881 // allocate new collection
883 Status
= HidParser_AllocateCollection(Parser
, CurrentCollection
, (UCHAR
)Data
, &ParserContext
->LocalItemState
, &NewCollection
);
884 ASSERT(Status
== HIDPARSER_STATUS_SUCCESS
);
887 // add new collection to current collection
889 Status
= HidParser_AddCollection(Parser
, CurrentCollection
, NewCollection
);
890 ASSERT(Status
== HIDPARSER_STATUS_SUCCESS
);
893 // make new collection current
895 CurrentCollection
= NewCollection
;
897 else if (CurrentItem
->Tag
== ITEM_TAG_MAIN_END_COLLECTION
)
900 // assert on ending the root collection
902 ASSERT(CurrentCollection
!= ParserContext
->RootCollection
);
905 // use parent of current collection
907 CurrentCollection
= CurrentCollection
->Root
;
908 ASSERT(CurrentCollection
);
912 ReportType
= HID_REPORT_TYPE_ANY
;
914 switch (CurrentItem
->Tag
) {
915 case ITEM_TAG_MAIN_INPUT
:
916 ReportType
= HID_REPORT_TYPE_INPUT
;
919 case ITEM_TAG_MAIN_OUTPUT
:
920 ReportType
= HID_REPORT_TYPE_OUTPUT
;
923 case ITEM_TAG_MAIN_FEATURE
:
924 ReportType
= HID_REPORT_TYPE_FEATURE
;
928 Parser
->Debug("[HIDPARSE] Unknown ReportType Tag %x Type %x Size %x CurrentItemSize %x\n", CurrentItem
->Tag
, CurrentItem
->Type
, CurrentItem
->Size
, CurrentItemSize
);
933 if (ReportType
== HID_REPORT_TYPE_ANY
)
939 Status
= HidParser_GetReport(Parser
, ParserContext
, CurrentCollection
, ReportType
, ParserContext
->GlobalItemState
.ReportId
, TRUE
, &Report
);
940 ASSERT(Status
== HIDPARSER_STATUS_SUCCESS
);
942 // fill in a sensible default if the index isn't set
943 if (!ParserContext
->LocalItemState
.DesignatorIndexSet
) {
944 ParserContext
->LocalItemState
.DesignatorIndex
945 = ParserContext
->LocalItemState
.DesignatorMinimum
;
948 if (!ParserContext
->LocalItemState
.StringIndexSet
)
949 ParserContext
->LocalItemState
.StringIndex
= ParserContext
->LocalItemState
.StringMinimum
;
952 // get main item data
954 MainItemData
= (PMAIN_ITEM_DATA
)&Data
;
957 // add states & data to the report
959 Status
= HidParser_AddMainItem(Parser
, ParserContext
, Report
, &ParserContext
->GlobalItemState
, &ParserContext
->LocalItemState
, MainItemData
, CurrentCollection
);
960 ASSERT(Status
== HIDPARSER_STATUS_SUCCESS
);
966 Index
= ParserContext
->LocalItemState
.UsageStackAllocated
;
967 NewUsageStack
= ParserContext
->LocalItemState
.UsageStack
;
970 // reset the local item state and clear the usage stack
972 Parser
->Zero(&ParserContext
->LocalItemState
, sizeof(LOCAL_ITEM_STATE
));
977 ParserContext
->LocalItemState
.UsageStack
= NewUsageStack
;
978 ParserContext
->LocalItemState
.UsageStackAllocated
= Index
;
981 case ITEM_TYPE_GLOBAL
:
983 switch (CurrentItem
->Tag
) {
984 case ITEM_TAG_GLOBAL_USAGE_PAGE
:
985 Parser
->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_USAGE_PAGE %x\n", Data
);
986 ParserContext
->GlobalItemState
.UsagePage
= Data
;
988 case ITEM_TAG_GLOBAL_LOGICAL_MINIMUM
:
989 Parser
->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_LOGICAL_MINIMUM %x\n", Data
);
990 ParserContext
->GlobalItemState
.LogicalMinimum
= Data
;
993 case ITEM_TAG_GLOBAL_LOGICAL_MAXIMUM
:
994 Parser
->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_LOCAL_MAXIMUM %x\n", Data
);
995 ParserContext
->GlobalItemState
.LogicialMaximum
= Data
;
998 case ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM
:
999 Parser
->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM %x\n", Data
);
1000 ParserContext
->GlobalItemState
.PhysicalMinimum
= Data
;
1003 case ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM
:
1004 Parser
->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM %x\n", Data
);
1005 ParserContext
->GlobalItemState
.PhysicalMaximum
= Data
;
1008 case ITEM_TAG_GLOBAL_UNIT_EXPONENT
:
1009 Parser
->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT_EXPONENT %x\n", Data
);
1010 ParserContext
->GlobalItemState
.UnitExponent
= Data
;
1013 case ITEM_TAG_GLOBAL_UNIT
:
1014 Parser
->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT %x\n", Data
);
1015 ParserContext
->GlobalItemState
.Unit
= Data
;
1018 case ITEM_TAG_GLOBAL_REPORT_SIZE
:
1019 Parser
->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_SIZE %x\n", Data
);
1020 ParserContext
->GlobalItemState
.ReportSize
= Data
;
1023 case ITEM_TAG_GLOBAL_REPORT_ID
:
1024 Parser
->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_ID %x\n", Data
);
1025 ParserContext
->GlobalItemState
.ReportId
= Data
;
1026 ParserContext
->UseReportIDs
= TRUE
;
1029 case ITEM_TAG_GLOBAL_REPORT_COUNT
:
1030 Parser
->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_COUNT %x\n", Data
);
1031 ParserContext
->GlobalItemState
.ReportCount
= Data
;
1034 case ITEM_TAG_GLOBAL_PUSH
:
1036 Parser
->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PUSH\n");
1038 // allocate global item state
1040 LinkedGlobalItemState
= (PGLOBAL_ITEM_STATE
)Parser
->Alloc(sizeof(GLOBAL_ITEM_STATE
));
1041 ASSERT(LinkedGlobalItemState
);
1044 // copy global item state
1046 Parser
->Copy(LinkedGlobalItemState
, &ParserContext
->GlobalItemState
, sizeof(GLOBAL_ITEM_STATE
));
1049 // store pushed item in link member
1051 ParserContext
->GlobalItemState
.Next
= (struct __GLOBAL_ITEM_STATE__
*)LinkedGlobalItemState
;
1054 case ITEM_TAG_GLOBAL_POP
:
1056 Parser
->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_POP\n");
1057 if (ParserContext
->GlobalItemState
.Next
== NULL
)
1069 LinkedGlobalItemState
= (PGLOBAL_ITEM_STATE
)ParserContext
->GlobalItemState
.Next
;
1072 // replace current item with linked one
1074 Parser
->Copy(&ParserContext
->GlobalItemState
, LinkedGlobalItemState
, sizeof(GLOBAL_ITEM_STATE
));
1079 Parser
->Free(LinkedGlobalItemState
);
1085 // unknown / unsupported tag
1093 case ITEM_TYPE_LOCAL
:
1095 switch (CurrentItem
->Tag
)
1097 case ITEM_TAG_LOCAL_USAGE
:
1099 if (ParserContext
->LocalItemState
.UsageStackUsed
>= ParserContext
->LocalItemState
.UsageStackAllocated
)
1102 // increment stack size
1104 ParserContext
->LocalItemState
.UsageStackAllocated
+= 10;
1107 // build new usage stack
1109 NewUsageStack
= (PUSAGE_VALUE
)Parser
->Alloc(sizeof(USAGE_VALUE
) * ParserContext
->LocalItemState
.UsageStackAllocated
);
1110 ASSERT(NewUsageStack
);
1113 // copy old usage stack
1115 Parser
->Copy(NewUsageStack
, ParserContext
->LocalItemState
.UsageStack
, sizeof(USAGE_VALUE
) * (ParserContext
->LocalItemState
.UsageStackAllocated
- 10));
1118 // free old usage stack
1120 Parser
->Free(ParserContext
->LocalItemState
.UsageStack
);
1123 // replace with new usage stack
1125 ParserContext
->LocalItemState
.UsageStack
= NewUsageStack
;
1129 // get fresh usage value
1131 UsageValue
= &ParserContext
->LocalItemState
.UsageStack
[ParserContext
->LocalItemState
.UsageStackUsed
];
1136 UsageValue
->IsExtended
= CurrentItemSize
== sizeof(ULONG
);
1137 UsageValue
->u
.Extended
= Data
;
1140 // increment usage stack usage count
1142 ParserContext
->LocalItemState
.UsageStackUsed
++;
1146 case ITEM_TAG_LOCAL_USAGE_MINIMUM
:
1147 Parser
->Debug("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MINIMUM Data %x\n", Data
);
1148 ParserContext
->LocalItemState
.UsageMinimum
.u
.Extended
= Data
;
1149 ParserContext
->LocalItemState
.UsageMinimum
.IsExtended
1150 = CurrentItemSize
== sizeof(ULONG
);
1151 ParserContext
->LocalItemState
.UsageMinimumSet
= TRUE
;
1154 case ITEM_TAG_LOCAL_USAGE_MAXIMUM
:
1155 Parser
->Debug("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MAXIMUM Data %x ItemSize %x %x\n", Data
, CurrentItemSize
, CurrentItem
->Size
);
1156 ParserContext
->LocalItemState
.UsageMaximum
.u
.Extended
= Data
;
1157 ParserContext
->LocalItemState
.UsageMaximum
.IsExtended
1158 = CurrentItemSize
== sizeof(ULONG
);
1159 ParserContext
->LocalItemState
.UsageMaximumSet
= TRUE
;
1162 case ITEM_TAG_LOCAL_DESIGNATOR_INDEX
:
1163 Parser
->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_INDEX Data %x\n", Data
);
1164 ParserContext
->LocalItemState
.DesignatorIndex
= Data
;
1165 ParserContext
->LocalItemState
.DesignatorIndexSet
= TRUE
;
1168 case ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM
:
1169 Parser
->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM Data %x\n", Data
);
1170 ParserContext
->LocalItemState
.DesignatorMinimum
= Data
;
1173 case ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM
:
1174 Parser
->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM Data %x\n", Data
);
1175 ParserContext
->LocalItemState
.DesignatorMaximum
= Data
;
1178 case ITEM_TAG_LOCAL_STRING_INDEX
:
1179 Parser
->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_INDEX Data %x\n", Data
);
1180 ParserContext
->LocalItemState
.StringIndex
= Data
;
1181 ParserContext
->LocalItemState
.StringIndexSet
= TRUE
;
1184 case ITEM_TAG_LOCAL_STRING_MINIMUM
:
1185 Parser
->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MINIMUM Data %x\n", Data
);
1186 ParserContext
->LocalItemState
.StringMinimum
= Data
;
1189 case ITEM_TAG_LOCAL_STRING_MAXIMUM
:
1190 Parser
->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MAXIMUM Data %x\n", Data
);
1191 ParserContext
->LocalItemState
.StringMaximum
= Data
;
1195 Parser
->Debug("Unknown Local Item Tag %x\n", CurrentItem
->Tag
);
1202 case ITEM_TYPE_LONG
:
1204 CurrentLongItem
= (PLONG_ITEM
)CurrentItem
;
1205 Parser
->Debug("Unsupported ITEM_TYPE_LONG Tag %x\n", CurrentLongItem
->LongItemTag
);
1211 // move to next item
1213 CurrentOffset
+= CurrentItemSize
+ sizeof(ITEM_PREFIX
);
1215 }while (CurrentOffset
< ReportEnd
);
1219 // cleanup global stack
1221 LinkedGlobalItemState
= (PGLOBAL_ITEM_STATE
)ParserContext
->GlobalItemState
.Next
;
1222 while(LinkedGlobalItemState
!= NULL
)
1224 Parser
->Debug("[HIDPARSE] Freeing GlobalState %p\n", LinkedGlobalItemState
);
1226 // free global item state
1228 NextLinkedGlobalItemState
= (PGLOBAL_ITEM_STATE
)LinkedGlobalItemState
->Next
;
1233 Parser
->Free(LinkedGlobalItemState
);
1236 // move to next global state
1238 LinkedGlobalItemState
= NextLinkedGlobalItemState
;
1244 Parser
->Free(ParserContext
->LocalItemState
.UsageStack
);
1245 ParserContext
->LocalItemState
.UsageStack
= NULL
;
1250 *OutParser
= ParserContext
;
1255 return HIDPARSER_STATUS_SUCCESS
;
1259 HidParser_GetCollection(
1260 IN PHID_PARSER Parser
,
1261 PHID_PARSER_CONTEXT ParserContext
,
1262 IN ULONG CollectionNumber
)
1267 ASSERT(ParserContext
);
1268 ASSERT(ParserContext
->RootCollection
);
1269 ASSERT(ParserContext
->RootCollection
->NodeCount
);
1272 // is collection index out of bounds
1274 if (CollectionNumber
< ParserContext
->RootCollection
->NodeCount
)
1279 return ParserContext
->RootCollection
->Nodes
[CollectionNumber
];
1283 // no such collection
1285 Parser
->Debug("HIDPARSE] No such collection %lu\n", CollectionNumber
);
1291 HidParser_NumberOfTopCollections(
1294 PHID_PARSER_CONTEXT ParserContext
;
1297 // get parser context
1299 ParserContext
= (PHID_PARSER_CONTEXT
)ParserCtx
;
1304 ASSERT(ParserContext
);
1305 ASSERT(ParserContext
->RootCollection
);
1306 ASSERT(ParserContext
->RootCollection
->NodeCount
);
1309 // number of top collections
1311 return ParserContext
->RootCollection
->NodeCount
;
1315 HidParser_BuildContext(
1316 IN PHID_PARSER Parser
,
1317 IN PVOID ParserContext
,
1318 IN ULONG CollectionIndex
,
1319 IN ULONG ContextSize
,
1320 OUT PVOID
*CollectionContext
)
1322 PHID_COLLECTION Collection
;
1324 HIDPARSER_STATUS Status
;
1327 // lets get the collection
1329 Collection
= HidParser_GetCollection(Parser
, (PHID_PARSER_CONTEXT
)ParserContext
, CollectionIndex
);
1333 // lets allocate the context
1335 Context
= Parser
->Alloc(ContextSize
);
1336 if (Context
== NULL
)
1341 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES
;
1345 // lets build the context
1347 Status
= HidParser_BuildCollectionContext(Parser
, Collection
, Context
, ContextSize
);
1348 if (Status
== HIDPARSER_STATUS_SUCCESS
)
1353 *CollectionContext
= Context
;
1364 HidParser_GetContextSize(
1365 IN PHID_PARSER Parser
,
1366 IN PVOID ParserContext
,
1367 IN ULONG CollectionIndex
)
1369 PHID_COLLECTION Collection
;
1373 // lets get the collection
1375 Collection
= HidParser_GetCollection(Parser
, (PHID_PARSER_CONTEXT
)ParserContext
, CollectionIndex
);
1380 Size
= HidParser_CalculateContextSize(Collection
);