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_GetReportByType(
99 IN PHID_PARSER Parser
,
102 PHID_PARSER_CONTEXT ParserContext
;
104 ULONG ReportCount
= 0;
107 // get parser context
109 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
114 ASSERT(ParserContext
);
117 // FIXME support multiple top collecions
119 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
120 for(Index
= 0; Index
< ParserContext
->ReportCount
; Index
++)
123 // check if the report type match
125 if (ParserContext
->Reports
[Index
]->Type
== ReportType
)
130 return ParserContext
->Reports
[Index
];
142 HidParser_NumberOfReports(
143 IN PHID_PARSER Parser
,
146 PHID_PARSER_CONTEXT ParserContext
;
148 ULONG ReportCount
= 0;
151 // get parser context
153 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
158 ASSERT(ParserContext
);
161 // FIXME support multiple top collecions
163 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
164 for(Index
= 0; Index
< ParserContext
->ReportCount
; Index
++)
167 // check if the report type match
169 if (ParserContext
->Reports
[Index
]->Type
== ReportType
)
185 HidParser_GetCollectionUsagePage(
186 IN PHID_PARSER Parser
,
187 IN ULONG CollectionIndex
,
189 OUT PUSHORT UsagePage
)
191 PHID_COLLECTION Collection
;
196 Collection
= HidParser_GetCollection(Parser
, CollectionIndex
);
200 // collection not found
202 return HIDPARSER_STATUS_COLLECTION_NOT_FOUND
;
208 *UsagePage
= (Collection
->Usage
>> 16);
209 *Usage
= (Collection
->Usage
& 0xFFFF);
210 return HIDPARSER_STATUS_SUCCESS
;
214 HidParser_GetReportLength(
215 IN PHID_PARSER Parser
,
218 PHID_PARSER_CONTEXT ParserContext
;
223 // get parser context
225 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
230 ASSERT(ParserContext
);
233 // FIXME support multiple top collecions
235 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
240 Report
= HidParser_GetReportByType(Parser
, ReportType
);
252 ReportLength
= Report
->ReportSize
;
260 // byte aligned length
262 ASSERT(ReportLength
% 8 == 0);
263 return ReportLength
/ 8;
269 HidParser_IsReportIDUsed(
270 IN PHID_PARSER Parser
)
272 PHID_PARSER_CONTEXT ParserContext
;
275 // get parser context
277 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
282 ASSERT(ParserContext
);
287 return ParserContext
->UseReportIDs
;
291 HidParser_GetReportItemCountFromReportType(
292 IN PHID_PARSER Parser
,
295 PHID_PARSER_CONTEXT ParserContext
;
299 // get parser context
301 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
306 ASSERT(ParserContext
);
309 // FIXME support multiple top collecions
311 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
316 Report
= HidParser_GetReportByType(Parser
, ReportType
);
326 // return report item count
328 return Report
->ItemCount
;
333 HidParser_GetReportItemTypeCountFromReportType(
334 IN PHID_PARSER Parser
,
338 PHID_PARSER_CONTEXT ParserContext
;
344 // get parser context
346 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
351 ASSERT(ParserContext
);
354 // FIXME support multiple top collecions
356 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
361 Report
= HidParser_GetReportByType(Parser
, ReportType
);
371 // enumerate all items
373 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
378 if (Report
->Items
[Index
]->HasData
&& bData
== TRUE
)
385 else if (Report
->Items
[Index
]->HasData
== FALSE
&& bData
== FALSE
)
401 HidParser_GetContextSize(
402 IN PHID_PARSER Parser
)
405 // FIXME the context must contain all parsed info
407 return sizeof(HID_PARSER_CONTEXT
);
411 HidParser_FreeContext(
412 IN PHID_PARSER Parser
,
414 IN ULONG ContextLength
)
417 // FIXME implement freeing of parsed info
422 HidParser_AllocateParser(
423 IN PHIDPARSER_ALLOC_FUNCTION AllocFunction
,
424 IN PHIDPARSER_FREE_FUNCTION FreeFunction
,
425 IN PHIDPARSER_ZERO_FUNCTION ZeroFunction
,
426 IN PHIDPARSER_COPY_FUNCTION CopyFunction
,
427 IN PHIDPARSER_DEBUG_FUNCTION DebugFunction
,
428 OUT PHID_PARSER
*OutParser
)
431 PHID_PARSER_CONTEXT ParserContext
;
436 Parser
= (PHID_PARSER
)AllocFunction(sizeof(HID_PARSER
));
442 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES
;
446 // allocate parser context
448 ParserContext
= (PHID_PARSER_CONTEXT
)AllocFunction(sizeof(HID_PARSER_CONTEXT
));
454 FreeFunction(Parser
);
455 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES
;
462 Parser
->Alloc
= AllocFunction
;
463 Parser
->Free
= FreeFunction
;
464 Parser
->Zero
= ZeroFunction
;
465 Parser
->Copy
= CopyFunction
;
466 Parser
->Debug
= DebugFunction
;
467 Parser
->ParserContext
= ParserContext
;
476 return HIDPARSER_STATUS_SUCCESS
;
480 HidParser_InitParser(
481 IN PHIDPARSER_ALLOC_FUNCTION AllocFunction
,
482 IN PHIDPARSER_FREE_FUNCTION FreeFunction
,
483 IN PHIDPARSER_ZERO_FUNCTION ZeroFunction
,
484 IN PHIDPARSER_COPY_FUNCTION CopyFunction
,
485 IN PHIDPARSER_DEBUG_FUNCTION DebugFunction
,
486 IN PVOID ParserContext
,
487 OUT PHID_PARSER Parser
)
489 Parser
->Alloc
= AllocFunction
;
490 Parser
->Free
= FreeFunction
;
491 Parser
->Zero
= ZeroFunction
;
492 Parser
->Copy
= CopyFunction
;
493 Parser
->Debug
= DebugFunction
;
494 Parser
->ParserContext
= ParserContext
;
498 HidParser_GetCollectionCount(
499 IN PHID_COLLECTION Collection
)
502 ULONG Count
= Collection
->NodeCount
;
504 for(Index
= 0; Index
< Collection
->NodeCount
; Index
++)
507 // count collection for sub nodes
509 Count
+= HidParser_GetCollectionCount(Collection
->Nodes
[Index
]);
519 HidParser_GetTotalCollectionCount(
520 IN PHID_PARSER Parser
)
522 PHID_PARSER_CONTEXT ParserContext
;
525 // get parser context
527 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
532 ASSERT(ParserContext
);
533 ASSERT(ParserContext
->RootCollection
);
538 return HidParser_GetCollectionCount(ParserContext
->RootCollection
);
542 HidParser_GetMaxUsageListLengthWithReportAndPage(
543 IN PHID_PARSER Parser
,
545 IN USAGE UsagePage OPTIONAL
)
547 PHID_PARSER_CONTEXT ParserContext
;
551 USHORT CurrentUsagePage
;
554 // get parser context
556 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
561 ASSERT(ParserContext
);
564 // FIXME support multiple top collecions
566 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
571 Report
= HidParser_GetReportByType(Parser
, ReportType
);
580 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
585 CurrentUsagePage
= (Report
->Items
[Index
]->UsageMinimum
>> 16);
586 if (CurrentUsagePage
== UsagePage
&& Report
->Items
[Index
]->HasData
)
602 HidParser_GetSpecificValueCapsWithReport(
603 IN PHID_PARSER Parser
,
607 OUT PHIDP_VALUE_CAPS ValueCaps
,
608 IN OUT PULONG ValueCapsLength
)
610 PHID_PARSER_CONTEXT ParserContext
;
614 USHORT CurrentUsagePage
;
618 // get parser context
620 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
625 ASSERT(ParserContext
);
628 // FIXME support multiple top collecions
630 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
635 Report
= HidParser_GetReportByType(Parser
, ReportType
);
641 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
644 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
649 CurrentUsagePage
= (Report
->Items
[Index
]->UsageMinimum
>> 16);
650 CurrentUsage
= (Report
->Items
[Index
]->UsageMinimum
& 0xFFFF);
652 if ((Usage
== CurrentUsage
&& UsagePage
== CurrentUsagePage
) || (Usage
== 0 && UsagePage
== CurrentUsagePage
) || (Usage
== CurrentUsage
&& UsagePage
== 0) || (Usage
== 0 && UsagePage
== 0))
655 // check if there is enough place for the caps
657 if (ItemCount
< *ValueCapsLength
)
662 Parser
->Zero(&ValueCaps
[ItemCount
], sizeof(HIDP_VALUE_CAPS
));
667 ValueCaps
[ItemCount
].UsagePage
= CurrentUsagePage
;
668 ValueCaps
[ItemCount
].ReportID
= Report
->ReportID
;
669 ValueCaps
[ItemCount
].LogicalMin
= Report
->Items
[Index
]->Minimum
;
670 ValueCaps
[ItemCount
].LogicalMax
= Report
->Items
[Index
]->Maximum
;
671 ValueCaps
[ItemCount
].IsAbsolute
= !Report
->Items
[Index
]->Relative
;
672 ValueCaps
[ItemCount
].BitSize
= Report
->Items
[Index
]->BitCount
;
690 *ValueCapsLength
= ItemCount
;
697 return HIDPARSER_STATUS_SUCCESS
;
703 return HIDPARSER_STATUS_USAGE_NOT_FOUND
;
707 HidParser_GetUsagesWithReport(
708 IN PHID_PARSER Parser
,
711 OUT USAGE
*UsageList
,
712 IN OUT PULONG UsageLength
,
713 IN PCHAR ReportDescriptor
,
714 IN ULONG ReportDescriptorLength
)
716 PHID_PARSER_CONTEXT ParserContext
;
720 USHORT CurrentUsagePage
;
721 PHID_REPORT_ITEM ReportItem
;
726 // get parser context
728 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
733 ASSERT(ParserContext
);
736 // FIXME support multiple top collecions
738 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
743 Report
= HidParser_GetReportByType(Parser
, ReportType
);
749 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
752 if (Report
->ReportSize
/ 8 != (ReportDescriptorLength
- 1))
755 // invalid report descriptor length
757 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH
;
760 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
765 ReportItem
= Report
->Items
[Index
];
770 if (!ReportItem
->HasData
)
776 CurrentUsagePage
= (ReportItem
->UsageMinimum
>> 16);
781 if (UsagePage
!= CurrentUsagePage
)
785 // check if the specified usage is activated
787 ASSERT(ReportItem
->ByteOffset
< ReportDescriptorLength
);
788 ASSERT(ReportItem
->BitCount
< 8);
791 // one extra shift for skipping the prepended report id
793 Data
= ReportDescriptor
[ReportItem
->ByteOffset
+ 1];
798 Data
>>= ReportItem
->Shift
;
801 // clear unwanted bits
803 Data
&= ReportItem
->Mask
;
808 Activated
= (Data
!= 0);
814 // is there enough space for the usage
816 if (ItemCount
>= *UsageLength
)
825 UsageList
[ItemCount
] = (ReportItem
->UsageMinimum
& 0xFFFF);
829 if (ItemCount
> *UsageLength
)
834 return HIDPARSER_STATUS_BUFFER_TOO_SMALL
;
838 // success, clear rest of array
840 Parser
->Zero(&UsageList
[ItemCount
], (*UsageLength
- ItemCount
) * sizeof(USAGE
));
845 *UsageLength
= ItemCount
;
850 return HIDPARSER_STATUS_SUCCESS
;
854 HidParser_GetScaledUsageValueWithReport(
855 IN PHID_PARSER Parser
,
859 OUT PLONG UsageValue
,
860 IN PCHAR ReportDescriptor
,
861 IN ULONG ReportDescriptorLength
)
863 PHID_PARSER_CONTEXT ParserContext
;
867 USHORT CurrentUsagePage
;
868 PHID_REPORT_ITEM ReportItem
;
872 // get parser context
874 ParserContext
= (PHID_PARSER_CONTEXT
)Parser
->ParserContext
;
879 ASSERT(ParserContext
);
882 // FIXME support multiple top collecions
884 ASSERT(ParserContext
->RootCollection
->NodeCount
== 1);
889 Report
= HidParser_GetReportByType(Parser
, ReportType
);
895 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
898 if (Report
->ReportSize
/ 8 != (ReportDescriptorLength
- 1))
901 // invalid report descriptor length
903 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH
;
906 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
911 ReportItem
= Report
->Items
[Index
];
916 CurrentUsagePage
= (ReportItem
->UsageMinimum
>> 16);
919 // does usage page match
921 if (UsagePage
!= CurrentUsagePage
)
925 // does the usage match
927 if (Usage
!= (ReportItem
->UsageMinimum
& 0xFFFF))
931 // check if the specified usage is activated
933 ASSERT(ReportItem
->ByteOffset
< ReportDescriptorLength
);
936 // one extra shift for skipping the prepended report id
939 Parser
->Copy(&Data
, &ReportDescriptor
[ReportItem
->ByteOffset
+1], min(sizeof(ULONG
), ReportDescriptorLength
- (ReportItem
->ByteOffset
+ 1)));
940 Data
= ReportDescriptor
[ReportItem
->ByteOffset
+ 1];
945 Data
>>= ReportItem
->Shift
;
948 // clear unwanted bits
950 Data
&= ReportItem
->Mask
;
952 if (ReportItem
->Minimum
> ReportItem
->Maximum
)
955 // logical boundaries are signed values
957 if ((Data
& ~(ReportItem
->Mask
>> 1)) != 0)
959 Data
|= ~ReportItem
->Mask
;
967 return HIDPARSER_STATUS_SUCCESS
;
973 return HIDPARSER_STATUS_USAGE_NOT_FOUND
;
977 HidParser_GetScanCode(
980 if (Usage
< sizeof(KeyboardScanCodes
) / sizeof(KeyboardScanCodes
[0]))
985 return KeyboardScanCodes
[Usage
];
995 HidParser_DispatchKey(
997 IN HIDP_KEYBOARD_DIRECTION KeyAction
,
998 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure
,
999 IN PVOID InsertCodesContext
)
1005 // count code length
1007 for(Index
= 0; Index
< sizeof(ULONG
); Index
++)
1009 if (ScanCodes
[Index
] == 0)
1018 // is this a key break
1020 if (KeyAction
== HidP_KeyboardBreak
)
1025 ScanCodes
[Index
] |= KEY_BREAK
;
1037 // dispatch scan codes
1039 InsertCodesProcedure(InsertCodesContext
, ScanCodes
, Length
);
1045 HidParser_TranslateUsage(
1046 IN PHID_PARSER Parser
,
1048 IN HIDP_KEYBOARD_DIRECTION KeyAction
,
1049 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState
,
1050 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure
,
1051 IN PVOID InsertCodesContext
)
1058 ScanCode
= HidParser_GetScanCode(Usage
);
1062 // invalid lookup or no scan code available
1064 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN
;
1068 // FIXME: translate modifier states
1071 HidParser_DispatchKey((PCHAR
)&ScanCode
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
1076 return HIDPARSER_STATUS_SUCCESS
;