xref: /reactos/sdk/lib/drivers/hidparser/api.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/api.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 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,
34 };
35 
36 static struct
37 {
38     USAGE Usage;
39     ULONG ScanCode;
40 } CustomerScanCodes[] =
41 {
42     { 0x00B5, 0xE019 },
43     { 0x00B6, 0xE010 },
44     { 0x00B7, 0xE024 },
45     { 0x00CD, 0xE022 },
46     { 0x00E2, 0xE020 },
47     { 0x00E9, 0xE030 },
48     { 0x00EA, 0xE02E },
49     { 0x0183, 0xE06D },
50     { 0x018A, 0xE06C },
51     { 0x0192, 0xE021 },
52     { 0x0194, 0xE06B },
53     { 0x0221, 0xE065 },
54     { 0x0223, 0xE032 },
55     { 0x0224, 0xE06A },
56     { 0x0225, 0xE069 },
57     { 0x0226, 0xE068 },
58     { 0x0227, 0xE067 },
59     { 0x022A, 0xE066 },
60 };
61 
62 #define NTOHS(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8))
63 
64 NTSTATUS
HidParser_GetCollectionUsagePage(IN PVOID CollectionContext,OUT PUSHORT Usage,OUT PUSHORT UsagePage)65 HidParser_GetCollectionUsagePage(
66     IN PVOID CollectionContext,
67     OUT PUSHORT Usage,
68     OUT PUSHORT UsagePage)
69 {
70     PHID_COLLECTION Collection;
71 
72     //
73     // find collection
74     //
75     Collection = HidParser_GetCollectionFromContext(CollectionContext);
76     if (!Collection)
77     {
78         //
79         // collection not found
80         //
81         return HIDP_STATUS_USAGE_NOT_FOUND;
82     }
83 
84     //
85     // store result
86     //
87     *UsagePage = (Collection->Usage >> 16);
88     *Usage = (Collection->Usage & 0xFFFF);
89     return HIDP_STATUS_SUCCESS;
90 }
91 
92 ULONG
HidParser_GetReportLength(IN PVOID CollectionContext,IN UCHAR ReportType)93 HidParser_GetReportLength(
94     IN PVOID CollectionContext,
95     IN UCHAR ReportType)
96 {
97     PHID_REPORT Report;
98     ULONG ReportLength;
99 
100     //
101     // get first report
102     //
103     Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
104     if (!Report)
105     {
106         //
107         // no report found
108         //
109         return 0;
110     }
111 
112     //
113     // get report length
114     //
115     ReportLength = Report->ReportSize;
116 
117     //
118     // done
119     //
120     if (ReportLength)
121     {
122         //
123         // byte aligned length
124         //
125         ASSERT(ReportLength % 8 == 0);
126         return ReportLength / 8;
127     }
128     return ReportLength;
129 }
130 
131 ULONG
HidParser_GetReportItemCountFromReportType(IN PVOID CollectionContext,IN UCHAR ReportType)132 HidParser_GetReportItemCountFromReportType(
133     IN PVOID CollectionContext,
134     IN UCHAR ReportType)
135 {
136     PHID_REPORT Report;
137 
138     //
139     // get report
140     //
141     Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
142     if (!Report)
143     {
144         //
145         // no such report
146         //
147         return 0;
148     }
149 
150     //
151     // return report item count
152     //
153     return Report->ItemCount;
154 }
155 
156 
157 ULONG
HidParser_GetReportItemTypeCountFromReportType(IN PVOID CollectionContext,IN UCHAR ReportType,IN ULONG bData)158 HidParser_GetReportItemTypeCountFromReportType(
159     IN PVOID CollectionContext,
160     IN UCHAR ReportType,
161     IN ULONG bData)
162 {
163     ULONG Index;
164     PHID_REPORT Report;
165     ULONG ItemCount = 0;
166 
167     //
168     // get report
169     //
170     Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
171     if (!Report)
172     {
173         //
174         // no such report
175         //
176         return 0;
177     }
178 
179     //
180     // enumerate all items
181     //
182     for(Index = 0; Index < Report->ItemCount; Index++)
183     {
184         //
185         // check item type
186         //
187         if (Report->Items[Index].HasData && bData)
188         {
189             //
190             // found data item
191             //
192             ItemCount++;
193         }
194         else if (Report->Items[Index].HasData == FALSE && bData == FALSE)
195         {
196             //
197             // found value item
198             //
199             ItemCount++;
200         }
201     }
202 
203     //
204     // no report items
205     //
206     return ItemCount;
207 }
208 
209 ULONG
HidParser_GetMaxUsageListLengthWithReportAndPage(IN PVOID CollectionContext,IN UCHAR ReportType,IN USAGE UsagePage OPTIONAL)210 HidParser_GetMaxUsageListLengthWithReportAndPage(
211     IN PVOID CollectionContext,
212     IN UCHAR ReportType,
213     IN USAGE  UsagePage  OPTIONAL)
214 {
215     ULONG Index;
216     PHID_REPORT Report;
217     ULONG ItemCount = 0;
218     USHORT CurrentUsagePage;
219 
220     //
221     // get report
222     //
223     Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
224     if (!Report)
225     {
226         //
227         // no such report
228         //
229         return 0;
230     }
231 
232     for(Index = 0; Index < Report->ItemCount; Index++)
233     {
234         //
235         // check usage page
236         //
237         CurrentUsagePage = (Report->Items[Index].UsageMinimum >> 16);
238         if (CurrentUsagePage == UsagePage && Report->Items[Index].HasData)
239         {
240             //
241             // found item
242             //
243             ItemCount++;
244         }
245     }
246 
247     //
248     // done
249     //
250     return ItemCount;
251 }
252 
253 NTSTATUS
HidParser_GetSpecificValueCapsWithReport(IN PVOID CollectionContext,IN UCHAR ReportType,IN USHORT UsagePage,IN USHORT Usage,OUT PHIDP_VALUE_CAPS ValueCaps,IN OUT PUSHORT ValueCapsLength)254 HidParser_GetSpecificValueCapsWithReport(
255     IN PVOID CollectionContext,
256     IN UCHAR ReportType,
257     IN USHORT UsagePage,
258     IN USHORT Usage,
259     OUT PHIDP_VALUE_CAPS  ValueCaps,
260     IN OUT PUSHORT  ValueCapsLength)
261 {
262     ULONG Index;
263     PHID_REPORT Report;
264     USHORT ItemCount = 0;
265     USHORT CurrentUsagePage;
266     USHORT CurrentUsage;
267 
268     //
269     // get report
270     //
271     Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
272     if (!Report)
273     {
274         //
275         // no such report
276         //
277         return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
278     }
279 
280     for(Index = 0; Index < Report->ItemCount; Index++)
281     {
282         //
283         // check usage page
284         //
285         CurrentUsagePage = (Report->Items[Index].UsageMinimum >> 16);
286         CurrentUsage = (Report->Items[Index].UsageMinimum & 0xFFFF);
287 
288         if ((Usage == CurrentUsage && UsagePage == CurrentUsagePage) || (Usage == 0 && UsagePage == CurrentUsagePage) || (Usage == CurrentUsage && UsagePage == 0) || (Usage == 0 && UsagePage == 0))
289         {
290             //
291             // check if there is enough place for the caps
292             //
293             if (ItemCount < *ValueCapsLength)
294             {
295                 //
296                 // zero caps
297                 //
298                 ZeroFunction(&ValueCaps[ItemCount], sizeof(HIDP_VALUE_CAPS));
299 
300                 //
301                 // init caps
302                 //
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;
309 
310                 //
311                 // FIXME: FILLMEIN
312                 //
313             }
314 
315 
316             //
317             // found item
318             //
319             ItemCount++;
320         }
321     }
322 
323     //
324     // store result
325     //
326     *ValueCapsLength = ItemCount;
327 
328     if (ItemCount)
329     {
330         //
331         // success
332         //
333         return HIDP_STATUS_SUCCESS;
334     }
335 
336     //
337     // item not found
338     //
339     return HIDP_STATUS_USAGE_NOT_FOUND;
340 }
341 
342 NTSTATUS
HidParser_GetUsagesWithReport(IN PVOID CollectionContext,IN UCHAR ReportType,IN USAGE UsagePage,OUT USAGE * UsageList,IN OUT PULONG UsageLength,IN PCHAR ReportDescriptor,IN ULONG ReportDescriptorLength)343 HidParser_GetUsagesWithReport(
344     IN PVOID CollectionContext,
345     IN UCHAR  ReportType,
346     IN USAGE  UsagePage,
347     OUT USAGE  *UsageList,
348     IN OUT PULONG UsageLength,
349     IN PCHAR  ReportDescriptor,
350     IN ULONG  ReportDescriptorLength)
351 {
352     ULONG Index;
353     PHID_REPORT Report;
354     ULONG ItemCount = 0;
355     USHORT CurrentUsagePage;
356     PHID_REPORT_ITEM ReportItem;
357     UCHAR Activated;
358     ULONG Data;
359     PUSAGE_AND_PAGE UsageAndPage = NULL;
360 
361     //
362     // get report
363     //
364     Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
365     if (!Report)
366     {
367         //
368         // no such report
369         //
370         return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
371     }
372 
373     if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
374     {
375         //
376         // invalid report descriptor length
377         //
378         return HIDP_STATUS_INVALID_REPORT_LENGTH;
379     }
380 
381     //
382     // cast to usage and page
383     //
384     if (UsagePage == HID_USAGE_PAGE_UNDEFINED)
385     {
386         //
387         // the caller requested any set usages
388         //
389         UsageAndPage = (PUSAGE_AND_PAGE)UsageList;
390     }
391 
392     for(Index = 0; Index < Report->ItemCount; Index++)
393     {
394         //
395         // get report item
396         //
397         ReportItem = &Report->Items[Index];
398 
399         //
400         // does it have data
401         //
402         if (!ReportItem->HasData)
403             continue;
404 
405         //
406         // check usage page
407         //
408         CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
409 
410         if (UsagePage != HID_USAGE_PAGE_UNDEFINED)
411         {
412             //
413             // does usage match
414             //
415             if (UsagePage != CurrentUsagePage)
416                 continue;
417         }
418 
419         //
420         // check if the specified usage is activated
421         //
422         ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
423         ASSERT(ReportItem->BitCount <= 8);
424 
425         //
426         // one extra shift for skipping the prepended report id
427         //
428         Data = ReportDescriptor[ReportItem->ByteOffset + 1];
429 
430         //
431         // shift data
432         //
433         Data >>= ReportItem->Shift;
434 
435         //
436         // clear unwanted bits
437         //
438         Data &= ReportItem->Mask;
439 
440         //
441         // is it activated
442         //
443         Activated = (Data != 0);
444 
445         if (!Activated)
446             continue;
447 
448         //
449         // is there enough space for the usage
450         //
451         if (ItemCount >= *UsageLength)
452         {
453             ItemCount++;
454             continue;
455         }
456 
457         if (UsagePage != HID_USAGE_PAGE_UNDEFINED)
458         {
459             //
460             // store item
461             //
462             UsageList[ItemCount] = (ReportItem->UsageMinimum & 0xFFFF);
463         }
464         else
465         {
466             //
467             // store usage and page
468             //
469             if (ReportItem->BitCount == 1)
470             {
471                 //
472                 // use usage minimum
473                 //
474                 UsageAndPage[ItemCount].Usage =(ReportItem->UsageMinimum & 0xFFFF);
475             }
476             else
477             {
478                 //
479                 // use value from control
480                 //
481                 UsageAndPage[ItemCount].Usage = (USHORT)Data;
482             }
483             UsageAndPage[ItemCount].UsagePage = CurrentUsagePage;
484         }
485         ItemCount++;
486     }
487 
488     if (ItemCount > *UsageLength)
489     {
490         //
491         // list too small
492         //
493         return HIDP_STATUS_BUFFER_TOO_SMALL;
494     }
495 
496     if (UsagePage == HID_USAGE_PAGE_UNDEFINED)
497     {
498         //
499         // success, clear rest of array
500         //
501         ZeroFunction(&UsageAndPage[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE_AND_PAGE));
502     }
503     else
504     {
505         //
506         // success, clear rest of array
507         //
508         ZeroFunction(&UsageList[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE));
509     }
510 
511 
512     //
513     // store result size
514     //
515     *UsageLength = ItemCount;
516 
517     //
518     // done
519     //
520     return HIDP_STATUS_SUCCESS;
521 }
522 
523 ULONG
HidParser_UsesReportId(IN PVOID CollectionContext,IN UCHAR ReportType)524 HidParser_UsesReportId(
525     IN PVOID CollectionContext,
526     IN UCHAR  ReportType)
527 {
528     PHID_REPORT Report;
529 
530     //
531     // get report
532     //
533     Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
534     if (!Report)
535     {
536         //
537         // no such report
538         //
539         return 0;
540     }
541 
542     //
543     // returns true when report id != 0
544     //
545     return (Report->ReportID != 0);
546 
547 }
548 
549 NTSTATUS
HidParser_GetUsageValueWithReport(IN PVOID CollectionContext,IN UCHAR ReportType,IN USAGE UsagePage,IN USAGE Usage,OUT PULONG UsageValue,IN PCHAR ReportDescriptor,IN ULONG ReportDescriptorLength)550 HidParser_GetUsageValueWithReport(
551     IN PVOID CollectionContext,
552     IN UCHAR ReportType,
553     IN USAGE UsagePage,
554     IN USAGE  Usage,
555     OUT PULONG UsageValue,
556     IN PCHAR ReportDescriptor,
557     IN ULONG ReportDescriptorLength)
558 {
559     ULONG Index;
560     PHID_REPORT Report;
561     USHORT CurrentUsagePage;
562     PHID_REPORT_ITEM ReportItem;
563     ULONG Data;
564 
565     //
566     // get report
567     //
568     Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
569     if (!Report)
570     {
571         //
572         // no such report
573         //
574         return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
575     }
576 
577     if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
578     {
579         //
580         // invalid report descriptor length
581         //
582         return HIDP_STATUS_INVALID_REPORT_LENGTH;
583     }
584 
585     for (Index = 0; Index < Report->ItemCount; Index++)
586     {
587         //
588         // get report item
589         //
590         ReportItem = &Report->Items[Index];
591 
592         //
593         // check usage page
594         //
595         CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
596 
597         //
598         // does usage page match
599         //
600         if (UsagePage != CurrentUsagePage)
601             continue;
602 
603         //
604         // does the usage match
605         //
606         if (Usage != (ReportItem->UsageMinimum & 0xFFFF))
607             continue;
608 
609         //
610         // check if the specified usage is activated
611         //
612         ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
613 
614         //
615         // one extra shift for skipping the prepended report id
616         //
617         Data = 0;
618         CopyFunction(&Data, &ReportDescriptor[ReportItem->ByteOffset + 1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1)));
619 
620         //
621         // shift data
622         //
623         Data >>= ReportItem->Shift;
624 
625         //
626         // clear unwanted bits
627         //
628         Data &= ReportItem->Mask;
629 
630         //
631         // store result
632         //
633         *UsageValue = Data;
634         return HIDP_STATUS_SUCCESS;
635     }
636 
637     //
638     // usage not found
639     //
640     return HIDP_STATUS_USAGE_NOT_FOUND;
641 }
642 
643 
644 
645 NTSTATUS
HidParser_GetScaledUsageValueWithReport(IN PVOID CollectionContext,IN UCHAR ReportType,IN USAGE UsagePage,IN USAGE Usage,OUT PLONG UsageValue,IN PCHAR ReportDescriptor,IN ULONG ReportDescriptorLength)646 HidParser_GetScaledUsageValueWithReport(
647     IN PVOID CollectionContext,
648     IN UCHAR ReportType,
649     IN USAGE UsagePage,
650     IN USAGE  Usage,
651     OUT PLONG UsageValue,
652     IN PCHAR ReportDescriptor,
653     IN ULONG ReportDescriptorLength)
654 {
655     ULONG Index;
656     PHID_REPORT Report;
657     USHORT CurrentUsagePage;
658     PHID_REPORT_ITEM ReportItem;
659     ULONG Data;
660 
661     //
662     // get report
663     //
664     Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
665     if (!Report)
666     {
667         //
668         // no such report
669         //
670         return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
671     }
672 
673     if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
674     {
675         //
676         // invalid report descriptor length
677         //
678         return HIDP_STATUS_INVALID_REPORT_LENGTH;
679     }
680 
681     for (Index = 0; Index < Report->ItemCount; Index++)
682     {
683         //
684         // get report item
685         //
686         ReportItem = &Report->Items[Index];
687 
688         //
689         // check usage page
690         //
691         CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
692 
693         //
694         // does usage page match
695         //
696         if (UsagePage != CurrentUsagePage)
697             continue;
698 
699         //
700         // does the usage match
701         //
702         if (Usage != (ReportItem->UsageMinimum & 0xFFFF))
703             continue;
704 
705         //
706         // check if the specified usage is activated
707         //
708         ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
709 
710         //
711         // one extra shift for skipping the prepended report id
712         //
713         Data = 0;
714         CopyFunction(&Data, &ReportDescriptor[ReportItem->ByteOffset + 1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1)));
715 
716         //
717         // shift data
718         //
719         Data >>= ReportItem->Shift;
720 
721         //
722         // clear unwanted bits
723         //
724         Data &= ReportItem->Mask;
725 
726         if (ReportItem->Minimum > ReportItem->Maximum)
727         {
728             //
729             // logical boundaries are signed values
730             //
731 
732             // FIXME: scale with physical min/max
733             if ((Data & ~(ReportItem->Mask >> 1)) != 0)
734             {
735                 Data |= ~ReportItem->Mask;
736             }
737         }
738         else
739         {
740             // logical boundaries are absolute values
741             return HIDP_STATUS_BAD_LOG_PHY_VALUES;
742         }
743 
744         //
745         // store result
746         //
747         *UsageValue = Data;
748         return HIDP_STATUS_SUCCESS;
749     }
750 
751     //
752     // usage not found
753     //
754     return HIDP_STATUS_USAGE_NOT_FOUND;
755 }
756 
757 ULONG
HidParser_GetScanCodeFromKbdUsage(IN USAGE Usage)758 HidParser_GetScanCodeFromKbdUsage(
759     IN USAGE Usage)
760 {
761     if (Usage < sizeof(KeyboardScanCodes) / sizeof(KeyboardScanCodes[0]))
762     {
763         //
764         // valid usage
765         //
766         return KeyboardScanCodes[Usage];
767     }
768 
769     //
770     // invalid usage
771     //
772     return 0;
773 }
774 
775 ULONG
HidParser_GetScanCodeFromCustUsage(IN USAGE Usage)776 HidParser_GetScanCodeFromCustUsage(
777     IN USAGE Usage)
778 {
779     ULONG i;
780 
781     //
782     // find usage in array
783     //
784     for (i = 0; i < sizeof(CustomerScanCodes) / sizeof(CustomerScanCodes[0]); ++i)
785     {
786         if (CustomerScanCodes[i].Usage == Usage)
787         {
788             //
789             // valid usage
790             //
791             return CustomerScanCodes[i].ScanCode;
792         }
793     }
794 
795     //
796     // invalid usage
797     //
798     return 0;
799 }
800 
801 VOID
HidParser_DispatchKey(IN PCHAR ScanCodes,IN HIDP_KEYBOARD_DIRECTION KeyAction,IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,IN PVOID InsertCodesContext)802 HidParser_DispatchKey(
803     IN PCHAR ScanCodes,
804     IN HIDP_KEYBOARD_DIRECTION KeyAction,
805     IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
806     IN PVOID InsertCodesContext)
807 {
808     ULONG Index;
809     ULONG Length = 0;
810 
811     //
812     // count code length
813     //
814     for(Index = 0; Index < sizeof(ULONG); Index++)
815     {
816         if (ScanCodes[Index] == 0)
817         {
818             //
819             // last scan code
820             //
821             break;
822         }
823 
824         //
825         // is this a key break
826         //
827         if (KeyAction == HidP_Keyboard_Break)
828         {
829             //
830             // add break - see USB HID to PS/2 Scan Code Translation Table
831             //
832             ScanCodes[Index] |= 0x80;
833         }
834 
835         //
836         // more scan counts
837         //
838         Length++;
839     }
840 
841     if (Length > 0)
842     {
843          //
844          // dispatch scan codes
845          //
846          InsertCodesProcedure(InsertCodesContext, ScanCodes, Length);
847     }
848 }
849 
850 NTSTATUS
HidParser_TranslateKbdUsage(IN USAGE Usage,IN HIDP_KEYBOARD_DIRECTION KeyAction,IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,IN PVOID InsertCodesContext)851 HidParser_TranslateKbdUsage(
852     IN USAGE Usage,
853     IN HIDP_KEYBOARD_DIRECTION  KeyAction,
854     IN OUT PHIDP_KEYBOARD_MODIFIER_STATE  ModifierState,
855     IN PHIDP_INSERT_SCANCODES  InsertCodesProcedure,
856     IN PVOID  InsertCodesContext)
857 {
858     ULONG ScanCode;
859     CHAR FakeShift[] = {0xE0, 0x2A, 0x00};
860     CHAR FakeCtrl[] = {0xE1, 0x1D, 0x00};
861 
862     //
863     // get scan code
864     //
865     ScanCode = HidParser_GetScanCodeFromKbdUsage(Usage);
866     if (!ScanCode)
867     {
868         //
869         // invalid lookup or no scan code available
870         //
871         DPRINT1("No Scan code for Usage %x\n", Usage);
872         return HIDP_STATUS_I8042_TRANS_UNKNOWN;
873     }
874 
875     if (ScanCode & 0xFF00)
876     {
877         //
878         // swap scan code
879         //
880         ScanCode = NTOHS(ScanCode);
881     }
882 
883     if (Usage == 0x46 && KeyAction == HidP_Keyboard_Make)
884     {
885         // Print Screen generates additional FakeShift
886         HidParser_DispatchKey(FakeShift, KeyAction, InsertCodesProcedure, InsertCodesContext);
887     }
888 
889     if (Usage == 0x48)
890     {
891         // Pause/Break generates additional FakeCtrl. Note: it's always before key press/release.
892         HidParser_DispatchKey(FakeCtrl, KeyAction, InsertCodesProcedure, InsertCodesContext);
893     }
894 
895     //
896     // FIXME: translate modifier states
897     //
898     HidParser_DispatchKey((PCHAR)&ScanCode, KeyAction, InsertCodesProcedure, InsertCodesContext);
899 
900     if (Usage == 0x46 && KeyAction == HidP_Keyboard_Break)
901     {
902         // Print Screen generates additional FakeShift
903         HidParser_DispatchKey(FakeShift, KeyAction, InsertCodesProcedure, InsertCodesContext);
904     }
905 
906     //
907     // done
908     //
909     return HIDP_STATUS_SUCCESS;
910 }
911 
912 NTSTATUS
HidParser_TranslateCustUsage(IN USAGE Usage,IN HIDP_KEYBOARD_DIRECTION KeyAction,IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,IN PVOID InsertCodesContext)913 HidParser_TranslateCustUsage(
914     IN USAGE Usage,
915     IN HIDP_KEYBOARD_DIRECTION  KeyAction,
916     IN OUT PHIDP_KEYBOARD_MODIFIER_STATE  ModifierState,
917     IN PHIDP_INSERT_SCANCODES  InsertCodesProcedure,
918     IN PVOID  InsertCodesContext)
919 {
920     ULONG ScanCode;
921 
922     //
923     // get scan code
924     //
925     ScanCode = HidParser_GetScanCodeFromCustUsage(Usage);
926     if (!ScanCode)
927     {
928         //
929         // invalid lookup or no scan code available
930         //
931         DPRINT1("No Scan code for Usage %x\n", Usage);
932         return HIDP_STATUS_I8042_TRANS_UNKNOWN;
933     }
934 
935     if (ScanCode & 0xFF00)
936     {
937         //
938         // swap scan code
939         //
940         ScanCode = NTOHS(ScanCode);
941     }
942 
943     //
944     // FIXME: translate modifier states
945     //
946     HidParser_DispatchKey((PCHAR)&ScanCode, KeyAction, InsertCodesProcedure, InsertCodesContext);
947 
948     //
949     // done
950     //
951     return HIDP_STATUS_SUCCESS;
952 }
953