xref: /reactos/sdk/lib/drivers/hidparser/hidparser.c (revision c4055c45)
1 /*
2  * PROJECT:     ReactOS HID Parser Library
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        lib/drivers/hidparser/hidparser.c
5  * PURPOSE:     HID Parser
6  * PROGRAMMERS:
7  *              Michael Martin (michael.martin@reactos.org)
8  *              Johannes Anderwald (johannes.anderwald@reactos.org)
9  */
10 
11 #include "parser.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 NTSTATUS
17 NTAPI
HidParser_GetCollectionDescription(IN PHIDP_REPORT_DESCRIPTOR ReportDesc,IN ULONG DescLength,IN POOL_TYPE PoolType,OUT PHIDP_DEVICE_DESC DeviceDescription)18 HidParser_GetCollectionDescription(
19     IN PHIDP_REPORT_DESCRIPTOR ReportDesc,
20     IN ULONG DescLength,
21     IN POOL_TYPE PoolType,
22     OUT PHIDP_DEVICE_DESC DeviceDescription)
23 {
24     NTSTATUS ParserStatus;
25     ULONG CollectionCount;
26     ULONG Index;
27     PVOID ParserContext;
28 
29     //
30     // first parse the report descriptor
31     //
32     ParserStatus = HidParser_ParseReportDescriptor(ReportDesc, DescLength, &ParserContext);
33     if (ParserStatus != HIDP_STATUS_SUCCESS)
34     {
35         //
36         // failed to parse report descriptor
37         //
38         DebugFunction("[HIDPARSER] Failed to parse report descriptor with %x\n", ParserStatus);
39         return ParserStatus;
40     }
41 
42     //
43     // get collection count
44     //
45     CollectionCount = HidParser_NumberOfTopCollections(ParserContext);
46     if (CollectionCount == 0)
47     {
48         //
49         // no top level collections found
50         //
51         ASSERT(FALSE);
52         return STATUS_NO_DATA_DETECTED;
53     }
54 
55     //
56     // zero description
57     //
58     ZeroFunction(DeviceDescription, sizeof(HIDP_DEVICE_DESC));
59 
60     //
61     // allocate collection
62     //
63     DeviceDescription->CollectionDesc = (PHIDP_COLLECTION_DESC)AllocFunction(sizeof(HIDP_COLLECTION_DESC) * CollectionCount);
64     if (!DeviceDescription->CollectionDesc)
65     {
66         //
67         // no memory
68         //
69         return STATUS_INSUFFICIENT_RESOURCES;
70     }
71 
72     //
73     // allocate report description
74     //
75     DeviceDescription->ReportIDs = (PHIDP_REPORT_IDS)AllocFunction(sizeof(HIDP_REPORT_IDS) * CollectionCount);
76     if (!DeviceDescription->ReportIDs)
77     {
78         //
79         // no memory
80         //
81         FreeFunction(DeviceDescription->CollectionDesc);
82         return STATUS_INSUFFICIENT_RESOURCES;
83     }
84 
85     for(Index = 0; Index < CollectionCount; Index++)
86     {
87         //
88         // set preparsed data length
89         //
90         DeviceDescription->CollectionDesc[Index].PreparsedDataLength = HidParser_GetContextSize(ParserContext, Index);
91         ParserStatus = HidParser_BuildContext(ParserContext, Index, DeviceDescription->CollectionDesc[Index].PreparsedDataLength, (PVOID*)&DeviceDescription->CollectionDesc[Index].PreparsedData);
92         if (ParserStatus != HIDP_STATUS_SUCCESS)
93         {
94             //
95             // no memory
96             //
97             FreeFunction(DeviceDescription->CollectionDesc);
98             FreeFunction(DeviceDescription->ReportIDs);
99             return ParserStatus;
100         }
101 
102         //
103         // init report description
104         //
105         DeviceDescription->ReportIDs[Index].CollectionNumber = Index + 1;
106         DeviceDescription->ReportIDs[Index].ReportID = Index; //FIXME
107         DeviceDescription->ReportIDs[Index].InputLength = HidParser_GetReportLength((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_INPUT);
108         DeviceDescription->ReportIDs[Index].OutputLength = HidParser_GetReportLength((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_OUTPUT);
109         DeviceDescription->ReportIDs[Index].FeatureLength = HidParser_GetReportLength((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_FEATURE);
110 
111 
112         DeviceDescription->ReportIDs[Index].InputLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_INPUT) ? 1 : 0);
113         DeviceDescription->ReportIDs[Index].OutputLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_OUTPUT) ? 1 : 0);
114         DeviceDescription->ReportIDs[Index].FeatureLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_FEATURE) ? 1 : 0);
115 
116 
117         //
118         // init collection description
119         //
120         DeviceDescription->CollectionDesc[Index].CollectionNumber = Index + 1;
121 
122         //
123         // get collection usage page
124         //
125         ParserStatus = HidParser_GetCollectionUsagePage((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, &DeviceDescription->CollectionDesc[Index].Usage, &DeviceDescription->CollectionDesc[Index].UsagePage);
126         if (ParserStatus != HIDP_STATUS_SUCCESS)
127         {
128             // collection not found
129             FreeFunction(DeviceDescription->CollectionDesc);
130             FreeFunction(DeviceDescription->ReportIDs);
131             return ParserStatus;
132         }
133 
134         //
135         // windows seems to prepend the report id, regardless if it is required
136         //
137         DeviceDescription->CollectionDesc[Index].CollectionNumber = Index + 1;
138         DeviceDescription->CollectionDesc[Index].InputLength = DeviceDescription->ReportIDs[Index].InputLength;
139         DeviceDescription->CollectionDesc[Index].OutputLength = DeviceDescription->ReportIDs[Index].OutputLength;
140         DeviceDescription->CollectionDesc[Index].FeatureLength = DeviceDescription->ReportIDs[Index].FeatureLength;
141 
142         DeviceDescription->CollectionDesc[Index].InputLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_INPUT) == FALSE ? 1 : 0);
143         DeviceDescription->CollectionDesc[Index].OutputLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_OUTPUT) == FALSE ? 1 : 0);
144         DeviceDescription->CollectionDesc[Index].FeatureLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_FEATURE) == FALSE ? 1 : 0);
145 
146 
147     }
148 
149     //
150     // store collection & report count
151     //
152     DeviceDescription->CollectionDescLength = CollectionCount;
153     DeviceDescription->ReportIDsLength = CollectionCount;
154 
155     //
156     // done
157     //
158     return STATUS_SUCCESS;
159 }
160 
161 VOID
162 NTAPI
HidParser_FreeCollectionDescription(IN PHIDP_DEVICE_DESC DeviceDescription)163 HidParser_FreeCollectionDescription(
164     IN PHIDP_DEVICE_DESC   DeviceDescription)
165 {
166     ULONG Index;
167 
168     //
169     // first free all context
170     //
171     for(Index = 0; Index < DeviceDescription->CollectionDescLength; Index++)
172     {
173         //
174         // free collection context
175         //
176         FreeFunction(DeviceDescription->CollectionDesc[Index].PreparsedData);
177     }
178 
179     //
180     // now free collection description
181     //
182     FreeFunction(DeviceDescription->CollectionDesc);
183 
184     //
185     // free report description
186     //
187     FreeFunction(DeviceDescription->ReportIDs);
188 }
189 
190 HIDAPI
191 NTSTATUS
192 NTAPI
HidParser_GetCaps(IN PVOID CollectionContext,OUT PHIDP_CAPS Capabilities)193 HidParser_GetCaps(
194     IN PVOID CollectionContext,
195     OUT PHIDP_CAPS  Capabilities)
196 {
197     //
198     // zero capabilities
199     //
200     ZeroFunction(Capabilities, sizeof(HIDP_CAPS));
201 
202     //
203     // init capabilities
204     //
205     HidParser_GetCollectionUsagePage(CollectionContext, &Capabilities->Usage, &Capabilities->UsagePage);
206     Capabilities->InputReportByteLength = HidParser_GetReportLength(CollectionContext, HID_REPORT_TYPE_INPUT);
207     Capabilities->OutputReportByteLength = HidParser_GetReportLength(CollectionContext, HID_REPORT_TYPE_OUTPUT);
208     Capabilities->FeatureReportByteLength = HidParser_GetReportLength(CollectionContext, HID_REPORT_TYPE_FEATURE);
209 
210     //
211     // always pre-prend report id
212     //
213     Capabilities->InputReportByteLength = (Capabilities->InputReportByteLength > 0 ? Capabilities->InputReportByteLength + 1 : 0);
214     Capabilities->OutputReportByteLength = (Capabilities->OutputReportByteLength > 0 ? Capabilities->OutputReportByteLength + 1 : 0);
215     Capabilities->FeatureReportByteLength = (Capabilities->FeatureReportByteLength > 0 ? Capabilities->FeatureReportByteLength + 1 : 0);
216 
217     //
218     // get number of link collection nodes
219     //
220     Capabilities->NumberLinkCollectionNodes = HidParser_GetTotalCollectionCount(CollectionContext);
221 
222     //
223     // get data indices
224     //
225     Capabilities->NumberInputDataIndices = HidParser_GetReportItemTypeCountFromReportType(CollectionContext, HID_REPORT_TYPE_INPUT, TRUE);
226     Capabilities->NumberOutputDataIndices = HidParser_GetReportItemTypeCountFromReportType(CollectionContext, HID_REPORT_TYPE_OUTPUT, TRUE);
227     Capabilities->NumberFeatureDataIndices = HidParser_GetReportItemTypeCountFromReportType(CollectionContext, HID_REPORT_TYPE_FEATURE, TRUE);
228 
229     //
230     // get value caps
231     //
232     Capabilities->NumberInputValueCaps = HidParser_GetReportItemTypeCountFromReportType(CollectionContext, HID_REPORT_TYPE_INPUT, FALSE);
233     Capabilities->NumberOutputValueCaps = HidParser_GetReportItemTypeCountFromReportType(CollectionContext, HID_REPORT_TYPE_OUTPUT, FALSE);
234     Capabilities->NumberFeatureValueCaps = HidParser_GetReportItemTypeCountFromReportType(CollectionContext, HID_REPORT_TYPE_FEATURE, FALSE);
235 
236 
237     //
238     // get button caps
239     //
240     Capabilities->NumberInputButtonCaps = HidParser_GetReportItemCountFromReportType(CollectionContext, HID_REPORT_TYPE_INPUT);
241     Capabilities->NumberOutputButtonCaps = HidParser_GetReportItemCountFromReportType(CollectionContext, HID_REPORT_TYPE_OUTPUT);
242     Capabilities->NumberFeatureButtonCaps = HidParser_GetReportItemCountFromReportType(CollectionContext, HID_REPORT_TYPE_FEATURE);
243 
244     //
245     // done
246     //
247     return HIDP_STATUS_SUCCESS;
248 }
249 
250 HIDAPI
251 ULONG
252 NTAPI
HidParser_MaxUsageListLength(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USAGE UsagePage OPTIONAL)253 HidParser_MaxUsageListLength(
254     IN PVOID CollectionContext,
255     IN HIDP_REPORT_TYPE  ReportType,
256     IN USAGE  UsagePage  OPTIONAL)
257 {
258     //
259     // FIXME test what should be returned when usage page is not defined
260     //
261     if (UsagePage == HID_USAGE_PAGE_UNDEFINED)
262     {
263         //
264         // implement me
265         //
266         UNIMPLEMENTED;
267 
268         //
269         // invalid report
270         //
271         return 0;
272     }
273 
274     if (ReportType == HidP_Input)
275     {
276         //
277         // input report
278         //
279         return HidParser_GetMaxUsageListLengthWithReportAndPage(CollectionContext, HID_REPORT_TYPE_INPUT, UsagePage);
280     }
281     else if (ReportType == HidP_Output)
282     {
283         //
284         // input report
285         //
286         return HidParser_GetMaxUsageListLengthWithReportAndPage(CollectionContext, HID_REPORT_TYPE_OUTPUT, UsagePage);
287     }
288     else if (ReportType == HidP_Feature)
289     {
290         //
291         // input report
292         //
293         return HidParser_GetMaxUsageListLengthWithReportAndPage(CollectionContext, HID_REPORT_TYPE_FEATURE, UsagePage);
294     }
295     else
296     {
297         //
298         // invalid report type
299         //
300         return 0;
301     }
302 }
303 
304 #undef HidParser_GetButtonCaps
305 
306 HIDAPI
307 NTSTATUS
308 NTAPI
HidParser_GetButtonCaps(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN PHIDP_BUTTON_CAPS ButtonCaps,IN PUSHORT ButtonCapsLength)309 HidParser_GetButtonCaps(
310     IN PVOID CollectionContext,
311     IN HIDP_REPORT_TYPE ReportType,
312     IN PHIDP_BUTTON_CAPS ButtonCaps,
313     IN PUSHORT ButtonCapsLength)
314 {
315     return HidParser_GetSpecificButtonCaps(CollectionContext, ReportType, HID_USAGE_PAGE_UNDEFINED, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_PAGE_UNDEFINED, ButtonCaps, (PULONG)ButtonCapsLength);
316 }
317 
318 HIDAPI
319 NTSTATUS
320 NTAPI
HidParser_GetSpecificValueCaps(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USAGE UsagePage,IN USHORT LinkCollection,IN USAGE Usage,OUT PHIDP_VALUE_CAPS ValueCaps,IN OUT PUSHORT ValueCapsLength)321 HidParser_GetSpecificValueCaps(
322     IN PVOID CollectionContext,
323     IN HIDP_REPORT_TYPE  ReportType,
324     IN USAGE  UsagePage,
325     IN USHORT  LinkCollection,
326     IN USAGE  Usage,
327     OUT PHIDP_VALUE_CAPS  ValueCaps,
328     IN OUT PUSHORT  ValueCapsLength)
329 {
330     NTSTATUS ParserStatus;
331 
332     //
333     // FIXME: implement searching in specific collection
334     //
335     ASSERT(LinkCollection == HIDP_LINK_COLLECTION_UNSPECIFIED);
336 
337     if (ReportType == HidP_Input)
338     {
339         //
340         // input report
341         //
342         ParserStatus = HidParser_GetSpecificValueCapsWithReport(CollectionContext, HID_REPORT_TYPE_INPUT, UsagePage, Usage, ValueCaps, ValueCapsLength);
343     }
344     else if (ReportType == HidP_Output)
345     {
346         //
347         // input report
348         //
349         ParserStatus = HidParser_GetSpecificValueCapsWithReport(CollectionContext, HID_REPORT_TYPE_OUTPUT, UsagePage, Usage, ValueCaps, ValueCapsLength);
350     }
351     else if (ReportType == HidP_Feature)
352     {
353         //
354         // input report
355         //
356         ParserStatus = HidParser_GetSpecificValueCapsWithReport(CollectionContext, HID_REPORT_TYPE_FEATURE, UsagePage, Usage, ValueCaps, ValueCapsLength);
357     }
358     else
359     {
360         //
361         // invalid report type
362         //
363         return HIDP_STATUS_INVALID_REPORT_TYPE;
364     }
365 
366     //
367     // return status
368     //
369     return ParserStatus;
370 }
371 
372 HIDAPI
373 NTSTATUS
374 NTAPI
HidParser_UsageListDifference(IN PUSAGE PreviousUsageList,IN PUSAGE CurrentUsageList,OUT PUSAGE BreakUsageList,OUT PUSAGE MakeUsageList,IN ULONG UsageListLength)375 HidParser_UsageListDifference(
376   IN PUSAGE  PreviousUsageList,
377   IN PUSAGE  CurrentUsageList,
378   OUT PUSAGE  BreakUsageList,
379   OUT PUSAGE  MakeUsageList,
380   IN ULONG  UsageListLength)
381 {
382     ULONG Index, SubIndex, bFound, BreakUsageIndex = 0, MakeUsageIndex = 0;
383     USAGE CurrentUsage, Usage;
384 
385     if (UsageListLength)
386     {
387         Index = 0;
388         do
389         {
390             /* get current usage */
391             CurrentUsage = PreviousUsageList[Index];
392 
393             /* is the end of list reached? */
394             if (!CurrentUsage)
395                 break;
396 
397             /* start searching in current usage list */
398             SubIndex = 0;
399             bFound = FALSE;
400             do
401             {
402                 /* get usage of current list */
403                 Usage = CurrentUsageList[SubIndex];
404 
405                 /* end of list reached? */
406                 if (!Usage)
407                     break;
408 
409                 /* check if it matches the current one */
410                 if (CurrentUsage == Usage)
411                 {
412                     /* it does */
413                     bFound = TRUE;
414                     break;
415                 }
416 
417                 /* move to next usage */
418                 SubIndex++;
419             }while(SubIndex < UsageListLength);
420 
421             /* was the usage found ?*/
422             if (!bFound)
423             {
424                 /* store it in the break usage list */
425                 BreakUsageList[BreakUsageIndex] = CurrentUsage;
426                 BreakUsageIndex++;
427             }
428 
429             /* move to next usage */
430             Index++;
431 
432         }while(Index < UsageListLength);
433 
434         /* now process the new items */
435         Index = 0;
436         do
437         {
438             /* get current usage */
439             CurrentUsage = CurrentUsageList[Index];
440 
441             /* is the end of list reached? */
442             if (!CurrentUsage)
443                 break;
444 
445             /* start searching in current usage list */
446             SubIndex = 0;
447             bFound = FALSE;
448             do
449             {
450                 /* get usage of previous list */
451                 Usage = PreviousUsageList[SubIndex];
452 
453                 /* end of list reached? */
454                 if (!Usage)
455                     break;
456 
457                 /* check if it matches the current one */
458                 if (CurrentUsage == Usage)
459                 {
460                     /* it does */
461                     bFound = TRUE;
462                     break;
463                 }
464 
465                 /* move to next usage */
466                 SubIndex++;
467             }while(SubIndex < UsageListLength);
468 
469             /* was the usage found ?*/
470             if (!bFound)
471             {
472                 /* store it in the make usage list */
473                 MakeUsageList[MakeUsageIndex] = CurrentUsage;
474                 MakeUsageIndex++;
475             }
476 
477             /* move to next usage */
478             Index++;
479 
480         }while(Index < UsageListLength);
481     }
482 
483     /* does the break list contain empty entries */
484     if (BreakUsageIndex < UsageListLength)
485     {
486         /* zeroize entries */
487         RtlZeroMemory(&BreakUsageList[BreakUsageIndex], sizeof(USAGE) * (UsageListLength - BreakUsageIndex));
488     }
489 
490     /* does the make usage list contain empty entries */
491     if (MakeUsageIndex < UsageListLength)
492     {
493         /* zeroize entries */
494         RtlZeroMemory(&MakeUsageList[MakeUsageIndex], sizeof(USAGE) * (UsageListLength - MakeUsageIndex));
495     }
496 
497     /* done */
498     return HIDP_STATUS_SUCCESS;
499 }
500 
501 HIDAPI
502 NTSTATUS
503 NTAPI
HidParser_GetUsages(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USAGE UsagePage,IN USHORT LinkCollection OPTIONAL,OUT USAGE * UsageList,IN OUT PULONG UsageLength,IN PCHAR Report,IN ULONG ReportLength)504 HidParser_GetUsages(
505     IN PVOID CollectionContext,
506     IN HIDP_REPORT_TYPE  ReportType,
507     IN USAGE  UsagePage,
508     IN USHORT  LinkCollection  OPTIONAL,
509     OUT USAGE  *UsageList,
510     IN OUT PULONG UsageLength,
511     IN PCHAR  Report,
512     IN ULONG  ReportLength)
513 {
514     NTSTATUS ParserStatus;
515 
516     //
517     // FIXME: implement searching in specific collection
518     //
519     ASSERT(LinkCollection == HIDP_LINK_COLLECTION_UNSPECIFIED);
520 
521     if (ReportType == HidP_Input)
522     {
523         //
524         // input report
525         //
526         ParserStatus = HidParser_GetUsagesWithReport(CollectionContext, HID_REPORT_TYPE_INPUT, UsagePage, UsageList, UsageLength, Report, ReportLength);
527     }
528     else if (ReportType == HidP_Output)
529     {
530         //
531         // input report
532         //
533         ParserStatus = HidParser_GetUsagesWithReport(CollectionContext, HID_REPORT_TYPE_OUTPUT, UsagePage, UsageList, UsageLength, Report, ReportLength);
534     }
535     else if (ReportType == HidP_Feature)
536     {
537         //
538         // input report
539         //
540         ParserStatus = HidParser_GetUsagesWithReport(CollectionContext, HID_REPORT_TYPE_FEATURE, UsagePage, UsageList, UsageLength, Report, ReportLength);
541     }
542     else
543     {
544         //
545         // invalid report type
546         //
547         return HIDP_STATUS_INVALID_REPORT_TYPE;
548     }
549 
550     //
551     // return status
552     //
553     return ParserStatus;
554 }
555 
556 HIDAPI
557 NTSTATUS
558 NTAPI
HidParser_GetScaledUsageValue(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USAGE UsagePage,IN USHORT LinkCollection OPTIONAL,IN USAGE Usage,OUT PLONG UsageValue,IN PCHAR Report,IN ULONG ReportLength)559 HidParser_GetScaledUsageValue(
560     IN PVOID CollectionContext,
561     IN HIDP_REPORT_TYPE  ReportType,
562     IN USAGE  UsagePage,
563     IN USHORT  LinkCollection  OPTIONAL,
564     IN USAGE  Usage,
565     OUT PLONG  UsageValue,
566     IN PCHAR  Report,
567     IN ULONG  ReportLength)
568 {
569     NTSTATUS ParserStatus;
570 
571     //
572     // FIXME: implement searching in specific collection
573     //
574     ASSERT(LinkCollection == HIDP_LINK_COLLECTION_UNSPECIFIED);
575 
576     if (ReportType == HidP_Input)
577     {
578         //
579         // input report
580         //
581         ParserStatus = HidParser_GetScaledUsageValueWithReport(CollectionContext, HID_REPORT_TYPE_INPUT, UsagePage, Usage, UsageValue, Report, ReportLength);
582     }
583     else if (ReportType == HidP_Output)
584     {
585         //
586         // input report
587         //
588         ParserStatus = HidParser_GetScaledUsageValueWithReport(CollectionContext, HID_REPORT_TYPE_OUTPUT, UsagePage, Usage, UsageValue, Report, ReportLength);
589     }
590     else if (ReportType == HidP_Feature)
591     {
592         //
593         // input report
594         //
595         ParserStatus = HidParser_GetScaledUsageValueWithReport(CollectionContext, HID_REPORT_TYPE_FEATURE,  UsagePage, Usage, UsageValue, Report, ReportLength);
596     }
597     else
598     {
599         //
600         // invalid report type
601         //
602         return HIDP_STATUS_INVALID_REPORT_TYPE;
603     }
604 
605     //
606     // return status
607     //
608     return ParserStatus;
609 }
610 
611 HIDAPI
612 NTSTATUS
613 NTAPI
HidParser_TranslateUsageAndPagesToI8042ScanCodes(IN PUSAGE_AND_PAGE ChangedUsageList,IN ULONG UsageListLength,IN HIDP_KEYBOARD_DIRECTION KeyAction,IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,IN PVOID InsertCodesContext)614 HidParser_TranslateUsageAndPagesToI8042ScanCodes(
615    IN PUSAGE_AND_PAGE  ChangedUsageList,
616    IN ULONG  UsageListLength,
617    IN HIDP_KEYBOARD_DIRECTION  KeyAction,
618    IN OUT PHIDP_KEYBOARD_MODIFIER_STATE  ModifierState,
619    IN PHIDP_INSERT_SCANCODES  InsertCodesProcedure,
620    IN PVOID  InsertCodesContext)
621 {
622     ULONG Index;
623     NTSTATUS Status = HIDP_STATUS_SUCCESS;
624 
625     for(Index = 0; Index < UsageListLength; Index++)
626     {
627         //
628         // check current usage
629         //
630         if (ChangedUsageList[Index].UsagePage == HID_USAGE_PAGE_KEYBOARD)
631         {
632             //
633             // process keyboard usage
634             //
635             Status = HidParser_TranslateKbdUsage(ChangedUsageList[Index].Usage, KeyAction, ModifierState, InsertCodesProcedure, InsertCodesContext);
636         }
637         else if (ChangedUsageList[Index].UsagePage == HID_USAGE_PAGE_CONSUMER)
638         {
639             //
640             // process consumer usage
641             //
642             Status = HidParser_TranslateCustUsage(ChangedUsageList[Index].Usage, KeyAction, ModifierState, InsertCodesProcedure, InsertCodesContext);
643         }
644         else
645         {
646             //
647             // invalid page / end of usage list page
648             //
649             return HIDP_STATUS_I8042_TRANS_UNKNOWN;
650         }
651 
652         //
653         // check status
654         //
655         if (Status != HIDP_STATUS_SUCCESS)
656         {
657             //
658             // failed
659             //
660             return Status;
661         }
662     }
663 
664     //
665     // return status
666     //
667     return Status;
668 }
669 
670 
671 HIDAPI
672 NTSTATUS
673 NTAPI
HidParser_GetUsagesEx(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USHORT LinkCollection,OUT PUSAGE_AND_PAGE ButtonList,IN OUT ULONG * UsageLength,IN PCHAR Report,IN ULONG ReportLength)674 HidParser_GetUsagesEx(
675     IN PVOID CollectionContext,
676     IN HIDP_REPORT_TYPE  ReportType,
677     IN USHORT  LinkCollection,
678     OUT PUSAGE_AND_PAGE  ButtonList,
679     IN OUT ULONG  *UsageLength,
680     IN PCHAR  Report,
681     IN ULONG  ReportLength)
682 {
683     return HidParser_GetUsages(CollectionContext, ReportType, HID_USAGE_PAGE_UNDEFINED, LinkCollection, (PUSAGE)ButtonList, UsageLength, Report, ReportLength);
684 }
685 
686 HIDAPI
687 NTSTATUS
688 NTAPI
HidParser_UsageAndPageListDifference(IN PUSAGE_AND_PAGE PreviousUsageList,IN PUSAGE_AND_PAGE CurrentUsageList,OUT PUSAGE_AND_PAGE BreakUsageList,OUT PUSAGE_AND_PAGE MakeUsageList,IN ULONG UsageListLength)689 HidParser_UsageAndPageListDifference(
690    IN PUSAGE_AND_PAGE  PreviousUsageList,
691    IN PUSAGE_AND_PAGE  CurrentUsageList,
692    OUT PUSAGE_AND_PAGE  BreakUsageList,
693    OUT PUSAGE_AND_PAGE  MakeUsageList,
694    IN ULONG  UsageListLength)
695 {
696     ULONG Index, SubIndex, BreakUsageListIndex = 0, MakeUsageListIndex = 0, bFound;
697     PUSAGE_AND_PAGE CurrentUsage, Usage;
698 
699     if (UsageListLength)
700     {
701         /* process removed usages */
702         Index = 0;
703         do
704         {
705             /* get usage from current index */
706             CurrentUsage = &PreviousUsageList[Index];
707 
708             /* end of list reached? */
709             if (CurrentUsage->Usage == 0 && CurrentUsage->UsagePage == 0)
710                 break;
711 
712             /* search in current list */
713             SubIndex = 0;
714             bFound = FALSE;
715             do
716             {
717                 /* get usage */
718                 Usage = &CurrentUsageList[SubIndex];
719 
720                 /* end of list reached? */
721                 if (Usage->Usage == 0 && Usage->UsagePage == 0)
722                     break;
723 
724                 /* does it match */
725                 if (Usage->Usage == CurrentUsage->Usage && Usage->UsagePage == CurrentUsage->UsagePage)
726                 {
727                     /* found match */
728                     bFound = TRUE;
729                 }
730 
731                 /* move to next index */
732                 SubIndex++;
733 
734             }while(SubIndex < UsageListLength);
735 
736             if (!bFound)
737             {
738                 /* store it in break usage list */
739                 BreakUsageList[BreakUsageListIndex].Usage = CurrentUsage->Usage;
740                 BreakUsageList[BreakUsageListIndex].UsagePage = CurrentUsage->UsagePage;
741                 BreakUsageListIndex++;
742             }
743 
744             /* move to next index */
745             Index++;
746 
747         }while(Index < UsageListLength);
748 
749         /* process new usages */
750         Index = 0;
751         do
752         {
753             /* get usage from current index */
754             CurrentUsage = &CurrentUsageList[Index];
755 
756             /* end of list reached? */
757             if (CurrentUsage->Usage == 0 && CurrentUsage->UsagePage == 0)
758                 break;
759 
760             /* search in current list */
761             SubIndex = 0;
762             bFound = FALSE;
763             do
764             {
765                 /* get usage */
766                 Usage = &PreviousUsageList[SubIndex];
767 
768                 /* end of list reached? */
769                 if (Usage->Usage == 0 && Usage->UsagePage == 0)
770                     break;
771 
772                 /* does it match */
773                 if (Usage->Usage == CurrentUsage->Usage && Usage->UsagePage == CurrentUsage->UsagePage)
774                 {
775                     /* found match */
776                     bFound = TRUE;
777                 }
778 
779                 /* move to next index */
780                 SubIndex++;
781 
782             }while(SubIndex < UsageListLength);
783 
784             if (!bFound)
785             {
786                 /* store it in break usage list */
787                 MakeUsageList[MakeUsageListIndex].Usage = CurrentUsage->Usage;
788                 MakeUsageList[MakeUsageListIndex].UsagePage = CurrentUsage->UsagePage;
789                 MakeUsageListIndex++;
790             }
791 
792             /* move to next index */
793             Index++;
794         }while(Index < UsageListLength);
795     }
796 
797     /* are there remaining free list entries */
798     if (BreakUsageListIndex < UsageListLength)
799     {
800         /* zero them */
801         RtlZeroMemory(&BreakUsageList[BreakUsageListIndex], (UsageListLength - BreakUsageListIndex) * sizeof(USAGE_AND_PAGE));
802     }
803 
804     /* are there remaining free list entries */
805     if (MakeUsageListIndex < UsageListLength)
806     {
807         /* zero them */
808         RtlZeroMemory(&MakeUsageList[MakeUsageListIndex], (UsageListLength - MakeUsageListIndex) * sizeof(USAGE_AND_PAGE));
809     }
810 
811     /* done */
812     return HIDP_STATUS_SUCCESS;
813 }
814 
815 HIDAPI
816 NTSTATUS
817 NTAPI
HidParser_GetSpecificButtonCaps(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USAGE UsagePage,IN USHORT LinkCollection,IN USAGE Usage,OUT PHIDP_BUTTON_CAPS ButtonCaps,IN OUT PULONG ButtonCapsLength)818 HidParser_GetSpecificButtonCaps(
819     IN PVOID CollectionContext,
820     IN HIDP_REPORT_TYPE  ReportType,
821     IN USAGE  UsagePage,
822     IN USHORT  LinkCollection,
823     IN USAGE  Usage,
824     OUT PHIDP_BUTTON_CAPS  ButtonCaps,
825     IN OUT PULONG  ButtonCapsLength)
826 {
827     UNIMPLEMENTED;
828     ASSERT(FALSE);
829     return STATUS_NOT_IMPLEMENTED;
830 }
831 
832 
833 HIDAPI
834 NTSTATUS
835 NTAPI
HidParser_GetData(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,OUT PHIDP_DATA DataList,IN OUT PULONG DataLength,IN PCHAR Report,IN ULONG ReportLength)836 HidParser_GetData(
837     IN PVOID CollectionContext,
838     IN HIDP_REPORT_TYPE  ReportType,
839     OUT PHIDP_DATA  DataList,
840     IN OUT PULONG  DataLength,
841     IN PCHAR  Report,
842     IN ULONG  ReportLength)
843 {
844     UNIMPLEMENTED;
845     ASSERT(FALSE);
846     return STATUS_NOT_IMPLEMENTED;
847 }
848 
849 HIDAPI
850 NTSTATUS
851 NTAPI
HidParser_GetExtendedAttributes(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USHORT DataIndex,OUT PHIDP_EXTENDED_ATTRIBUTES Attributes,IN OUT PULONG LengthAttributes)852 HidParser_GetExtendedAttributes(
853     IN PVOID CollectionContext,
854     IN HIDP_REPORT_TYPE  ReportType,
855     IN USHORT  DataIndex,
856     OUT PHIDP_EXTENDED_ATTRIBUTES  Attributes,
857     IN OUT PULONG  LengthAttributes)
858 {
859     UNIMPLEMENTED;
860     ASSERT(FALSE);
861     return STATUS_NOT_IMPLEMENTED;
862 }
863 
864 HIDAPI
865 NTSTATUS
866 NTAPI
HidParser_GetLinkCollectionNodes(IN PVOID CollectionContext,OUT PHIDP_LINK_COLLECTION_NODE LinkCollectionNodes,IN OUT PULONG LinkCollectionNodesLength)867 HidParser_GetLinkCollectionNodes(
868     IN PVOID CollectionContext,
869     OUT PHIDP_LINK_COLLECTION_NODE  LinkCollectionNodes,
870     IN OUT PULONG  LinkCollectionNodesLength)
871 {
872     UNIMPLEMENTED;
873     ASSERT(FALSE);
874     return STATUS_NOT_IMPLEMENTED;
875 }
876 
877 HIDAPI
878 NTSTATUS
879 NTAPI
HidParser_GetUsageValue(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USAGE UsagePage,IN USHORT LinkCollection,IN USAGE Usage,OUT PULONG UsageValue,IN PCHAR Report,IN ULONG ReportLength)880 HidParser_GetUsageValue(
881     IN PVOID CollectionContext,
882     IN HIDP_REPORT_TYPE  ReportType,
883     IN USAGE  UsagePage,
884     IN USHORT  LinkCollection,
885     IN USAGE  Usage,
886     OUT PULONG  UsageValue,
887     IN PCHAR  Report,
888     IN ULONG  ReportLength)
889 {
890     NTSTATUS ParserStatus;
891 
892     //
893     // FIXME: implement searching in specific collection
894     //
895     ASSERT(LinkCollection == HIDP_LINK_COLLECTION_UNSPECIFIED);
896 
897     if (ReportType == HidP_Input)
898     {
899         //
900         // input report
901         //
902         ParserStatus = HidParser_GetUsageValueWithReport(CollectionContext, HID_REPORT_TYPE_INPUT, UsagePage, Usage, UsageValue, Report, ReportLength);
903     }
904     else if (ReportType == HidP_Output)
905     {
906         //
907         // input report
908         //
909         ParserStatus = HidParser_GetUsageValueWithReport(CollectionContext, HID_REPORT_TYPE_OUTPUT, UsagePage, Usage, UsageValue, Report, ReportLength);
910     }
911     else if (ReportType == HidP_Feature)
912     {
913         //
914         // input report
915         //
916         ParserStatus = HidParser_GetUsageValueWithReport(CollectionContext, HID_REPORT_TYPE_FEATURE,  UsagePage, Usage, UsageValue, Report, ReportLength);
917     }
918     else
919     {
920         //
921         // invalid report type
922         //
923         return HIDP_STATUS_INVALID_REPORT_TYPE;
924     }
925 
926     //
927     // return status
928     //
929     return ParserStatus;
930 }
931 
932 NTSTATUS
933 NTAPI
HidParser_SysPowerEvent(IN PVOID CollectionContext,IN PCHAR HidPacket,IN USHORT HidPacketLength,OUT PULONG OutputBuffer)934 HidParser_SysPowerEvent(
935     IN PVOID CollectionContext,
936     IN PCHAR HidPacket,
937     IN USHORT HidPacketLength,
938     OUT PULONG OutputBuffer)
939 {
940     UNIMPLEMENTED;
941     ASSERT(FALSE);
942     return STATUS_NOT_IMPLEMENTED;
943 }
944 
945 NTSTATUS
946 NTAPI
HidParser_SysPowerCaps(IN PVOID CollectionContext,OUT PULONG OutputBuffer)947 HidParser_SysPowerCaps (
948     IN PVOID CollectionContext,
949     OUT PULONG OutputBuffer)
950 {
951     UNIMPLEMENTED;
952     ASSERT(FALSE);
953     return STATUS_NOT_IMPLEMENTED;
954 }
955 
956 HIDAPI
957 NTSTATUS
958 NTAPI
HidParser_GetUsageValueArray(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USAGE UsagePage,IN USHORT LinkCollection OPTIONAL,IN USAGE Usage,OUT PCHAR UsageValue,IN USHORT UsageValueByteLength,IN PCHAR Report,IN ULONG ReportLength)959 HidParser_GetUsageValueArray(
960     IN PVOID CollectionContext,
961     IN HIDP_REPORT_TYPE  ReportType,
962     IN USAGE  UsagePage,
963     IN USHORT  LinkCollection  OPTIONAL,
964     IN USAGE  Usage,
965     OUT PCHAR  UsageValue,
966     IN USHORT  UsageValueByteLength,
967     IN PCHAR  Report,
968     IN ULONG  ReportLength)
969 {
970     UNIMPLEMENTED;
971     ASSERT(FALSE);
972     return STATUS_NOT_IMPLEMENTED;
973 }
974 
975 HIDAPI
976 NTSTATUS
977 NTAPI
HidParser_UnsetUsages(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USAGE UsagePage,IN USHORT LinkCollection,IN PUSAGE UsageList,IN OUT PULONG UsageLength,IN OUT PCHAR Report,IN ULONG ReportLength)978 HidParser_UnsetUsages(
979     IN PVOID CollectionContext,
980     IN HIDP_REPORT_TYPE  ReportType,
981     IN USAGE  UsagePage,
982     IN USHORT  LinkCollection,
983     IN PUSAGE  UsageList,
984     IN OUT PULONG  UsageLength,
985     IN OUT PCHAR  Report,
986     IN ULONG  ReportLength)
987 {
988     UNIMPLEMENTED;
989     ASSERT(FALSE);
990     return STATUS_NOT_IMPLEMENTED;
991 }
992 
993 HIDAPI
994 NTSTATUS
995 NTAPI
HidParser_TranslateUsagesToI8042ScanCodes(IN PUSAGE ChangedUsageList,IN ULONG UsageListLength,IN HIDP_KEYBOARD_DIRECTION KeyAction,IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,IN PVOID InsertCodesContext)996 HidParser_TranslateUsagesToI8042ScanCodes(
997   IN PUSAGE  ChangedUsageList,
998   IN ULONG  UsageListLength,
999   IN HIDP_KEYBOARD_DIRECTION  KeyAction,
1000   IN OUT PHIDP_KEYBOARD_MODIFIER_STATE  ModifierState,
1001   IN PHIDP_INSERT_SCANCODES  InsertCodesProcedure,
1002   IN PVOID  InsertCodesContext)
1003 {
1004     UNIMPLEMENTED;
1005     ASSERT(FALSE);
1006     return STATUS_NOT_IMPLEMENTED;
1007 }
1008 
1009 HIDAPI
1010 NTSTATUS
1011 NTAPI
HidParser_SetUsages(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USAGE UsagePage,IN USHORT LinkCollection,IN PUSAGE UsageList,IN OUT PULONG UsageLength,IN OUT PCHAR Report,IN ULONG ReportLength)1012 HidParser_SetUsages(
1013     IN PVOID CollectionContext,
1014     IN HIDP_REPORT_TYPE  ReportType,
1015     IN USAGE  UsagePage,
1016     IN USHORT  LinkCollection,
1017     IN PUSAGE  UsageList,
1018     IN OUT PULONG  UsageLength,
1019     IN OUT PCHAR  Report,
1020     IN ULONG  ReportLength)
1021 {
1022     UNIMPLEMENTED;
1023     ASSERT(FALSE);
1024     return STATUS_NOT_IMPLEMENTED;
1025 }
1026 
1027 HIDAPI
1028 NTSTATUS
1029 NTAPI
HidParser_SetUsageValueArray(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USAGE UsagePage,IN USHORT LinkCollection OPTIONAL,IN USAGE Usage,IN PCHAR UsageValue,IN USHORT UsageValueByteLength,OUT PCHAR Report,IN ULONG ReportLength)1030 HidParser_SetUsageValueArray(
1031     IN PVOID CollectionContext,
1032     IN HIDP_REPORT_TYPE  ReportType,
1033     IN USAGE  UsagePage,
1034     IN USHORT  LinkCollection  OPTIONAL,
1035     IN USAGE  Usage,
1036     IN PCHAR  UsageValue,
1037     IN USHORT  UsageValueByteLength,
1038     OUT PCHAR  Report,
1039     IN ULONG  ReportLength)
1040 {
1041     UNIMPLEMENTED;
1042     ASSERT(FALSE);
1043     return STATUS_NOT_IMPLEMENTED;
1044 }
1045 
1046 HIDAPI
1047 NTSTATUS
1048 NTAPI
HidParser_SetUsageValue(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USAGE UsagePage,IN USHORT LinkCollection,IN USAGE Usage,IN ULONG UsageValue,IN OUT PCHAR Report,IN ULONG ReportLength)1049 HidParser_SetUsageValue(
1050     IN PVOID CollectionContext,
1051     IN HIDP_REPORT_TYPE  ReportType,
1052     IN USAGE  UsagePage,
1053     IN USHORT  LinkCollection,
1054     IN USAGE  Usage,
1055     IN ULONG  UsageValue,
1056     IN OUT PCHAR  Report,
1057     IN ULONG  ReportLength)
1058 {
1059     UNIMPLEMENTED;
1060     ASSERT(FALSE);
1061     return STATUS_NOT_IMPLEMENTED;
1062 }
1063 
1064 HIDAPI
1065 NTSTATUS
1066 NTAPI
HidParser_SetScaledUsageValue(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN USAGE UsagePage,IN USHORT LinkCollection OPTIONAL,IN USAGE Usage,IN LONG UsageValue,IN OUT PCHAR Report,IN ULONG ReportLength)1067 HidParser_SetScaledUsageValue(
1068     IN PVOID CollectionContext,
1069     IN HIDP_REPORT_TYPE  ReportType,
1070     IN USAGE  UsagePage,
1071     IN USHORT  LinkCollection  OPTIONAL,
1072     IN USAGE  Usage,
1073     IN LONG  UsageValue,
1074     IN OUT PCHAR  Report,
1075     IN ULONG  ReportLength)
1076 {
1077     UNIMPLEMENTED;
1078     ASSERT(FALSE);
1079     return STATUS_NOT_IMPLEMENTED;
1080 }
1081 
1082 HIDAPI
1083 NTSTATUS
1084 NTAPI
HidParser_SetData(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN PHIDP_DATA DataList,IN OUT PULONG DataLength,IN OUT PCHAR Report,IN ULONG ReportLength)1085 HidParser_SetData(
1086     IN PVOID CollectionContext,
1087     IN HIDP_REPORT_TYPE  ReportType,
1088     IN PHIDP_DATA  DataList,
1089     IN OUT PULONG  DataLength,
1090     IN OUT PCHAR  Report,
1091     IN ULONG  ReportLength)
1092 {
1093     UNIMPLEMENTED;
1094     ASSERT(FALSE);
1095     return STATUS_NOT_IMPLEMENTED;
1096 }
1097 
1098 HIDAPI
1099 ULONG
1100 NTAPI
HidParser_MaxDataListLength(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType)1101 HidParser_MaxDataListLength(
1102     IN PVOID CollectionContext,
1103     IN HIDP_REPORT_TYPE  ReportType)
1104 {
1105     UNIMPLEMENTED;
1106     ASSERT(FALSE);
1107     return 0;
1108 }
1109 
1110 HIDAPI
1111 NTSTATUS
1112 NTAPI
HidParser_InitializeReportForID(IN PVOID CollectionContext,IN HIDP_REPORT_TYPE ReportType,IN UCHAR ReportID,IN OUT PCHAR Report,IN ULONG ReportLength)1113 HidParser_InitializeReportForID(
1114     IN PVOID CollectionContext,
1115     IN HIDP_REPORT_TYPE  ReportType,
1116     IN UCHAR  ReportID,
1117     IN OUT PCHAR  Report,
1118     IN ULONG  ReportLength)
1119 {
1120     UNIMPLEMENTED;
1121     ASSERT(FALSE);
1122     return STATUS_NOT_IMPLEMENTED;
1123 }
1124 
1125 #undef HidParser_GetValueCaps
1126 
1127 HIDAPI
1128 NTSTATUS
1129 NTAPI
HidParser_GetValueCaps(IN PVOID CollectionContext,HIDP_REPORT_TYPE ReportType,PHIDP_VALUE_CAPS ValueCaps,PULONG ValueCapsLength)1130 HidParser_GetValueCaps(
1131     IN PVOID CollectionContext,
1132     HIDP_REPORT_TYPE ReportType,
1133     PHIDP_VALUE_CAPS ValueCaps,
1134     PULONG ValueCapsLength)
1135 {
1136     UNIMPLEMENTED;
1137     ASSERT(FALSE);
1138     return STATUS_NOT_IMPLEMENTED;
1139 }
1140