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