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)
16 static ULONG KeyboardScanCodes
[256] =
17 { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
18 /* 0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020, 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
19 /* 1 */ 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014, 0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
20 /* 2 */ 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
21 /* 3 */ 0x001b, 0x002b, 0x002b, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034, 0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
22 /* 4 */ 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xE037, 0x0046, 0x0045, 0xE052, 0xE047, 0xE049, 0xE053, 0xE04F, 0xE051, 0xE04D,
23 /* 5 */ 0xE04B, 0xE050, 0xE048, 0x0045, 0xE035, 0x0037, 0x004a, 0x004e, 0xE01C, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
24 /* 6 */ 0x0048, 0x0049, 0x0052, 0x0053, 0x0056, 0xE05D, 0xE05E, 0x0075, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be,
25 /* 7 */ 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x0086, 0x008a, 0x0082, 0x0084, 0x0080, 0x0081, 0x0083, 0x0089, 0x0085, 0x0087, 0x0088, 0x0071,
26 /* 8 */ 0x0073, 0x0072, 0x0000, 0x0000, 0x0000, 0x0079, 0x0000, 0x0059, 0x005d, 0x007c, 0x005c, 0x005e, 0x005f, 0x0000, 0x0000, 0x0000,
27 /* 9 */ 0x007a, 0x007b, 0x005a, 0x005b, 0x0055, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
28 /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
29 /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
30 /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
31 /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
32 /* E */ 0x001D, 0x002A, 0x0038, 0xE05B, 0xE01D, 0x0036, 0xE038, 0xE05C, 0x00a4, 0x00a6, 0x00a5, 0x00a3, 0x00a1, 0x0073, 0x0072, 0x0071,
33 /* F */ 0x0096, 0x009e, 0x009f, 0x0080, 0x0088, 0x00b1, 0x00b2, 0x00b0, 0x008e, 0x0098, 0x00ad, 0x008c, 0x0000, 0x0000, 0x0000, 0x0000,
40 } CustomerScanCodes
[] =
62 #define NTOHS(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8))
65 HidParser_GetCollectionUsagePage(
66 IN PVOID CollectionContext
,
68 OUT PUSHORT UsagePage
)
70 PHID_COLLECTION Collection
;
75 Collection
= HidParser_GetCollectionFromContext(CollectionContext
);
79 // collection not found
81 return HIDPARSER_STATUS_COLLECTION_NOT_FOUND
;
87 *UsagePage
= (Collection
->Usage
>> 16);
88 *Usage
= (Collection
->Usage
& 0xFFFF);
89 return HIDPARSER_STATUS_SUCCESS
;
93 HidParser_GetReportLength(
94 IN PVOID CollectionContext
,
103 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
115 ReportLength
= Report
->ReportSize
;
123 // byte aligned length
125 ASSERT(ReportLength
% 8 == 0);
126 return ReportLength
/ 8;
132 HidParser_GetReportItemCountFromReportType(
133 IN PVOID CollectionContext
,
141 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
151 // return report item count
153 return Report
->ItemCount
;
158 HidParser_GetReportItemTypeCountFromReportType(
159 IN PVOID CollectionContext
,
170 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
180 // enumerate all items
182 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
187 if (Report
->Items
[Index
].HasData
&& bData
)
194 else if (Report
->Items
[Index
].HasData
== FALSE
&& bData
== FALSE
)
210 HidParser_GetMaxUsageListLengthWithReportAndPage(
211 IN PVOID CollectionContext
,
213 IN USAGE UsagePage OPTIONAL
)
218 USHORT CurrentUsagePage
;
223 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
232 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
237 CurrentUsagePage
= (Report
->Items
[Index
].UsageMinimum
>> 16);
238 if (CurrentUsagePage
== UsagePage
&& Report
->Items
[Index
].HasData
)
254 HidParser_GetSpecificValueCapsWithReport(
255 IN PVOID CollectionContext
,
259 OUT PHIDP_VALUE_CAPS ValueCaps
,
260 IN OUT PUSHORT ValueCapsLength
)
264 USHORT ItemCount
= 0;
265 USHORT CurrentUsagePage
;
271 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
277 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
280 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
285 CurrentUsagePage
= (Report
->Items
[Index
].UsageMinimum
>> 16);
286 CurrentUsage
= (Report
->Items
[Index
].UsageMinimum
& 0xFFFF);
288 if ((Usage
== CurrentUsage
&& UsagePage
== CurrentUsagePage
) || (Usage
== 0 && UsagePage
== CurrentUsagePage
) || (Usage
== CurrentUsage
&& UsagePage
== 0) || (Usage
== 0 && UsagePage
== 0))
291 // check if there is enough place for the caps
293 if (ItemCount
< *ValueCapsLength
)
298 ZeroFunction(&ValueCaps
[ItemCount
], sizeof(HIDP_VALUE_CAPS
));
303 ValueCaps
[ItemCount
].UsagePage
= CurrentUsagePage
;
304 ValueCaps
[ItemCount
].ReportID
= Report
->ReportID
;
305 ValueCaps
[ItemCount
].LogicalMin
= Report
->Items
[Index
].Minimum
;
306 ValueCaps
[ItemCount
].LogicalMax
= Report
->Items
[Index
].Maximum
;
307 ValueCaps
[ItemCount
].IsAbsolute
= !Report
->Items
[Index
].Relative
;
308 ValueCaps
[ItemCount
].BitSize
= Report
->Items
[Index
].BitCount
;
326 *ValueCapsLength
= ItemCount
;
333 return HIDPARSER_STATUS_SUCCESS
;
339 return HIDPARSER_STATUS_USAGE_NOT_FOUND
;
343 HidParser_GetUsagesWithReport(
344 IN PVOID CollectionContext
,
347 OUT USAGE
*UsageList
,
348 IN OUT PULONG UsageLength
,
349 IN PCHAR ReportDescriptor
,
350 IN ULONG ReportDescriptorLength
)
355 USHORT CurrentUsagePage
;
356 PHID_REPORT_ITEM ReportItem
;
359 PUSAGE_AND_PAGE UsageAndPage
= NULL
;
364 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
370 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
373 if (Report
->ReportSize
/ 8 != (ReportDescriptorLength
- 1))
376 // invalid report descriptor length
378 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH
;
382 // cast to usage and page
384 if (UsagePage
== HID_USAGE_PAGE_UNDEFINED
)
387 // the caller requested any set usages
389 UsageAndPage
= (PUSAGE_AND_PAGE
)UsageList
;
392 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
397 ReportItem
= &Report
->Items
[Index
];
402 if (!ReportItem
->HasData
)
408 CurrentUsagePage
= (ReportItem
->UsageMinimum
>> 16);
410 if (UsagePage
!= HID_USAGE_PAGE_UNDEFINED
)
415 if (UsagePage
!= CurrentUsagePage
)
420 // check if the specified usage is activated
422 ASSERT(ReportItem
->ByteOffset
< ReportDescriptorLength
);
423 ASSERT(ReportItem
->BitCount
<= 8);
426 // one extra shift for skipping the prepended report id
428 Data
= ReportDescriptor
[ReportItem
->ByteOffset
+ 1];
433 Data
>>= ReportItem
->Shift
;
436 // clear unwanted bits
438 Data
&= ReportItem
->Mask
;
443 Activated
= (Data
!= 0);
449 // is there enough space for the usage
451 if (ItemCount
>= *UsageLength
)
457 if (UsagePage
!= HID_USAGE_PAGE_UNDEFINED
)
462 UsageList
[ItemCount
] = (ReportItem
->UsageMinimum
& 0xFFFF);
467 // store usage and page
469 if (ReportItem
->BitCount
== 1)
474 UsageAndPage
[ItemCount
].Usage
=(ReportItem
->UsageMinimum
& 0xFFFF);
479 // use value from control
481 UsageAndPage
[ItemCount
].Usage
= (USHORT
)Data
;
483 UsageAndPage
[ItemCount
].UsagePage
= CurrentUsagePage
;
488 if (ItemCount
> *UsageLength
)
493 return HIDPARSER_STATUS_BUFFER_TOO_SMALL
;
496 if (UsagePage
== HID_USAGE_PAGE_UNDEFINED
)
499 // success, clear rest of array
501 ZeroFunction(&UsageAndPage
[ItemCount
], (*UsageLength
- ItemCount
) * sizeof(USAGE_AND_PAGE
));
506 // success, clear rest of array
508 ZeroFunction(&UsageList
[ItemCount
], (*UsageLength
- ItemCount
) * sizeof(USAGE
));
515 *UsageLength
= ItemCount
;
520 return HIDPARSER_STATUS_SUCCESS
;
524 HidParser_UsesReportId(
525 IN PVOID CollectionContext
,
533 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
543 // returns true when report id != 0
545 return (Report
->ReportID
!= 0);
550 HidParser_GetUsageValueWithReport(
551 IN PVOID CollectionContext
,
555 OUT PULONG UsageValue
,
556 IN PCHAR ReportDescriptor
,
557 IN ULONG ReportDescriptorLength
)
561 USHORT CurrentUsagePage
;
562 PHID_REPORT_ITEM ReportItem
;
568 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
574 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
577 if (Report
->ReportSize
/ 8 != (ReportDescriptorLength
- 1))
580 // invalid report descriptor length
582 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH
;
585 for (Index
= 0; Index
< Report
->ItemCount
; Index
++)
590 ReportItem
= &Report
->Items
[Index
];
595 CurrentUsagePage
= (ReportItem
->UsageMinimum
>> 16);
598 // does usage page match
600 if (UsagePage
!= CurrentUsagePage
)
604 // does the usage match
606 if (Usage
!= (ReportItem
->UsageMinimum
& 0xFFFF))
610 // check if the specified usage is activated
612 ASSERT(ReportItem
->ByteOffset
< ReportDescriptorLength
);
615 // one extra shift for skipping the prepended report id
618 CopyFunction(&Data
, &ReportDescriptor
[ReportItem
->ByteOffset
+ 1], min(sizeof(ULONG
), ReportDescriptorLength
- (ReportItem
->ByteOffset
+ 1)));
623 Data
>>= ReportItem
->Shift
;
626 // clear unwanted bits
628 Data
&= ReportItem
->Mask
;
634 return HIDPARSER_STATUS_SUCCESS
;
640 return HIDPARSER_STATUS_USAGE_NOT_FOUND
;
646 HidParser_GetScaledUsageValueWithReport(
647 IN PVOID CollectionContext
,
651 OUT PLONG UsageValue
,
652 IN PCHAR ReportDescriptor
,
653 IN ULONG ReportDescriptorLength
)
657 USHORT CurrentUsagePage
;
658 PHID_REPORT_ITEM ReportItem
;
664 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
670 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
673 if (Report
->ReportSize
/ 8 != (ReportDescriptorLength
- 1))
676 // invalid report descriptor length
678 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH
;
681 for (Index
= 0; Index
< Report
->ItemCount
; Index
++)
686 ReportItem
= &Report
->Items
[Index
];
691 CurrentUsagePage
= (ReportItem
->UsageMinimum
>> 16);
694 // does usage page match
696 if (UsagePage
!= CurrentUsagePage
)
700 // does the usage match
702 if (Usage
!= (ReportItem
->UsageMinimum
& 0xFFFF))
706 // check if the specified usage is activated
708 ASSERT(ReportItem
->ByteOffset
< ReportDescriptorLength
);
711 // one extra shift for skipping the prepended report id
714 CopyFunction(&Data
, &ReportDescriptor
[ReportItem
->ByteOffset
+ 1], min(sizeof(ULONG
), ReportDescriptorLength
- (ReportItem
->ByteOffset
+ 1)));
719 Data
>>= ReportItem
->Shift
;
722 // clear unwanted bits
724 Data
&= ReportItem
->Mask
;
726 if (ReportItem
->Minimum
> ReportItem
->Maximum
)
729 // logical boundaries are signed values
732 // FIXME: scale with physical min/max
733 if ((Data
& ~(ReportItem
->Mask
>> 1)) != 0)
735 Data
|= ~ReportItem
->Mask
;
740 // logical boundaries are absolute values
741 return HIDPARSER_STATUS_BAD_LOG_PHY_VALUES
;
748 return HIDPARSER_STATUS_SUCCESS
;
754 return HIDPARSER_STATUS_USAGE_NOT_FOUND
;
758 HidParser_GetScanCodeFromKbdUsage(
761 if (Usage
< sizeof(KeyboardScanCodes
) / sizeof(KeyboardScanCodes
[0]))
766 return KeyboardScanCodes
[Usage
];
776 HidParser_GetScanCodeFromCustUsage(
782 // find usage in array
784 for (i
= 0; i
< sizeof(CustomerScanCodes
) / sizeof(CustomerScanCodes
[0]); ++i
)
786 if (CustomerScanCodes
[i
].Usage
== Usage
)
791 return CustomerScanCodes
[i
].ScanCode
;
802 HidParser_DispatchKey(
804 IN HIDP_KEYBOARD_DIRECTION KeyAction
,
805 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure
,
806 IN PVOID InsertCodesContext
)
814 for(Index
= 0; Index
< sizeof(ULONG
); Index
++)
816 if (ScanCodes
[Index
] == 0)
825 // is this a key break
827 if (KeyAction
== HidP_Keyboard_Break
)
830 // add break - see USB HID to PS/2 Scan Code Translation Table
832 ScanCodes
[Index
] |= 0x80;
844 // dispatch scan codes
846 InsertCodesProcedure(InsertCodesContext
, ScanCodes
, Length
);
851 HidParser_TranslateKbdUsage(
853 IN HIDP_KEYBOARD_DIRECTION KeyAction
,
854 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState
,
855 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure
,
856 IN PVOID InsertCodesContext
)
859 CHAR FakeShift
[] = {0xE0, 0x2A, 0x00};
860 CHAR FakeCtrl
[] = {0xE1, 0x1D, 0x00};
865 ScanCode
= HidParser_GetScanCodeFromKbdUsage(Usage
);
869 // invalid lookup or no scan code available
871 DPRINT1("No Scan code for Usage %x\n", Usage
);
872 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN
;
875 if (ScanCode
& 0xFF00)
880 ScanCode
= NTOHS(ScanCode
);
883 if (Usage
== 0x46 && KeyAction
== HidP_Keyboard_Make
)
885 // Print Screen generates additional FakeShift
886 HidParser_DispatchKey(FakeShift
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
891 // Pause/Break generates additional FakeCtrl. Note: it's always before key press/release.
892 HidParser_DispatchKey(FakeCtrl
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
896 // FIXME: translate modifier states
898 HidParser_DispatchKey((PCHAR
)&ScanCode
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
900 if (Usage
== 0x46 && KeyAction
== HidP_Keyboard_Break
)
902 // Print Screen generates additional FakeShift
903 HidParser_DispatchKey(FakeShift
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
909 return HIDPARSER_STATUS_SUCCESS
;
913 HidParser_TranslateCustUsage(
915 IN HIDP_KEYBOARD_DIRECTION KeyAction
,
916 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState
,
917 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure
,
918 IN PVOID InsertCodesContext
)
925 ScanCode
= HidParser_GetScanCodeFromCustUsage(Usage
);
929 // invalid lookup or no scan code available
931 DPRINT1("No Scan code for Usage %x\n", Usage
);
932 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN
;
935 if (ScanCode
& 0xFF00)
940 ScanCode
= NTOHS(ScanCode
);
944 // FIXME: translate modifier states
946 HidParser_DispatchKey((PCHAR
)&ScanCode
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
951 return HIDPARSER_STATUS_SUCCESS
;