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
)
211 HidParser_InitParser(
212 IN PHIDPARSER_ALLOC_FUNCTION AllocFunction
,
213 IN PHIDPARSER_FREE_FUNCTION FreeFunction
,
214 IN PHIDPARSER_ZERO_FUNCTION ZeroFunction
,
215 IN PHIDPARSER_COPY_FUNCTION CopyFunction
,
216 IN PHIDPARSER_DEBUG_FUNCTION DebugFunction
,
217 OUT PHID_PARSER Parser
)
219 Parser
->Alloc
= AllocFunction
;
220 Parser
->Free
= FreeFunction
;
221 Parser
->Zero
= ZeroFunction
;
222 Parser
->Copy
= CopyFunction
;
223 Parser
->Debug
= DebugFunction
;
227 HidParser_GetMaxUsageListLengthWithReportAndPage(
228 IN PVOID CollectionContext
,
230 IN USAGE UsagePage OPTIONAL
)
235 USHORT CurrentUsagePage
;
240 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
249 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
254 CurrentUsagePage
= (Report
->Items
[Index
].UsageMinimum
>> 16);
255 if (CurrentUsagePage
== UsagePage
&& Report
->Items
[Index
].HasData
)
271 HidParser_GetSpecificValueCapsWithReport(
272 IN PHID_PARSER Parser
,
273 IN PVOID CollectionContext
,
277 OUT PHIDP_VALUE_CAPS ValueCaps
,
278 IN OUT PUSHORT ValueCapsLength
)
282 USHORT ItemCount
= 0;
283 USHORT CurrentUsagePage
;
289 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
295 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
298 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
303 CurrentUsagePage
= (Report
->Items
[Index
].UsageMinimum
>> 16);
304 CurrentUsage
= (Report
->Items
[Index
].UsageMinimum
& 0xFFFF);
306 if ((Usage
== CurrentUsage
&& UsagePage
== CurrentUsagePage
) || (Usage
== 0 && UsagePage
== CurrentUsagePage
) || (Usage
== CurrentUsage
&& UsagePage
== 0) || (Usage
== 0 && UsagePage
== 0))
309 // check if there is enough place for the caps
311 if (ItemCount
< *ValueCapsLength
)
316 Parser
->Zero(&ValueCaps
[ItemCount
], sizeof(HIDP_VALUE_CAPS
));
321 ValueCaps
[ItemCount
].UsagePage
= CurrentUsagePage
;
322 ValueCaps
[ItemCount
].ReportID
= Report
->ReportID
;
323 ValueCaps
[ItemCount
].LogicalMin
= Report
->Items
[Index
].Minimum
;
324 ValueCaps
[ItemCount
].LogicalMax
= Report
->Items
[Index
].Maximum
;
325 ValueCaps
[ItemCount
].IsAbsolute
= !Report
->Items
[Index
].Relative
;
326 ValueCaps
[ItemCount
].BitSize
= Report
->Items
[Index
].BitCount
;
344 *ValueCapsLength
= ItemCount
;
351 return HIDPARSER_STATUS_SUCCESS
;
357 return HIDPARSER_STATUS_USAGE_NOT_FOUND
;
361 HidParser_GetUsagesWithReport(
362 IN PHID_PARSER Parser
,
363 IN PVOID CollectionContext
,
366 OUT USAGE
*UsageList
,
367 IN OUT PULONG UsageLength
,
368 IN PCHAR ReportDescriptor
,
369 IN ULONG ReportDescriptorLength
)
374 USHORT CurrentUsagePage
;
375 PHID_REPORT_ITEM ReportItem
;
378 PUSAGE_AND_PAGE UsageAndPage
= NULL
;
383 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
389 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
392 if (Report
->ReportSize
/ 8 != (ReportDescriptorLength
- 1))
395 // invalid report descriptor length
397 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH
;
401 // cast to usage and page
403 if (UsagePage
== HID_USAGE_PAGE_UNDEFINED
)
406 // the caller requested any set usages
408 UsageAndPage
= (PUSAGE_AND_PAGE
)UsageList
;
411 for(Index
= 0; Index
< Report
->ItemCount
; Index
++)
416 ReportItem
= &Report
->Items
[Index
];
421 if (!ReportItem
->HasData
)
427 CurrentUsagePage
= (ReportItem
->UsageMinimum
>> 16);
429 if (UsagePage
!= HID_USAGE_PAGE_UNDEFINED
)
434 if (UsagePage
!= CurrentUsagePage
)
439 // check if the specified usage is activated
441 ASSERT(ReportItem
->ByteOffset
< ReportDescriptorLength
);
442 ASSERT(ReportItem
->BitCount
<= 8);
445 // one extra shift for skipping the prepended report id
447 Data
= ReportDescriptor
[ReportItem
->ByteOffset
+ 1];
452 Data
>>= ReportItem
->Shift
;
455 // clear unwanted bits
457 Data
&= ReportItem
->Mask
;
462 Activated
= (Data
!= 0);
468 // is there enough space for the usage
470 if (ItemCount
>= *UsageLength
)
476 if (UsagePage
!= HID_USAGE_PAGE_UNDEFINED
)
481 UsageList
[ItemCount
] = (ReportItem
->UsageMinimum
& 0xFFFF);
486 // store usage and page
488 if (ReportItem
->BitCount
== 1)
493 UsageAndPage
[ItemCount
].Usage
=(ReportItem
->UsageMinimum
& 0xFFFF);
498 // use value from control
500 UsageAndPage
[ItemCount
].Usage
= (USHORT
)Data
;
502 UsageAndPage
[ItemCount
].UsagePage
= CurrentUsagePage
;
507 if (ItemCount
> *UsageLength
)
512 return HIDPARSER_STATUS_BUFFER_TOO_SMALL
;
515 if (UsagePage
== HID_USAGE_PAGE_UNDEFINED
)
518 // success, clear rest of array
520 Parser
->Zero(&UsageAndPage
[ItemCount
], (*UsageLength
- ItemCount
) * sizeof(USAGE_AND_PAGE
));
525 // success, clear rest of array
527 Parser
->Zero(&UsageList
[ItemCount
], (*UsageLength
- ItemCount
) * sizeof(USAGE
));
534 *UsageLength
= ItemCount
;
539 return HIDPARSER_STATUS_SUCCESS
;
543 HidParser_UsesReportId(
544 IN PVOID CollectionContext
,
552 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
562 // returns true when report id != 0
564 return (Report
->ReportID
!= 0);
569 HidParser_GetUsageValueWithReport(
570 IN PHID_PARSER Parser
,
571 IN PVOID CollectionContext
,
575 OUT PULONG UsageValue
,
576 IN PCHAR ReportDescriptor
,
577 IN ULONG ReportDescriptorLength
)
581 USHORT CurrentUsagePage
;
582 PHID_REPORT_ITEM ReportItem
;
588 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
594 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
597 if (Report
->ReportSize
/ 8 != (ReportDescriptorLength
- 1))
600 // invalid report descriptor length
602 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH
;
605 for (Index
= 0; Index
< Report
->ItemCount
; Index
++)
610 ReportItem
= &Report
->Items
[Index
];
615 CurrentUsagePage
= (ReportItem
->UsageMinimum
>> 16);
618 // does usage page match
620 if (UsagePage
!= CurrentUsagePage
)
624 // does the usage match
626 if (Usage
!= (ReportItem
->UsageMinimum
& 0xFFFF))
630 // check if the specified usage is activated
632 ASSERT(ReportItem
->ByteOffset
< ReportDescriptorLength
);
635 // one extra shift for skipping the prepended report id
638 Parser
->Copy(&Data
, &ReportDescriptor
[ReportItem
->ByteOffset
+ 1], min(sizeof(ULONG
), ReportDescriptorLength
- (ReportItem
->ByteOffset
+ 1)));
643 Data
>>= ReportItem
->Shift
;
646 // clear unwanted bits
648 Data
&= ReportItem
->Mask
;
654 return HIDPARSER_STATUS_SUCCESS
;
660 return HIDPARSER_STATUS_USAGE_NOT_FOUND
;
666 HidParser_GetScaledUsageValueWithReport(
667 IN PHID_PARSER Parser
,
668 IN PVOID CollectionContext
,
672 OUT PLONG UsageValue
,
673 IN PCHAR ReportDescriptor
,
674 IN ULONG ReportDescriptorLength
)
678 USHORT CurrentUsagePage
;
679 PHID_REPORT_ITEM ReportItem
;
685 Report
= HidParser_GetReportInCollection(CollectionContext
, ReportType
);
691 return HIDPARSER_STATUS_REPORT_NOT_FOUND
;
694 if (Report
->ReportSize
/ 8 != (ReportDescriptorLength
- 1))
697 // invalid report descriptor length
699 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH
;
702 for (Index
= 0; Index
< Report
->ItemCount
; Index
++)
707 ReportItem
= &Report
->Items
[Index
];
712 CurrentUsagePage
= (ReportItem
->UsageMinimum
>> 16);
715 // does usage page match
717 if (UsagePage
!= CurrentUsagePage
)
721 // does the usage match
723 if (Usage
!= (ReportItem
->UsageMinimum
& 0xFFFF))
727 // check if the specified usage is activated
729 ASSERT(ReportItem
->ByteOffset
< ReportDescriptorLength
);
732 // one extra shift for skipping the prepended report id
735 Parser
->Copy(&Data
, &ReportDescriptor
[ReportItem
->ByteOffset
+ 1], min(sizeof(ULONG
), ReportDescriptorLength
- (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 // 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
;
823 HidParser_DispatchKey(
825 IN HIDP_KEYBOARD_DIRECTION KeyAction
,
826 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure
,
827 IN PVOID InsertCodesContext
)
835 for(Index
= 0; Index
< sizeof(ULONG
); Index
++)
837 if (ScanCodes
[Index
] == 0)
846 // is this a key break
848 if (KeyAction
== HidP_Keyboard_Break
)
851 // add break - see USB HID to PS/2 Scan Code Translation Table
853 ScanCodes
[Index
] |= 0x80;
865 // dispatch scan codes
867 InsertCodesProcedure(InsertCodesContext
, ScanCodes
, Length
);
872 HidParser_TranslateKbdUsage(
873 IN PHID_PARSER Parser
,
875 IN HIDP_KEYBOARD_DIRECTION KeyAction
,
876 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState
,
877 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure
,
878 IN PVOID InsertCodesContext
)
881 CHAR FakeShift
[] = {0xE0, 0x2A, 0x00};
882 CHAR FakeCtrl
[] = {0xE1, 0x1D, 0x00};
887 ScanCode
= HidParser_GetScanCodeFromKbdUsage(Usage
);
891 // invalid lookup or no scan code available
893 DPRINT1("No Scan code for Usage %x\n", Usage
);
894 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN
;
897 if (ScanCode
& 0xFF00)
902 ScanCode
= NTOHS(ScanCode
);
905 if (Usage
== 0x46 && KeyAction
== HidP_Keyboard_Make
)
907 // Print Screen generates additional FakeShift
908 HidParser_DispatchKey(FakeShift
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
913 // Pause/Break generates additional FakeCtrl. Note: it's always before key press/release.
914 HidParser_DispatchKey(FakeCtrl
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
918 // FIXME: translate modifier states
920 HidParser_DispatchKey((PCHAR
)&ScanCode
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
922 if (Usage
== 0x46 && KeyAction
== HidP_Keyboard_Break
)
924 // Print Screen generates additional FakeShift
925 HidParser_DispatchKey(FakeShift
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
931 return HIDPARSER_STATUS_SUCCESS
;
935 HidParser_TranslateCustUsage(
936 IN PHID_PARSER Parser
,
938 IN HIDP_KEYBOARD_DIRECTION KeyAction
,
939 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState
,
940 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure
,
941 IN PVOID InsertCodesContext
)
948 ScanCode
= HidParser_GetScanCodeFromCustUsage(Usage
);
952 // invalid lookup or no scan code available
954 DPRINT1("No Scan code for Usage %x\n", Usage
);
955 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN
;
958 if (ScanCode
& 0xFF00)
963 ScanCode
= NTOHS(ScanCode
);
967 // FIXME: translate modifier states
969 HidParser_DispatchKey((PCHAR
)&ScanCode
, KeyAction
, InsertCodesProcedure
, InsertCodesContext
);
974 return HIDPARSER_STATUS_SUCCESS
;