[MOUHID]
[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 // FIXME: support items with variable bitlength
634 //
635 ASSERT(ReportItem->BitCount == 16);
636 Data = (ReportDescriptor[ReportItem->ByteOffset +1] & 0xFF) | (ReportDescriptor[ReportItem->ByteOffset +2] & 0xFF) << 8;
637
638 //
639 // shift data
640 //
641 Data >>= ReportItem->Shift;
642
643 //
644 // clear unwanted bits
645 //
646 Data &= ReportItem->Mask;
647
648 //
649 // store result
650 //
651 *UsageValue = Data;
652 return HIDPARSER_STATUS_SUCCESS;
653 }
654
655 //
656 // usage not found
657 //
658 return HIDPARSER_STATUS_USAGE_NOT_FOUND;
659 }
660
661
662
663 HIDPARSER_STATUS
664 HidParser_GetScaledUsageValueWithReport(
665 IN PHID_PARSER Parser,
666 IN PVOID CollectionContext,
667 IN UCHAR ReportType,
668 IN USAGE UsagePage,
669 IN USAGE Usage,
670 OUT PLONG UsageValue,
671 IN PCHAR ReportDescriptor,
672 IN ULONG ReportDescriptorLength)
673 {
674 ULONG Index;
675 PHID_REPORT Report;
676 USHORT CurrentUsagePage;
677 PHID_REPORT_ITEM ReportItem;
678 ULONG Data;
679
680 //
681 // get report
682 //
683 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
684 if (!Report)
685 {
686 //
687 // no such report
688 //
689 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
690 }
691
692 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
693 {
694 //
695 // invalid report descriptor length
696 //
697 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
698 }
699
700 for(Index = 0; Index < Report->ItemCount; Index++)
701 {
702 //
703 // get report item
704 //
705 ReportItem = &Report->Items[Index];
706
707 //
708 // check usage page
709 //
710 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
711
712 //
713 // does usage page match
714 //
715 if (UsagePage != CurrentUsagePage)
716 continue;
717
718 //
719 // does the usage match
720 //
721 if (Usage != (ReportItem->UsageMinimum & 0xFFFF))
722 continue;
723
724 //
725 // check if the specified usage is activated
726 //
727 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
728
729 //
730 // one extra shift for skipping the prepended report id
731 //
732 Data = 0;
733 Parser->Copy(&Data, &ReportDescriptor[ReportItem->ByteOffset +1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1)));
734 Data = ReportDescriptor[ReportItem->ByteOffset + 1];
735
736 //
737 // shift data
738 //
739 Data >>= ReportItem->Shift;
740
741 //
742 // clear unwanted bits
743 //
744 Data &= ReportItem->Mask;
745
746 if (ReportItem->Minimum > ReportItem->Maximum)
747 {
748 //
749 // logical boundaries are signed values
750 //
751
752 // FIXME: scale with physical min/max
753 if ((Data & ~(ReportItem->Mask >> 1)) != 0)
754 {
755 Data |= ~ReportItem->Mask;
756 }
757 }
758 else
759 {
760 // HACK: logical boundaries are absolute values
761 return HIDPARSER_STATUS_BAD_LOG_PHY_VALUES;
762 }
763
764 //
765 // store result
766 //
767 *UsageValue = Data;
768 return HIDPARSER_STATUS_SUCCESS;
769 }
770
771 //
772 // usage not found
773 //
774 return HIDPARSER_STATUS_USAGE_NOT_FOUND;
775 }
776
777 ULONG
778 HidParser_GetScanCodeFromKbdUsage(
779 IN USAGE Usage)
780 {
781 if (Usage < sizeof(KeyboardScanCodes) / sizeof(KeyboardScanCodes[0]))
782 {
783 //
784 // valid usage
785 //
786 return KeyboardScanCodes[Usage];
787 }
788
789 //
790 // invalid usage
791 //
792 return 0;
793 }
794
795 ULONG
796 HidParser_GetScanCodeFromCustUsage(
797 IN USAGE Usage)
798 {
799 ULONG i;
800
801 //
802 // find usage in array
803 //
804 for (i = 0; i < sizeof(CustomerScanCodes) / sizeof(CustomerScanCodes[0]); ++i)
805 {
806 if (CustomerScanCodes[i].Usage == Usage)
807 {
808 //
809 // valid usage
810 //
811 return CustomerScanCodes[i].ScanCode;
812 }
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 }