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