[HIDPARSER]
[reactos.git] / lib / drivers / hidparser / parser.c
1 /*
2 * PROJECT: ReactOS HID Parser Library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: lib/drivers/hidparser/parser.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 UCHAR ItemSize[4] = { 0, 1, 2, 4 };
15
16 VOID
17 HidParser_DeleteReport(
18 IN PHID_PARSER Parser,
19 IN PHID_REPORT Report)
20 {
21 //
22 // not implemented
23 //
24 }
25
26 VOID
27 HidParser_FreeCollection(
28 IN PHID_PARSER Parser,
29 IN PHID_COLLECTION Collection)
30 {
31 //
32 // not implemented
33 //
34 }
35
36 HIDPARSER_STATUS
37 HidParser_AllocateCollection(
38 IN PHID_PARSER Parser,
39 IN PHID_COLLECTION ParentCollection,
40 IN UCHAR Type,
41 IN PLOCAL_ITEM_STATE LocalItemState,
42 OUT PHID_COLLECTION * OutCollection)
43 {
44 PHID_COLLECTION Collection;
45 USAGE_VALUE UsageValue;
46
47 //
48 // first allocate the collection
49 //
50 Collection = (PHID_COLLECTION)Parser->Alloc(sizeof(HID_COLLECTION));
51 if (!Collection)
52 {
53 //
54 // no memory
55 //
56 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
57 }
58
59 //
60 // init collection
61 //
62 Collection->Root = ParentCollection;
63 Collection->Type = Type;
64 Collection->StringID = LocalItemState->StringIndex;
65 Collection->PhysicalID = LocalItemState->DesignatorIndex;
66
67 //
68 // set Usage
69 //
70 ASSERT(LocalItemState);
71 ASSERT(LocalItemState->UsageStack);
72
73 if (LocalItemState->UsageStackUsed > 0)
74 {
75 //
76 // usage value from first local stack item
77 //
78 UsageValue.u.Extended = LocalItemState->UsageStack[0].u.Extended;
79 }
80 else if (LocalItemState->UsageMinimumSet)
81 {
82 //
83 // use value from minimum
84 //
85 UsageValue.u.Extended = LocalItemState->UsageMinimum.u.Extended;
86 }
87 else if (LocalItemState->UsageMaximumSet)
88 {
89 //
90 // use value from maximum
91 //
92 UsageValue.u.Extended = LocalItemState->UsageMaximum.u.Extended;
93 }
94 else if (Type == COLLECTION_LOGICAL)
95 {
96 //
97 // root collection
98 //
99 UsageValue.u.Extended = 0;
100 }
101 else
102 {
103 //
104 // no usage set
105 //
106 Parser->Debug("HIDPARSE] No usage set\n");
107 UsageValue.u.Extended = 0;
108 }
109
110 //
111 // store usage
112 //
113 Collection->Usage = UsageValue.u.Extended;
114
115 //
116 // store result
117 //
118 *OutCollection = Collection;
119
120 //
121 // done
122 //
123 return HIDPARSER_STATUS_SUCCESS;
124 }
125
126 HIDPARSER_STATUS
127 HidParser_AddCollection(
128 IN PHID_PARSER Parser,
129 IN PHID_COLLECTION CurrentCollection,
130 IN PHID_COLLECTION NewCollection)
131 {
132 PHID_COLLECTION * NewAllocCollection;
133 ULONG CollectionCount;
134
135 //
136 // increment collection array
137 //
138 CollectionCount = CurrentCollection->NodeCount + 1;
139
140 //
141 // allocate new collection
142 //
143 NewAllocCollection = (PHID_COLLECTION*)Parser->Alloc(sizeof(PHID_COLLECTION) * CollectionCount);
144 if (!NewAllocCollection)
145 {
146 //
147 // no memory
148 //
149 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
150 }
151
152 if (CurrentCollection->NodeCount)
153 {
154 //
155 // copy old array
156 //
157 Parser->Copy(NewAllocCollection, CurrentCollection->Nodes, CurrentCollection->NodeCount * sizeof(PHID_COLLECTION));
158
159 //
160 // delete old array
161 //
162 Parser->Free(CurrentCollection->Nodes);
163 }
164
165 //
166 // insert new item
167 //
168 NewAllocCollection[CurrentCollection->NodeCount] = (struct __HID_COLLECTION__*)NewCollection;
169
170
171 //
172 // store new array
173 //
174 CurrentCollection->Nodes = NewAllocCollection;
175 CurrentCollection->NodeCount++;
176
177 //
178 // done
179 //
180 return HIDPARSER_STATUS_SUCCESS;
181 }
182
183 HIDPARSER_STATUS
184 HidParser_FindReportInCollection(
185 IN PHID_COLLECTION Collection,
186 IN UCHAR ReportType,
187 IN UCHAR ReportID,
188 OUT PHID_REPORT *OutReport)
189 {
190 ULONG Index;
191 HIDPARSER_STATUS Status;
192
193 //
194 // search in local list
195 //
196 for(Index = 0; Index < Collection->ReportCount; Index++)
197 {
198 if (Collection->Reports[Index]->Type == ReportType && Collection->Reports[Index]->ReportID == ReportID)
199 {
200 //
201 // found report
202 //
203 *OutReport = Collection->Reports[Index];
204 return HIDPARSER_STATUS_SUCCESS;
205 }
206 }
207
208 //
209 // search in sub collections
210 //
211 for(Index = 0; Index < Collection->NodeCount; Index++)
212 {
213 Status = HidParser_FindReportInCollection(Collection->Nodes[Index], ReportType, ReportID, OutReport);
214 if (Status == HIDPARSER_STATUS_SUCCESS)
215 return Status;
216 }
217
218 //
219 // no such report found
220 //
221 *OutReport = NULL;
222 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
223 }
224
225
226 HIDPARSER_STATUS
227 HidParser_FindReport(
228 IN PHID_PARSER Parser,
229 IN PHID_PARSER_CONTEXT ParserContext,
230 IN UCHAR ReportType,
231 IN UCHAR ReportID,
232 OUT PHID_REPORT *OutReport)
233 {
234 //
235 // search in current top level collection
236 //
237 return HidParser_FindReportInCollection(ParserContext->RootCollection->Nodes[ParserContext->RootCollection->NodeCount-1], ReportType, ReportID, OutReport);
238 }
239
240 HIDPARSER_STATUS
241 HidParser_AllocateReport(
242 IN PHID_PARSER Parser,
243 IN UCHAR ReportType,
244 IN UCHAR ReportID,
245 OUT PHID_REPORT *OutReport)
246 {
247 PHID_REPORT Report;
248
249 //
250 // allocate report
251 //
252 Report = (PHID_REPORT)Parser->Alloc(sizeof(HID_REPORT));
253 if (!Report)
254 {
255 //
256 // no memory
257 //
258 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
259 }
260
261 //
262 // init report
263 //
264 Report->ReportID = ReportID;
265 Report->Type = ReportType;
266
267 //
268 // done
269 //
270 *OutReport = Report;
271 return HIDPARSER_STATUS_SUCCESS;
272 }
273
274 HIDPARSER_STATUS
275 HidParser_AddReportToCollection(
276 IN PHID_PARSER Parser,
277 IN PHID_PARSER_CONTEXT ParserContext,
278 IN PHID_COLLECTION CurrentCollection,
279 IN PHID_REPORT NewReport)
280 {
281 PHID_REPORT * NewReportArray;
282
283 //
284 // allocate new report array
285 //
286 NewReportArray = (PHID_REPORT*)Parser->Alloc(sizeof(PHID_REPORT) * (CurrentCollection->ReportCount + 1));
287 if (!NewReportArray)
288 {
289 //
290 // no memory
291 //
292 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
293 }
294
295 if (CurrentCollection->ReportCount)
296 {
297 //
298 // copy old array contents
299 //
300 Parser->Copy(NewReportArray, CurrentCollection->Reports, sizeof(PHID_REPORT) * CurrentCollection->ReportCount);
301
302 //
303 // free old array
304 //
305 Parser->Free(CurrentCollection->Reports);
306 }
307
308 //
309 // store result
310 //
311 NewReportArray[CurrentCollection->ReportCount] = NewReport;
312 CurrentCollection->Reports = NewReportArray;
313 CurrentCollection->ReportCount++;
314
315 //
316 // completed successfully
317 //
318 return HIDPARSER_STATUS_SUCCESS;
319 }
320
321 HIDPARSER_STATUS
322 HidParser_GetReport(
323 IN PHID_PARSER Parser,
324 IN PHID_PARSER_CONTEXT ParserContext,
325 IN PHID_COLLECTION Collection,
326 IN UCHAR ReportType,
327 IN UCHAR ReportID,
328 IN UCHAR CreateIfNotExists,
329 OUT PHID_REPORT *OutReport)
330 {
331 HIDPARSER_STATUS Status;
332
333 //
334 // try finding existing report
335 //
336 Status = HidParser_FindReport(Parser, ParserContext, ReportType, ReportID, OutReport);
337 if (Status == HIDPARSER_STATUS_SUCCESS || CreateIfNotExists == FALSE)
338 {
339 //
340 // founed report
341 //
342 return Status;
343 }
344
345 //
346 // allocate new report
347 //
348 Status = HidParser_AllocateReport(Parser, ReportType, ReportID, OutReport);
349 if (Status != HIDPARSER_STATUS_SUCCESS)
350 {
351 //
352 // failed to allocate report
353 //
354 return Status;
355 }
356
357 //
358 // add report
359 //
360 Status = HidParser_AddReportToCollection(Parser, ParserContext, Collection, *OutReport);
361 if (Status != HIDPARSER_STATUS_SUCCESS)
362 {
363 //
364 // failed to allocate report
365 //
366 Parser->Free(*OutReport);
367 }
368
369 //
370 // done
371 //
372 return Status;
373 }
374
375 HIDPARSER_STATUS
376 HidParser_ReserveReportItems(
377 IN PHID_PARSER Parser,
378 IN PHID_REPORT Report,
379 IN ULONG ReportCount,
380 OUT PHID_REPORT *OutReport)
381 {
382 PHID_REPORT NewReport;
383 ULONG OldSize, Size;
384
385 if (Report->ItemCount + ReportCount <= Report->ItemAllocated)
386 {
387 //
388 // space is already allocated
389 //
390 *OutReport = Report;
391 return HIDPARSER_STATUS_SUCCESS;
392 }
393
394 //
395 //calculate new size
396 //
397 OldSize = sizeof(HID_REPORT) + (Report->ItemCount) * sizeof(HID_REPORT_ITEM);
398 Size = ReportCount * sizeof(HID_REPORT_ITEM);
399
400 //
401 // allocate memory
402 //
403 NewReport = (PHID_REPORT)Parser->Alloc(Size + OldSize);
404 if (!NewReport)
405 {
406 //
407 // no memory
408 //
409 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
410 }
411
412
413 //
414 // copy old report
415 //
416 Parser->Copy(NewReport, Report, OldSize);
417
418 //
419 // increase array size
420 //
421 NewReport->ItemAllocated += ReportCount;
422
423 //
424 // store result
425 //
426 *OutReport = NewReport;
427
428 //
429 // completed sucessfully
430 //
431 return HIDPARSER_STATUS_SUCCESS;
432 }
433
434 VOID
435 HidParser_SignRange(
436 IN ULONG Minimum,
437 IN ULONG Maximum,
438 OUT PULONG NewMinimum,
439 OUT PULONG NewMaximum)
440 {
441 ULONG Mask = 0x80000000;
442 ULONG Index;
443
444 for (Index = 0; Index < 4; Index++)
445 {
446 if (Minimum & Mask)
447 {
448 Minimum |= Mask;
449 if (Maximum & Mask)
450 Maximum |= Mask;
451 return;
452 }
453
454 Mask >>= 8;
455 Mask |= 0xff000000;
456 }
457
458 *NewMinimum = Minimum;
459 *NewMaximum = Maximum;
460 }
461
462 HIDPARSER_STATUS
463 HidParser_InitReportItem(
464 IN PHID_REPORT Report,
465 IN PHID_REPORT_ITEM ReportItem,
466 IN PGLOBAL_ITEM_STATE GlobalItemState,
467 IN PLOCAL_ITEM_STATE LocalItemState,
468 IN PMAIN_ITEM_DATA ItemData,
469 IN ULONG ReportItemIndex)
470 {
471 ULONG LogicalMinimum;
472 ULONG LogicalMaximum;
473 ULONG PhysicalMinimum;
474 ULONG PhysicalMaximum;
475 ULONG UsageMinimum;
476 ULONG UsageMaximum;
477 USAGE_VALUE UsageValue;
478
479 //
480 // get logical bounds
481 //
482 LogicalMinimum = GlobalItemState->LogicalMinimum;
483 LogicalMaximum = GlobalItemState->LogicialMaximum;
484 if (LogicalMinimum > LogicalMaximum)
485 {
486 //
487 // make them signed
488 //
489 HidParser_SignRange(LogicalMinimum, LogicalMaximum, &LogicalMinimum, &LogicalMaximum);
490 }
491 //ASSERT(LogicalMinimum <= LogicalMaximum);
492
493 //
494 // get physical bounds
495 //
496 PhysicalMinimum = GlobalItemState->PhysicalMinimum;
497 PhysicalMaximum = GlobalItemState->PhysicalMaximum;
498 if (PhysicalMinimum > PhysicalMaximum)
499 {
500 //
501 // make them signed
502 //
503 HidParser_SignRange(PhysicalMinimum, PhysicalMaximum, &PhysicalMinimum, &PhysicalMaximum);
504 }
505 //ASSERT(PhysicalMinimum <= PhysicalMaximum);
506
507 //
508 // get usage bounds
509 //
510 UsageMinimum = 0;
511 UsageMaximum = 0;
512 if (ItemData->ArrayVariable == FALSE)
513 {
514 //
515 // get usage bounds
516 //
517 UsageMinimum = LocalItemState->UsageMinimum.u.Extended;
518 UsageMaximum = LocalItemState->UsageMaximum.u.Extended;
519 }
520 else
521 {
522 //
523 // get usage value from stack
524 //
525 if (ReportItemIndex < LocalItemState->UsageStackUsed)
526 {
527 //
528 // use stack item
529 //
530 UsageValue = LocalItemState->UsageStack[ReportItemIndex];
531 }
532 else
533 {
534 //
535 // get usage minimum from local state
536 //
537 UsageValue = LocalItemState->UsageMinimum;
538 ASSERT(LocalItemState->UsageMinimumSet);
539 ASSERT(LocalItemState->UsageMaximumSet);
540
541 //
542 // append item index
543 //
544 UsageValue.u.Extended += ReportItemIndex;
545
546 if (UsageValue.u.Extended > LocalItemState->UsageMaximum.u.Extended)
547 {
548 //
549 // maximum reached
550 //
551 UsageValue.u.Extended = LocalItemState->UsageMaximum.u.Extended;
552 }
553 }
554
555 //
556 // usage usage bounds
557 //
558 UsageMinimum = UsageMaximum = UsageValue.u.Extended;
559 }
560
561 //
562 // now store all values
563 //
564 ReportItem->ByteOffset = (Report->ReportSize / 8);
565 ReportItem->Shift = (Report->ReportSize % 8);
566 ReportItem->Mask = ~(0xFFFFFFFF << GlobalItemState->ReportSize);
567 ReportItem->BitCount = GlobalItemState->ReportSize;
568 ReportItem->HasData = (ItemData->DataConstant == FALSE);
569 ReportItem->Array = (ItemData->ArrayVariable == 0);
570 ReportItem->Relative = (ItemData->Relative == TRUE);
571 ReportItem->Minimum = LogicalMinimum;
572 ReportItem->Maximum = LogicalMaximum;
573 ReportItem->UsageMinimum = UsageMinimum;
574 ReportItem->UsageMaximum = UsageMaximum;
575
576 //
577 // increment report size
578 //
579 Report->ReportSize += GlobalItemState->ReportSize;
580
581 //
582 // completed successfully
583 //
584 return HIDPARSER_STATUS_SUCCESS;
585 }
586
587 BOOLEAN
588 HidParser_UpdateCurrentCollectionReport(
589 IN PHID_COLLECTION Collection,
590 IN PHID_REPORT Report,
591 IN PHID_REPORT NewReport)
592 {
593 ULONG Index;
594 BOOLEAN Found = FALSE, TempFound;
595
596 //
597 // search in local list
598 //
599 for(Index = 0; Index < Collection->ReportCount; Index++)
600 {
601 if (Collection->Reports[Index] == Report)
602 {
603 //
604 // update report
605 //
606 Collection->Reports[Index] = NewReport;
607 Found = TRUE;
608 }
609 }
610
611 //
612 // search in sub collections
613 //
614 for(Index = 0; Index < Collection->NodeCount; Index++)
615 {
616 //
617 // was it found
618 //
619 TempFound = HidParser_UpdateCurrentCollectionReport(Collection->Nodes[Index], Report, NewReport);
620 if (TempFound)
621 {
622 //
623 // the same report should not be found in different collections
624 //
625 ASSERT(Found == FALSE);
626 Found = TRUE;
627 }
628 }
629
630 //
631 // done
632 //
633 return Found;
634 }
635
636 BOOLEAN
637 HidParser_UpdateCollectionReport(
638 IN PHID_PARSER_CONTEXT ParserContext,
639 IN PHID_REPORT Report,
640 IN PHID_REPORT NewReport)
641 {
642 //
643 // update in current collection
644 //
645 return HidParser_UpdateCurrentCollectionReport(ParserContext->RootCollection->Nodes[ParserContext->RootCollection->NodeCount-1], Report, NewReport);
646 }
647
648
649 HIDPARSER_STATUS
650 HidParser_AddMainItem(
651 IN PHID_PARSER Parser,
652 IN PHID_PARSER_CONTEXT ParserContext,
653 IN PHID_REPORT Report,
654 IN PGLOBAL_ITEM_STATE GlobalItemState,
655 IN PLOCAL_ITEM_STATE LocalItemState,
656 IN PMAIN_ITEM_DATA ItemData,
657 IN PHID_COLLECTION Collection)
658 {
659 HIDPARSER_STATUS Status;
660 ULONG Index;
661 PHID_REPORT NewReport;
662 BOOLEAN Found;
663
664 //
665 // first grow report item array
666 //
667 Status = HidParser_ReserveReportItems(Parser, Report, GlobalItemState->ReportCount, &NewReport);
668 if (Status != HIDPARSER_STATUS_SUCCESS)
669 {
670 //
671 // failed to allocate memory
672 //
673 return Status;
674 }
675
676 if (NewReport != Report)
677 {
678 //
679 // update current top level collection
680 //
681 Found = HidParser_UpdateCollectionReport(ParserContext, Report, NewReport);
682 ASSERT(Found);
683 }
684
685 //
686 // sanity check
687 //
688 ASSERT(NewReport->ItemCount + GlobalItemState->ReportCount <= NewReport->ItemAllocated);
689
690 for(Index = 0; Index < GlobalItemState->ReportCount; Index++)
691 {
692 Status = HidParser_InitReportItem(NewReport, &NewReport->Items[NewReport->ItemCount], GlobalItemState, LocalItemState, ItemData, Index);
693 if (Status != HIDPARSER_STATUS_SUCCESS)
694 {
695 //
696 // failed to init report item
697 //
698 return Status;
699 }
700
701 //
702 // increment report item count
703 //
704 NewReport->ItemCount++;
705 }
706
707 //
708 // done
709 //
710 return HIDPARSER_STATUS_SUCCESS;
711 }
712
713 HIDPARSER_STATUS
714 AllocateParserContext(
715 IN PHID_PARSER Parser,
716 OUT PHID_PARSER_CONTEXT *OutParserContext)
717 {
718 PHID_PARSER_CONTEXT ParserContext;
719
720 ParserContext = Parser->Alloc(sizeof(HID_PARSER_CONTEXT));
721 if (!ParserContext)
722 {
723 //
724 // failed
725 //
726 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
727 }
728
729 //
730 // store result
731 //
732 *OutParserContext = ParserContext;
733 return HIDPARSER_STATUS_SUCCESS;
734 }
735
736
737 HIDPARSER_STATUS
738 HidParser_ParseReportDescriptor(
739 IN PHID_PARSER Parser,
740 IN PUCHAR ReportDescriptor,
741 IN ULONG ReportLength,
742 OUT PVOID *OutParser)
743 {
744 PGLOBAL_ITEM_STATE LinkedGlobalItemState, NextLinkedGlobalItemState;
745 ULONG Index;
746 PUSAGE_VALUE NewUsageStack, UsageValue;
747 HIDPARSER_STATUS Status;
748 PHID_COLLECTION CurrentCollection, NewCollection;
749 PUCHAR CurrentOffset, ReportEnd;
750 PITEM_PREFIX CurrentItem;
751 ULONG CurrentItemSize;
752 PLONG_ITEM CurrentLongItem;
753 PSHORT_ITEM CurrentShortItem;
754 ULONG Data;
755 UCHAR ReportType;
756 PHID_REPORT Report;
757 PMAIN_ITEM_DATA MainItemData;
758 PHID_PARSER_CONTEXT ParserContext;
759
760 //
761 // allocate parser
762 //
763 Status = AllocateParserContext(Parser, &ParserContext);
764 if (Status != HIDPARSER_STATUS_SUCCESS)
765 return Status;
766
767
768 //
769 // allocate usage stack
770 //
771 ParserContext->LocalItemState.UsageStackAllocated = 10;
772 ParserContext->LocalItemState.UsageStack = (PUSAGE_VALUE)Parser->Alloc(ParserContext->LocalItemState.UsageStackAllocated * sizeof(USAGE_VALUE));
773 if (!ParserContext->LocalItemState.UsageStack)
774 {
775 //
776 // no memory
777 //
778 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
779 }
780
781 //
782 // now allocate root collection
783 //
784 Status = HidParser_AllocateCollection(Parser, NULL, COLLECTION_LOGICAL, &ParserContext->LocalItemState, &ParserContext->RootCollection);
785 if (Status != HIDPARSER_STATUS_SUCCESS)
786 {
787 //
788 // no memory
789 //
790 Parser->Free(ParserContext->LocalItemState.UsageStack);
791 ParserContext->LocalItemState.UsageStack = NULL;
792 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
793 }
794
795 //
796 // start parsing
797 //
798 CurrentCollection = ParserContext->RootCollection;
799 CurrentOffset = ReportDescriptor;
800 ReportEnd = ReportDescriptor + ReportLength;
801
802 do
803 {
804 //
805 // get current item
806 //
807 CurrentItem = (PITEM_PREFIX)CurrentOffset;
808
809 //
810 // get item size
811 //
812 CurrentItemSize = ItemSize[CurrentItem->Size];
813 Data = 0;
814
815 if (CurrentItem->Type == ITEM_TYPE_LONG)
816 {
817 //
818 // increment item size with size of data item
819 //
820 CurrentLongItem = (PLONG_ITEM)CurrentItem;
821 CurrentItemSize += CurrentLongItem->DataSize;
822 }
823 else
824 {
825 //
826 // get short item
827 //
828 CurrentShortItem = (PSHORT_ITEM)CurrentItem;
829
830 //
831 // get associated data
832 //
833 //ASSERT(CurrentItemSize == 1 || CurrentItemSize == 2 || CurrentItemSize == 4);
834 if (CurrentItemSize == 1)
835 Data = CurrentShortItem->Data.UData8[0];
836 else if (CurrentItemSize == 2)
837 Data = CurrentShortItem->Data.UData16[0];
838 else if (CurrentItemSize == 4)
839 Data = CurrentShortItem->Data.UData32;
840 else
841 {
842 //
843 // invalid item size
844 //
845 //Parser->Debug("CurrentItem invalid item size %lu\n", CurrentItemSize);
846 }
847
848 }
849 Parser->Debug("Tag %x Type %x Size %x Offset %lu Length %lu\n", CurrentItem->Tag, CurrentItem->Type, CurrentItem->Size, ((ULONG_PTR)CurrentItem - (ULONG_PTR)ReportDescriptor), ReportLength);
850 //
851 // handle items
852 //
853 ASSERT(CurrentItem->Type >= ITEM_TYPE_MAIN && CurrentItem->Type <= ITEM_TYPE_LONG);
854 switch(CurrentItem->Type)
855 {
856 case ITEM_TYPE_MAIN:
857 {
858 // preprocess the local state if relevant (usages for
859 // collections and report items)
860 if (CurrentItem->Tag != ITEM_TAG_MAIN_END_COLLECTION)
861 {
862 // make all usages extended for easier later processing
863 for (Index = 0; Index < ParserContext->LocalItemState.UsageStackUsed; Index++)
864 {
865 //
866 // is it already extended
867 //
868 if (ParserContext->LocalItemState.UsageStack[Index].IsExtended)
869 continue;
870
871 //
872 // extend usage item
873 //
874 ParserContext->LocalItemState.UsageStack[Index].u.s.UsagePage = ParserContext->GlobalItemState.UsagePage;
875 ParserContext->LocalItemState.UsageStack[Index].IsExtended = TRUE;
876 }
877
878 if (!ParserContext->LocalItemState.UsageMinimum.IsExtended) {
879 // the specs say if one of them is extended they must
880 // both be extended, so if the minimum isn't, the
881 // maximum mustn't either.
882 ParserContext->LocalItemState.UsageMinimum.u.s.UsagePage
883 = ParserContext->LocalItemState.UsageMaximum.u.s.UsagePage
884 = ParserContext->GlobalItemState.UsagePage;
885 ParserContext->LocalItemState.UsageMinimum.IsExtended
886 = ParserContext->LocalItemState.UsageMaximum.IsExtended = TRUE;
887 }
888
889 //LocalItemState.usage_stack = usageStack;
890 //ParserContext->LocalItemState.UsageStackUsed = UsageStackUsed;
891 }
892
893 if (CurrentItem->Tag == ITEM_TAG_MAIN_COLLECTION) {
894
895 //
896 // allocate new collection
897 //
898 Status = HidParser_AllocateCollection(Parser, CurrentCollection, (UCHAR)Data, &ParserContext->LocalItemState, &NewCollection);
899 ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
900
901 //
902 // add new collection to current collection
903 //
904 Status = HidParser_AddCollection(Parser, CurrentCollection, NewCollection);
905 ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
906
907 //
908 // make new collection current
909 //
910 CurrentCollection = NewCollection;
911 }
912 else if (CurrentItem->Tag == ITEM_TAG_MAIN_END_COLLECTION)
913 {
914 //
915 // assert on ending the root collection
916 //
917 ASSERT(CurrentCollection != ParserContext->RootCollection);
918
919 //
920 // use parent of current collection
921 //
922 CurrentCollection = CurrentCollection->Root;
923 ASSERT(CurrentCollection);
924 }
925 else
926 {
927 ReportType = HID_REPORT_TYPE_ANY;
928
929 switch (CurrentItem->Tag) {
930 case ITEM_TAG_MAIN_INPUT:
931 ReportType = HID_REPORT_TYPE_INPUT;
932 break;
933
934 case ITEM_TAG_MAIN_OUTPUT:
935 ReportType = HID_REPORT_TYPE_OUTPUT;
936 break;
937
938 case ITEM_TAG_MAIN_FEATURE:
939 ReportType = HID_REPORT_TYPE_FEATURE;
940 break;
941
942 default:
943 Parser->Debug("[HIDPARSE] Unknown ReportType Tag %x Type %x Size %x CurrentItemSize %x\n", CurrentItem->Tag, CurrentItem->Type, CurrentItem->Size, CurrentItemSize);
944 ASSERT(FALSE);
945 break;
946 }
947
948 if (ReportType == HID_REPORT_TYPE_ANY)
949 break;
950
951 //
952 // get report
953 //
954 Status = HidParser_GetReport(Parser, ParserContext, CurrentCollection, ReportType, ParserContext->GlobalItemState.ReportId, TRUE, &Report);
955 ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
956
957 // fill in a sensible default if the index isn't set
958 if (!ParserContext->LocalItemState.DesignatorIndexSet) {
959 ParserContext->LocalItemState.DesignatorIndex
960 = ParserContext->LocalItemState.DesignatorMinimum;
961 }
962
963 if (!ParserContext->LocalItemState.StringIndexSet)
964 ParserContext->LocalItemState.StringIndex = ParserContext->LocalItemState.StringMinimum;
965
966 //
967 // get main item data
968 //
969 MainItemData = (PMAIN_ITEM_DATA)&Data;
970
971 //
972 // add states & data to the report
973 //
974 Status = HidParser_AddMainItem(Parser, ParserContext, Report, &ParserContext->GlobalItemState, &ParserContext->LocalItemState, MainItemData, CurrentCollection);
975 ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
976 }
977
978 //
979 // backup stack
980 //
981 Index = ParserContext->LocalItemState.UsageStackAllocated;
982 NewUsageStack = ParserContext->LocalItemState.UsageStack;
983
984 //
985 // reset the local item state and clear the usage stack
986 //
987 Parser->Zero(&ParserContext->LocalItemState, sizeof(LOCAL_ITEM_STATE));
988
989 //
990 // restore stack
991 //
992 ParserContext->LocalItemState.UsageStack = NewUsageStack;
993 ParserContext->LocalItemState.UsageStackAllocated = Index;
994 break;
995 }
996 case ITEM_TYPE_GLOBAL:
997 {
998 switch (CurrentItem->Tag) {
999 case ITEM_TAG_GLOBAL_USAGE_PAGE:
1000 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_USAGE_PAGE %x\n", Data);
1001 ParserContext->GlobalItemState.UsagePage = Data;
1002 break;
1003 case ITEM_TAG_GLOBAL_LOGICAL_MINIMUM:
1004 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_LOGICAL_MINIMUM %x\n", Data);
1005 ParserContext->GlobalItemState.LogicalMinimum = Data;
1006 break;
1007
1008 case ITEM_TAG_GLOBAL_LOGICAL_MAXIMUM:
1009 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_LOCAL_MAXIMUM %x\n", Data);
1010 ParserContext->GlobalItemState.LogicialMaximum = Data;
1011 break;
1012
1013 case ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM:
1014 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM %x\n", Data);
1015 ParserContext->GlobalItemState.PhysicalMinimum = Data;
1016 break;
1017
1018 case ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM:
1019 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM %x\n", Data);
1020 ParserContext->GlobalItemState.PhysicalMaximum = Data;
1021 break;
1022
1023 case ITEM_TAG_GLOBAL_UNIT_EXPONENT:
1024 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT_EXPONENT %x\n", Data);
1025 ParserContext->GlobalItemState.UnitExponent = Data;
1026 break;
1027
1028 case ITEM_TAG_GLOBAL_UNIT:
1029 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT %x\n", Data);
1030 ParserContext->GlobalItemState.Unit = Data;
1031 break;
1032
1033 case ITEM_TAG_GLOBAL_REPORT_SIZE:
1034 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_SIZE %x\n", Data);
1035 ParserContext->GlobalItemState.ReportSize = Data;
1036 break;
1037
1038 case ITEM_TAG_GLOBAL_REPORT_ID:
1039 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_ID %x\n", Data);
1040 ParserContext->GlobalItemState.ReportId = Data;
1041 ParserContext->UseReportIDs = TRUE;
1042 break;
1043
1044 case ITEM_TAG_GLOBAL_REPORT_COUNT:
1045 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_COUNT %x\n", Data);
1046 ParserContext->GlobalItemState.ReportCount = Data;
1047 break;
1048
1049 case ITEM_TAG_GLOBAL_PUSH:
1050 {
1051 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PUSH\n");
1052 //
1053 // allocate global item state
1054 //
1055 LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)Parser->Alloc(sizeof(GLOBAL_ITEM_STATE));
1056 ASSERT(LinkedGlobalItemState);
1057
1058 //
1059 // copy global item state
1060 //
1061 Parser->Copy(LinkedGlobalItemState, &ParserContext->GlobalItemState, sizeof(GLOBAL_ITEM_STATE));
1062
1063 //
1064 // store pushed item in link member
1065 //
1066 ParserContext->GlobalItemState.Next = (struct __GLOBAL_ITEM_STATE__*)LinkedGlobalItemState;
1067 break;
1068 }
1069 case ITEM_TAG_GLOBAL_POP:
1070 {
1071 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_POP\n");
1072 if (ParserContext->GlobalItemState.Next == NULL)
1073 {
1074 //
1075 // pop without push
1076 //
1077 ASSERT(FALSE);
1078 break;
1079 }
1080
1081 //
1082 // get link
1083 //
1084 LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)ParserContext->GlobalItemState.Next;
1085
1086 //
1087 // replace current item with linked one
1088 //
1089 Parser->Copy(&ParserContext->GlobalItemState, LinkedGlobalItemState, sizeof(GLOBAL_ITEM_STATE));
1090
1091 //
1092 // free item
1093 //
1094 Parser->Free(LinkedGlobalItemState);
1095 break;
1096 }
1097
1098 default:
1099 //
1100 // unknown / unsupported tag
1101 //
1102 ASSERT(FALSE);
1103 break;
1104 }
1105
1106 break;
1107 }
1108 case ITEM_TYPE_LOCAL:
1109 {
1110 switch (CurrentItem->Tag)
1111 {
1112 case ITEM_TAG_LOCAL_USAGE:
1113 {
1114 if (ParserContext->LocalItemState.UsageStackUsed >= ParserContext->LocalItemState.UsageStackAllocated)
1115 {
1116 //
1117 // increment stack size
1118 //
1119 ParserContext->LocalItemState.UsageStackAllocated += 10;
1120
1121 //
1122 // build new usage stack
1123 //
1124 NewUsageStack = (PUSAGE_VALUE)Parser->Alloc(sizeof(USAGE_VALUE) * ParserContext->LocalItemState.UsageStackAllocated);
1125 ASSERT(NewUsageStack);
1126
1127 //
1128 // copy old usage stack
1129 //
1130 Parser->Copy(NewUsageStack, ParserContext->LocalItemState.UsageStack, sizeof(USAGE_VALUE) * (ParserContext->LocalItemState.UsageStackAllocated - 10));
1131
1132 //
1133 // free old usage stack
1134 //
1135 Parser->Free(ParserContext->LocalItemState.UsageStack);
1136
1137 //
1138 // replace with new usage stack
1139 //
1140 ParserContext->LocalItemState.UsageStack = NewUsageStack;
1141 }
1142
1143 //
1144 // get fresh usage value
1145 //
1146 UsageValue = &ParserContext->LocalItemState.UsageStack[ParserContext->LocalItemState.UsageStackUsed];
1147
1148 //
1149 // init usage stack
1150 //
1151 UsageValue->IsExtended = CurrentItemSize == sizeof(ULONG);
1152 UsageValue->u.Extended = Data;
1153
1154 //
1155 // increment usage stack usage count
1156 //
1157 ParserContext->LocalItemState.UsageStackUsed++;
1158 break;
1159 }
1160
1161 case ITEM_TAG_LOCAL_USAGE_MINIMUM:
1162 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MINIMUM Data %x\n", Data);
1163 ParserContext->LocalItemState.UsageMinimum.u.Extended = Data;
1164 ParserContext->LocalItemState.UsageMinimum.IsExtended
1165 = CurrentItemSize == sizeof(ULONG);
1166 ParserContext->LocalItemState.UsageMinimumSet = TRUE;
1167 break;
1168
1169 case ITEM_TAG_LOCAL_USAGE_MAXIMUM:
1170 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MAXIMUM Data %x ItemSize %x %x\n", Data, CurrentItemSize, CurrentItem->Size);
1171 ParserContext->LocalItemState.UsageMaximum.u.Extended = Data;
1172 ParserContext->LocalItemState.UsageMaximum.IsExtended
1173 = CurrentItemSize == sizeof(ULONG);
1174 ParserContext->LocalItemState.UsageMaximumSet = TRUE;
1175 break;
1176
1177 case ITEM_TAG_LOCAL_DESIGNATOR_INDEX:
1178 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_INDEX Data %x\n", Data);
1179 ParserContext->LocalItemState.DesignatorIndex = Data;
1180 ParserContext->LocalItemState.DesignatorIndexSet = TRUE;
1181 break;
1182
1183 case ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM:
1184 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM Data %x\n", Data);
1185 ParserContext->LocalItemState.DesignatorMinimum = Data;
1186 break;
1187
1188 case ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM:
1189 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM Data %x\n", Data);
1190 ParserContext->LocalItemState.DesignatorMaximum = Data;
1191 break;
1192
1193 case ITEM_TAG_LOCAL_STRING_INDEX:
1194 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_INDEX Data %x\n", Data);
1195 ParserContext->LocalItemState.StringIndex = Data;
1196 ParserContext->LocalItemState.StringIndexSet = TRUE;
1197 break;
1198
1199 case ITEM_TAG_LOCAL_STRING_MINIMUM:
1200 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MINIMUM Data %x\n", Data);
1201 ParserContext->LocalItemState.StringMinimum = Data;
1202 break;
1203
1204 case ITEM_TAG_LOCAL_STRING_MAXIMUM:
1205 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MAXIMUM Data %x\n", Data);
1206 ParserContext->LocalItemState.StringMaximum = Data;
1207 break;
1208
1209 default:
1210 Parser->Debug("Unknown Local Item Tag %x\n", CurrentItem->Tag);
1211 ASSERT(FALSE);
1212 break;
1213 }
1214 break;
1215 }
1216
1217 case ITEM_TYPE_LONG:
1218 {
1219 CurrentLongItem = (PLONG_ITEM)CurrentItem;
1220 Parser->Debug("Unsupported ITEM_TYPE_LONG Tag %x\n", CurrentLongItem->LongItemTag);
1221 break;
1222 }
1223 }
1224
1225 //
1226 // move to next item
1227 //
1228 CurrentOffset += CurrentItemSize + sizeof(ITEM_PREFIX);
1229
1230
1231 }while(CurrentOffset < ReportEnd);
1232
1233
1234 //
1235 // cleanup global stack
1236 //
1237 LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)ParserContext->GlobalItemState.Next;
1238 while(LinkedGlobalItemState != NULL)
1239 {
1240 Parser->Debug("[HIDPARSE] Freeing GlobalState %p\n", LinkedGlobalItemState);
1241 //
1242 // free global item state
1243 //
1244 NextLinkedGlobalItemState = (PGLOBAL_ITEM_STATE)LinkedGlobalItemState->Next;
1245
1246 //
1247 // free state
1248 //
1249 Parser->Free(LinkedGlobalItemState);
1250
1251 //
1252 // move to next global state
1253 //
1254 LinkedGlobalItemState = NextLinkedGlobalItemState;
1255 }
1256
1257 //
1258 // free usage stack
1259 //
1260 Parser->Free(ParserContext->LocalItemState.UsageStack);
1261 ParserContext->LocalItemState.UsageStack = NULL;
1262
1263 //
1264 // store result
1265 //
1266 *OutParser = ParserContext;
1267
1268 //
1269 // done
1270 //
1271 return HIDPARSER_STATUS_SUCCESS;
1272 }
1273
1274 PHID_COLLECTION
1275 HidParser_GetCollection(
1276 IN PHID_PARSER Parser,
1277 PHID_PARSER_CONTEXT ParserContext,
1278 IN ULONG CollectionNumber)
1279 {
1280 //
1281 // sanity checks
1282 //
1283 ASSERT(ParserContext);
1284 ASSERT(ParserContext->RootCollection);
1285 ASSERT(ParserContext->RootCollection->NodeCount);
1286
1287 //
1288 // is collection index out of bounds
1289 //
1290 if (CollectionNumber < ParserContext->RootCollection->NodeCount)
1291 {
1292 //
1293 // valid collection
1294 //
1295 return ParserContext->RootCollection->Nodes[CollectionNumber];
1296 }
1297
1298 //
1299 // no such collection
1300 //
1301 Parser->Debug("HIDPARSE] No such collection %lu\n", CollectionNumber);
1302 return NULL;
1303 }
1304
1305
1306 ULONG
1307 HidParser_NumberOfTopCollections(
1308 IN PVOID ParserCtx)
1309 {
1310 PHID_PARSER_CONTEXT ParserContext;
1311
1312 //
1313 // get parser context
1314 //
1315 ParserContext = (PHID_PARSER_CONTEXT)ParserCtx;
1316
1317 //
1318 // sanity checks
1319 //
1320 ASSERT(ParserContext);
1321 ASSERT(ParserContext->RootCollection);
1322 ASSERT(ParserContext->RootCollection->NodeCount);
1323
1324 //
1325 // number of top collections
1326 //
1327 return ParserContext->RootCollection->NodeCount;
1328 }
1329
1330 HIDPARSER_STATUS
1331 HidParser_BuildContext(
1332 IN PHID_PARSER Parser,
1333 IN PVOID ParserContext,
1334 IN ULONG CollectionIndex,
1335 IN ULONG ContextSize,
1336 OUT PVOID *CollectionContext)
1337 {
1338 PHID_COLLECTION Collection;
1339 PVOID Context;
1340 HIDPARSER_STATUS Status;
1341
1342 //
1343 // lets get the collection
1344 //
1345 Collection = HidParser_GetCollection(Parser, (PHID_PARSER_CONTEXT)ParserContext, CollectionIndex);
1346 ASSERT(Collection);
1347
1348 //
1349 // lets allocate the context
1350 //
1351 Context = Parser->Alloc(ContextSize);
1352 if (Context == NULL)
1353 {
1354 //
1355 // no memory
1356 //
1357 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
1358 }
1359
1360 //
1361 // lets build the context
1362 //
1363 Status = HidParser_BuildCollectionContext(Parser, Collection, Context, ContextSize);
1364 if (Status == HIDPARSER_STATUS_SUCCESS)
1365 {
1366 //
1367 // store context
1368 //
1369 *CollectionContext = Context;
1370 }
1371
1372 //
1373 // done
1374 //
1375 return Status;
1376 }
1377
1378
1379 ULONG
1380 HidParser_GetContextSize(
1381 IN PHID_PARSER Parser,
1382 IN PVOID ParserContext,
1383 IN ULONG CollectionIndex)
1384 {
1385 PHID_COLLECTION Collection;
1386 ULONG Size;
1387
1388 //
1389 // lets get the collection
1390 //
1391 Collection = HidParser_GetCollection(Parser, (PHID_PARSER_CONTEXT)ParserContext, CollectionIndex);
1392
1393 //
1394 // calculate size
1395 //
1396 Size = HidParser_CalculateContextSize(Collection);
1397 return Size;
1398 }
1399