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