[HIDPARSE][HIDPARSER]
[reactos.git] / reactos / 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
12 #include "parser.h"
13
14 static ULONG KeyboardScanCodes[256] =
15 { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
16 /* 0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020, 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
17 /* 1 */ 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014, 0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
18 /* 2 */ 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
19 /* 3 */ 0x001b, 0x002b, 0x002b, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034, 0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
20 /* 4 */ 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xE037, 0x0046, 0x0045, 0xE052, 0xE047, 0xE049, 0xE053, 0xE04F, 0xE051, 0xE04D,
21 /* 5 */ 0xE04B, 0xE050, 0xE048, 0x0045, 0xE035, 0x0037, 0x004a, 0x004e, 0xE01C, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
22 /* 6 */ 0x0048, 0x0049, 0x0052, 0x0053, 0x0056, 0xE05D, 0xE05E, 0x0075, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be,
23 /* 7 */ 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x0086, 0x008a, 0x0082, 0x0084, 0x0080, 0x0081, 0x0083, 0x0089, 0x0085, 0x0087, 0x0088, 0x0071,
24 /* 8 */ 0x0073, 0x0072, 0x0000, 0x0000, 0x0000, 0x0079, 0x0000, 0x0059, 0x005d, 0x007c, 0x005c, 0x005e, 0x005f, 0x0000, 0x0000, 0x0000,
25 /* 9 */ 0x007a, 0x007b, 0x005a, 0x005b, 0x0055, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
26 /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
27 /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
28 /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
29 /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
30 /* E */ 0x001D, 0x002A, 0x0038, 0xE05B, 0xE01D, 0x0036, 0xE038, 0xE05C, 0x00a4, 0x00a6, 0x00a5, 0x00a3, 0x00a1, 0x0073, 0x0072, 0x0071,
31 /* F */ 0x0096, 0x009e, 0x009f, 0x0080, 0x0088, 0x00b1, 0x00b2, 0x00b0, 0x008e, 0x0098, 0x00ad, 0x008c, 0x0000, 0x0000, 0x0000, 0x0000,
32 };
33
34 static struct
35 {
36 USAGE Usage;
37 ULONG ScanCode;
38 } CustomerScanCodes[] =
39 {
40 { 0x00B5, 0xE019 },
41 { 0x00B6, 0xE010 },
42 { 0x00B7, 0xE024 },
43 { 0x00CD, 0xE022 },
44 { 0x00E2, 0xE020 },
45 { 0x00E9, 0xE030 },
46 { 0x00EA, 0xE02E },
47 { 0x0183, 0xE06D },
48 { 0x018A, 0xE06C },
49 { 0x0192, 0xE021 },
50 { 0x0194, 0xE06B },
51 { 0x0221, 0xE065 },
52 { 0x0223, 0xE032 },
53 { 0x0224, 0xE06A },
54 { 0x0225, 0xE069 },
55 { 0x0226, 0xE068 },
56 { 0x0227, 0xE067 },
57 { 0x022A, 0xE066 },
58 };
59
60 #define NTOHS(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8))
61
62 HIDPARSER_STATUS
63 HidParser_GetCollectionUsagePage(
64 IN PVOID CollectionContext,
65 OUT PUSHORT Usage,
66 OUT PUSHORT UsagePage)
67 {
68 PHID_COLLECTION Collection;
69
70 //
71 // find collection
72 //
73 Collection = HidParser_GetCollectionFromContext(CollectionContext);
74 if (!Collection)
75 {
76 //
77 // collection not found
78 //
79 return HIDPARSER_STATUS_COLLECTION_NOT_FOUND;
80 }
81
82 //
83 // store result
84 //
85 *UsagePage = (Collection->Usage >> 16);
86 *Usage = (Collection->Usage & 0xFFFF);
87 return HIDPARSER_STATUS_SUCCESS;
88 }
89
90 ULONG
91 HidParser_GetReportLength(
92 IN PVOID CollectionContext,
93 IN UCHAR ReportType)
94 {
95 PHID_REPORT Report;
96 ULONG ReportLength;
97
98 //
99 // get first report
100 //
101 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
102 if (!Report)
103 {
104 //
105 // no report found
106 //
107 return 0;
108 }
109
110 //
111 // get report length
112 //
113 ReportLength = Report->ReportSize;
114
115 //
116 // done
117 //
118 if (ReportLength)
119 {
120 //
121 // byte aligned length
122 //
123 ASSERT(ReportLength % 8 == 0);
124 return ReportLength / 8;
125 }
126 return ReportLength;
127 }
128
129 ULONG
130 HidParser_GetReportItemCountFromReportType(
131 IN PVOID CollectionContext,
132 IN UCHAR ReportType)
133 {
134 PHID_REPORT Report;
135
136 //
137 // get report
138 //
139 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
140 if (!Report)
141 {
142 //
143 // no such report
144 //
145 return 0;
146 }
147
148 //
149 // return report item count
150 //
151 return Report->ItemCount;
152 }
153
154
155 ULONG
156 HidParser_GetReportItemTypeCountFromReportType(
157 IN PVOID CollectionContext,
158 IN UCHAR ReportType,
159 IN ULONG bData)
160 {
161 ULONG Index;
162 PHID_REPORT Report;
163 ULONG ItemCount = 0;
164
165 //
166 // get report
167 //
168 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
169 if (!Report)
170 {
171 //
172 // no such report
173 //
174 return 0;
175 }
176
177 //
178 // enumerate all items
179 //
180 for(Index = 0; Index < Report->ItemCount; Index++)
181 {
182 //
183 // check item type
184 //
185 if (Report->Items[Index].HasData && bData == TRUE)
186 {
187 //
188 // found data item
189 //
190 ItemCount++;
191 }
192 else if (Report->Items[Index].HasData == FALSE && bData == FALSE)
193 {
194 //
195 // found value item
196 //
197 ItemCount++;
198 }
199 }
200
201 //
202 // no report items
203 //
204 return ItemCount;
205 }
206
207
208 VOID
209 HidParser_InitParser(
210 IN PHIDPARSER_ALLOC_FUNCTION AllocFunction,
211 IN PHIDPARSER_FREE_FUNCTION FreeFunction,
212 IN PHIDPARSER_ZERO_FUNCTION ZeroFunction,
213 IN PHIDPARSER_COPY_FUNCTION CopyFunction,
214 IN PHIDPARSER_DEBUG_FUNCTION DebugFunction,
215 OUT PHID_PARSER Parser)
216 {
217 Parser->Alloc = AllocFunction;
218 Parser->Free = FreeFunction;
219 Parser->Zero = ZeroFunction;
220 Parser->Copy = CopyFunction;
221 Parser->Debug = DebugFunction;
222 }
223
224 ULONG
225 HidParser_GetMaxUsageListLengthWithReportAndPage(
226 IN PVOID CollectionContext,
227 IN UCHAR ReportType,
228 IN USAGE UsagePage OPTIONAL)
229 {
230 ULONG Index;
231 PHID_REPORT Report;
232 ULONG ItemCount = 0;
233 USHORT CurrentUsagePage;
234
235 //
236 // get report
237 //
238 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
239 if (!Report)
240 {
241 //
242 // no such report
243 //
244 return 0;
245 }
246
247 for(Index = 0; Index < Report->ItemCount; Index++)
248 {
249 //
250 // check usage page
251 //
252 CurrentUsagePage = (Report->Items[Index].UsageMinimum >> 16);
253 if (CurrentUsagePage == UsagePage && Report->Items[Index].HasData)
254 {
255 //
256 // found item
257 //
258 ItemCount++;
259 }
260 }
261
262 //
263 // done
264 //
265 return ItemCount;
266 }
267
268 HIDPARSER_STATUS
269 HidParser_GetSpecificValueCapsWithReport(
270 IN PHID_PARSER Parser,
271 IN PVOID CollectionContext,
272 IN UCHAR ReportType,
273 IN USHORT UsagePage,
274 IN USHORT Usage,
275 OUT PHIDP_VALUE_CAPS ValueCaps,
276 IN OUT PULONG ValueCapsLength)
277 {
278 ULONG Index;
279 PHID_REPORT Report;
280 ULONG ItemCount = 0;
281 USHORT CurrentUsagePage;
282 USHORT CurrentUsage;
283
284 //
285 // get report
286 //
287 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
288 if (!Report)
289 {
290 //
291 // no such report
292 //
293 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
294 }
295
296 for(Index = 0; Index < Report->ItemCount; Index++)
297 {
298 //
299 // check usage page
300 //
301 CurrentUsagePage = (Report->Items[Index].UsageMinimum >> 16);
302 CurrentUsage = (Report->Items[Index].UsageMinimum & 0xFFFF);
303
304 if ((Usage == CurrentUsage && UsagePage == CurrentUsagePage) || (Usage == 0 && UsagePage == CurrentUsagePage) || (Usage == CurrentUsage && UsagePage == 0) || (Usage == 0 && UsagePage == 0))
305 {
306 //
307 // check if there is enough place for the caps
308 //
309 if (ItemCount < *ValueCapsLength)
310 {
311 //
312 // zero caps
313 //
314 Parser->Zero(&ValueCaps[ItemCount], sizeof(HIDP_VALUE_CAPS));
315
316 //
317 // init caps
318 //
319 ValueCaps[ItemCount].UsagePage = CurrentUsagePage;
320 ValueCaps[ItemCount].ReportID = Report->ReportID;
321 ValueCaps[ItemCount].LogicalMin = Report->Items[Index].Minimum;
322 ValueCaps[ItemCount].LogicalMax = Report->Items[Index].Maximum;
323 ValueCaps[ItemCount].IsAbsolute = !Report->Items[Index].Relative;
324 ValueCaps[ItemCount].BitSize = Report->Items[Index].BitCount;
325
326 //
327 // FIXME: FILLMEIN
328 //
329 }
330
331
332 //
333 // found item
334 //
335 ItemCount++;
336 }
337 }
338
339 //
340 // store result
341 //
342 *ValueCapsLength = ItemCount;
343
344 if (ItemCount)
345 {
346 //
347 // success
348 //
349 return HIDPARSER_STATUS_SUCCESS;
350 }
351
352 //
353 // item not found
354 //
355 return HIDPARSER_STATUS_USAGE_NOT_FOUND;
356 }
357
358 HIDPARSER_STATUS
359 HidParser_GetUsagesWithReport(
360 IN PHID_PARSER Parser,
361 IN PVOID CollectionContext,
362 IN UCHAR ReportType,
363 IN USAGE UsagePage,
364 OUT USAGE *UsageList,
365 IN OUT PULONG UsageLength,
366 IN PCHAR ReportDescriptor,
367 IN ULONG ReportDescriptorLength)
368 {
369 ULONG Index;
370 PHID_REPORT Report;
371 ULONG ItemCount = 0;
372 USHORT CurrentUsagePage;
373 PHID_REPORT_ITEM ReportItem;
374 UCHAR Activated;
375 ULONG Data;
376 PUSAGE_AND_PAGE UsageAndPage = NULL;
377
378 //
379 // get report
380 //
381 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
382 if (!Report)
383 {
384 //
385 // no such report
386 //
387 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
388 }
389
390 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
391 {
392 //
393 // invalid report descriptor length
394 //
395 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
396 }
397
398 //
399 // cast to usage and page
400 //
401 if (UsagePage == HID_USAGE_PAGE_UNDEFINED)
402 {
403 //
404 // the caller requested any set usages
405 //
406 UsageAndPage = (PUSAGE_AND_PAGE)UsageList;
407 }
408
409 for(Index = 0; Index < Report->ItemCount; Index++)
410 {
411 //
412 // get report item
413 //
414 ReportItem = &Report->Items[Index];
415
416 //
417 // does it have data
418 //
419 if (!ReportItem->HasData)
420 continue;
421
422 //
423 // check usage page
424 //
425 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
426
427 if (UsagePage != HID_USAGE_PAGE_UNDEFINED)
428 {
429 //
430 // does usage match
431 //
432 if (UsagePage != CurrentUsagePage)
433 continue;
434 }
435
436 //
437 // check if the specified usage is activated
438 //
439 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
440 ASSERT(ReportItem->BitCount <= 8);
441
442 //
443 // one extra shift for skipping the prepended report id
444 //
445 Data = ReportDescriptor[ReportItem->ByteOffset + 1];
446
447 //
448 // shift data
449 //
450 Data >>= ReportItem->Shift;
451
452 //
453 // clear unwanted bits
454 //
455 Data &= ReportItem->Mask;
456
457 //
458 // is it activated
459 //
460 Activated = (Data != 0);
461
462 if (!Activated)
463 continue;
464
465 //
466 // is there enough space for the usage
467 //
468 if (ItemCount >= *UsageLength)
469 {
470 ItemCount++;
471 continue;
472 }
473
474 if (UsagePage != HID_USAGE_PAGE_UNDEFINED)
475 {
476 //
477 // store item
478 //
479 UsageList[ItemCount] = (ReportItem->UsageMinimum & 0xFFFF);
480 }
481 else
482 {
483 //
484 // store usage and page
485 //
486 if (ReportItem->BitCount == 1)
487 {
488 //
489 // use usage minimum
490 //
491 UsageAndPage[ItemCount].Usage =(ReportItem->UsageMinimum & 0xFFFF);
492 }
493 else
494 {
495 //
496 // use value from control
497 //
498 UsageAndPage[ItemCount].Usage = (USHORT)Data;
499 }
500 UsageAndPage[ItemCount].UsagePage = CurrentUsagePage;
501 }
502 ItemCount++;
503 }
504
505 if (ItemCount > *UsageLength)
506 {
507 //
508 // list too small
509 //
510 return HIDPARSER_STATUS_BUFFER_TOO_SMALL;
511 }
512
513 if (UsagePage == HID_USAGE_PAGE_UNDEFINED)
514 {
515 //
516 // success, clear rest of array
517 //
518 Parser->Zero(&UsageAndPage[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE_AND_PAGE));
519 }
520 else
521 {
522 //
523 // success, clear rest of array
524 //
525 Parser->Zero(&UsageList[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE));
526 }
527
528
529 //
530 // store result size
531 //
532 *UsageLength = ItemCount;
533
534 //
535 // done
536 //
537 return HIDPARSER_STATUS_SUCCESS;
538 }
539
540 ULONG
541 HidParser_UsesReportId(
542 IN PVOID CollectionContext,
543 IN UCHAR ReportType)
544 {
545 PHID_REPORT Report;
546
547 //
548 // get report
549 //
550 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
551 if (!Report)
552 {
553 //
554 // no such report
555 //
556 return 0;
557 }
558
559 //
560 // returns true when report id != 0
561 //
562 return (Report->ReportID != 0);
563
564 }
565
566 HIDPARSER_STATUS
567 HidParser_GetUsageValueWithReport(
568 IN PHID_PARSER Parser,
569 IN PVOID CollectionContext,
570 IN UCHAR ReportType,
571 IN USAGE UsagePage,
572 IN USAGE Usage,
573 OUT PULONG UsageValue,
574 IN PCHAR ReportDescriptor,
575 IN ULONG ReportDescriptorLength)
576 {
577 ULONG Index;
578 PHID_REPORT Report;
579 USHORT CurrentUsagePage;
580 PHID_REPORT_ITEM ReportItem;
581 ULONG Data;
582
583 //
584 // get report
585 //
586 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
587 if (!Report)
588 {
589 //
590 // no such report
591 //
592 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
593 }
594
595 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
596 {
597 //
598 // invalid report descriptor length
599 //
600 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
601 }
602
603 for(Index = 0; Index < Report->ItemCount; Index++)
604 {
605 //
606 // get report item
607 //
608 ReportItem = &Report->Items[Index];
609
610 //
611 // check usage page
612 //
613 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
614
615 //
616 // does usage page match
617 //
618 if (UsagePage != CurrentUsagePage)
619 continue;
620
621 //
622 // does the usage match
623 //
624 if (Usage != (ReportItem->UsageMinimum & 0xFFFF))
625 continue;
626
627 //
628 // check if the specified usage is activated
629 //
630 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
631
632 //
633 // one extra shift for skipping the prepended report id
634 //
635 Data = 0;
636 Parser->Copy(&Data, &ReportDescriptor[ReportItem->ByteOffset +1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1)));
637 //Data = ReportDescriptor[ReportItem->ByteOffset + 1];
638
639 //
640 // shift data
641 //
642 Data >>= ReportItem->Shift;
643
644 //
645 // clear unwanted bits
646 //
647 Data &= ReportItem->Mask;
648
649 //
650 // store result
651 //
652 *UsageValue = Data;
653 return HIDPARSER_STATUS_SUCCESS;
654 }
655
656 //
657 // usage not found
658 //
659 return HIDPARSER_STATUS_USAGE_NOT_FOUND;
660 }
661
662
663
664 HIDPARSER_STATUS
665 HidParser_GetScaledUsageValueWithReport(
666 IN PHID_PARSER Parser,
667 IN PVOID CollectionContext,
668 IN UCHAR ReportType,
669 IN USAGE UsagePage,
670 IN USAGE Usage,
671 OUT PLONG UsageValue,
672 IN PCHAR ReportDescriptor,
673 IN ULONG ReportDescriptorLength)
674 {
675 ULONG Index;
676 PHID_REPORT Report;
677 USHORT CurrentUsagePage;
678 PHID_REPORT_ITEM ReportItem;
679 ULONG Data;
680
681 //
682 // get report
683 //
684 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
685 if (!Report)
686 {
687 //
688 // no such report
689 //
690 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
691 }
692
693 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
694 {
695 //
696 // invalid report descriptor length
697 //
698 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
699 }
700
701 for(Index = 0; Index < Report->ItemCount; Index++)
702 {
703 //
704 // get report item
705 //
706 ReportItem = &Report->Items[Index];
707
708 //
709 // check usage page
710 //
711 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
712
713 //
714 // does usage page match
715 //
716 if (UsagePage != CurrentUsagePage)
717 continue;
718
719 //
720 // does the usage match
721 //
722 if (Usage != (ReportItem->UsageMinimum & 0xFFFF))
723 continue;
724
725 //
726 // check if the specified usage is activated
727 //
728 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
729
730 //
731 // one extra shift for skipping the prepended report id
732 //
733 Data = 0;
734 Parser->Copy(&Data, &ReportDescriptor[ReportItem->ByteOffset +1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1)));
735 Data = ReportDescriptor[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 // HACK: 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 //
818 // invalid usage
819 //
820 return 0;
821 }
822
823 VOID
824 HidParser_DispatchKey(
825 IN PCHAR ScanCodes,
826 IN HIDP_KEYBOARD_DIRECTION KeyAction,
827 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
828 IN PVOID InsertCodesContext)
829 {
830 ULONG Index;
831 ULONG Length = 0;
832
833 //
834 // count code length
835 //
836 for(Index = 0; Index < sizeof(ULONG); Index++)
837 {
838 if (ScanCodes[Index] == 0)
839 {
840 //
841 // last scan code
842 //
843 break;
844 }
845
846 //
847 // is this a key break
848 //
849 if (KeyAction == HidP_Keyboard_Break)
850 {
851 //
852 // add break - see USB HID to PS/2 Scan Code Translation Table
853 //
854 ScanCodes[Index] |= 0x80;
855 }
856
857 //
858 // more scan counts
859 //
860 Length++;
861 }
862
863 if (Length > 0)
864 {
865 //
866 // dispatch scan codes
867 //
868 InsertCodesProcedure(InsertCodesContext, ScanCodes, Length);
869 }
870 }
871
872 HIDPARSER_STATUS
873 HidParser_TranslateKbdUsage(
874 IN PHID_PARSER Parser,
875 IN USAGE Usage,
876 IN HIDP_KEYBOARD_DIRECTION KeyAction,
877 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,
878 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
879 IN PVOID InsertCodesContext)
880 {
881 ULONG ScanCode;
882 CHAR FakeShift[] = {0xE0, 0x2A, 0x00};
883 CHAR FakeCtrl[] = {0xE1, 0x1D, 0x00};
884
885 //
886 // get scan code
887 //
888 ScanCode = HidParser_GetScanCodeFromKbdUsage(Usage);
889 if (!ScanCode)
890 {
891 //
892 // invalid lookup or no scan code available
893 //
894 DPRINT1("No Scan code for Usage %x\n", Usage);
895 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN;
896 }
897
898 if (ScanCode & 0xFF00)
899 {
900 //
901 // swap scan code
902 //
903 ScanCode = NTOHS(ScanCode);
904 }
905
906 if (Usage == 0x46 && KeyAction == HidP_Keyboard_Make)
907 {
908 // Print Screen generates additional FakeShift
909 HidParser_DispatchKey(FakeShift, KeyAction, InsertCodesProcedure, InsertCodesContext);
910 }
911
912 if (Usage == 0x48)
913 {
914 // Pause/Break generates additional FakeCtrl. Note: it's always before key press/release.
915 HidParser_DispatchKey(FakeCtrl, KeyAction, InsertCodesProcedure, InsertCodesContext);
916 }
917
918 //
919 // FIXME: translate modifier states
920 //
921 HidParser_DispatchKey((PCHAR)&ScanCode, KeyAction, InsertCodesProcedure, InsertCodesContext);
922
923 if (Usage == 0x46 && KeyAction == HidP_Keyboard_Break)
924 {
925 // Print Screen generates additional FakeShift
926 HidParser_DispatchKey(FakeShift, KeyAction, InsertCodesProcedure, InsertCodesContext);
927 }
928
929 //
930 // done
931 //
932 return HIDPARSER_STATUS_SUCCESS;
933 }
934
935 HIDPARSER_STATUS
936 HidParser_TranslateCustUsage(
937 IN PHID_PARSER Parser,
938 IN USAGE Usage,
939 IN HIDP_KEYBOARD_DIRECTION KeyAction,
940 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,
941 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
942 IN PVOID InsertCodesContext)
943 {
944 ULONG ScanCode;
945
946 //
947 // get scan code
948 //
949 ScanCode = HidParser_GetScanCodeFromCustUsage(Usage);
950 if (!ScanCode)
951 {
952 //
953 // invalid lookup or no scan code available
954 //
955 DPRINT1("No Scan code for Usage %x\n", Usage);
956 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN;
957 }
958
959 if (ScanCode & 0xFF00)
960 {
961 //
962 // swap scan code
963 //
964 ScanCode = NTOHS(ScanCode);
965 }
966
967 //
968 // FIXME: translate modifier states
969 //
970 HidParser_DispatchKey((PCHAR)&ScanCode, KeyAction, InsertCodesProcedure, InsertCodesContext);
971
972 //
973 // done
974 //
975 return HIDPARSER_STATUS_SUCCESS;
976 }