Create the AHCI branch for Aman's work
[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 AllocateParserContext(
718 IN PHID_PARSER Parser,
719 OUT PHID_PARSER_CONTEXT *OutParserContext)
720 {
721 PHID_PARSER_CONTEXT ParserContext;
722
723 ParserContext = Parser->Alloc(sizeof(HID_PARSER_CONTEXT));
724 if (!ParserContext)
725 {
726 //
727 // failed
728 //
729 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
730 }
731
732 //
733 // store result
734 //
735 *OutParserContext = ParserContext;
736 return HIDPARSER_STATUS_SUCCESS;
737 }
738
739
740 HIDPARSER_STATUS
741 HidParser_ParseReportDescriptor(
742 IN PHID_PARSER Parser,
743 IN PUCHAR ReportDescriptor,
744 IN ULONG ReportLength,
745 OUT PVOID *OutParser)
746 {
747 PGLOBAL_ITEM_STATE LinkedGlobalItemState, NextLinkedGlobalItemState;
748 ULONG Index;
749 PUSAGE_VALUE NewUsageStack, UsageValue;
750 HIDPARSER_STATUS Status;
751 PHID_COLLECTION CurrentCollection, NewCollection;
752 PUCHAR CurrentOffset, ReportEnd;
753 PITEM_PREFIX CurrentItem;
754 ULONG CurrentItemSize;
755 PLONG_ITEM CurrentLongItem;
756 PSHORT_ITEM CurrentShortItem;
757 ULONG Data;
758 UCHAR ReportType;
759 PHID_REPORT Report;
760 PMAIN_ITEM_DATA MainItemData;
761 PHID_PARSER_CONTEXT ParserContext;
762
763 //
764 // allocate parser
765 //
766 Status = AllocateParserContext(Parser, &ParserContext);
767 if (Status != HIDPARSER_STATUS_SUCCESS)
768 return Status;
769
770
771 //
772 // allocate usage stack
773 //
774 ParserContext->LocalItemState.UsageStackAllocated = 10;
775 ParserContext->LocalItemState.UsageStack = (PUSAGE_VALUE)Parser->Alloc(ParserContext->LocalItemState.UsageStackAllocated * sizeof(USAGE_VALUE));
776 if (!ParserContext->LocalItemState.UsageStack)
777 {
778 //
779 // no memory
780 //
781 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
782 }
783
784 //
785 // now allocate root collection
786 //
787 Status = HidParser_AllocateCollection(Parser, NULL, COLLECTION_LOGICAL, &ParserContext->LocalItemState, &ParserContext->RootCollection);
788 if (Status != HIDPARSER_STATUS_SUCCESS)
789 {
790 //
791 // no memory
792 //
793 Parser->Free(ParserContext->LocalItemState.UsageStack);
794 ParserContext->LocalItemState.UsageStack = NULL;
795 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
796 }
797
798 //
799 // start parsing
800 //
801 CurrentCollection = ParserContext->RootCollection;
802 CurrentOffset = ReportDescriptor;
803 ReportEnd = ReportDescriptor + ReportLength;
804
805 do
806 {
807 //
808 // get current item
809 //
810 CurrentItem = (PITEM_PREFIX)CurrentOffset;
811
812 //
813 // get item size
814 //
815 CurrentItemSize = ItemSize[CurrentItem->Size];
816 Data = 0;
817
818 if (CurrentItem->Type == ITEM_TYPE_LONG)
819 {
820 //
821 // increment item size with size of data item
822 //
823 CurrentLongItem = (PLONG_ITEM)CurrentItem;
824 CurrentItemSize += CurrentLongItem->DataSize;
825 }
826 else
827 {
828 //
829 // get short item
830 //
831 CurrentShortItem = (PSHORT_ITEM)CurrentItem;
832
833 //
834 // get associated data
835 //
836 //ASSERT(CurrentItemSize == 1 || CurrentItemSize == 2 || CurrentItemSize == 4);
837 if (CurrentItemSize == 1)
838 Data = CurrentShortItem->Data.UData8[0];
839 else if (CurrentItemSize == 2)
840 Data = CurrentShortItem->Data.UData16[0];
841 else if (CurrentItemSize == 4)
842 Data = CurrentShortItem->Data.UData32;
843 else
844 {
845 //
846 // invalid item size
847 //
848 //Parser->Debug("CurrentItem invalid item size %lu\n", CurrentItemSize);
849 }
850
851 }
852 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);
853 //
854 // handle items
855 //
856 ASSERT(CurrentItem->Type >= ITEM_TYPE_MAIN && CurrentItem->Type <= ITEM_TYPE_LONG);
857 switch(CurrentItem->Type)
858 {
859 case ITEM_TYPE_MAIN:
860 {
861 // preprocess the local state if relevant (usages for
862 // collections and report items)
863 if (CurrentItem->Tag != ITEM_TAG_MAIN_END_COLLECTION)
864 {
865 // make all usages extended for easier later processing
866 for (Index = 0; Index < ParserContext->LocalItemState.UsageStackUsed; Index++)
867 {
868 //
869 // is it already extended
870 //
871 if (ParserContext->LocalItemState.UsageStack[Index].IsExtended)
872 continue;
873
874 //
875 // extend usage item
876 //
877 ParserContext->LocalItemState.UsageStack[Index].u.s.UsagePage = ParserContext->GlobalItemState.UsagePage;
878 ParserContext->LocalItemState.UsageStack[Index].IsExtended = TRUE;
879 }
880
881 if (!ParserContext->LocalItemState.UsageMinimum.IsExtended) {
882 // the specs say if one of them is extended they must
883 // both be extended, so if the minimum isn't, the
884 // maximum mustn't either.
885 ParserContext->LocalItemState.UsageMinimum.u.s.UsagePage
886 = ParserContext->LocalItemState.UsageMaximum.u.s.UsagePage
887 = ParserContext->GlobalItemState.UsagePage;
888 ParserContext->LocalItemState.UsageMinimum.IsExtended
889 = ParserContext->LocalItemState.UsageMaximum.IsExtended = TRUE;
890 }
891
892 //LocalItemState.usage_stack = usageStack;
893 //ParserContext->LocalItemState.UsageStackUsed = UsageStackUsed;
894 }
895
896 if (CurrentItem->Tag == ITEM_TAG_MAIN_COLLECTION) {
897
898 //
899 // allocate new collection
900 //
901 Status = HidParser_AllocateCollection(Parser, CurrentCollection, (UCHAR)Data, &ParserContext->LocalItemState, &NewCollection);
902 ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
903
904 //
905 // add new collection to current collection
906 //
907 Status = HidParser_AddCollection(Parser, CurrentCollection, NewCollection);
908 ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
909
910 //
911 // make new collection current
912 //
913 CurrentCollection = NewCollection;
914 }
915 else if (CurrentItem->Tag == ITEM_TAG_MAIN_END_COLLECTION)
916 {
917 //
918 // assert on ending the root collection
919 //
920 ASSERT(CurrentCollection != ParserContext->RootCollection);
921
922 //
923 // use parent of current collection
924 //
925 CurrentCollection = CurrentCollection->Root;
926 ASSERT(CurrentCollection);
927 }
928 else
929 {
930 ReportType = HID_REPORT_TYPE_ANY;
931
932 switch (CurrentItem->Tag) {
933 case ITEM_TAG_MAIN_INPUT:
934 ReportType = HID_REPORT_TYPE_INPUT;
935 break;
936
937 case ITEM_TAG_MAIN_OUTPUT:
938 ReportType = HID_REPORT_TYPE_OUTPUT;
939 break;
940
941 case ITEM_TAG_MAIN_FEATURE:
942 ReportType = HID_REPORT_TYPE_FEATURE;
943 break;
944
945 default:
946 Parser->Debug("[HIDPARSE] Unknown ReportType Tag %x Type %x Size %x CurrentItemSize %x\n", CurrentItem->Tag, CurrentItem->Type, CurrentItem->Size, CurrentItemSize);
947 ASSERT(FALSE);
948 break;
949 }
950
951 if (ReportType == HID_REPORT_TYPE_ANY)
952 break;
953
954 //
955 // get report
956 //
957 Status = HidParser_GetReport(Parser, ParserContext, CurrentCollection, ReportType, ParserContext->GlobalItemState.ReportId, TRUE, &Report);
958 ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
959
960 // fill in a sensible default if the index isn't set
961 if (!ParserContext->LocalItemState.DesignatorIndexSet) {
962 ParserContext->LocalItemState.DesignatorIndex
963 = ParserContext->LocalItemState.DesignatorMinimum;
964 }
965
966 if (!ParserContext->LocalItemState.StringIndexSet)
967 ParserContext->LocalItemState.StringIndex = ParserContext->LocalItemState.StringMinimum;
968
969 //
970 // get main item data
971 //
972 MainItemData = (PMAIN_ITEM_DATA)&Data;
973
974 //
975 // add states & data to the report
976 //
977 Status = HidParser_AddMainItem(Parser, ParserContext, Report, &ParserContext->GlobalItemState, &ParserContext->LocalItemState, MainItemData, CurrentCollection);
978 ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
979 }
980
981 //
982 // backup stack
983 //
984 Index = ParserContext->LocalItemState.UsageStackAllocated;
985 NewUsageStack = ParserContext->LocalItemState.UsageStack;
986
987 //
988 // reset the local item state and clear the usage stack
989 //
990 Parser->Zero(&ParserContext->LocalItemState, sizeof(LOCAL_ITEM_STATE));
991
992 //
993 // restore stack
994 //
995 ParserContext->LocalItemState.UsageStack = NewUsageStack;
996 ParserContext->LocalItemState.UsageStackAllocated = Index;
997 break;
998 }
999 case ITEM_TYPE_GLOBAL:
1000 {
1001 switch (CurrentItem->Tag) {
1002 case ITEM_TAG_GLOBAL_USAGE_PAGE:
1003 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_USAGE_PAGE %x\n", Data);
1004 ParserContext->GlobalItemState.UsagePage = Data;
1005 break;
1006 case ITEM_TAG_GLOBAL_LOGICAL_MINIMUM:
1007 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_LOGICAL_MINIMUM %x\n", Data);
1008 ParserContext->GlobalItemState.LogicalMinimum = Data;
1009 break;
1010
1011 case ITEM_TAG_GLOBAL_LOGICAL_MAXIMUM:
1012 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_LOCAL_MAXIMUM %x\n", Data);
1013 ParserContext->GlobalItemState.LogicialMaximum = Data;
1014 break;
1015
1016 case ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM:
1017 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM %x\n", Data);
1018 ParserContext->GlobalItemState.PhysicalMinimum = Data;
1019 break;
1020
1021 case ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM:
1022 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM %x\n", Data);
1023 ParserContext->GlobalItemState.PhysicalMaximum = Data;
1024 break;
1025
1026 case ITEM_TAG_GLOBAL_UNIT_EXPONENT:
1027 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT_EXPONENT %x\n", Data);
1028 ParserContext->GlobalItemState.UnitExponent = Data;
1029 break;
1030
1031 case ITEM_TAG_GLOBAL_UNIT:
1032 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT %x\n", Data);
1033 ParserContext->GlobalItemState.Unit = Data;
1034 break;
1035
1036 case ITEM_TAG_GLOBAL_REPORT_SIZE:
1037 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_SIZE %x\n", Data);
1038 ParserContext->GlobalItemState.ReportSize = Data;
1039 break;
1040
1041 case ITEM_TAG_GLOBAL_REPORT_ID:
1042 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_ID %x\n", Data);
1043 ParserContext->GlobalItemState.ReportId = Data;
1044 ParserContext->UseReportIDs = TRUE;
1045 break;
1046
1047 case ITEM_TAG_GLOBAL_REPORT_COUNT:
1048 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_COUNT %x\n", Data);
1049 ParserContext->GlobalItemState.ReportCount = Data;
1050 break;
1051
1052 case ITEM_TAG_GLOBAL_PUSH:
1053 {
1054 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PUSH\n");
1055 //
1056 // allocate global item state
1057 //
1058 LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)Parser->Alloc(sizeof(GLOBAL_ITEM_STATE));
1059 ASSERT(LinkedGlobalItemState);
1060
1061 //
1062 // copy global item state
1063 //
1064 Parser->Copy(LinkedGlobalItemState, &ParserContext->GlobalItemState, sizeof(GLOBAL_ITEM_STATE));
1065
1066 //
1067 // store pushed item in link member
1068 //
1069 ParserContext->GlobalItemState.Next = (struct __GLOBAL_ITEM_STATE__*)LinkedGlobalItemState;
1070 break;
1071 }
1072 case ITEM_TAG_GLOBAL_POP:
1073 {
1074 Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_POP\n");
1075 if (ParserContext->GlobalItemState.Next == NULL)
1076 {
1077 //
1078 // pop without push
1079 //
1080 ASSERT(FALSE);
1081 break;
1082 }
1083
1084 //
1085 // get link
1086 //
1087 LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)ParserContext->GlobalItemState.Next;
1088
1089 //
1090 // replace current item with linked one
1091 //
1092 Parser->Copy(&ParserContext->GlobalItemState, LinkedGlobalItemState, sizeof(GLOBAL_ITEM_STATE));
1093
1094 //
1095 // free item
1096 //
1097 Parser->Free(LinkedGlobalItemState);
1098 break;
1099 }
1100
1101 default:
1102 //
1103 // unknown / unsupported tag
1104 //
1105 ASSERT(FALSE);
1106 break;
1107 }
1108
1109 break;
1110 }
1111 case ITEM_TYPE_LOCAL:
1112 {
1113 switch (CurrentItem->Tag)
1114 {
1115 case ITEM_TAG_LOCAL_USAGE:
1116 {
1117 if (ParserContext->LocalItemState.UsageStackUsed >= ParserContext->LocalItemState.UsageStackAllocated)
1118 {
1119 //
1120 // increment stack size
1121 //
1122 ParserContext->LocalItemState.UsageStackAllocated += 10;
1123
1124 //
1125 // build new usage stack
1126 //
1127 NewUsageStack = (PUSAGE_VALUE)Parser->Alloc(sizeof(USAGE_VALUE) * ParserContext->LocalItemState.UsageStackAllocated);
1128 ASSERT(NewUsageStack);
1129
1130 //
1131 // copy old usage stack
1132 //
1133 Parser->Copy(NewUsageStack, ParserContext->LocalItemState.UsageStack, sizeof(USAGE_VALUE) * (ParserContext->LocalItemState.UsageStackAllocated - 10));
1134
1135 //
1136 // free old usage stack
1137 //
1138 Parser->Free(ParserContext->LocalItemState.UsageStack);
1139
1140 //
1141 // replace with new usage stack
1142 //
1143 ParserContext->LocalItemState.UsageStack = NewUsageStack;
1144 }
1145
1146 //
1147 // get fresh usage value
1148 //
1149 UsageValue = &ParserContext->LocalItemState.UsageStack[ParserContext->LocalItemState.UsageStackUsed];
1150
1151 //
1152 // init usage stack
1153 //
1154 UsageValue->IsExtended = CurrentItemSize == sizeof(ULONG);
1155 UsageValue->u.Extended = Data;
1156
1157 //
1158 // increment usage stack usage count
1159 //
1160 ParserContext->LocalItemState.UsageStackUsed++;
1161 break;
1162 }
1163
1164 case ITEM_TAG_LOCAL_USAGE_MINIMUM:
1165 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MINIMUM Data %x\n", Data);
1166 ParserContext->LocalItemState.UsageMinimum.u.Extended = Data;
1167 ParserContext->LocalItemState.UsageMinimum.IsExtended
1168 = CurrentItemSize == sizeof(ULONG);
1169 ParserContext->LocalItemState.UsageMinimumSet = TRUE;
1170 break;
1171
1172 case ITEM_TAG_LOCAL_USAGE_MAXIMUM:
1173 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MAXIMUM Data %x ItemSize %x %x\n", Data, CurrentItemSize, CurrentItem->Size);
1174 ParserContext->LocalItemState.UsageMaximum.u.Extended = Data;
1175 ParserContext->LocalItemState.UsageMaximum.IsExtended
1176 = CurrentItemSize == sizeof(ULONG);
1177 ParserContext->LocalItemState.UsageMaximumSet = TRUE;
1178 break;
1179
1180 case ITEM_TAG_LOCAL_DESIGNATOR_INDEX:
1181 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_INDEX Data %x\n", Data);
1182 ParserContext->LocalItemState.DesignatorIndex = Data;
1183 ParserContext->LocalItemState.DesignatorIndexSet = TRUE;
1184 break;
1185
1186 case ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM:
1187 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM Data %x\n", Data);
1188 ParserContext->LocalItemState.DesignatorMinimum = Data;
1189 break;
1190
1191 case ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM:
1192 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM Data %x\n", Data);
1193 ParserContext->LocalItemState.DesignatorMaximum = Data;
1194 break;
1195
1196 case ITEM_TAG_LOCAL_STRING_INDEX:
1197 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_INDEX Data %x\n", Data);
1198 ParserContext->LocalItemState.StringIndex = Data;
1199 ParserContext->LocalItemState.StringIndexSet = TRUE;
1200 break;
1201
1202 case ITEM_TAG_LOCAL_STRING_MINIMUM:
1203 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MINIMUM Data %x\n", Data);
1204 ParserContext->LocalItemState.StringMinimum = Data;
1205 break;
1206
1207 case ITEM_TAG_LOCAL_STRING_MAXIMUM:
1208 Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MAXIMUM Data %x\n", Data);
1209 ParserContext->LocalItemState.StringMaximum = Data;
1210 break;
1211
1212 default:
1213 Parser->Debug("Unknown Local Item Tag %x\n", CurrentItem->Tag);
1214 ASSERT(FALSE);
1215 break;
1216 }
1217 break;
1218 }
1219
1220 case ITEM_TYPE_LONG:
1221 {
1222 CurrentLongItem = (PLONG_ITEM)CurrentItem;
1223 Parser->Debug("Unsupported ITEM_TYPE_LONG Tag %x\n", CurrentLongItem->LongItemTag);
1224 break;
1225 }
1226 }
1227
1228 //
1229 // move to next item
1230 //
1231 CurrentOffset += CurrentItemSize + sizeof(ITEM_PREFIX);
1232
1233
1234 }while(CurrentOffset < ReportEnd);
1235
1236
1237 //
1238 // cleanup global stack
1239 //
1240 LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)ParserContext->GlobalItemState.Next;
1241 while(LinkedGlobalItemState != NULL)
1242 {
1243 Parser->Debug("[HIDPARSE] Freeing GlobalState %p\n", LinkedGlobalItemState);
1244 //
1245 // free global item state
1246 //
1247 NextLinkedGlobalItemState = (PGLOBAL_ITEM_STATE)LinkedGlobalItemState->Next;
1248
1249 //
1250 // free state
1251 //
1252 Parser->Free(LinkedGlobalItemState);
1253
1254 //
1255 // move to next global state
1256 //
1257 LinkedGlobalItemState = NextLinkedGlobalItemState;
1258 }
1259
1260 //
1261 // free usage stack
1262 //
1263 Parser->Free(ParserContext->LocalItemState.UsageStack);
1264 ParserContext->LocalItemState.UsageStack = NULL;
1265
1266 //
1267 // store result
1268 //
1269 *OutParser = ParserContext;
1270
1271 //
1272 // done
1273 //
1274 return HIDPARSER_STATUS_SUCCESS;
1275 }
1276
1277 PHID_COLLECTION
1278 HidParser_GetCollection(
1279 IN PHID_PARSER Parser,
1280 PHID_PARSER_CONTEXT ParserContext,
1281 IN ULONG CollectionNumber)
1282 {
1283 //
1284 // sanity checks
1285 //
1286 ASSERT(ParserContext);
1287 ASSERT(ParserContext->RootCollection);
1288 ASSERT(ParserContext->RootCollection->NodeCount);
1289
1290 //
1291 // is collection index out of bounds
1292 //
1293 if (CollectionNumber < ParserContext->RootCollection->NodeCount)
1294 {
1295 //
1296 // valid collection
1297 //
1298 return ParserContext->RootCollection->Nodes[CollectionNumber];
1299 }
1300
1301 //
1302 // no such collection
1303 //
1304 Parser->Debug("HIDPARSE] No such collection %lu\n", CollectionNumber);
1305 return NULL;
1306 }
1307
1308
1309 ULONG
1310 HidParser_NumberOfTopCollections(
1311 IN PVOID ParserCtx)
1312 {
1313 PHID_PARSER_CONTEXT ParserContext;
1314
1315 //
1316 // get parser context
1317 //
1318 ParserContext = (PHID_PARSER_CONTEXT)ParserCtx;
1319
1320 //
1321 // sanity checks
1322 //
1323 ASSERT(ParserContext);
1324 ASSERT(ParserContext->RootCollection);
1325 ASSERT(ParserContext->RootCollection->NodeCount);
1326
1327 //
1328 // number of top collections
1329 //
1330 return ParserContext->RootCollection->NodeCount;
1331 }
1332
1333 HIDPARSER_STATUS
1334 HidParser_BuildContext(
1335 IN PHID_PARSER Parser,
1336 IN PVOID ParserContext,
1337 IN ULONG CollectionIndex,
1338 IN ULONG ContextSize,
1339 OUT PVOID *CollectionContext)
1340 {
1341 PHID_COLLECTION Collection;
1342 PVOID Context;
1343 HIDPARSER_STATUS Status;
1344
1345 //
1346 // lets get the collection
1347 //
1348 Collection = HidParser_GetCollection(Parser, (PHID_PARSER_CONTEXT)ParserContext, CollectionIndex);
1349 ASSERT(Collection);
1350
1351 //
1352 // lets allocate the context
1353 //
1354 Context = Parser->Alloc(ContextSize);
1355 if (Context == NULL)
1356 {
1357 //
1358 // no memory
1359 //
1360 return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
1361 }
1362
1363 //
1364 // lets build the context
1365 //
1366 Status = HidParser_BuildCollectionContext(Parser, Collection, Context, ContextSize);
1367 if (Status == HIDPARSER_STATUS_SUCCESS)
1368 {
1369 //
1370 // store context
1371 //
1372 *CollectionContext = Context;
1373 }
1374
1375 //
1376 // done
1377 //
1378 return Status;
1379 }
1380
1381
1382 ULONG
1383 HidParser_GetContextSize(
1384 IN PHID_PARSER Parser,
1385 IN PVOID ParserContext,
1386 IN ULONG CollectionIndex)
1387 {
1388 PHID_COLLECTION Collection;
1389 ULONG Size;
1390
1391 //
1392 // lets get the collection
1393 //
1394 Collection = HidParser_GetCollection(Parser, (PHID_PARSER_CONTEXT)ParserContext, CollectionIndex);
1395
1396 //
1397 // calculate size
1398 //
1399 Size = HidParser_CalculateContextSize(Collection);
1400 return Size;
1401 }
1402