Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / sdk / lib / drivers / hidparser / api.c
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 HIDPARSER_STATUS
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 HIDPARSER_STATUS_COLLECTION_NOT_FOUND;
82 }
83
84 //
85 // store result
86 //
87 *UsagePage = (Collection->Usage >> 16);
88 *Usage = (Collection->Usage & 0xFFFF);
89 return HIDPARSER_STATUS_SUCCESS;
90 }
91
92 ULONG
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
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
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
210 VOID
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)
218 {
219 Parser->Alloc = AllocFunction;
220 Parser->Free = FreeFunction;
221 Parser->Zero = ZeroFunction;
222 Parser->Copy = CopyFunction;
223 Parser->Debug = DebugFunction;
224 }
225
226 ULONG
227 HidParser_GetMaxUsageListLengthWithReportAndPage(
228 IN PVOID CollectionContext,
229 IN UCHAR ReportType,
230 IN USAGE UsagePage OPTIONAL)
231 {
232 ULONG Index;
233 PHID_REPORT Report;
234 ULONG ItemCount = 0;
235 USHORT CurrentUsagePage;
236
237 //
238 // get report
239 //
240 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
241 if (!Report)
242 {
243 //
244 // no such report
245 //
246 return 0;
247 }
248
249 for(Index = 0; Index < Report->ItemCount; Index++)
250 {
251 //
252 // check usage page
253 //
254 CurrentUsagePage = (Report->Items[Index].UsageMinimum >> 16);
255 if (CurrentUsagePage == UsagePage && Report->Items[Index].HasData)
256 {
257 //
258 // found item
259 //
260 ItemCount++;
261 }
262 }
263
264 //
265 // done
266 //
267 return ItemCount;
268 }
269
270 HIDPARSER_STATUS
271 HidParser_GetSpecificValueCapsWithReport(
272 IN PHID_PARSER Parser,
273 IN PVOID CollectionContext,
274 IN UCHAR ReportType,
275 IN USHORT UsagePage,
276 IN USHORT Usage,
277 OUT PHIDP_VALUE_CAPS ValueCaps,
278 IN OUT PUSHORT ValueCapsLength)
279 {
280 ULONG Index;
281 PHID_REPORT Report;
282 USHORT ItemCount = 0;
283 USHORT CurrentUsagePage;
284 USHORT CurrentUsage;
285
286 //
287 // get report
288 //
289 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
290 if (!Report)
291 {
292 //
293 // no such report
294 //
295 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
296 }
297
298 for(Index = 0; Index < Report->ItemCount; Index++)
299 {
300 //
301 // check usage page
302 //
303 CurrentUsagePage = (Report->Items[Index].UsageMinimum >> 16);
304 CurrentUsage = (Report->Items[Index].UsageMinimum & 0xFFFF);
305
306 if ((Usage == CurrentUsage && UsagePage == CurrentUsagePage) || (Usage == 0 && UsagePage == CurrentUsagePage) || (Usage == CurrentUsage && UsagePage == 0) || (Usage == 0 && UsagePage == 0))
307 {
308 //
309 // check if there is enough place for the caps
310 //
311 if (ItemCount < *ValueCapsLength)
312 {
313 //
314 // zero caps
315 //
316 Parser->Zero(&ValueCaps[ItemCount], sizeof(HIDP_VALUE_CAPS));
317
318 //
319 // init caps
320 //
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;
327
328 //
329 // FIXME: FILLMEIN
330 //
331 }
332
333
334 //
335 // found item
336 //
337 ItemCount++;
338 }
339 }
340
341 //
342 // store result
343 //
344 *ValueCapsLength = ItemCount;
345
346 if (ItemCount)
347 {
348 //
349 // success
350 //
351 return HIDPARSER_STATUS_SUCCESS;
352 }
353
354 //
355 // item not found
356 //
357 return HIDPARSER_STATUS_USAGE_NOT_FOUND;
358 }
359
360 HIDPARSER_STATUS
361 HidParser_GetUsagesWithReport(
362 IN PHID_PARSER Parser,
363 IN PVOID CollectionContext,
364 IN UCHAR ReportType,
365 IN USAGE UsagePage,
366 OUT USAGE *UsageList,
367 IN OUT PULONG UsageLength,
368 IN PCHAR ReportDescriptor,
369 IN ULONG ReportDescriptorLength)
370 {
371 ULONG Index;
372 PHID_REPORT Report;
373 ULONG ItemCount = 0;
374 USHORT CurrentUsagePage;
375 PHID_REPORT_ITEM ReportItem;
376 UCHAR Activated;
377 ULONG Data;
378 PUSAGE_AND_PAGE UsageAndPage = NULL;
379
380 //
381 // get report
382 //
383 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
384 if (!Report)
385 {
386 //
387 // no such report
388 //
389 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
390 }
391
392 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
393 {
394 //
395 // invalid report descriptor length
396 //
397 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
398 }
399
400 //
401 // cast to usage and page
402 //
403 if (UsagePage == HID_USAGE_PAGE_UNDEFINED)
404 {
405 //
406 // the caller requested any set usages
407 //
408 UsageAndPage = (PUSAGE_AND_PAGE)UsageList;
409 }
410
411 for(Index = 0; Index < Report->ItemCount; Index++)
412 {
413 //
414 // get report item
415 //
416 ReportItem = &Report->Items[Index];
417
418 //
419 // does it have data
420 //
421 if (!ReportItem->HasData)
422 continue;
423
424 //
425 // check usage page
426 //
427 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
428
429 if (UsagePage != HID_USAGE_PAGE_UNDEFINED)
430 {
431 //
432 // does usage match
433 //
434 if (UsagePage != CurrentUsagePage)
435 continue;
436 }
437
438 //
439 // check if the specified usage is activated
440 //
441 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
442 ASSERT(ReportItem->BitCount <= 8);
443
444 //
445 // one extra shift for skipping the prepended report id
446 //
447 Data = ReportDescriptor[ReportItem->ByteOffset + 1];
448
449 //
450 // shift data
451 //
452 Data >>= ReportItem->Shift;
453
454 //
455 // clear unwanted bits
456 //
457 Data &= ReportItem->Mask;
458
459 //
460 // is it activated
461 //
462 Activated = (Data != 0);
463
464 if (!Activated)
465 continue;
466
467 //
468 // is there enough space for the usage
469 //
470 if (ItemCount >= *UsageLength)
471 {
472 ItemCount++;
473 continue;
474 }
475
476 if (UsagePage != HID_USAGE_PAGE_UNDEFINED)
477 {
478 //
479 // store item
480 //
481 UsageList[ItemCount] = (ReportItem->UsageMinimum & 0xFFFF);
482 }
483 else
484 {
485 //
486 // store usage and page
487 //
488 if (ReportItem->BitCount == 1)
489 {
490 //
491 // use usage minimum
492 //
493 UsageAndPage[ItemCount].Usage =(ReportItem->UsageMinimum & 0xFFFF);
494 }
495 else
496 {
497 //
498 // use value from control
499 //
500 UsageAndPage[ItemCount].Usage = (USHORT)Data;
501 }
502 UsageAndPage[ItemCount].UsagePage = CurrentUsagePage;
503 }
504 ItemCount++;
505 }
506
507 if (ItemCount > *UsageLength)
508 {
509 //
510 // list too small
511 //
512 return HIDPARSER_STATUS_BUFFER_TOO_SMALL;
513 }
514
515 if (UsagePage == HID_USAGE_PAGE_UNDEFINED)
516 {
517 //
518 // success, clear rest of array
519 //
520 Parser->Zero(&UsageAndPage[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE_AND_PAGE));
521 }
522 else
523 {
524 //
525 // success, clear rest of array
526 //
527 Parser->Zero(&UsageList[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE));
528 }
529
530
531 //
532 // store result size
533 //
534 *UsageLength = ItemCount;
535
536 //
537 // done
538 //
539 return HIDPARSER_STATUS_SUCCESS;
540 }
541
542 ULONG
543 HidParser_UsesReportId(
544 IN PVOID CollectionContext,
545 IN UCHAR ReportType)
546 {
547 PHID_REPORT Report;
548
549 //
550 // get report
551 //
552 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
553 if (!Report)
554 {
555 //
556 // no such report
557 //
558 return 0;
559 }
560
561 //
562 // returns true when report id != 0
563 //
564 return (Report->ReportID != 0);
565
566 }
567
568 HIDPARSER_STATUS
569 HidParser_GetUsageValueWithReport(
570 IN PHID_PARSER Parser,
571 IN PVOID CollectionContext,
572 IN UCHAR ReportType,
573 IN USAGE UsagePage,
574 IN USAGE Usage,
575 OUT PULONG UsageValue,
576 IN PCHAR ReportDescriptor,
577 IN ULONG ReportDescriptorLength)
578 {
579 ULONG Index;
580 PHID_REPORT Report;
581 USHORT CurrentUsagePage;
582 PHID_REPORT_ITEM ReportItem;
583 ULONG Data;
584
585 //
586 // get report
587 //
588 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
589 if (!Report)
590 {
591 //
592 // no such report
593 //
594 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
595 }
596
597 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
598 {
599 //
600 // invalid report descriptor length
601 //
602 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
603 }
604
605 for (Index = 0; Index < Report->ItemCount; Index++)
606 {
607 //
608 // get report item
609 //
610 ReportItem = &Report->Items[Index];
611
612 //
613 // check usage page
614 //
615 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
616
617 //
618 // does usage page match
619 //
620 if (UsagePage != CurrentUsagePage)
621 continue;
622
623 //
624 // does the usage match
625 //
626 if (Usage != (ReportItem->UsageMinimum & 0xFFFF))
627 continue;
628
629 //
630 // check if the specified usage is activated
631 //
632 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
633
634 //
635 // one extra shift for skipping the prepended report id
636 //
637 Data = 0;
638 Parser->Copy(&Data, &ReportDescriptor[ReportItem->ByteOffset + 1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1)));
639
640 //
641 // shift data
642 //
643 Data >>= ReportItem->Shift;
644
645 //
646 // clear unwanted bits
647 //
648 Data &= ReportItem->Mask;
649
650 //
651 // store result
652 //
653 *UsageValue = Data;
654 return HIDPARSER_STATUS_SUCCESS;
655 }
656
657 //
658 // usage not found
659 //
660 return HIDPARSER_STATUS_USAGE_NOT_FOUND;
661 }
662
663
664
665 HIDPARSER_STATUS
666 HidParser_GetScaledUsageValueWithReport(
667 IN PHID_PARSER Parser,
668 IN PVOID CollectionContext,
669 IN UCHAR ReportType,
670 IN USAGE UsagePage,
671 IN USAGE Usage,
672 OUT PLONG UsageValue,
673 IN PCHAR ReportDescriptor,
674 IN ULONG ReportDescriptorLength)
675 {
676 ULONG Index;
677 PHID_REPORT Report;
678 USHORT CurrentUsagePage;
679 PHID_REPORT_ITEM ReportItem;
680 ULONG Data;
681
682 //
683 // get report
684 //
685 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
686 if (!Report)
687 {
688 //
689 // no such report
690 //
691 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
692 }
693
694 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
695 {
696 //
697 // invalid report descriptor length
698 //
699 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
700 }
701
702 for (Index = 0; Index < Report->ItemCount; Index++)
703 {
704 //
705 // get report item
706 //
707 ReportItem = &Report->Items[Index];
708
709 //
710 // check usage page
711 //
712 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
713
714 //
715 // does usage page match
716 //
717 if (UsagePage != CurrentUsagePage)
718 continue;
719
720 //
721 // does the usage match
722 //
723 if (Usage != (ReportItem->UsageMinimum & 0xFFFF))
724 continue;
725
726 //
727 // check if the specified usage is activated
728 //
729 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
730
731 //
732 // one extra shift for skipping the prepended report id
733 //
734 Data = 0;
735 Parser->Copy(&Data, &ReportDescriptor[ReportItem->ByteOffset + 1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1)));
736
737 //
738 // shift data
739 //
740 Data >>= ReportItem->Shift;
741
742 //
743 // clear unwanted bits
744 //
745 Data &= ReportItem->Mask;
746
747 if (ReportItem->Minimum > ReportItem->Maximum)
748 {
749 //
750 // logical boundaries are signed values
751 //
752
753 // FIXME: scale with physical min/max
754 if ((Data & ~(ReportItem->Mask >> 1)) != 0)
755 {
756 Data |= ~ReportItem->Mask;
757 }
758 }
759 else
760 {
761 // logical boundaries are absolute values
762 return HIDPARSER_STATUS_BAD_LOG_PHY_VALUES;
763 }
764
765 //
766 // store result
767 //
768 *UsageValue = Data;
769 return HIDPARSER_STATUS_SUCCESS;
770 }
771
772 //
773 // usage not found
774 //
775 return HIDPARSER_STATUS_USAGE_NOT_FOUND;
776 }
777
778 ULONG
779 HidParser_GetScanCodeFromKbdUsage(
780 IN USAGE Usage)
781 {
782 if (Usage < sizeof(KeyboardScanCodes) / sizeof(KeyboardScanCodes[0]))
783 {
784 //
785 // valid usage
786 //
787 return KeyboardScanCodes[Usage];
788 }
789
790 //
791 // invalid usage
792 //
793 return 0;
794 }
795
796 ULONG
797 HidParser_GetScanCodeFromCustUsage(
798 IN USAGE Usage)
799 {
800 ULONG i;
801
802 //
803 // find usage in array
804 //
805 for (i = 0; i < sizeof(CustomerScanCodes) / sizeof(CustomerScanCodes[0]); ++i)
806 {
807 if (CustomerScanCodes[i].Usage == Usage)
808 {
809 //
810 // valid usage
811 //
812 return CustomerScanCodes[i].ScanCode;
813 }
814 }
815
816 //
817 // invalid usage
818 //
819 return 0;
820 }
821
822 VOID
823 HidParser_DispatchKey(
824 IN PCHAR ScanCodes,
825 IN HIDP_KEYBOARD_DIRECTION KeyAction,
826 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
827 IN PVOID InsertCodesContext)
828 {
829 ULONG Index;
830 ULONG Length = 0;
831
832 //
833 // count code length
834 //
835 for(Index = 0; Index < sizeof(ULONG); Index++)
836 {
837 if (ScanCodes[Index] == 0)
838 {
839 //
840 // last scan code
841 //
842 break;
843 }
844
845 //
846 // is this a key break
847 //
848 if (KeyAction == HidP_Keyboard_Break)
849 {
850 //
851 // add break - see USB HID to PS/2 Scan Code Translation Table
852 //
853 ScanCodes[Index] |= 0x80;
854 }
855
856 //
857 // more scan counts
858 //
859 Length++;
860 }
861
862 if (Length > 0)
863 {
864 //
865 // dispatch scan codes
866 //
867 InsertCodesProcedure(InsertCodesContext, ScanCodes, Length);
868 }
869 }
870
871 HIDPARSER_STATUS
872 HidParser_TranslateKbdUsage(
873 IN PHID_PARSER Parser,
874 IN USAGE Usage,
875 IN HIDP_KEYBOARD_DIRECTION KeyAction,
876 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,
877 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
878 IN PVOID InsertCodesContext)
879 {
880 ULONG ScanCode;
881 CHAR FakeShift[] = {0xE0, 0x2A, 0x00};
882 CHAR FakeCtrl[] = {0xE1, 0x1D, 0x00};
883
884 //
885 // get scan code
886 //
887 ScanCode = HidParser_GetScanCodeFromKbdUsage(Usage);
888 if (!ScanCode)
889 {
890 //
891 // invalid lookup or no scan code available
892 //
893 DPRINT1("No Scan code for Usage %x\n", Usage);
894 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN;
895 }
896
897 if (ScanCode & 0xFF00)
898 {
899 //
900 // swap scan code
901 //
902 ScanCode = NTOHS(ScanCode);
903 }
904
905 if (Usage == 0x46 && KeyAction == HidP_Keyboard_Make)
906 {
907 // Print Screen generates additional FakeShift
908 HidParser_DispatchKey(FakeShift, KeyAction, InsertCodesProcedure, InsertCodesContext);
909 }
910
911 if (Usage == 0x48)
912 {
913 // Pause/Break generates additional FakeCtrl. Note: it's always before key press/release.
914 HidParser_DispatchKey(FakeCtrl, KeyAction, InsertCodesProcedure, InsertCodesContext);
915 }
916
917 //
918 // FIXME: translate modifier states
919 //
920 HidParser_DispatchKey((PCHAR)&ScanCode, KeyAction, InsertCodesProcedure, InsertCodesContext);
921
922 if (Usage == 0x46 && KeyAction == HidP_Keyboard_Break)
923 {
924 // Print Screen generates additional FakeShift
925 HidParser_DispatchKey(FakeShift, KeyAction, InsertCodesProcedure, InsertCodesContext);
926 }
927
928 //
929 // done
930 //
931 return HIDPARSER_STATUS_SUCCESS;
932 }
933
934 HIDPARSER_STATUS
935 HidParser_TranslateCustUsage(
936 IN PHID_PARSER Parser,
937 IN USAGE Usage,
938 IN HIDP_KEYBOARD_DIRECTION KeyAction,
939 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,
940 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
941 IN PVOID InsertCodesContext)
942 {
943 ULONG ScanCode;
944
945 //
946 // get scan code
947 //
948 ScanCode = HidParser_GetScanCodeFromCustUsage(Usage);
949 if (!ScanCode)
950 {
951 //
952 // invalid lookup or no scan code available
953 //
954 DPRINT1("No Scan code for Usage %x\n", Usage);
955 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN;
956 }
957
958 if (ScanCode & 0xFF00)
959 {
960 //
961 // swap scan code
962 //
963 ScanCode = NTOHS(ScanCode);
964 }
965
966 //
967 // FIXME: translate modifier states
968 //
969 HidParser_DispatchKey((PCHAR)&ScanCode, KeyAction, InsertCodesProcedure, InsertCodesContext);
970
971 //
972 // done
973 //
974 return HIDPARSER_STATUS_SUCCESS;
975 }