2 * PROJECT: ReactOS HID Parser Library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: lib/drivers/hidparser/api.c
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
14 static ULONG KeyboardScanCodes
[256] =
16 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
17 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
18 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
19 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
20 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
21 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
22 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
23 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
24 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
25 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
27 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
28 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
29 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
30 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
31 150,158,159,128,136,177,178,176,142,152,173,140
37 HidParser_NumberOfTopCollections(
38 IN PHID_PARSER Parser
)
40 PHID_PARSER_CONTEXT ParserContext
;
45 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
50 ASSERT(ParserContext
);
51 ASSERT(ParserContext
->RootCollection
);
52 ASSERT(ParserContext
->RootCollection
->NodeCount
);
55 // number of top collections
57 return ParserContext
->RootCollection
->NodeCount
;
61 HidParser_GetCollection(
62 IN PHID_PARSER Parser
,
63 IN ULONG CollectionNumber
)
65 PHID_PARSER_CONTEXT ParserContext
;
70 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
75 ASSERT(ParserContext
);
76 ASSERT(ParserContext
->RootCollection
);
77 ASSERT(ParserContext
->RootCollection
->NodeCount
);
80 // is collection index out of bounds
82 if (CollectionNumber
< ParserContext
->RootCollection
->NodeCount
)
87 return ParserContext
->RootCollection
->Nodes
[CollectionNumber
];
93 Parser
->Debug("HIDPARSE] No such collection %lu\n", CollectionNumber
);
98 HidParser_GetReportInCollection(
99 PHID_COLLECTION Collection
,
106 // search in local array
108 for(Index
= 0; Index
< Collection
->ReportCount
; Index
++)
110 if (Collection
->Reports
[Index
]->Type
== ReportType
)
115 return Collection
->Reports
[Index
];
120 // search in local array
122 for(Index
= 0; Index
< Collection
->NodeCount
; Index
++)
124 Report
= HidParser_GetReportInCollection(Collection
->Nodes
[Index
], ReportType
);
141 HidParser_GetReportByType(
142 IN PHID_PARSER Parser
,
143 IN ULONG CollectionIndex
,
146 PHID_COLLECTION Collection
;
151 Collection
= HidParser_GetCollection(Parser
, CollectionIndex
);
155 // no such collection
164 return HidParser_GetReportInCollection(Collection
, ReportType
);
168 HidParser_GetCollectionUsagePage(
169 IN PHID_PARSER Parser
,
170 IN ULONG CollectionIndex
,
172 OUT PUSHORT UsagePage
)
174 PHID_COLLECTION Collection
;
179 Collection
= HidParser_GetCollection(Parser
, CollectionIndex
);
183 // collection not found
185 return HIDPARSER_STATUS_COLLECTION_NOT_FOUND
;
191 *UsagePage
= (Collection
->Usage
>> 16);
192 *Usage
= (Collection
->Usage
& 0xFFFF);
193 return HIDPARSER_STATUS_SUCCESS
;
197 HidParser_GetReportLength(
198 IN PHID_PARSER Parser
,
199 IN ULONG CollectionIndex
,
202 PHID_PARSER_CONTEXT ParserContext
;
207 // get parser context
209 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
214 ASSERT(ParserContext
);
217 // FIXME support multiple top collecions
219 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
224 Report
= HidParser_GetReportByType(Parser
, CollectionIndex
, ReportType
);
236 ReportLength
= Report
->ReportSize
;
244 // byte aligned length
246 ASSERT(ReportLength
% 8 == 0);
247 return ReportLength
/ 8;
253 HidParser_IsReportIDUsed(
254 IN PHID_PARSER Parser
)
256 PHID_PARSER_CONTEXT ParserContext
;
259 // get parser context
261 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
266 ASSERT(ParserContext
);
271 return ParserContext
->UseReportIDs
;
275 HidParser_GetReportItemCountFromReportType(
276 IN PHID_PARSER Parser
,
277 IN ULONG CollectionIndex
,
280 PHID_PARSER_CONTEXT ParserContext
;
284 // get parser context
286 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
291 ASSERT(ParserContext
);
294 // FIXME support multiple top collecions
296 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
301 Report
= HidParser_GetReportByType(Parser
, CollectionIndex
, ReportType
);
311 // return report item count
313 return Report
->ItemCount
;
318 HidParser_GetReportItemTypeCountFromReportType(
319 IN PHID_PARSER Parser
,
320 IN ULONG CollectionIndex
,
324 PHID_PARSER_CONTEXT ParserContext
;
330 // get parser context
332 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
337 ASSERT(ParserContext
);
340 // FIXME support multiple top collecions
342 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
347 Report
= HidParser_GetReportByType(Parser
, CollectionIndex
, ReportType
);
357 // enumerate all items
359 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
364 if (Report
->Items
[Index
]->HasData
&& bData
== TRUE
)
371 else if (Report
->Items
[Index
]->HasData
== FALSE
&& bData
== FALSE
)
387 HidParser_GetContextSize(
388 IN PHID_PARSER Parser
,
389 IN ULONG CollectionIndex
)
392 // FIXME the context must contain all parsed info
394 return sizeof(HID_PARSER_CONTEXT
);
398 HidParser_FreeContext(
399 IN PHID_PARSER Parser
,
401 IN ULONG ContextLength
)
404 // FIXME implement freeing of parsed info
409 HidParser_AllocateParser(
410 IN PHIDPARSER_ALLOC_FUNCTION AllocFunction
,
411 IN PHIDPARSER_FREE_FUNCTION FreeFunction
,
412 IN PHIDPARSER_ZERO_FUNCTION ZeroFunction
,
413 IN PHIDPARSER_COPY_FUNCTION CopyFunction
,
414 IN PHIDPARSER_DEBUG_FUNCTION DebugFunction
,
415 OUT PHID_PARSER
*OutParser
)
418 PHID_PARSER_CONTEXT ParserContext
;
423 Parser
= (PHID_PARSER
)AllocFunction(sizeof(HID_PARSER
));
429 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES
;
433 // allocate parser context
435 ParserContext
= (PHID_PARSER_CONTEXT
)AllocFunction(sizeof(HID_PARSER_CONTEXT
));
441 FreeFunction(Parser
);
442 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES
;
449 Parser
->Alloc
= AllocFunction
;
450 Parser
->Free
= FreeFunction
;
451 Parser
->Zero
= ZeroFunction
;
452 Parser
->Copy
= CopyFunction
;
453 Parser
->Debug
= DebugFunction
;
454 Parser
->ParserContext
= ParserContext
;
463 return HIDPARSER_STATUS_SUCCESS
;
467 HidParser_InitParser(
468 IN PHIDPARSER_ALLOC_FUNCTION AllocFunction
,
469 IN PHIDPARSER_FREE_FUNCTION FreeFunction
,
470 IN PHIDPARSER_ZERO_FUNCTION ZeroFunction
,
471 IN PHIDPARSER_COPY_FUNCTION CopyFunction
,
472 IN PHIDPARSER_DEBUG_FUNCTION DebugFunction
,
473 IN PVOID ParserContext
,
474 OUT PHID_PARSER Parser
)
476 Parser
->Alloc
= AllocFunction
;
477 Parser
->Free
= FreeFunction
;
478 Parser
->Zero
= ZeroFunction
;
479 Parser
->Copy
= CopyFunction
;
480 Parser
->Debug
= DebugFunction
;
481 Parser
->ParserContext
= ParserContext
;
485 HidParser_GetCollectionCount(
486 IN PHID_COLLECTION Collection
)
489 ULONG Count
= Collection
->NodeCount
;
491 for(Index
= 0; Index
< Collection
->NodeCount
; Index
++)
494 // count collection for sub nodes
496 Count
+= HidParser_GetCollectionCount(Collection
->Nodes
[Index
]);
506 HidParser_GetTotalCollectionCount(
507 IN PHID_PARSER Parser
)
509 PHID_PARSER_CONTEXT ParserContext
;
512 // get parser context
514 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
519 ASSERT(ParserContext
);
520 ASSERT(ParserContext
->RootCollection
);
525 return HidParser_GetCollectionCount(ParserContext
->RootCollection
);
529 HidParser_GetMaxUsageListLengthWithReportAndPage(
530 IN PHID_PARSER Parser
,
531 IN ULONG CollectionIndex
,
533 IN USAGE UsagePage OPTIONAL
)
535 PHID_PARSER_CONTEXT ParserContext
;
539 USHORT CurrentUsagePage
;
542 // get parser context
544 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
549 ASSERT(ParserContext
);
552 // FIXME support multiple top collecions
554 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
559 Report
= HidParser_GetReportByType(Parser
, CollectionIndex
, ReportType
);
568 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
573 CurrentUsagePage
= (Report
->Items
[Index
]->UsageMinimum
>> 16);
574 if (CurrentUsagePage
== UsagePage
&& Report
->Items
[Index
]->HasData
)
590 HidParser_GetSpecificValueCapsWithReport(
591 IN PHID_PARSER Parser
,
592 IN ULONG CollectionIndex
,
596 OUT PHIDP_VALUE_CAPS ValueCaps
,
597 IN OUT PULONG ValueCapsLength
)
599 PHID_PARSER_CONTEXT ParserContext
;
603 USHORT CurrentUsagePage
;
607 // get parser context
609 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
614 ASSERT(ParserContext
);
617 // FIXME support multiple top collecions
619 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
624 Report
= HidParser_GetReportByType(Parser
, CollectionIndex
, ReportType
);
630 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
633 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
638 CurrentUsagePage
= (Report
->Items
[Index
]->UsageMinimum
>> 16);
639 CurrentUsage
= (Report
->Items
[Index
]->UsageMinimum
& 0xFFFF);
641 if ((Usage
== CurrentUsage
&& UsagePage
== CurrentUsagePage
) || (Usage
== 0 && UsagePage
== CurrentUsagePage
) || (Usage
== CurrentUsage
&& UsagePage
== 0) || (Usage
== 0 && UsagePage
== 0))
644 // check if there is enough place for the caps
646 if (ItemCount
< *ValueCapsLength
)
651 Parser
->Zero(&ValueCaps
[ItemCount
], sizeof(HIDP_VALUE_CAPS
));
656 ValueCaps
[ItemCount
].UsagePage
= CurrentUsagePage
;
657 ValueCaps
[ItemCount
].ReportID
= Report
->ReportID
;
658 ValueCaps
[ItemCount
].LogicalMin
= Report
->Items
[Index
]->Minimum
;
659 ValueCaps
[ItemCount
].LogicalMax
= Report
->Items
[Index
]->Maximum
;
660 ValueCaps
[ItemCount
].IsAbsolute
= !Report
->Items
[Index
]->Relative
;
661 ValueCaps
[ItemCount
].BitSize
= Report
->Items
[Index
]->BitCount
;
679 *ValueCapsLength
= ItemCount
;
686 return HIDPARSER_STATUS_SUCCESS
;
692 return HIDPARSER_STATUS_USAGE_NOT_FOUND
;
696 HidParser_GetUsagesWithReport(
697 IN PHID_PARSER Parser
,
698 IN ULONG CollectionIndex
,
701 OUT USAGE
*UsageList
,
702 IN OUT PULONG UsageLength
,
703 IN PCHAR ReportDescriptor
,
704 IN ULONG ReportDescriptorLength
)
706 PHID_PARSER_CONTEXT ParserContext
;
710 USHORT CurrentUsagePage
;
711 PHID_REPORT_ITEM ReportItem
;
716 // get parser context
718 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
723 ASSERT(ParserContext
);
726 // FIXME support multiple top collecions
728 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
733 Report
= HidParser_GetReportByType(Parser
, CollectionIndex
, ReportType
);
739 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
742 if (Report
->ReportSize
/ 8 != (ReportDescriptorLength
- 1))
745 // invalid report descriptor length
747 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH
;
750 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
755 ReportItem
= Report
->Items
[Index
];
760 if (!ReportItem
->HasData
)
766 CurrentUsagePage
= (ReportItem
->UsageMinimum
>> 16);
771 if (UsagePage
!= CurrentUsagePage
)
775 // check if the specified usage is activated
777 ASSERT(ReportItem
->ByteOffset
< ReportDescriptorLength
);
778 ASSERT(ReportItem
->BitCount
< 8);
781 // one extra shift for skipping the prepended report id
783 Data
= ReportDescriptor
[ReportItem
->ByteOffset
+ 1];
788 Data
>>= ReportItem
->Shift
;
791 // clear unwanted bits
793 Data
&= ReportItem
->Mask
;
798 Activated
= (Data
!= 0);
804 // is there enough space for the usage
806 if (ItemCount
>= *UsageLength
)
815 UsageList
[ItemCount
] = (ReportItem
->UsageMinimum
& 0xFFFF);
819 if (ItemCount
> *UsageLength
)
824 return HIDPARSER_STATUS_BUFFER_TOO_SMALL
;
828 // success, clear rest of array
830 Parser
->Zero(&UsageList
[ItemCount
], (*UsageLength
- ItemCount
) * sizeof(USAGE
));
835 *UsageLength
= ItemCount
;
840 return HIDPARSER_STATUS_SUCCESS
;
844 HidParser_GetScaledUsageValueWithReport(
845 IN PHID_PARSER Parser
,
846 IN ULONG CollectionIndex
,
850 OUT PLONG UsageValue
,
851 IN PCHAR ReportDescriptor
,
852 IN ULONG ReportDescriptorLength
)
854 PHID_PARSER_CONTEXT ParserContext
;
857 USHORT CurrentUsagePage
;
858 PHID_REPORT_ITEM ReportItem
;
862 // get parser context
864 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
869 ASSERT(ParserContext
);
872 // FIXME support multiple top collecions
874 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
879 Report
= HidParser_GetReportByType(Parser
, CollectionIndex
, ReportType
);
885 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
888 if (Report
->ReportSize
/ 8 != (ReportDescriptorLength
- 1))
891 // invalid report descriptor length
893 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH
;
896 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
901 ReportItem
= Report
->Items
[Index
];
906 CurrentUsagePage
= (ReportItem
->UsageMinimum
>> 16);
909 // does usage page match
911 if (UsagePage
!= CurrentUsagePage
)
915 // does the usage match
917 if (Usage
!= (ReportItem
->UsageMinimum
& 0xFFFF))
921 // check if the specified usage is activated
923 ASSERT(ReportItem
->ByteOffset
< ReportDescriptorLength
);
926 // one extra shift for skipping the prepended report id
929 Parser
->Copy(&Data
, &ReportDescriptor
[ReportItem
->ByteOffset
+1], min(sizeof(ULONG
), ReportDescriptorLength
- (ReportItem
->ByteOffset
+ 1)));
930 Data
= ReportDescriptor
[ReportItem
->ByteOffset
+ 1];
935 Data
>>= ReportItem
->Shift
;
938 // clear unwanted bits
940 Data
&= ReportItem
->Mask
;
942 if (ReportItem
->Minimum
> ReportItem
->Maximum
)
945 // logical boundaries are signed values
947 if ((Data
& ~(ReportItem
->Mask
>> 1)) != 0)
949 Data
|= ~ReportItem
->Mask
;
957 return HIDPARSER_STATUS_SUCCESS
;
963 return HIDPARSER_STATUS_USAGE_NOT_FOUND
;
967 HidParser_GetScanCode(
970 if (Usage
< sizeof(KeyboardScanCodes
) / sizeof(KeyboardScanCodes
[0]))
975 return KeyboardScanCodes
[Usage
];
985 HidParser_DispatchKey(
987 IN HIDP_KEYBOARD_DIRECTION KeyAction
,
988 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure
,
989 IN PVOID InsertCodesContext
)
997 for(Index
= 0; Index
< sizeof(ULONG
); Index
++)
999 if (ScanCodes
[Index
] == 0)
1008 // is this a key break
1010 if (KeyAction
== HidP_Keyboard_Break
)
1015 ScanCodes
[Index
] |= KEY_BREAK
;
1027 // dispatch scan codes
1029 InsertCodesProcedure(InsertCodesContext
, ScanCodes
, Length
);
1035 HidParser_TranslateUsage(
1036 IN PHID_PARSER Parser
,
1037 IN ULONG CollectionIndex
,
1039 IN HIDP_KEYBOARD_DIRECTION KeyAction
,
1040 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState
,
1041 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure
,
1042 IN PVOID InsertCodesContext
)
1049 ScanCode
= HidParser_GetScanCode(Usage
);
1053 // invalid lookup or no scan code available
1055 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN
;
1059 // FIXME: translate modifier states
1062 HidParser_DispatchKey((PCHAR
)&ScanCode
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
1067 return HIDPARSER_STATUS_SUCCESS
;
1071 HidParser_GetCollectionNumberFromParserContext(
1072 IN PHID_PARSER Parser
)
1074 PHID_PARSER_CONTEXT Context
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
1077 // get parser context
1079 return Context
->CollectionIndex
;