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