Add svn:eol-style property to source files, so that the line endings are correctly...
[pub/USBasp.git] / LUFA / Drivers / USB / Class / Host / HIDParser.c
index 386c3b9..7116ed8 100644 (file)
-/*\r
-             LUFA Library\r
-     Copyright (C) Dean Camera, 2010.\r
-              \r
-  dean [at] fourwalledcubicle [dot] com\r
-      www.fourwalledcubicle.com\r
-*/\r
-\r
-/*\r
-  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
-\r
-  Permission to use, copy, modify, distribute, and sell this \r
-  software and its documentation for any purpose is hereby granted\r
-  without fee, provided that the above copyright notice appear in \r
-  all copies and that both that the copyright notice and this\r
-  permission notice and warranty disclaimer appear in supporting \r
-  documentation, and that the name of the author not be used in \r
-  advertising or publicity pertaining to distribution of the \r
-  software without specific, written prior permission.\r
-\r
-  The author disclaim all warranties with regard to this\r
-  software, including all implied warranties of merchantability\r
-  and fitness.  In no event shall the author be liable for any\r
-  special, indirect or consequential damages or any damages\r
-  whatsoever resulting from loss of use, data or profits, whether\r
-  in an action of contract, negligence or other tortious action,\r
-  arising out of or in connection with the use or performance of\r
-  this software.\r
-*/\r
-\r
-#define  __INCLUDE_FROM_USB_DRIVER\r
-#include "../../HighLevel/USBMode.h"\r
-#if defined(USB_CAN_BE_HOST)\r
-\r
-#include "HIDParser.h"\r
-\r
-uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, HID_ReportInfo_t* const ParserData)\r
-{\r
-       HID_StateTable_t      StateTable[HID_STATETABLE_STACK_DEPTH];\r
-       HID_StateTable_t*     CurrStateTable          = &StateTable[0];\r
-       HID_CollectionPath_t* CurrCollectionPath      = NULL;\r
-       HID_ReportSizeInfo_t* CurrReportIDInfo        = &ParserData->ReportIDSizes[0];                  \r
-       uint16_t              UsageList[HID_USAGE_STACK_DEPTH];\r
-       uint8_t               UsageListSize           = 0;\r
-       HID_MinMax_t          UsageMinMax             = {0, 0};\r
-\r
-       memset(ParserData,       0x00, sizeof(HID_ReportInfo_t));\r
-       memset(CurrStateTable,   0x00, sizeof(HID_StateTable_t));\r
-       memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));\r
-\r
-       ParserData->TotalDeviceReports = 1;     \r
-\r
-       while (ReportSize)\r
-       {\r
-               uint8_t  HIDReportItem  = *ReportData;\r
-               uint32_t ReportItemData = 0;\r
-               \r
-               ReportData++;\r
-               ReportSize--;\r
-               \r
-               switch (HIDReportItem & DATA_SIZE_MASK)\r
-               {\r
-                       case DATA_SIZE_4:\r
-                               ReportItemData  = *((uint32_t*)ReportData);\r
-                               ReportSize     -= 4;\r
-                               ReportData     += 4;\r
-                               break;\r
-                       case DATA_SIZE_2:\r
-                               ReportItemData  = *((uint16_t*)ReportData);\r
-                               ReportSize     -= 2;\r
-                               ReportData     += 2;\r
-                               break;\r
-                       case DATA_SIZE_1:\r
-                               ReportItemData  = *((uint8_t*)ReportData);\r
-                               ReportSize     -= 1;\r
-                               ReportData     += 1;\r
-                               break;\r
-               }\r
-\r
-               switch (HIDReportItem & (TYPE_MASK | TAG_MASK))\r
-               {\r
-                       case (TYPE_GLOBAL | TAG_GLOBAL_PUSH):\r
-                               if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1])\r
-                                 return HID_PARSE_HIDStackOverflow;\r
-       \r
-                               memcpy((CurrStateTable + 1),\r
-                                      CurrStateTable,\r
-                                      sizeof(HID_ReportItem_t));\r
-\r
-                               CurrStateTable++;\r
-                               break;\r
-                       case (TYPE_GLOBAL | TAG_GLOBAL_POP):\r
-                               if (CurrStateTable == &StateTable[0])\r
-                                 return HID_PARSE_HIDStackUnderflow;\r
-                                 \r
-                               CurrStateTable--;\r
-                               break;\r
-                       case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE):\r
-                               CurrStateTable->Attributes.Usage.Page       = ReportItemData;\r
-                               break;\r
-                       case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN):\r
-                               CurrStateTable->Attributes.Logical.Minimum  = ReportItemData;\r
-                               break;\r
-                       case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX):\r
-                               CurrStateTable->Attributes.Logical.Maximum  = ReportItemData;\r
-                               break;\r
-                       case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN):\r
-                               CurrStateTable->Attributes.Physical.Minimum = ReportItemData;\r
-                               break;\r
-                       case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX):\r
-                               CurrStateTable->Attributes.Physical.Maximum = ReportItemData;\r
-                               break;\r
-                       case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP):\r
-                               CurrStateTable->Attributes.Unit.Exponent    = ReportItemData;\r
-                               break;\r
-                       case (TYPE_GLOBAL | TAG_GLOBAL_UNIT):\r
-                               CurrStateTable->Attributes.Unit.Type        = ReportItemData;\r
-                               break;\r
-                       case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE):\r
-                               CurrStateTable->Attributes.BitSize          = ReportItemData;\r
-                               break;\r
-                       case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT):\r
-                               CurrStateTable->ReportCount                 = ReportItemData;\r
-                               break;\r
-                       case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID):\r
-                               CurrStateTable->ReportID                    = ReportItemData;\r
-\r
-                               if (ParserData->UsingReportIDs)\r
-                               {\r
-                                       CurrReportIDInfo = NULL;\r
-\r
-                                       for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++)\r
-                                       {\r
-                                               if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID)\r
-                                               {\r
-                                                       CurrReportIDInfo = &ParserData->ReportIDSizes[i];\r
-                                                       break;\r
-                                               }\r
-                                       }\r
-                                       \r
-                                       if (CurrReportIDInfo == NULL)\r
-                                       {\r
-                                               if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS)\r
-                                                 return HID_PARSE_InsufficientReportIDItems;\r
-                                       \r
-                                               CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++];\r
-                                               memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));\r
-                                       }\r
-                               }\r
-\r
-                               ParserData->UsingReportIDs = true;                              \r
-\r
-                               CurrReportIDInfo->ReportID = CurrStateTable->ReportID;\r
-                               break;\r
-                       case (TYPE_LOCAL | TAG_LOCAL_USAGE):\r
-                               if (UsageListSize == HID_USAGE_STACK_DEPTH)\r
-                                 return HID_PARSE_UsageListOverflow;\r
-                       \r
-                               UsageList[UsageListSize++] = ReportItemData;\r
-                               break;\r
-                       case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN):\r
-                               UsageMinMax.Minimum = ReportItemData;\r
-                               break;\r
-                       case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX):\r
-                               UsageMinMax.Maximum = ReportItemData;\r
-                               break;\r
-                       case (TYPE_MAIN | TAG_MAIN_COLLECTION):\r
-                               if (CurrCollectionPath == NULL)\r
-                               {\r
-                                       CurrCollectionPath = &ParserData->CollectionPaths[0];\r
-                               }\r
-                               else\r
-                               {\r
-                                       HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath;\r
-                       \r
-                                       CurrCollectionPath = &ParserData->CollectionPaths[1];\r
-\r
-                                       while (CurrCollectionPath->Parent != NULL)\r
-                                       {\r
-                                               if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS - 1])\r
-                                                 return HID_PARSE_InsufficientCollectionPaths;\r
-                                       \r
-                                               CurrCollectionPath++;\r
-                                       }\r
-\r
-                                       CurrCollectionPath->Parent = ParentCollectionPath;\r
-                               }\r
-                               \r
-                               CurrCollectionPath->Type = ReportItemData;\r
-                               CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page;\r
-                               \r
-                               if (UsageListSize)\r
-                               {\r
-                                       CurrCollectionPath->Usage.Usage = UsageList[0];\r
-\r
-                                       for (uint8_t i = 0; i < UsageListSize; i++)\r
-                                         UsageList[i] = UsageList[i + 1];\r
-                                       \r
-                                       UsageListSize--;\r
-                               }\r
-                               else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)\r
-                               {\r
-                                       CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++;\r
-                               }\r
-                               \r
-                               break;\r
-                       case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION):\r
-                               if (CurrCollectionPath == NULL)\r
-                                 return HID_PARSE_UnexpectedEndCollection;\r
-               \r
-                               CurrCollectionPath = CurrCollectionPath->Parent;\r
-                               break;\r
-                       case (TYPE_MAIN | TAG_MAIN_INPUT):\r
-                       case (TYPE_MAIN | TAG_MAIN_OUTPUT):\r
-                       case (TYPE_MAIN | TAG_MAIN_FEATURE):\r
-                               for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++)\r
-                               {\r
-                                       HID_ReportItem_t NewReportItem;\r
-                                 \r
-                                       memcpy(&NewReportItem.Attributes,\r
-                                              &CurrStateTable->Attributes,\r
-                                              sizeof(HID_ReportItem_Attributes_t));\r
-\r
-                                       NewReportItem.ItemFlags      = ReportItemData;\r
-                                       NewReportItem.CollectionPath = CurrCollectionPath;\r
-                                       NewReportItem.ReportID       = CurrStateTable->ReportID;\r
-\r
-                                       if (UsageListSize)\r
-                                       {\r
-                                               NewReportItem.Attributes.Usage.Usage = UsageList[0];\r
-\r
-                                               for (uint8_t i = 0; i < UsageListSize; i++)\r
-                                                 UsageList[i] = UsageList[i + 1];\r
-                                                 \r
-                                               UsageListSize--;\r
-                                       }\r
-                                       else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)\r
-                                       {\r
-                                               NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++;\r
-                                       }\r
-                                       \r
-                                       uint8_t ItemTag = (HIDReportItem & TAG_MASK);\r
-\r
-                                       if (ItemTag == TAG_MAIN_INPUT)\r
-                                         NewReportItem.ItemType = REPORT_ITEM_TYPE_In;\r
-                                       else if (ItemTag == TAG_MAIN_OUTPUT)\r
-                                         NewReportItem.ItemType = REPORT_ITEM_TYPE_Out;\r
-                                       else\r
-                                         NewReportItem.ItemType = REPORT_ITEM_TYPE_Feature;\r
-                                       \r
-                                       NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType];\r
-\r
-                                       CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize;\r
-\r
-                                       if (ParserData->LargestReportSizeBits < NewReportItem.BitOffset)\r
-                                         ParserData->LargestReportSizeBits = NewReportItem.BitOffset;\r
-                                       \r
-                                       if (!(ReportItemData & IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem))\r
-                                       {                                       \r
-                                               if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS)\r
-                                                 return HID_PARSE_InsufficientReportItems;\r
-                                       \r
-                                               memcpy(&ParserData->ReportItems[ParserData->TotalReportItems],\r
-                                                      &NewReportItem, sizeof(HID_ReportItem_t));\r
-                                       \r
-                                               ParserData->TotalReportItems++;\r
-                                       }\r
-                               }\r
-                               \r
-                               break;\r
-               }\r
-         \r
-               if ((HIDReportItem & TYPE_MASK) == TYPE_MAIN)\r
-               {\r
-                       UsageMinMax.Minimum = 0;\r
-                       UsageMinMax.Maximum = 0;\r
-                       UsageListSize   = 0;\r
-               }\r
-       }\r
-       \r
-       if (!(ParserData->TotalReportItems))\r
-         return HID_PARSE_NoUnfilteredReportItems;\r
-       \r
-       return HID_PARSE_Successful;\r
-}\r
-\r
-bool USB_GetHIDReportItemInfo(const uint8_t* ReportData, HID_ReportItem_t* const ReportItem)\r
-{\r
-       uint16_t DataBitsRem  = ReportItem->Attributes.BitSize;\r
-       uint16_t CurrentBit   = ReportItem->BitOffset;\r
-       uint32_t BitMask      = (1 << 0);\r
-\r
-       ReportItem->PreviousValue = ReportItem->Value;\r
-       ReportItem->Value = 0;\r
-       \r
-       if (ReportItem->ReportID)\r
-       {\r
-               if (ReportItem->ReportID != ReportData[0])\r
-                 return false;\r
-\r
-               ReportData++;\r
-       }\r
-\r
-       while (DataBitsRem--)\r
-       {\r
-               if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8)))\r
-                 ReportItem->Value |= BitMask;\r
-               \r
-               CurrentBit++;\r
-               BitMask <<= 1;\r
-       }\r
-       \r
-       return true;\r
-}\r
-\r
-void USB_SetHIDReportItemInfo(uint8_t* ReportData, HID_ReportItem_t* const ReportItem)\r
-{\r
-       uint16_t DataBitsRem  = ReportItem->Attributes.BitSize;\r
-       uint16_t CurrentBit   = ReportItem->BitOffset;\r
-       uint32_t BitMask      = (1 << 0);\r
-\r
-       if (ReportItem->ReportID)\r
-       {\r
-               ReportData[0] = ReportItem->ReportID;\r
-               ReportData++;\r
-       }\r
-\r
-       ReportItem->PreviousValue = ReportItem->Value;\r
-\r
-       while (DataBitsRem--)\r
-       {\r
-               if (ReportItem->Value & (1 << (CurrentBit % 8)))\r
-                 ReportData[CurrentBit / 8] |= BitMask;\r
-\r
-               CurrentBit++;\r
-               BitMask <<= 1;\r
-       }\r
-}\r
-\r
-uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData, const uint8_t ReportID, const uint8_t ReportType)\r
-{\r
-       for (uint8_t i = 0; i < HID_MAX_REPORT_IDS; i++)\r
-       {\r
-               uint16_t ReportSizeBits = ParserData->ReportIDSizes[i].ReportSizeBits[ReportType];\r
-       \r
-               if (ParserData->ReportIDSizes[i].ReportID == ReportID)\r
-                 return ((ReportSizeBits >> 3) + ((ReportSizeBits & 0x07) ? 1 : 0));\r
-       }\r
-\r
-       return 0;\r
-}\r
-\r
-#endif\r
+/*
+             LUFA Library
+     Copyright (C) Dean Camera, 2010.
+              
+  dean [at] fourwalledcubicle [dot] com
+      www.fourwalledcubicle.com
+*/
+
+/*
+  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+  Permission to use, copy, modify, distribute, and sell this 
+  software and its documentation for any purpose is hereby granted
+  without fee, provided that the above copyright notice appear in 
+  all copies and that both that the copyright notice and this
+  permission notice and warranty disclaimer appear in supporting 
+  documentation, and that the name of the author not be used in 
+  advertising or publicity pertaining to distribution of the 
+  software without specific, written prior permission.
+
+  The author disclaim all warranties with regard to this
+  software, including all implied warranties of merchantability
+  and fitness.  In no event shall the author be liable for any
+  special, indirect or consequential damages or any damages
+  whatsoever resulting from loss of use, data or profits, whether
+  in an action of contract, negligence or other tortious action,
+  arising out of or in connection with the use or performance of
+  this software.
+*/
+
+#define  __INCLUDE_FROM_USB_DRIVER
+#include "../../HighLevel/USBMode.h"
+#if defined(USB_CAN_BE_HOST)
+
+#include "HIDParser.h"
+
+uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, HID_ReportInfo_t* const ParserData)
+{
+       HID_StateTable_t      StateTable[HID_STATETABLE_STACK_DEPTH];
+       HID_StateTable_t*     CurrStateTable          = &StateTable[0];
+       HID_CollectionPath_t* CurrCollectionPath      = NULL;
+       HID_ReportSizeInfo_t* CurrReportIDInfo        = &ParserData->ReportIDSizes[0];                  
+       uint16_t              UsageList[HID_USAGE_STACK_DEPTH];
+       uint8_t               UsageListSize           = 0;
+       HID_MinMax_t          UsageMinMax             = {0, 0};
+
+       memset(ParserData,       0x00, sizeof(HID_ReportInfo_t));
+       memset(CurrStateTable,   0x00, sizeof(HID_StateTable_t));
+       memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
+
+       ParserData->TotalDeviceReports = 1;     
+
+       while (ReportSize)
+       {
+               uint8_t  HIDReportItem  = *ReportData;
+               uint32_t ReportItemData = 0;
+               
+               ReportData++;
+               ReportSize--;
+               
+               switch (HIDReportItem & DATA_SIZE_MASK)
+               {
+                       case DATA_SIZE_4:
+                               ReportItemData  = *((uint32_t*)ReportData);
+                               ReportSize     -= 4;
+                               ReportData     += 4;
+                               break;
+                       case DATA_SIZE_2:
+                               ReportItemData  = *((uint16_t*)ReportData);
+                               ReportSize     -= 2;
+                               ReportData     += 2;
+                               break;
+                       case DATA_SIZE_1:
+                               ReportItemData  = *((uint8_t*)ReportData);
+                               ReportSize     -= 1;
+                               ReportData     += 1;
+                               break;
+               }
+
+               switch (HIDReportItem & (TYPE_MASK | TAG_MASK))
+               {
+                       case (TYPE_GLOBAL | TAG_GLOBAL_PUSH):
+                               if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1])
+                                 return HID_PARSE_HIDStackOverflow;
+       
+                               memcpy((CurrStateTable + 1),
+                                      CurrStateTable,
+                                      sizeof(HID_ReportItem_t));
+
+                               CurrStateTable++;
+                               break;
+                       case (TYPE_GLOBAL | TAG_GLOBAL_POP):
+                               if (CurrStateTable == &StateTable[0])
+                                 return HID_PARSE_HIDStackUnderflow;
+                                 
+                               CurrStateTable--;
+                               break;
+                       case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE):
+                               CurrStateTable->Attributes.Usage.Page       = ReportItemData;
+                               break;
+                       case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN):
+                               CurrStateTable->Attributes.Logical.Minimum  = ReportItemData;
+                               break;
+                       case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX):
+                               CurrStateTable->Attributes.Logical.Maximum  = ReportItemData;
+                               break;
+                       case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN):
+                               CurrStateTable->Attributes.Physical.Minimum = ReportItemData;
+                               break;
+                       case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX):
+                               CurrStateTable->Attributes.Physical.Maximum = ReportItemData;
+                               break;
+                       case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP):
+                               CurrStateTable->Attributes.Unit.Exponent    = ReportItemData;
+                               break;
+                       case (TYPE_GLOBAL | TAG_GLOBAL_UNIT):
+                               CurrStateTable->Attributes.Unit.Type        = ReportItemData;
+                               break;
+                       case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE):
+                               CurrStateTable->Attributes.BitSize          = ReportItemData;
+                               break;
+                       case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT):
+                               CurrStateTable->ReportCount                 = ReportItemData;
+                               break;
+                       case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID):
+                               CurrStateTable->ReportID                    = ReportItemData;
+
+                               if (ParserData->UsingReportIDs)
+                               {
+                                       CurrReportIDInfo = NULL;
+
+                                       for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++)
+                                       {
+                                               if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID)
+                                               {
+                                                       CurrReportIDInfo = &ParserData->ReportIDSizes[i];
+                                                       break;
+                                               }
+                                       }
+                                       
+                                       if (CurrReportIDInfo == NULL)
+                                       {
+                                               if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS)
+                                                 return HID_PARSE_InsufficientReportIDItems;
+                                       
+                                               CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++];
+                                               memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
+                                       }
+                               }
+
+                               ParserData->UsingReportIDs = true;                              
+
+                               CurrReportIDInfo->ReportID = CurrStateTable->ReportID;
+                               break;
+                       case (TYPE_LOCAL | TAG_LOCAL_USAGE):
+                               if (UsageListSize == HID_USAGE_STACK_DEPTH)
+                                 return HID_PARSE_UsageListOverflow;
+                       
+                               UsageList[UsageListSize++] = ReportItemData;
+                               break;
+                       case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN):
+                               UsageMinMax.Minimum = ReportItemData;
+                               break;
+                       case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX):
+                               UsageMinMax.Maximum = ReportItemData;
+                               break;
+                       case (TYPE_MAIN | TAG_MAIN_COLLECTION):
+                               if (CurrCollectionPath == NULL)
+                               {
+                                       CurrCollectionPath = &ParserData->CollectionPaths[0];
+                               }
+                               else
+                               {
+                                       HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath;
+                       
+                                       CurrCollectionPath = &ParserData->CollectionPaths[1];
+
+                                       while (CurrCollectionPath->Parent != NULL)
+                                       {
+                                               if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS - 1])
+                                                 return HID_PARSE_InsufficientCollectionPaths;
+                                       
+                                               CurrCollectionPath++;
+                                       }
+
+                                       CurrCollectionPath->Parent = ParentCollectionPath;
+                               }
+                               
+                               CurrCollectionPath->Type = ReportItemData;
+                               CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page;
+                               
+                               if (UsageListSize)
+                               {
+                                       CurrCollectionPath->Usage.Usage = UsageList[0];
+
+                                       for (uint8_t i = 0; i < UsageListSize; i++)
+                                         UsageList[i] = UsageList[i + 1];
+                                       
+                                       UsageListSize--;
+                               }
+                               else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
+                               {
+                                       CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++;
+                               }
+                               
+                               break;
+                       case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION):
+                               if (CurrCollectionPath == NULL)
+                                 return HID_PARSE_UnexpectedEndCollection;
+               
+                               CurrCollectionPath = CurrCollectionPath->Parent;
+                               break;
+                       case (TYPE_MAIN | TAG_MAIN_INPUT):
+                       case (TYPE_MAIN | TAG_MAIN_OUTPUT):
+                       case (TYPE_MAIN | TAG_MAIN_FEATURE):
+                               for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++)
+                               {
+                                       HID_ReportItem_t NewReportItem;
+                                 
+                                       memcpy(&NewReportItem.Attributes,
+                                              &CurrStateTable->Attributes,
+                                              sizeof(HID_ReportItem_Attributes_t));
+
+                                       NewReportItem.ItemFlags      = ReportItemData;
+                                       NewReportItem.CollectionPath = CurrCollectionPath;
+                                       NewReportItem.ReportID       = CurrStateTable->ReportID;
+
+                                       if (UsageListSize)
+                                       {
+                                               NewReportItem.Attributes.Usage.Usage = UsageList[0];
+
+                                               for (uint8_t i = 0; i < UsageListSize; i++)
+                                                 UsageList[i] = UsageList[i + 1];
+                                                 
+                                               UsageListSize--;
+                                       }
+                                       else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
+                                       {
+                                               NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++;
+                                       }
+                                       
+                                       uint8_t ItemTag = (HIDReportItem & TAG_MASK);
+
+                                       if (ItemTag == TAG_MAIN_INPUT)
+                                         NewReportItem.ItemType = REPORT_ITEM_TYPE_In;
+                                       else if (ItemTag == TAG_MAIN_OUTPUT)
+                                         NewReportItem.ItemType = REPORT_ITEM_TYPE_Out;
+                                       else
+                                         NewReportItem.ItemType = REPORT_ITEM_TYPE_Feature;
+                                       
+                                       NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType];
+
+                                       CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize;
+
+                                       if (ParserData->LargestReportSizeBits < NewReportItem.BitOffset)
+                                         ParserData->LargestReportSizeBits = NewReportItem.BitOffset;
+                                       
+                                       if (!(ReportItemData & IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem))
+                                       {                                       
+                                               if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS)
+                                                 return HID_PARSE_InsufficientReportItems;
+                                       
+                                               memcpy(&ParserData->ReportItems[ParserData->TotalReportItems],
+                                                      &NewReportItem, sizeof(HID_ReportItem_t));
+                                       
+                                               ParserData->TotalReportItems++;
+                                       }
+                               }
+                               
+                               break;
+               }
+         
+               if ((HIDReportItem & TYPE_MASK) == TYPE_MAIN)
+               {
+                       UsageMinMax.Minimum = 0;
+                       UsageMinMax.Maximum = 0;
+                       UsageListSize   = 0;
+               }
+       }
+       
+       if (!(ParserData->TotalReportItems))
+         return HID_PARSE_NoUnfilteredReportItems;
+       
+       return HID_PARSE_Successful;
+}
+
+bool USB_GetHIDReportItemInfo(const uint8_t* ReportData, HID_ReportItem_t* const ReportItem)
+{
+       uint16_t DataBitsRem  = ReportItem->Attributes.BitSize;
+       uint16_t CurrentBit   = ReportItem->BitOffset;
+       uint32_t BitMask      = (1 << 0);
+
+       ReportItem->PreviousValue = ReportItem->Value;
+       ReportItem->Value = 0;
+       
+       if (ReportItem->ReportID)
+       {
+               if (ReportItem->ReportID != ReportData[0])
+                 return false;
+
+               ReportData++;
+       }
+
+       while (DataBitsRem--)
+       {
+               if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8)))
+                 ReportItem->Value |= BitMask;
+               
+               CurrentBit++;
+               BitMask <<= 1;
+       }
+       
+       return true;
+}
+
+void USB_SetHIDReportItemInfo(uint8_t* ReportData, HID_ReportItem_t* const ReportItem)
+{
+       uint16_t DataBitsRem  = ReportItem->Attributes.BitSize;
+       uint16_t CurrentBit   = ReportItem->BitOffset;
+       uint32_t BitMask      = (1 << 0);
+
+       if (ReportItem->ReportID)
+       {
+               ReportData[0] = ReportItem->ReportID;
+               ReportData++;
+       }
+
+       ReportItem->PreviousValue = ReportItem->Value;
+
+       while (DataBitsRem--)
+       {
+               if (ReportItem->Value & (1 << (CurrentBit % 8)))
+                 ReportData[CurrentBit / 8] |= BitMask;
+
+               CurrentBit++;
+               BitMask <<= 1;
+       }
+}
+
+uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData, const uint8_t ReportID, const uint8_t ReportType)
+{
+       for (uint8_t i = 0; i < HID_MAX_REPORT_IDS; i++)
+       {
+               uint16_t ReportSizeBits = ParserData->ReportIDSizes[i].ReportSizeBits[ReportType];
+       
+               if (ParserData->ReportIDSizes[i].ReportID == ReportID)
+                 return ((ReportSizeBits >> 3) + ((ReportSizeBits & 0x07) ? 1 : 0));
+       }
+
+       return 0;
+}
+
+#endif