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