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] =
15 { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
16 /* 0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020, 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
17 /* 1 */ 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014, 0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
18 /* 2 */ 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
19 /* 3 */ 0x001b, 0x002b, 0x002b, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034, 0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
20 /* 4 */ 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xE037, 0x0046, 0x0045, 0xE052, 0xE047, 0xE049, 0xE053, 0xE04F, 0xE051, 0xE04D,
21 /* 5 */ 0xE04B, 0xE050, 0xE048, 0x0045, 0xE035, 0x0037, 0x004a, 0x004e, 0xE01C, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
22 /* 6 */ 0x0048, 0x0049, 0x0052, 0x0053, 0x0056, 0xE05D, 0xE05E, 0x0075, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be,
23 /* 7 */ 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x0086, 0x008a, 0x0082, 0x0084, 0x0080, 0x0081, 0x0083, 0x0089, 0x0085, 0x0087, 0x0088, 0x0071,
24 /* 8 */ 0x0073, 0x0072, 0x0000, 0x0000, 0x0000, 0x0079, 0x0000, 0x0059, 0x005d, 0x007c, 0x005c, 0x005e, 0x005f, 0x0000, 0x0000, 0x0000,
25 /* 9 */ 0x007a, 0x007b, 0x005a, 0x005b, 0x0055, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
26 /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
27 /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
28 /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
29 /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
30 /* E */ 0x001D, 0x002A, 0x0038, 0xE05B, 0xE01D, 0x0036, 0xE038, 0xE05C, 0x00a4, 0x00a6, 0x00a5, 0x00a3, 0x00a1, 0x0073, 0x0072, 0x0071,
31 /* F */ 0x0096, 0x009e, 0x009f, 0x0080, 0x0088, 0x00b1, 0x00b2, 0x00b0, 0x008e, 0x0098, 0x00ad, 0x008c, 0x0000, 0x0000, 0x0000, 0x0000,
38 } CustomerScanCodes
[] =
60 #define NTOHS(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8))
63 HidParser_GetCollectionUsagePage(
64 IN PVOID CollectionContext
,
66 OUT PUSHORT UsagePage
)
68 PHID_COLLECTION Collection
;
73 Collection
= HidParser_GetCollectionFromContext(CollectionContext
);
77 // collection not found
79 return HIDPARSER_STATUS_COLLECTION_NOT_FOUND
;
85 *UsagePage
= (Collection
->Usage
>> 16);
86 *Usage
= (Collection
->Usage
& 0xFFFF);
87 return HIDPARSER_STATUS_SUCCESS
;
91 HidParser_GetReportLength(
92 IN PVOID CollectionContext
,
101 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
113 ReportLength
= Report
->ReportSize
;
121 // byte aligned length
123 ASSERT(ReportLength
% 8 == 0);
124 return ReportLength
/ 8;
130 HidParser_GetReportItemCountFromReportType(
131 IN PVOID CollectionContext
,
139 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
149 // return report item count
151 return Report
->ItemCount
;
156 HidParser_GetReportItemTypeCountFromReportType(
157 IN PVOID CollectionContext
,
168 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
178 // enumerate all items
180 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
185 if (Report
->Items
[Index
].HasData
&& bData
== TRUE
)
192 else if (Report
->Items
[Index
].HasData
== FALSE
&& bData
== FALSE
)
209 HidParser_InitParser(
210 IN PHIDPARSER_ALLOC_FUNCTION AllocFunction
,
211 IN PHIDPARSER_FREE_FUNCTION FreeFunction
,
212 IN PHIDPARSER_ZERO_FUNCTION ZeroFunction
,
213 IN PHIDPARSER_COPY_FUNCTION CopyFunction
,
214 IN PHIDPARSER_DEBUG_FUNCTION DebugFunction
,
215 OUT PHID_PARSER Parser
)
217 Parser
->Alloc
= AllocFunction
;
218 Parser
->Free
= FreeFunction
;
219 Parser
->Zero
= ZeroFunction
;
220 Parser
->Copy
= CopyFunction
;
221 Parser
->Debug
= DebugFunction
;
225 HidParser_GetMaxUsageListLengthWithReportAndPage(
226 IN PVOID CollectionContext
,
228 IN USAGE UsagePage OPTIONAL
)
233 USHORT CurrentUsagePage
;
238 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
247 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
252 CurrentUsagePage
= (Report
->Items
[Index
].UsageMinimum
>> 16);
253 if (CurrentUsagePage
== UsagePage
&& Report
->Items
[Index
].HasData
)
269 HidParser_GetSpecificValueCapsWithReport(
270 IN PHID_PARSER Parser
,
271 IN PVOID CollectionContext
,
275 OUT PHIDP_VALUE_CAPS ValueCaps
,
276 IN OUT PULONG ValueCapsLength
)
281 USHORT CurrentUsagePage
;
287 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
293 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
296 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
301 CurrentUsagePage
= (Report
->Items
[Index
].UsageMinimum
>> 16);
302 CurrentUsage
= (Report
->Items
[Index
].UsageMinimum
& 0xFFFF);
304 if ((Usage
== CurrentUsage
&& UsagePage
== CurrentUsagePage
) || (Usage
== 0 && UsagePage
== CurrentUsagePage
) || (Usage
== CurrentUsage
&& UsagePage
== 0) || (Usage
== 0 && UsagePage
== 0))
307 // check if there is enough place for the caps
309 if (ItemCount
< *ValueCapsLength
)
314 Parser
->Zero(&ValueCaps
[ItemCount
], sizeof(HIDP_VALUE_CAPS
));
319 ValueCaps
[ItemCount
].UsagePage
= CurrentUsagePage
;
320 ValueCaps
[ItemCount
].ReportID
= Report
->ReportID
;
321 ValueCaps
[ItemCount
].LogicalMin
= Report
->Items
[Index
].Minimum
;
322 ValueCaps
[ItemCount
].LogicalMax
= Report
->Items
[Index
].Maximum
;
323 ValueCaps
[ItemCount
].IsAbsolute
= !Report
->Items
[Index
].Relative
;
324 ValueCaps
[ItemCount
].BitSize
= Report
->Items
[Index
].BitCount
;
342 *ValueCapsLength
= ItemCount
;
349 return HIDPARSER_STATUS_SUCCESS
;
355 return HIDPARSER_STATUS_USAGE_NOT_FOUND
;
359 HidParser_GetUsagesWithReport(
360 IN PHID_PARSER Parser
,
361 IN PVOID CollectionContext
,
364 OUT USAGE
*UsageList
,
365 IN OUT PULONG UsageLength
,
366 IN PCHAR ReportDescriptor
,
367 IN ULONG ReportDescriptorLength
)
372 USHORT CurrentUsagePage
;
373 PHID_REPORT_ITEM ReportItem
;
376 PUSAGE_AND_PAGE UsageAndPage
= NULL
;
381 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
387 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
390 if (Report
->ReportSize
/ 8 != (ReportDescriptorLength
- 1))
393 // invalid report descriptor length
395 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH
;
399 // cast to usage and page
401 if (UsagePage
== HID_USAGE_PAGE_UNDEFINED
)
404 // the caller requested any set usages
406 UsageAndPage
= (PUSAGE_AND_PAGE
)UsageList
;
409 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
414 ReportItem
= &Report
->Items
[Index
];
419 if (!ReportItem
->HasData
)
425 CurrentUsagePage
= (ReportItem
->UsageMinimum
>> 16);
427 if (UsagePage
!= HID_USAGE_PAGE_UNDEFINED
)
432 if (UsagePage
!= CurrentUsagePage
)
437 // check if the specified usage is activated
439 ASSERT(ReportItem
->ByteOffset
< ReportDescriptorLength
);
440 ASSERT(ReportItem
->BitCount
<= 8);
443 // one extra shift for skipping the prepended report id
445 Data
= ReportDescriptor
[ReportItem
->ByteOffset
+ 1];
450 Data
>>= ReportItem
->Shift
;
453 // clear unwanted bits
455 Data
&= ReportItem
->Mask
;
460 Activated
= (Data
!= 0);
466 // is there enough space for the usage
468 if (ItemCount
>= *UsageLength
)
474 if (UsagePage
!= HID_USAGE_PAGE_UNDEFINED
)
479 UsageList
[ItemCount
] = (ReportItem
->UsageMinimum
& 0xFFFF);
484 // store usage and page
486 if (ReportItem
->BitCount
== 1)
491 UsageAndPage
[ItemCount
].Usage
=(ReportItem
->UsageMinimum
& 0xFFFF);
496 // use value from control
498 UsageAndPage
[ItemCount
].Usage
= (USHORT
)Data
;
500 UsageAndPage
[ItemCount
].UsagePage
= CurrentUsagePage
;
505 if (ItemCount
> *UsageLength
)
510 return HIDPARSER_STATUS_BUFFER_TOO_SMALL
;
513 if (UsagePage
== HID_USAGE_PAGE_UNDEFINED
)
516 // success, clear rest of array
518 Parser
->Zero(&UsageAndPage
[ItemCount
], (*UsageLength
- ItemCount
) * sizeof(USAGE_AND_PAGE
));
523 // success, clear rest of array
525 Parser
->Zero(&UsageList
[ItemCount
], (*UsageLength
- ItemCount
) * sizeof(USAGE
));
532 *UsageLength
= ItemCount
;
537 return HIDPARSER_STATUS_SUCCESS
;
541 HidParser_UsesReportId(
542 IN PVOID CollectionContext
,
550 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
560 // returns true when report id != 0
562 return (Report
->ReportID
!= 0);
567 HidParser_GetUsageValueWithReport(
568 IN PHID_PARSER Parser
,
569 IN PVOID CollectionContext
,
573 OUT PULONG UsageValue
,
574 IN PCHAR ReportDescriptor
,
575 IN ULONG ReportDescriptorLength
)
579 USHORT CurrentUsagePage
;
580 PHID_REPORT_ITEM ReportItem
;
586 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
592 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
595 if (Report
->ReportSize
/ 8 != (ReportDescriptorLength
- 1))
598 // invalid report descriptor length
600 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH
;
603 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
608 ReportItem
= &Report
->Items
[Index
];
613 CurrentUsagePage
= (ReportItem
->UsageMinimum
>> 16);
616 // does usage page match
618 if (UsagePage
!= CurrentUsagePage
)
622 // does the usage match
624 if (Usage
!= (ReportItem
->UsageMinimum
& 0xFFFF))
628 // check if the specified usage is activated
630 ASSERT(ReportItem
->ByteOffset
< ReportDescriptorLength
);
633 // one extra shift for skipping the prepended report id
636 Parser
->Copy(&Data
, &ReportDescriptor
[ReportItem
->ByteOffset
+1], min(sizeof(ULONG
), ReportDescriptorLength
- (ReportItem
->ByteOffset
+ 1)));
637 //Data = ReportDescriptor[ReportItem->ByteOffset + 1];
642 Data
>>= ReportItem
->Shift
;
645 // clear unwanted bits
647 Data
&= ReportItem
->Mask
;
653 return HIDPARSER_STATUS_SUCCESS
;
659 return HIDPARSER_STATUS_USAGE_NOT_FOUND
;
665 HidParser_GetScaledUsageValueWithReport(
666 IN PHID_PARSER Parser
,
667 IN PVOID CollectionContext
,
671 OUT PLONG UsageValue
,
672 IN PCHAR ReportDescriptor
,
673 IN ULONG ReportDescriptorLength
)
677 USHORT CurrentUsagePage
;
678 PHID_REPORT_ITEM ReportItem
;
684 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
690 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
693 if (Report
->ReportSize
/ 8 != (ReportDescriptorLength
- 1))
696 // invalid report descriptor length
698 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH
;
701 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
706 ReportItem
= &Report
->Items
[Index
];
711 CurrentUsagePage
= (ReportItem
->UsageMinimum
>> 16);
714 // does usage page match
716 if (UsagePage
!= CurrentUsagePage
)
720 // does the usage match
722 if (Usage
!= (ReportItem
->UsageMinimum
& 0xFFFF))
726 // check if the specified usage is activated
728 ASSERT(ReportItem
->ByteOffset
< ReportDescriptorLength
);
731 // one extra shift for skipping the prepended report id
734 Parser
->Copy(&Data
, &ReportDescriptor
[ReportItem
->ByteOffset
+1], min(sizeof(ULONG
), ReportDescriptorLength
- (ReportItem
->ByteOffset
+ 1)));
735 Data
= ReportDescriptor
[ReportItem
->ByteOffset
+ 1];
740 Data
>>= ReportItem
->Shift
;
743 // clear unwanted bits
745 Data
&= ReportItem
->Mask
;
747 if (ReportItem
->Minimum
> ReportItem
->Maximum
)
750 // logical boundaries are signed values
753 // FIXME: scale with physical min/max
754 if ((Data
& ~(ReportItem
->Mask
>> 1)) != 0)
756 Data
|= ~ReportItem
->Mask
;
761 // HACK: logical boundaries are absolute values
762 return HIDPARSER_STATUS_BAD_LOG_PHY_VALUES
;
769 return HIDPARSER_STATUS_SUCCESS
;
775 return HIDPARSER_STATUS_USAGE_NOT_FOUND
;
779 HidParser_GetScanCodeFromKbdUsage(
782 if (Usage
< sizeof(KeyboardScanCodes
) / sizeof(KeyboardScanCodes
[0]))
787 return KeyboardScanCodes
[Usage
];
797 HidParser_GetScanCodeFromCustUsage(
803 // find usage in array
805 for (i
= 0; i
< sizeof(CustomerScanCodes
) / sizeof(CustomerScanCodes
[0]); ++i
)
807 if (CustomerScanCodes
[i
].Usage
== Usage
)
812 return CustomerScanCodes
[i
].ScanCode
;
824 HidParser_DispatchKey(
826 IN HIDP_KEYBOARD_DIRECTION KeyAction
,
827 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure
,
828 IN PVOID InsertCodesContext
)
836 for(Index
= 0; Index
< sizeof(ULONG
); Index
++)
838 if (ScanCodes
[Index
] == 0)
847 // is this a key break
849 if (KeyAction
== HidP_Keyboard_Break
)
852 // add break - see USB HID to PS/2 Scan Code Translation Table
854 ScanCodes
[Index
] |= 0x80;
866 // dispatch scan codes
868 InsertCodesProcedure(InsertCodesContext
, ScanCodes
, Length
);
873 HidParser_TranslateKbdUsage(
874 IN PHID_PARSER Parser
,
876 IN HIDP_KEYBOARD_DIRECTION KeyAction
,
877 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState
,
878 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure
,
879 IN PVOID InsertCodesContext
)
882 CHAR FakeShift
[] = {0xE0, 0x2A, 0x00};
883 CHAR FakeCtrl
[] = {0xE1, 0x1D, 0x00};
888 ScanCode
= HidParser_GetScanCodeFromKbdUsage(Usage
);
892 // invalid lookup or no scan code available
894 DPRINT1("No Scan code for Usage %x\n", Usage
);
895 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN
;
898 if (ScanCode
& 0xFF00)
903 ScanCode
= NTOHS(ScanCode
);
906 if (Usage
== 0x46 && KeyAction
== HidP_Keyboard_Make
)
908 // Print Screen generates additional FakeShift
909 HidParser_DispatchKey(FakeShift
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
914 // Pause/Break generates additional FakeCtrl. Note: it's always before key press/release.
915 HidParser_DispatchKey(FakeCtrl
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
919 // FIXME: translate modifier states
921 HidParser_DispatchKey((PCHAR
)&ScanCode
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
923 if (Usage
== 0x46 && KeyAction
== HidP_Keyboard_Break
)
925 // Print Screen generates additional FakeShift
926 HidParser_DispatchKey(FakeShift
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
932 return HIDPARSER_STATUS_SUCCESS
;
936 HidParser_TranslateCustUsage(
937 IN PHID_PARSER Parser
,
939 IN HIDP_KEYBOARD_DIRECTION KeyAction
,
940 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState
,
941 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure
,
942 IN PVOID InsertCodesContext
)
949 ScanCode
= HidParser_GetScanCodeFromCustUsage(Usage
);
953 // invalid lookup or no scan code available
955 DPRINT1("No Scan code for Usage %x\n", Usage
);
956 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN
;
959 if (ScanCode
& 0xFF00)
964 ScanCode
= NTOHS(ScanCode
);
968 // FIXME: translate modifier states
970 HidParser_DispatchKey((PCHAR
)&ScanCode
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
975 return HIDPARSER_STATUS_SUCCESS
;