[HIDPARSE]
[reactos.git] / 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 {
16 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
17 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
18 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
19 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
20 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
21 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
22 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
23 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
24 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
25 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
27 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
28 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
29 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
30 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
31 150,158,159,128,136,177,178,176,142,152,173,140
32 };
33
34
35
36 ULONG
37 HidParser_NumberOfTopCollections(
38 IN PHID_PARSER Parser)
39 {
40 PHID_PARSER_CONTEXT ParserContext;
41
42 //
43 // get parser context
44 //
45 ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
46
47 //
48 // sanity checks
49 //
50 ASSERT(ParserContext);
51 ASSERT(ParserContext->RootCollection);
52 ASSERT(ParserContext->RootCollection->NodeCount);
53
54 //
55 // number of top collections
56 //
57 return ParserContext->RootCollection->NodeCount;
58 }
59
60 PHID_COLLECTION
61 HidParser_GetCollection(
62 IN PHID_PARSER Parser,
63 IN ULONG CollectionNumber)
64 {
65 PHID_PARSER_CONTEXT ParserContext;
66
67 //
68 // get parser context
69 //
70 ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
71
72 //
73 // sanity checks
74 //
75 ASSERT(ParserContext);
76 ASSERT(ParserContext->RootCollection);
77 ASSERT(ParserContext->RootCollection->NodeCount);
78
79 //
80 // is collection index out of bounds
81 //
82 if (CollectionNumber < ParserContext->RootCollection->NodeCount)
83 {
84 //
85 // valid collection
86 //
87 return ParserContext->RootCollection->Nodes[CollectionNumber];
88 }
89
90 //
91 // no such collection
92 //
93 Parser->Debug("HIDPARSE] No such collection %lu\n", CollectionNumber);
94 return NULL;
95 }
96
97 PHID_REPORT
98 HidParser_GetReportInCollection(
99 PHID_COLLECTION Collection,
100 IN UCHAR ReportType)
101 {
102 ULONG Index;
103 PHID_REPORT Report;
104
105 //
106 // search in local array
107 //
108 for(Index = 0; Index < Collection->ReportCount; Index++)
109 {
110 if (Collection->Reports[Index]->Type == ReportType)
111 {
112 //
113 // found report
114 //
115 return Collection->Reports[Index];
116 }
117 }
118
119 //
120 // search in local array
121 //
122 for(Index = 0; Index < Collection->NodeCount; Index++)
123 {
124 Report = HidParser_GetReportInCollection(Collection->Nodes[Index], ReportType);
125 if (Report)
126 {
127 //
128 // found report
129 //
130 return Report;
131 }
132 }
133
134 //
135 // not found
136 //
137 return NULL;
138 }
139
140 PHID_REPORT
141 HidParser_GetReportByType(
142 IN PHID_PARSER Parser,
143 IN ULONG CollectionIndex,
144 IN UCHAR ReportType)
145 {
146 PHID_COLLECTION Collection;
147
148 //
149 // find collection
150 //
151 Collection = HidParser_GetCollection(Parser, CollectionIndex);
152 if (!Collection)
153 {
154 //
155 // no such collection
156 //
157 ASSERT(FALSE);
158 return NULL;
159 }
160
161 //
162 // search report
163 //
164 return HidParser_GetReportInCollection(Collection, ReportType);
165 }
166
167 HIDPARSER_STATUS
168 HidParser_GetCollectionUsagePage(
169 IN PHID_PARSER Parser,
170 IN ULONG CollectionIndex,
171 OUT PUSHORT Usage,
172 OUT PUSHORT UsagePage)
173 {
174 PHID_COLLECTION Collection;
175
176 //
177 // find collection
178 //
179 Collection = HidParser_GetCollection(Parser, CollectionIndex);
180 if (!Collection)
181 {
182 //
183 // collection not found
184 //
185 return HIDPARSER_STATUS_COLLECTION_NOT_FOUND;
186 }
187
188 //
189 // store result
190 //
191 *UsagePage = (Collection->Usage >> 16);
192 *Usage = (Collection->Usage & 0xFFFF);
193 return HIDPARSER_STATUS_SUCCESS;
194 }
195
196 ULONG
197 HidParser_GetReportLength(
198 IN PHID_PARSER Parser,
199 IN ULONG CollectionIndex,
200 IN ULONG ReportType)
201 {
202 PHID_PARSER_CONTEXT ParserContext;
203 PHID_REPORT Report;
204 ULONG ReportLength;
205
206 //
207 // get parser context
208 //
209 ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
210
211 //
212 // sanity checks
213 //
214 ASSERT(ParserContext);
215
216 //
217 // FIXME support multiple top collecions
218 //
219 ASSERT(ParserContext->RootCollection->NodeCount == 1);
220
221 //
222 // get first report
223 //
224 Report = HidParser_GetReportByType(Parser, CollectionIndex, ReportType);
225 if (!Report)
226 {
227 //
228 // no report found
229 //
230 return 0;
231 }
232
233 //
234 // get report length
235 //
236 ReportLength = Report->ReportSize;
237
238 //
239 // done
240 //
241 if (ReportLength)
242 {
243 //
244 // byte aligned length
245 //
246 ASSERT(ReportLength % 8 == 0);
247 return ReportLength / 8;
248 }
249 return ReportLength;
250 }
251
252 UCHAR
253 HidParser_IsReportIDUsed(
254 IN PHID_PARSER Parser)
255 {
256 PHID_PARSER_CONTEXT ParserContext;
257
258 //
259 // get parser context
260 //
261 ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
262
263 //
264 // sanity checks
265 //
266 ASSERT(ParserContext);
267
268 //
269 // return flag
270 //
271 return ParserContext->UseReportIDs;
272 }
273
274 ULONG
275 HidParser_GetReportItemCountFromReportType(
276 IN PHID_PARSER Parser,
277 IN ULONG CollectionIndex,
278 IN ULONG ReportType)
279 {
280 PHID_PARSER_CONTEXT ParserContext;
281 PHID_REPORT Report;
282
283 //
284 // get parser context
285 //
286 ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
287
288 //
289 // sanity checks
290 //
291 ASSERT(ParserContext);
292
293 //
294 // FIXME support multiple top collecions
295 //
296 ASSERT(ParserContext->RootCollection->NodeCount == 1);
297
298 //
299 // get report
300 //
301 Report = HidParser_GetReportByType(Parser, CollectionIndex, ReportType);
302 if (!Report)
303 {
304 //
305 // no such report
306 //
307 return 0;
308 }
309
310 //
311 // return report item count
312 //
313 return Report->ItemCount;
314 }
315
316
317 ULONG
318 HidParser_GetReportItemTypeCountFromReportType(
319 IN PHID_PARSER Parser,
320 IN ULONG CollectionIndex,
321 IN ULONG ReportType,
322 IN ULONG bData)
323 {
324 PHID_PARSER_CONTEXT ParserContext;
325 ULONG Index;
326 PHID_REPORT Report;
327 ULONG ItemCount = 0;
328
329 //
330 // get parser context
331 //
332 ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
333
334 //
335 // sanity checks
336 //
337 ASSERT(ParserContext);
338
339 //
340 // FIXME support multiple top collecions
341 //
342 ASSERT(ParserContext->RootCollection->NodeCount == 1);
343
344 //
345 // get report
346 //
347 Report = HidParser_GetReportByType(Parser, CollectionIndex, ReportType);
348 if (!Report)
349 {
350 //
351 // no such report
352 //
353 return 0;
354 }
355
356 //
357 // enumerate all items
358 //
359 for(Index = 0; Index < Report->ItemCount; Index++)
360 {
361 //
362 // check item type
363 //
364 if (Report->Items[Index]->HasData && bData == TRUE)
365 {
366 //
367 // found data item
368 //
369 ItemCount++;
370 }
371 else if (Report->Items[Index]->HasData == FALSE && bData == FALSE)
372 {
373 //
374 // found value item
375 //
376 ItemCount++;
377 }
378 }
379
380 //
381 // no report items
382 //
383 return ItemCount;
384 }
385
386 ULONG
387 HidParser_GetContextSize(
388 IN PHID_PARSER Parser,
389 IN ULONG CollectionIndex)
390 {
391 //
392 // FIXME the context must contain all parsed info
393 //
394 return sizeof(HID_PARSER_CONTEXT);
395 }
396
397 VOID
398 HidParser_FreeContext(
399 IN PHID_PARSER Parser,
400 IN PUCHAR Context,
401 IN ULONG ContextLength)
402 {
403 //
404 // FIXME implement freeing of parsed info
405 //
406 }
407
408 HIDPARSER_STATUS
409 HidParser_AllocateParser(
410 IN PHIDPARSER_ALLOC_FUNCTION AllocFunction,
411 IN PHIDPARSER_FREE_FUNCTION FreeFunction,
412 IN PHIDPARSER_ZERO_FUNCTION ZeroFunction,
413 IN PHIDPARSER_COPY_FUNCTION CopyFunction,
414 IN PHIDPARSER_DEBUG_FUNCTION DebugFunction,
415 OUT PHID_PARSER *OutParser)
416 {
417 PHID_PARSER Parser;
418 PHID_PARSER_CONTEXT ParserContext;
419
420 //
421 // allocate
422 //
423 Parser = (PHID_PARSER)AllocFunction(sizeof(HID_PARSER));
424 if (!Parser)
425 {
426 //
427 // no memory
428 //
429 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
430 }
431
432 //
433 // allocate parser context
434 //
435 ParserContext = (PHID_PARSER_CONTEXT)AllocFunction(sizeof(HID_PARSER_CONTEXT));
436 if (!ParserContext)
437 {
438 //
439 // no memory
440 //
441 FreeFunction(Parser);
442 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
443 }
444
445
446 //
447 // init parser
448 //
449 Parser->Alloc = AllocFunction;
450 Parser->Free = FreeFunction;
451 Parser->Zero = ZeroFunction;
452 Parser->Copy = CopyFunction;
453 Parser->Debug = DebugFunction;
454 Parser->ParserContext = ParserContext;
455
456 //
457 // store result
458 //
459 *OutParser = Parser;
460 //
461 // success
462 //
463 return HIDPARSER_STATUS_SUCCESS;
464 }
465
466 VOID
467 HidParser_InitParser(
468 IN PHIDPARSER_ALLOC_FUNCTION AllocFunction,
469 IN PHIDPARSER_FREE_FUNCTION FreeFunction,
470 IN PHIDPARSER_ZERO_FUNCTION ZeroFunction,
471 IN PHIDPARSER_COPY_FUNCTION CopyFunction,
472 IN PHIDPARSER_DEBUG_FUNCTION DebugFunction,
473 IN PVOID ParserContext,
474 OUT PHID_PARSER Parser)
475 {
476 Parser->Alloc = AllocFunction;
477 Parser->Free = FreeFunction;
478 Parser->Zero = ZeroFunction;
479 Parser->Copy = CopyFunction;
480 Parser->Debug = DebugFunction;
481 Parser->ParserContext = ParserContext;
482 }
483
484 ULONG
485 HidParser_GetCollectionCount(
486 IN PHID_COLLECTION Collection)
487 {
488 ULONG Index;
489 ULONG Count = Collection->NodeCount;
490
491 for(Index = 0; Index < Collection->NodeCount; Index++)
492 {
493 //
494 // count collection for sub nodes
495 //
496 Count += HidParser_GetCollectionCount(Collection->Nodes[Index]);
497 }
498
499 //
500 // done
501 //
502 return Count;
503 }
504
505 ULONG
506 HidParser_GetTotalCollectionCount(
507 IN PHID_PARSER Parser)
508 {
509 PHID_PARSER_CONTEXT ParserContext;
510
511 //
512 // get parser context
513 //
514 ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
515
516 //
517 // sanity check
518 //
519 ASSERT(ParserContext);
520 ASSERT(ParserContext->RootCollection);
521
522 //
523 // count collections
524 //
525 return HidParser_GetCollectionCount(ParserContext->RootCollection);
526 }
527
528 ULONG
529 HidParser_GetMaxUsageListLengthWithReportAndPage(
530 IN PHID_PARSER Parser,
531 IN ULONG CollectionIndex,
532 IN ULONG ReportType,
533 IN USAGE UsagePage OPTIONAL)
534 {
535 PHID_PARSER_CONTEXT ParserContext;
536 ULONG Index;
537 PHID_REPORT Report;
538 ULONG ItemCount = 0;
539 USHORT CurrentUsagePage;
540
541 //
542 // get parser context
543 //
544 ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
545
546 //
547 // sanity checks
548 //
549 ASSERT(ParserContext);
550
551 //
552 // FIXME support multiple top collecions
553 //
554 ASSERT(ParserContext->RootCollection->NodeCount == 1);
555
556 //
557 // get report
558 //
559 Report = HidParser_GetReportByType(Parser, CollectionIndex, ReportType);
560 if (!Report)
561 {
562 //
563 // no such report
564 //
565 return 0;
566 }
567
568 for(Index = 0; Index < Report->ItemCount; Index++)
569 {
570 //
571 // check usage page
572 //
573 CurrentUsagePage = (Report->Items[Index]->UsageMinimum >> 16);
574 if (CurrentUsagePage == UsagePage && Report->Items[Index]->HasData)
575 {
576 //
577 // found item
578 //
579 ItemCount++;
580 }
581 }
582
583 //
584 // done
585 //
586 return ItemCount;
587 }
588
589 HIDPARSER_STATUS
590 HidParser_GetSpecificValueCapsWithReport(
591 IN PHID_PARSER Parser,
592 IN ULONG CollectionIndex,
593 IN ULONG ReportType,
594 IN USHORT UsagePage,
595 IN USHORT Usage,
596 OUT PHIDP_VALUE_CAPS ValueCaps,
597 IN OUT PULONG ValueCapsLength)
598 {
599 PHID_PARSER_CONTEXT ParserContext;
600 ULONG Index;
601 PHID_REPORT Report;
602 ULONG ItemCount = 0;
603 USHORT CurrentUsagePage;
604 USHORT CurrentUsage;
605
606 //
607 // get parser context
608 //
609 ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
610
611 //
612 // sanity checks
613 //
614 ASSERT(ParserContext);
615
616 //
617 // FIXME support multiple top collecions
618 //
619 ASSERT(ParserContext->RootCollection->NodeCount == 1);
620
621 //
622 // get report
623 //
624 Report = HidParser_GetReportByType(Parser, CollectionIndex, ReportType);
625 if (!Report)
626 {
627 //
628 // no such report
629 //
630 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
631 }
632
633 for(Index = 0; Index < Report->ItemCount; Index++)
634 {
635 //
636 // check usage page
637 //
638 CurrentUsagePage = (Report->Items[Index]->UsageMinimum >> 16);
639 CurrentUsage = (Report->Items[Index]->UsageMinimum & 0xFFFF);
640
641 if ((Usage == CurrentUsage && UsagePage == CurrentUsagePage) || (Usage == 0 && UsagePage == CurrentUsagePage) || (Usage == CurrentUsage && UsagePage == 0) || (Usage == 0 && UsagePage == 0))
642 {
643 //
644 // check if there is enough place for the caps
645 //
646 if (ItemCount < *ValueCapsLength)
647 {
648 //
649 // zero caps
650 //
651 Parser->Zero(&ValueCaps[ItemCount], sizeof(HIDP_VALUE_CAPS));
652
653 //
654 // init caps
655 //
656 ValueCaps[ItemCount].UsagePage = CurrentUsagePage;
657 ValueCaps[ItemCount].ReportID = Report->ReportID;
658 ValueCaps[ItemCount].LogicalMin = Report->Items[Index]->Minimum;
659 ValueCaps[ItemCount].LogicalMax = Report->Items[Index]->Maximum;
660 ValueCaps[ItemCount].IsAbsolute = !Report->Items[Index]->Relative;
661 ValueCaps[ItemCount].BitSize = Report->Items[Index]->BitCount;
662
663 //
664 // FIXME: FILLMEIN
665 //
666 }
667
668
669 //
670 // found item
671 //
672 ItemCount++;
673 }
674 }
675
676 //
677 // store result
678 //
679 *ValueCapsLength = ItemCount;
680
681 if (ItemCount)
682 {
683 //
684 // success
685 //
686 return HIDPARSER_STATUS_SUCCESS;
687 }
688
689 //
690 // item not found
691 //
692 return HIDPARSER_STATUS_USAGE_NOT_FOUND;
693 }
694
695 HIDPARSER_STATUS
696 HidParser_GetUsagesWithReport(
697 IN PHID_PARSER Parser,
698 IN ULONG CollectionIndex,
699 IN ULONG ReportType,
700 IN USAGE UsagePage,
701 OUT USAGE *UsageList,
702 IN OUT PULONG UsageLength,
703 IN PCHAR ReportDescriptor,
704 IN ULONG ReportDescriptorLength)
705 {
706 PHID_PARSER_CONTEXT ParserContext;
707 ULONG Index;
708 PHID_REPORT Report;
709 ULONG ItemCount = 0;
710 USHORT CurrentUsagePage;
711 PHID_REPORT_ITEM ReportItem;
712 UCHAR Activated;
713 ULONG Data;
714
715 //
716 // get parser context
717 //
718 ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
719
720 //
721 // sanity checks
722 //
723 ASSERT(ParserContext);
724
725 //
726 // FIXME support multiple top collecions
727 //
728 ASSERT(ParserContext->RootCollection->NodeCount == 1);
729
730 //
731 // get report
732 //
733 Report = HidParser_GetReportByType(Parser, CollectionIndex, ReportType);
734 if (!Report)
735 {
736 //
737 // no such report
738 //
739 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
740 }
741
742 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
743 {
744 //
745 // invalid report descriptor length
746 //
747 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
748 }
749
750 for(Index = 0; Index < Report->ItemCount; Index++)
751 {
752 //
753 // get report item
754 //
755 ReportItem = Report->Items[Index];
756
757 //
758 // does it have data
759 //
760 if (!ReportItem->HasData)
761 continue;
762
763 //
764 // check usage page
765 //
766 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
767
768 //
769 // does usage match
770 //
771 if (UsagePage != CurrentUsagePage)
772 continue;
773
774 //
775 // check if the specified usage is activated
776 //
777 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
778 ASSERT(ReportItem->BitCount < 8);
779
780 //
781 // one extra shift for skipping the prepended report id
782 //
783 Data = ReportDescriptor[ReportItem->ByteOffset + 1];
784
785 //
786 // shift data
787 //
788 Data >>= ReportItem->Shift;
789
790 //
791 // clear unwanted bits
792 //
793 Data &= ReportItem->Mask;
794
795 //
796 // is it activated
797 //
798 Activated = (Data != 0);
799
800 if (!Activated)
801 continue;
802
803 //
804 // is there enough space for the usage
805 //
806 if (ItemCount >= *UsageLength)
807 {
808 ItemCount++;
809 continue;
810 }
811
812 //
813 // store item
814 //
815 UsageList[ItemCount] = (ReportItem->UsageMinimum & 0xFFFF);
816 ItemCount++;
817 }
818
819 if (ItemCount > *UsageLength)
820 {
821 //
822 // list too small
823 //
824 return HIDPARSER_STATUS_BUFFER_TOO_SMALL;
825 }
826
827 //
828 // success, clear rest of array
829 //
830 Parser->Zero(&UsageList[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE));
831
832 //
833 // store result size
834 //
835 *UsageLength = ItemCount;
836
837 //
838 // done
839 //
840 return HIDPARSER_STATUS_SUCCESS;
841 }
842
843 HIDPARSER_STATUS
844 HidParser_GetScaledUsageValueWithReport(
845 IN PHID_PARSER Parser,
846 IN ULONG CollectionIndex,
847 IN ULONG ReportType,
848 IN USAGE UsagePage,
849 IN USAGE Usage,
850 OUT PLONG UsageValue,
851 IN PCHAR ReportDescriptor,
852 IN ULONG ReportDescriptorLength)
853 {
854 PHID_PARSER_CONTEXT ParserContext;
855 ULONG Index;
856 PHID_REPORT Report;
857 USHORT CurrentUsagePage;
858 PHID_REPORT_ITEM ReportItem;
859 ULONG Data;
860
861 //
862 // get parser context
863 //
864 ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
865
866 //
867 // sanity checks
868 //
869 ASSERT(ParserContext);
870
871 //
872 // FIXME support multiple top collecions
873 //
874 ASSERT(ParserContext->RootCollection->NodeCount == 1);
875
876 //
877 // get report
878 //
879 Report = HidParser_GetReportByType(Parser, CollectionIndex, ReportType);
880 if (!Report)
881 {
882 //
883 // no such report
884 //
885 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
886 }
887
888 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
889 {
890 //
891 // invalid report descriptor length
892 //
893 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
894 }
895
896 for(Index = 0; Index < Report->ItemCount; Index++)
897 {
898 //
899 // get report item
900 //
901 ReportItem = Report->Items[Index];
902
903 //
904 // check usage page
905 //
906 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
907
908 //
909 // does usage page match
910 //
911 if (UsagePage != CurrentUsagePage)
912 continue;
913
914 //
915 // does the usage match
916 //
917 if (Usage != (ReportItem->UsageMinimum & 0xFFFF))
918 continue;
919
920 //
921 // check if the specified usage is activated
922 //
923 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
924
925 //
926 // one extra shift for skipping the prepended report id
927 //
928 Data = 0;
929 Parser->Copy(&Data, &ReportDescriptor[ReportItem->ByteOffset +1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1)));
930 Data = ReportDescriptor[ReportItem->ByteOffset + 1];
931
932 //
933 // shift data
934 //
935 Data >>= ReportItem->Shift;
936
937 //
938 // clear unwanted bits
939 //
940 Data &= ReportItem->Mask;
941
942 if (ReportItem->Minimum > ReportItem->Maximum)
943 {
944 //
945 // logical boundaries are signed values
946 //
947 if ((Data & ~(ReportItem->Mask >> 1)) != 0)
948 {
949 Data |= ~ReportItem->Mask;
950 }
951 }
952
953 //
954 // store result
955 //
956 *UsageValue = Data;
957 return HIDPARSER_STATUS_SUCCESS;
958 }
959
960 //
961 // usage not found
962 //
963 return HIDPARSER_STATUS_USAGE_NOT_FOUND;
964 }
965
966 ULONG
967 HidParser_GetScanCode(
968 IN USAGE Usage)
969 {
970 if (Usage < sizeof(KeyboardScanCodes) / sizeof(KeyboardScanCodes[0]))
971 {
972 //
973 // valid usage
974 //
975 return KeyboardScanCodes[Usage];
976 }
977
978 //
979 // invalid usage
980 //
981 return 0;
982 }
983
984 VOID
985 HidParser_DispatchKey(
986 IN PCHAR ScanCodes,
987 IN HIDP_KEYBOARD_DIRECTION KeyAction,
988 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
989 IN PVOID InsertCodesContext)
990 {
991 ULONG Index;
992 ULONG Length = 0;
993
994 //
995 // count code length
996 //
997 for(Index = 0; Index < sizeof(ULONG); Index++)
998 {
999 if (ScanCodes[Index] == 0)
1000 {
1001 //
1002 // last scan code
1003 //
1004 break;
1005 }
1006
1007 //
1008 // is this a key break
1009 //
1010 if (KeyAction == HidP_Keyboard_Break)
1011 {
1012 //
1013 // add break
1014 //
1015 ScanCodes[Index] |= KEY_BREAK;
1016 }
1017
1018 //
1019 // more scan counts
1020 //
1021 Length++;
1022 }
1023
1024 if (Length > 0)
1025 {
1026 //
1027 // dispatch scan codes
1028 //
1029 InsertCodesProcedure(InsertCodesContext, ScanCodes, Length);
1030 }
1031 }
1032
1033
1034 HIDPARSER_STATUS
1035 HidParser_TranslateUsage(
1036 IN PHID_PARSER Parser,
1037 IN ULONG CollectionIndex,
1038 IN USAGE Usage,
1039 IN HIDP_KEYBOARD_DIRECTION KeyAction,
1040 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,
1041 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
1042 IN PVOID InsertCodesContext)
1043 {
1044 ULONG ScanCode;
1045
1046 //
1047 // get scan code
1048 //
1049 ScanCode = HidParser_GetScanCode(Usage);
1050 if (!ScanCode)
1051 {
1052 //
1053 // invalid lookup or no scan code available
1054 //
1055 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN;
1056 }
1057
1058 //
1059 // FIXME: translate modifier states
1060 //
1061
1062 HidParser_DispatchKey((PCHAR)&ScanCode, KeyAction, InsertCodesProcedure, InsertCodesContext);
1063
1064 //
1065 // done
1066 //
1067 return HIDPARSER_STATUS_SUCCESS;
1068 }
1069
1070 ULONG
1071 HidParser_GetCollectionNumberFromParserContext(
1072 IN PHID_PARSER Parser)
1073 {
1074 PHID_PARSER_CONTEXT Context = (PHID_PARSER_CONTEXT)Parser->ParserContext;
1075
1076 //
1077 // get parser context
1078 //
1079 return Context->CollectionIndex;
1080 }