[USB-BRINGUP]
authorJohannes Anderwald <johannes.anderwald@reactos.org>
Wed, 4 Jan 2012 21:58:18 +0000 (21:58 +0000)
committerJohannes Anderwald <johannes.anderwald@reactos.org>
Wed, 4 Jan 2012 21:58:18 +0000 (21:58 +0000)
- Implement a HID parsing library, which is based on Haiku`s exellent HID Stack
- Implement HidP_FreeCollection, HidP_GetCaps, HidP_GetCollectionDescription, HidP_MaxUsageListLength, HidP_GetSpecificValueCaps, HidP_GetUsages, HidP_GetScaledUsageValue
- hidparse driver is now implemented enough to support a hid mouse
- Tested in VBox 4.1.4 + WinXP + ReactOS usbohci+ mouhid+ hidclass+ hidparse+hidusb

svn path=/branches/usb-bringup/; revision=54834

drivers/hid/hidparse/CMakeLists.txt
drivers/hid/hidparse/hidparse.c
drivers/hid/hidparse/hidparse.h
lib/drivers/CMakeLists.txt
lib/drivers/hidparser/CMakeLists.txt [new file with mode: 0644]
lib/drivers/hidparser/api.c [new file with mode: 0644]
lib/drivers/hidparser/hidparser.c [new file with mode: 0644]
lib/drivers/hidparser/hidparser.h [new file with mode: 0644]
lib/drivers/hidparser/parser.c [new file with mode: 0644]
lib/drivers/hidparser/parser.h [new file with mode: 0644]

index a6740cc..14a1f87 100644 (file)
@@ -2,7 +2,10 @@
 spec2def(hidparse.sys hidparse.spec)
 add_definitions(-DDEBUG_MODE)
 
-include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include)
+include_directories(
+    ${REACTOS_SOURCE_DIR}/ntoskrnl/include
+    ${REACTOS_SOURCE_DIR}/lib/drivers/hidparser)
+
 
 add_library(hidparse SHARED hidparse.c hidparse.rc ${CMAKE_CURRENT_BINARY_DIR}/hidparse.def)
 
@@ -12,3 +15,5 @@ add_cab_target(hidparse 2)
 
 add_cab_target(hidparse 2)
 add_importlib_target(hidparse.spec)
+
+target_link_libraries(hidparse hidparser)
index fea2650..265cbcd 100644 (file)
 
 #include "hidparse.h"
 
+PVOID
+NTAPI
+AllocFunction(
+    IN ULONG ItemSize)
+{
+    PVOID Item = ExAllocatePool(NonPagedPool, ItemSize);
+    if (Item)
+    {
+        //
+        // zero item
+        //
+        RtlZeroMemory(Item, ItemSize);
+    }
+
+    //
+    // done
+    //
+    return Item;
+}
 
 VOID
 NTAPI
-HidP_FreeCollectionDescription (
-    IN PHIDP_DEVICE_DESC   DeviceDescription)
+FreeFunction(
+    IN PVOID Item)
 {
-    DPRINT1("HidP_FreeCollectionDescription DeviceDescription %p\n", DeviceDescription);
-
     //
-    // free collection
+    // free item
     //
-    ExFreePool(DeviceDescription->CollectionDesc);
+    ExFreePool(Item);
+}
 
+VOID
+NTAPI
+ZeroFunction(
+    IN PVOID Item,
+    IN ULONG ItemSize)
+{
     //
-    // free report ids
+    // zero item
     //
-    ExFreePool(DeviceDescription->ReportIDs);
+    RtlZeroMemory(Item, ItemSize);
 }
 
-#undef HidP_GetButtonCaps
+VOID
+NTAPI
+CopyFunction(
+    IN PVOID Target,
+    IN PVOID Source,
+    IN ULONG Length)
+{
+    //
+    // copy item
+    //
+    RtlCopyMemory(Target, Source, Length);
+}
 
-HIDAPI
-NTSTATUS
+VOID
 NTAPI
-HidP_GetButtonCaps(
-    HIDP_REPORT_TYPE ReportType,
-    PHIDP_BUTTON_CAPS ButtonCaps,
-    PUSHORT ButtonCapsLength,
-    PHIDP_PREPARSED_DATA PreparsedData)
+DebugFunction(
+    IN LPCSTR FormatStr, ...)
 {
-    return HidP_GetSpecificButtonCaps(ReportType, HID_USAGE_PAGE_UNDEFINED, 0, 0, ButtonCaps, (PULONG)ButtonCapsLength, PreparsedData);
+
+    va_list args;
+    unsigned int i;
+     char printbuffer[1024];
+
+     va_start(args, FormatStr);
+     i = vsprintf(printbuffer, FormatStr, args);
+     va_end(args);
+
+     DbgPrint(printbuffer);
 }
 
-HIDAPI
-NTSTATUS
+VOID
 NTAPI
-HidP_GetSpecificButtonCaps(
-  IN HIDP_REPORT_TYPE  ReportType,
-  IN USAGE  UsagePage,
-  IN USHORT  LinkCollection,
-  IN USAGE  Usage,
-  OUT PHIDP_BUTTON_CAPS  ButtonCaps,
-  IN OUT PULONG  ButtonCapsLength,
-  IN PHIDP_PREPARSED_DATA  PreparsedData)
+HidP_FreeCollectionDescription (
+    IN PHIDP_DEVICE_DESC   DeviceDescription)
 {
-    UNIMPLEMENTED
-    ASSERT(FALSE);
-    return STATUS_NOT_IMPLEMENTED;
+    HID_PARSER Parser;
+
+    //
+    // init parser
+    //
+    HidParser_InitParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, NULL, &Parser);
+
+    //
+    // free collection
+    //
+    HidParser_FreeCollectionDescription(&Parser, DeviceDescription);
 }
 
 
@@ -68,9 +109,17 @@ HidP_GetCaps(
     IN PHIDP_PREPARSED_DATA  PreparsedData,
     OUT PHIDP_CAPS  Capabilities)
 {
-    UNIMPLEMENTED
-    ASSERT(FALSE);
-    return STATUS_NOT_IMPLEMENTED;
+    HID_PARSER Parser;
+
+    //
+    // init parser
+    //
+    HidParser_InitParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, PreparsedData, &Parser);
+
+    //
+    // get caps
+    //
+    return HidParser_GetCaps(&Parser, Capabilities);
 }
 
 NTSTATUS
@@ -81,53 +130,162 @@ HidP_GetCollectionDescription(
     IN POOL_TYPE PoolType,
     OUT PHIDP_DEVICE_DESC DeviceDescription)
 {
-    UNIMPLEMENTED
-    ASSERT(FALSE);
-    return STATUS_NOT_IMPLEMENTED;
+    PHID_PARSER Parser;
+    HIDPARSER_STATUS Status;
+
+    //
+    // first allocate the parser
+    //
+    Status = HidParser_AllocateParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, &Parser);
+    if (Status != HIDPARSER_STATUS_SUCCESS)
+    {
+        //
+        // not enough memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // get description;
+    //
+    Status = HidParser_GetCollectionDescription(Parser, ReportDesc, DescLength, PoolType, DeviceDescription);
+
+    //
+    // FIXME parser memory leak
+    //
+    return Status;
+}
+
+HIDAPI
+ULONG
+NTAPI
+HidP_MaxUsageListLength(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage  OPTIONAL,
+  IN PHIDP_PREPARSED_DATA  PreparsedData)
+{
+    HID_PARSER Parser;
+
+    //
+    // sanity check
+    //
+    ASSERT(ReportType == HidP_Input || ReportType == HidP_Output || ReportType == HidP_Feature);
+
+    //
+    // init parser
+    //
+    HidParser_InitParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, PreparsedData, &Parser);
+
+
+    //
+    // get usage length
+    //
+    return HidParser_MaxUsageListLength(&Parser, ReportType, UsagePage);
 }
 
 HIDAPI
 NTSTATUS
 NTAPI
-HidP_GetData(
+HidP_GetSpecificValueCaps(
   IN HIDP_REPORT_TYPE  ReportType,
-  OUT PHIDP_DATA  DataList,
-  IN OUT PULONG  DataLength,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection,
+  IN USAGE  Usage,
+  OUT PHIDP_VALUE_CAPS  ValueCaps,
+  IN OUT PULONG  ValueCapsLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData)
+{
+    HID_PARSER Parser;
+
+    //
+    // sanity check
+    //
+    ASSERT(ReportType == HidP_Input || ReportType == HidP_Output || ReportType == HidP_Feature);
+
+    //
+    // init parser
+    //
+    HidParser_InitParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, PreparsedData, &Parser);
+
+    //
+    // get value caps
+    //
+    return HidParser_GetSpecificValueCaps(&Parser, ReportType, UsagePage, LinkCollection, Usage, ValueCaps, ValueCapsLength);
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidP_GetUsages(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection  OPTIONAL,
+  OUT USAGE  *UsageList,
+  IN OUT ULONG  *UsageLength,
   IN PHIDP_PREPARSED_DATA  PreparsedData,
   IN PCHAR  Report,
   IN ULONG  ReportLength)
 {
-    UNIMPLEMENTED
-    ASSERT(FALSE);
-    return STATUS_NOT_IMPLEMENTED;
+    HID_PARSER Parser;
+
+    //
+    // sanity check
+    //
+    ASSERT(ReportType == HidP_Input || ReportType == HidP_Output || ReportType == HidP_Feature);
+
+    //
+    // init parser
+    //
+    HidParser_InitParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, PreparsedData, &Parser);
+
+    //
+    // get usages
+    //
+    return HidParser_GetUsages(&Parser, ReportType, UsagePage, LinkCollection, UsageList, UsageLength, Report, ReportLength);
 }
 
+
+#undef HidP_GetButtonCaps
+
 HIDAPI
 NTSTATUS
 NTAPI
-HidP_GetExtendedAttributes(
+HidP_UsageListDifference(
+  IN PUSAGE  PreviousUsageList,
+  IN PUSAGE  CurrentUsageList,
+  OUT PUSAGE  BreakUsageList,
+  OUT PUSAGE  MakeUsageList,
+  IN ULONG  UsageListLength)
+{
+    return HidParser_UsageListDifference(PreviousUsageList, CurrentUsageList, BreakUsageList, MakeUsageList, UsageListLength);
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidP_GetUsagesEx(
   IN HIDP_REPORT_TYPE  ReportType,
-  IN USHORT  DataIndex,
+  IN USHORT  LinkCollection,
+  OUT PUSAGE_AND_PAGE  ButtonList,
+  IN OUT ULONG  *UsageLength,
   IN PHIDP_PREPARSED_DATA  PreparsedData,
-  OUT PHIDP_EXTENDED_ATTRIBUTES  Attributes,
-  IN OUT PULONG  LengthAttributes)
+  IN PCHAR  Report,
+  IN ULONG  ReportLength)
 {
-    UNIMPLEMENTED
-    ASSERT(FALSE);
-    return STATUS_NOT_IMPLEMENTED;
+    return HidP_GetUsages(ReportType, HID_USAGE_PAGE_UNDEFINED, LinkCollection, (PUSAGE)ButtonList, UsageLength, PreparsedData, Report, ReportLength);
 }
 
 HIDAPI
 NTSTATUS
 NTAPI
-HidP_GetLinkCollectionNodes(
-    OUT PHIDP_LINK_COLLECTION_NODE  LinkCollectionNodes,
-    IN OUT PULONG  LinkCollectionNodesLength,
-    IN PHIDP_PREPARSED_DATA  PreparsedData)
+HidP_UsageAndPageListDifference(
+   IN PUSAGE_AND_PAGE  PreviousUsageList,
+   IN PUSAGE_AND_PAGE  CurrentUsageList,
+   OUT PUSAGE_AND_PAGE  BreakUsageList,
+   OUT PUSAGE_AND_PAGE  MakeUsageList,
+   IN ULONG  UsageListLength)
 {
-    UNIMPLEMENTED
-    ASSERT(FALSE);
-    return STATUS_NOT_IMPLEMENTED;
+    return HidParser_UsageAndPageListDifference(PreviousUsageList, CurrentUsageList, BreakUsageList, MakeUsageList, UsageListLength);
 }
 
 HIDAPI
@@ -143,171 +301,78 @@ HidP_GetScaledUsageValue(
   IN PCHAR  Report,
   IN ULONG  ReportLength)
 {
-    UNIMPLEMENTED
-    ASSERT(FALSE);
-    return STATUS_NOT_IMPLEMENTED;
+    HID_PARSER Parser;
+
+    //
+    // sanity check
+    //
+    ASSERT(ReportType == HidP_Input || ReportType == HidP_Output || ReportType == HidP_Feature);
+
+    //
+    // init parser
+    //
+    HidParser_InitParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, PreparsedData, &Parser);
+
+    //
+    // get scaled usage value
+    //
+    return HidParser_GetScaledUsageValue(&Parser, ReportType, UsagePage, LinkCollection, Usage, UsageValue, Report, ReportLength);
 }
 
 HIDAPI
 NTSTATUS
 NTAPI
-HidP_GetUsageValue(
+HidP_GetButtonCaps(
+    HIDP_REPORT_TYPE ReportType,
+    PHIDP_BUTTON_CAPS ButtonCaps,
+    PUSHORT ButtonCapsLength,
+    PHIDP_PREPARSED_DATA PreparsedData)
+{
+    return HidP_GetSpecificButtonCaps(ReportType, HID_USAGE_PAGE_UNDEFINED, 0, 0, ButtonCaps, (PULONG)ButtonCapsLength, PreparsedData);
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidP_GetSpecificButtonCaps(
   IN HIDP_REPORT_TYPE  ReportType,
   IN USAGE  UsagePage,
   IN USHORT  LinkCollection,
   IN USAGE  Usage,
-  OUT PULONG  UsageValue,
-  IN PHIDP_PREPARSED_DATA  PreparsedData,
-  IN PCHAR  Report,
-  IN ULONG  ReportLength)
+  OUT PHIDP_BUTTON_CAPS  ButtonCaps,
+  IN OUT PULONG  ButtonCapsLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData)
 {
     UNIMPLEMENTED
     ASSERT(FALSE);
     return STATUS_NOT_IMPLEMENTED;
 }
 
-
-
 HIDAPI
 NTSTATUS
 NTAPI
-HidP_UsageListDifference(
-  IN PUSAGE  PreviousUsageList,
-  IN PUSAGE  CurrentUsageList,
-  OUT PUSAGE  BreakUsageList,
-  OUT PUSAGE  MakeUsageList,
-  IN ULONG  UsageListLength)
+HidP_GetData(
+  IN HIDP_REPORT_TYPE  ReportType,
+  OUT PHIDP_DATA  DataList,
+  IN OUT PULONG  DataLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN PCHAR  Report,
+  IN ULONG  ReportLength)
 {
-    ULONG Index, SubIndex, bFound, BreakUsageIndex = 0, MakeUsageIndex = 0;
-    USAGE CurrentUsage, Usage;
-
-    if (UsageListLength)
-    {
-        Index = 0;
-        do
-        {
-            /* get current usage */
-            CurrentUsage = PreviousUsageList[Index];
-
-            /* is the end of list reached? */
-            if (!CurrentUsage)
-                break;
-
-            /* start searching in current usage list */
-            SubIndex = 0;
-            bFound = FALSE;
-            do
-            {
-                /* get usage of current list */
-                Usage = CurrentUsageList[SubIndex];
-
-                /* end of list reached? */
-                if (!Usage)
-                    break;
-
-                /* check if it matches the current one */
-                if (CurrentUsage == Usage)
-                {
-                    /* it does */
-                    bFound = TRUE;
-                    break;
-                }
-
-                /* move to next usage */
-                SubIndex++;
-            }while(SubIndex < UsageListLength);
-
-            /* was the usage found ?*/
-            if (!bFound)
-            {
-                /* store it in the break usage list */
-                BreakUsageList[BreakUsageIndex] = CurrentUsage;
-                BreakUsageIndex++;
-            }
-
-            /* move to next usage */
-            Index++;
-
-        }while(Index < UsageListLength);
-
-        /* now process the new items */
-        Index = 0;
-        do
-        {
-            /* get current usage */
-            CurrentUsage = CurrentUsageList[Index];
-
-            /* is the end of list reached? */
-            if (!CurrentUsage)
-                break;
-
-            /* start searching in current usage list */
-            SubIndex = 0;
-            bFound = FALSE;
-            do
-            {
-                /* get usage of previous list */
-                Usage = PreviousUsageList[SubIndex];
-
-                /* end of list reached? */
-                if (!Usage)
-                    break;
-
-                /* check if it matches the current one */
-                if (CurrentUsage == Usage)
-                {
-                    /* it does */
-                    bFound = TRUE;
-                    break;
-                }
-
-                /* move to next usage */
-                SubIndex++;
-            }while(SubIndex < UsageListLength);
-
-            /* was the usage found ?*/
-            if (!bFound)
-            {
-                /* store it in the make usage list */
-                MakeUsageList[MakeUsageIndex] = CurrentUsage;
-                MakeUsageIndex++;
-            }
-
-            /* move to next usage */
-            Index++;
-
-        }while(Index < UsageListLength);
-    }
-
-    /* does the break list contain empty entries */
-    if (BreakUsageIndex < UsageListLength)
-    {
-        /* zeroize entries */
-        RtlZeroMemory(&BreakUsageList[BreakUsageIndex], sizeof(USAGE) * (UsageListLength - BreakUsageIndex));
-    }
-
-    /* does the make usage list contain empty entries */
-    if (MakeUsageIndex < UsageListLength)
-    {
-        /* zeroize entries */
-        RtlZeroMemory(&MakeUsageList[MakeUsageIndex], sizeof(USAGE) * (UsageListLength - MakeUsageIndex));
-    }
-
-    /* done */
-    return HIDP_STATUS_SUCCESS;
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
 }
 
 HIDAPI
 NTSTATUS
 NTAPI
-HidP_GetSpecificValueCaps(
+HidP_GetExtendedAttributes(
   IN HIDP_REPORT_TYPE  ReportType,
   IN USAGE  UsagePage,
-  IN USHORT  LinkCollection,
-  IN USAGE  Usage,
-  OUT PHIDP_VALUE_CAPS  ValueCaps,
-  IN OUT PULONG  ValueCapsLength,
-  IN PHIDP_PREPARSED_DATA  PreparsedData)
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  OUT PHIDP_EXTENDED_ATTRIBUTES  Attributes,
+  IN OUT PULONG  LengthAttributes)
 {
     UNIMPLEMENTED
     ASSERT(FALSE);
@@ -315,12 +380,12 @@ HidP_GetSpecificValueCaps(
 }
 
 HIDAPI
-ULONG
+NTSTATUS
 NTAPI
-HidP_MaxUsageListLength(
-  IN HIDP_REPORT_TYPE  ReportType,
-  IN USAGE  UsagePage  OPTIONAL,
-  IN PHIDP_PREPARSED_DATA  PreparsedData)
+HidP_GetLinkCollectionNodes(
+    OUT PHIDP_LINK_COLLECTION_NODE  LinkCollectionNodes,
+    IN OUT PULONG  LinkCollectionNodesLength,
+    IN PHIDP_PREPARSED_DATA  PreparsedData)
 {
     UNIMPLEMENTED
     ASSERT(FALSE);
@@ -330,12 +395,12 @@ HidP_MaxUsageListLength(
 HIDAPI
 NTSTATUS
 NTAPI
-HidP_GetUsages(
+HidP_GetUsageValue(
   IN HIDP_REPORT_TYPE  ReportType,
   IN USAGE  UsagePage,
-  IN USHORT  LinkCollection  OPTIONAL,
-  OUT USAGE  *UsageList,
-  IN OUT ULONG  *UsageLength,
+  IN USHORT  LinkCollection,
+  IN USAGE  Usage,
+  OUT PULONG  UsageValue,
   IN PHIDP_PREPARSED_DATA  PreparsedData,
   IN PCHAR  Report,
   IN ULONG  ReportLength)
@@ -388,150 +453,6 @@ HidP_GetUsageValueArray(
     return STATUS_NOT_IMPLEMENTED;
 }
 
-HIDAPI
-NTSTATUS
-NTAPI
-HidP_GetUsagesEx(
-  IN HIDP_REPORT_TYPE  ReportType,
-  IN USHORT  LinkCollection,
-  OUT PUSAGE_AND_PAGE  ButtonList,
-  IN OUT ULONG  *UsageLength,
-  IN PHIDP_PREPARSED_DATA  PreparsedData,
-  IN PCHAR  Report,
-  IN ULONG  ReportLength)
-{
-    return HidP_GetUsages(ReportType, HID_USAGE_PAGE_UNDEFINED, LinkCollection, (PUSAGE)ButtonList, UsageLength, PreparsedData, Report, ReportLength);
-}
-
-
-HIDAPI
-NTSTATUS
-NTAPI
-HidP_UsageAndPageListDifference(
-   IN PUSAGE_AND_PAGE  PreviousUsageList,
-   IN PUSAGE_AND_PAGE  CurrentUsageList,
-   OUT PUSAGE_AND_PAGE  BreakUsageList,
-   OUT PUSAGE_AND_PAGE  MakeUsageList,
-   IN ULONG  UsageListLength)
-{
-    ULONG Index, SubIndex, BreakUsageListIndex = 0, MakeUsageListIndex = 0, bFound;
-    PUSAGE_AND_PAGE CurrentUsage, Usage;
-
-    if (UsageListLength)
-    {
-        /* process removed usages */
-        Index = 0;
-        do
-        {
-            /* get usage from current index */
-            CurrentUsage = &PreviousUsageList[Index];
-
-            /* end of list reached? */
-            if (CurrentUsage->Usage == 0 && CurrentUsage->UsagePage == 0)
-                break;
-
-            /* search in current list */
-            SubIndex = 0;
-            bFound = FALSE;
-            do
-            {
-                /* get usage */
-                Usage = &CurrentUsageList[SubIndex];
-
-                /* end of list reached? */
-                if (Usage->Usage == 0 && Usage->UsagePage == 0)
-                    break;
-
-                /* does it match */
-                if (Usage->Usage == CurrentUsage->Usage && Usage->UsagePage == CurrentUsage->UsagePage)
-                {
-                    /* found match */
-                    bFound = TRUE;
-                }
-
-                /* move to next index */
-                SubIndex++;
-
-            }while(SubIndex < UsageListLength);
-
-            if (!bFound)
-            {
-                /* store it in break usage list */
-                BreakUsageList[BreakUsageListIndex].Usage = CurrentUsage->Usage;
-                BreakUsageList[BreakUsageListIndex].UsagePage = CurrentUsage->UsagePage;
-                BreakUsageListIndex++;
-            }
-
-            /* move to next index */
-            Index++;
-
-        }while(Index < UsageListLength);
-
-        /* process new usages */
-        Index = 0;
-        do
-        {
-            /* get usage from current index */
-            CurrentUsage = &CurrentUsageList[Index];
-
-            /* end of list reached? */
-            if (CurrentUsage->Usage == 0 && CurrentUsage->UsagePage == 0)
-                break;
-
-            /* search in current list */
-            SubIndex = 0;
-            bFound = FALSE;
-            do
-            {
-                /* get usage */
-                Usage = &PreviousUsageList[SubIndex];
-
-                /* end of list reached? */
-                if (Usage->Usage == 0 && Usage->UsagePage == 0)
-                    break;
-
-                /* does it match */
-                if (Usage->Usage == CurrentUsage->Usage && Usage->UsagePage == CurrentUsage->UsagePage)
-                {
-                    /* found match */
-                    bFound = TRUE;
-                }
-
-                /* move to next index */
-                SubIndex++;
-
-            }while(SubIndex < UsageListLength);
-
-            if (!bFound)
-            {
-                /* store it in break usage list */
-                MakeUsageList[MakeUsageListIndex].Usage = CurrentUsage->Usage;
-                MakeUsageList[MakeUsageListIndex].UsagePage = CurrentUsage->UsagePage;
-                MakeUsageListIndex++;
-            }
-
-            /* move to next index */
-            Index++;
-        }while(Index < UsageListLength);
-    }
-
-    /* are there remaining free list entries */
-    if (BreakUsageListIndex < UsageListLength)
-    {
-        /* zero them */
-        RtlZeroMemory(&BreakUsageList[BreakUsageListIndex], (UsageListLength - BreakUsageListIndex) * sizeof(USAGE_AND_PAGE));
-    }
-
-    /* are there remaining free list entries */
-    if (MakeUsageListIndex < UsageListLength)
-    {
-        /* zero them */
-        RtlZeroMemory(&MakeUsageList[MakeUsageListIndex], (UsageListLength - MakeUsageListIndex) * sizeof(USAGE_AND_PAGE));
-    }
-
-    /* done */
-    return HIDP_STATUS_SUCCESS;
-}
 
 HIDAPI
 NTSTATUS
index f0bc0d2..fa516eb 100644 (file)
@@ -5,4 +5,6 @@
 #include <ntddk.h>
 #include <hidpddi.h>
 #include <hidpi.h>
+#define NDEBUG
 #include <debug.h>
+#include "hidparser.h"
\ No newline at end of file
index 72024e8..f49a39f 100644 (file)
@@ -1,6 +1,7 @@
 
 add_subdirectory(chew)
 add_subdirectory(csq)
+add_subdirectory(hidparser)
 add_subdirectory(ip)
 add_subdirectory(oskittcp)
 add_subdirectory(sound)
diff --git a/lib/drivers/hidparser/CMakeLists.txt b/lib/drivers/hidparser/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5d16301
--- /dev/null
@@ -0,0 +1,13 @@
+
+add_definitions(
+    -DUNICODE -D_UNICODE
+    -DNDEBUG=1)
+
+list(APPEND SOURCE
+    hidparser.c
+    parser.c
+    api.c)
+
+add_library(hidparser ${SOURCE})
+add_dependencies(hidparser bugcodes)
+
diff --git a/lib/drivers/hidparser/api.c b/lib/drivers/hidparser/api.c
new file mode 100644 (file)
index 0000000..45765f0
--- /dev/null
@@ -0,0 +1,953 @@
+/*
+ * PROJECT:     ReactOS HID Parser Library
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        lib/drivers/hidparser/api.c
+ * PURPOSE:     HID Parser
+ * PROGRAMMERS:
+ *              Michael Martin (michael.martin@reactos.org)
+ *              Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+
+#include "parser.h"
+
+
+ULONG
+HidParser_NumberOfTopCollections(
+    IN PHID_PARSER Parser)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+    //
+    // sanity checks
+    //
+    ASSERT(ParserContext);
+    ASSERT(ParserContext->RootCollection);
+    ASSERT(ParserContext->RootCollection->NodeCount);
+
+    //
+    // number of top collections
+    //
+    return ParserContext->RootCollection->NodeCount;
+}
+
+PHID_COLLECTION
+HidParser_GetCollection(
+    IN PHID_PARSER Parser,
+    IN ULONG CollectionNumber)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+    //
+    // sanity checks
+    //
+    ASSERT(ParserContext);
+    ASSERT(ParserContext->RootCollection);
+    ASSERT(ParserContext->RootCollection->NodeCount);
+
+    //
+    // is collection index out of bounds
+    //
+    if (CollectionNumber < ParserContext->RootCollection->NodeCount)
+    {
+        //
+        // valid collection
+        //
+        return ParserContext->RootCollection->Nodes[CollectionNumber];
+    }
+
+    //
+    // no such collection
+    //
+    Parser->Debug("HIDPARSE] No such collection %lu\n", CollectionNumber);
+    return NULL;
+}
+
+PHID_REPORT
+HidParser_GetReportByType(
+    IN PHID_PARSER Parser,
+    IN ULONG ReportType)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+    ULONG Index;
+    ULONG ReportCount = 0;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+    //
+    // sanity checks
+    //
+    ASSERT(ParserContext);
+
+    //
+    // FIXME support multiple top collecions
+    //
+    ASSERT(ParserContext->RootCollection->NodeCount == 1);
+    for(Index = 0; Index < ParserContext->ReportCount; Index++)
+    {
+        //
+        // check if the report type match
+        //
+        if (ParserContext->Reports[Index]->Type == ReportType)
+        {
+            //
+            // found report
+            //
+            return ParserContext->Reports[Index];
+        }
+    }
+
+    //
+    // report not found
+    //
+    return NULL;
+}
+
+
+ULONG
+HidParser_NumberOfReports(
+    IN PHID_PARSER Parser,
+    IN ULONG ReportType)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+    ULONG Index;
+    ULONG ReportCount = 0;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+    //
+    // sanity checks
+    //
+    ASSERT(ParserContext);
+
+    //
+    // FIXME support multiple top collecions
+    //
+    ASSERT(ParserContext->RootCollection->NodeCount == 1);
+    for(Index = 0; Index < ParserContext->ReportCount; Index++)
+    {
+        //
+        // check if the report type match
+        //
+        if (ParserContext->Reports[Index]->Type == ReportType)
+        {
+            //
+            // found report
+            //
+            ReportCount++;
+        }
+    }
+
+    //
+    // done
+    //
+    return ReportCount;
+}
+
+HIDPARSER_STATUS
+HidParser_GetCollectionUsagePage(
+    IN PHID_PARSER Parser,
+    IN ULONG CollectionIndex,
+    OUT PUSHORT Usage,
+    OUT PUSHORT UsagePage)
+{
+    PHID_COLLECTION Collection;
+
+    //
+    // find collection
+    //
+    Collection = HidParser_GetCollection(Parser, CollectionIndex);
+    if (!Collection)
+    {
+        //
+        // collection not found
+        //
+        return HIDPARSER_STATUS_COLLECTION_NOT_FOUND;
+    }
+
+    //
+    // store result
+    //
+    *UsagePage = (Collection->Usage >> 16);
+    *Usage = (Collection->Usage & 0xFFFF);
+    return HIDPARSER_STATUS_SUCCESS;
+}
+
+ULONG
+HidParser_GetReportLength(
+    IN PHID_PARSER Parser,
+    IN ULONG ReportType)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+    PHID_REPORT Report;
+    ULONG ReportLength;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+    //
+    // sanity checks
+    //
+    ASSERT(ParserContext);
+
+    //
+    // FIXME support multiple top collecions
+    //
+    ASSERT(ParserContext->RootCollection->NodeCount == 1);
+
+    //
+    // get first report
+    //
+    Report = HidParser_GetReportByType(Parser, ReportType);
+    if (!Report)
+    {
+        //
+        // no report found
+        //
+        return 0;
+    }
+
+    //
+    // get report length
+    //
+    ReportLength = Report->ReportSize;
+
+    //
+    // done
+    //
+    if (ReportLength)
+    {
+        //
+        // byte aligned length
+        //
+        ASSERT(ReportLength % 8 == 0);
+        return ReportLength / 8;
+    }
+    return ReportLength;
+}
+
+UCHAR
+HidParser_IsReportIDUsed(
+    IN PHID_PARSER Parser)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+    //
+    // sanity checks
+    //
+    ASSERT(ParserContext);
+
+    //
+    // return flag
+    //
+    return ParserContext->UseReportIDs;
+}
+
+ULONG
+HidParser_GetReportItemCountFromReportType(
+    IN PHID_PARSER Parser,
+    IN ULONG ReportType)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+    PHID_REPORT Report;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+    //
+    // sanity checks
+    //
+    ASSERT(ParserContext);
+
+    //
+    // FIXME support multiple top collecions
+    //
+    ASSERT(ParserContext->RootCollection->NodeCount == 1);
+
+    //
+    // get report
+    //
+    Report = HidParser_GetReportByType(Parser, ReportType);
+    if (!Report)
+    {
+        //
+        // no such report
+        //
+        return 0;
+    }
+
+    //
+    // return report item count
+    //
+    return Report->ItemCount;
+}
+
+
+ULONG
+HidParser_GetReportItemTypeCountFromReportType(
+    IN PHID_PARSER Parser,
+    IN ULONG ReportType,
+    IN ULONG bData)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+    ULONG Index;
+    PHID_REPORT Report;
+    ULONG ItemCount = 0;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+    //
+    // sanity checks
+    //
+    ASSERT(ParserContext);
+
+    //
+    // FIXME support multiple top collecions
+    //
+    ASSERT(ParserContext->RootCollection->NodeCount == 1);
+
+    //
+    // get report
+    //
+    Report = HidParser_GetReportByType(Parser, ReportType);
+    if (!Report)
+    {
+        //
+        // no such report
+        //
+        return 0;
+    }
+
+    //
+    // enumerate all items
+    //
+    for(Index = 0; Index < Report->ItemCount; Index++)
+    {
+        //
+        // check item type
+        //
+        if (Report->Items[Index]->HasData && bData == TRUE)
+        {
+            //
+            // found data item
+            //
+            ItemCount++;
+        }
+        else if (Report->Items[Index]->HasData == FALSE && bData == FALSE)
+        {
+            //
+            // found value item
+            //
+            ItemCount++;
+        }
+    }
+
+    //
+    // no report items
+    //
+    return ItemCount;
+}
+
+ULONG
+HidParser_GetContextSize(
+    IN PHID_PARSER Parser)
+{
+    //
+    // FIXME the context must contain all parsed info
+    //
+    return sizeof(HID_PARSER_CONTEXT);
+}
+
+VOID
+HidParser_FreeContext(
+    IN PHID_PARSER Parser,
+    IN PUCHAR Context,
+    IN ULONG ContextLength)
+{
+    //
+    // FIXME implement freeing of parsed info
+    //
+}
+
+HIDPARSER_STATUS
+HidParser_AllocateParser(
+    IN PHIDPARSER_ALLOC_FUNCTION AllocFunction,
+    IN PHIDPARSER_FREE_FUNCTION FreeFunction,
+    IN PHIDPARSER_ZERO_FUNCTION ZeroFunction,
+    IN PHIDPARSER_COPY_FUNCTION CopyFunction,
+    IN PHIDPARSER_DEBUG_FUNCTION DebugFunction,
+    OUT PHID_PARSER *OutParser)
+{
+    PHID_PARSER Parser;
+    PHID_PARSER_CONTEXT ParserContext;
+
+    //
+    // allocate 
+    //
+    Parser = (PHID_PARSER)AllocFunction(sizeof(HID_PARSER));
+    if (!Parser)
+    {
+        //
+        // no memory
+        //
+        return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // allocate parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)AllocFunction(sizeof(HID_PARSER_CONTEXT));
+    if (!ParserContext)
+    {
+        //
+        // no memory
+        //
+        FreeFunction(Parser);
+        return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+
+    //
+    // init parser
+    //
+    Parser->Alloc = AllocFunction;
+    Parser->Free = FreeFunction;
+    Parser->Zero = ZeroFunction;
+    Parser->Copy = CopyFunction;
+    Parser->Debug = DebugFunction;
+    Parser->ParserContext = ParserContext;
+
+    //
+    // store result
+    //
+    *OutParser = Parser;
+    //
+    // success
+    //
+    return HIDPARSER_STATUS_SUCCESS;
+}
+
+VOID
+HidParser_InitParser(
+    IN PHIDPARSER_ALLOC_FUNCTION AllocFunction,
+    IN PHIDPARSER_FREE_FUNCTION FreeFunction,
+    IN PHIDPARSER_ZERO_FUNCTION ZeroFunction,
+    IN PHIDPARSER_COPY_FUNCTION CopyFunction,
+    IN PHIDPARSER_DEBUG_FUNCTION DebugFunction,
+    IN PVOID ParserContext,
+    OUT PHID_PARSER Parser)
+{
+    Parser->Alloc = AllocFunction;
+    Parser->Free = FreeFunction;
+    Parser->Zero = ZeroFunction;
+    Parser->Copy = CopyFunction;
+    Parser->Debug = DebugFunction;
+    Parser->ParserContext = ParserContext;
+}
+
+ULONG
+HidParser_GetCollectionCount(
+    IN PHID_COLLECTION Collection)
+{
+    ULONG Index;
+    ULONG Count = Collection->NodeCount;
+
+    for(Index = 0; Index < Collection->NodeCount; Index++)
+    {
+        //
+        // count collection for sub nodes
+        //
+        Count += HidParser_GetCollectionCount(Collection->Nodes[Index]);
+    }
+
+    //
+    // done
+    //
+    return Count;
+}
+
+ULONG
+HidParser_GetTotalCollectionCount(
+    IN PHID_PARSER Parser)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+    //
+    // sanity check
+    //
+    ASSERT(ParserContext);
+    ASSERT(ParserContext->RootCollection);
+
+    //
+    // count collections
+    //
+    return HidParser_GetCollectionCount(ParserContext->RootCollection);
+}
+
+ULONG
+HidParser_GetMaxUsageListLengthWithReportAndPage(
+    IN PHID_PARSER Parser,
+    IN ULONG ReportType,
+    IN USAGE  UsagePage  OPTIONAL)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+    ULONG Index;
+    PHID_REPORT Report;
+    ULONG ItemCount = 0;
+    USHORT CurrentUsagePage;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+    //
+    // sanity checks
+    //
+    ASSERT(ParserContext);
+
+    //
+    // FIXME support multiple top collecions
+    //
+    ASSERT(ParserContext->RootCollection->NodeCount == 1);
+
+    //
+    // get report
+    //
+    Report = HidParser_GetReportByType(Parser, ReportType);
+    if (!Report)
+    {
+        //
+        // no such report
+        //
+        return 0;
+    }
+
+    for(Index = 0; Index < Report->ItemCount; Index++)
+    {
+        //
+        // check usage page
+        //
+        CurrentUsagePage = (Report->Items[Index]->UsageMinimum >> 16);
+        if (CurrentUsagePage == UsagePage && Report->Items[Index]->HasData)
+        {
+            //
+            // found item
+            //
+            ItemCount++;
+        }
+    }
+
+    //
+    // done
+    //
+    return ItemCount;
+}
+
+HIDPARSER_STATUS
+HidParser_GetSpecificValueCapsWithReport(
+    IN PHID_PARSER Parser,
+    IN ULONG ReportType,
+    IN USHORT UsagePage,
+    IN USHORT Usage,
+    OUT PHIDP_VALUE_CAPS  ValueCaps,
+    IN OUT PULONG  ValueCapsLength)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+    ULONG Index;
+    PHID_REPORT Report;
+    ULONG ItemCount = 0;
+    USHORT CurrentUsagePage;
+    USHORT CurrentUsage;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+    //
+    // sanity checks
+    //
+    ASSERT(ParserContext);
+
+    //
+    // FIXME support multiple top collecions
+    //
+    ASSERT(ParserContext->RootCollection->NodeCount == 1);
+
+    //
+    // get report
+    //
+    Report = HidParser_GetReportByType(Parser, ReportType);
+    if (!Report)
+    {
+        //
+        // no such report
+        //
+        return HIDPARSER_STATUS_REPORT_NOT_FOUND;
+    }
+
+    for(Index = 0; Index < Report->ItemCount; Index++)
+    {
+        //
+        // check usage page
+        //
+        CurrentUsagePage = (Report->Items[Index]->UsageMinimum >> 16);
+        CurrentUsage = (Report->Items[Index]->UsageMinimum & 0xFFFF);
+
+        if ((Usage == CurrentUsage && UsagePage == CurrentUsagePage) || (Usage == 0 && UsagePage == CurrentUsagePage) || (Usage == CurrentUsage && UsagePage == 0) || (Usage == 0 && UsagePage == 0))
+        {
+            //
+            // check if there is enough place for the caps
+            //
+            if (ItemCount < *ValueCapsLength)
+            {
+                //
+                // zero caps
+                //
+                Parser->Zero(&ValueCaps[ItemCount], sizeof(HIDP_VALUE_CAPS));
+
+                //
+                // init caps
+                //
+                ValueCaps[ItemCount].UsagePage = CurrentUsagePage;
+                ValueCaps[ItemCount].ReportID = Report->ReportID;
+                ValueCaps[ItemCount].LogicalMin = Report->Items[Index]->Minimum;
+                ValueCaps[ItemCount].LogicalMax = Report->Items[Index]->Maximum;
+                ValueCaps[ItemCount].IsAbsolute = !Report->Items[Index]->Relative;
+                ValueCaps[ItemCount].BitSize = Report->Items[Index]->BitCount;
+
+                //
+                // FIXME: FILLMEIN
+                //
+            }
+
+
+            //
+            // found item
+            //
+            ItemCount++;
+        }
+    }
+
+    //
+    // store result
+    //
+    *ValueCapsLength = ItemCount;
+
+    if (ItemCount)
+    {
+        //
+        // success
+        //
+        return HIDPARSER_STATUS_SUCCESS;
+    }
+
+    //
+    // item not found
+    //
+    return HIDPARSER_STATUS_USAGE_NOT_FOUND;
+}
+
+HIDPARSER_STATUS
+HidParser_GetUsagesWithReport(
+    IN PHID_PARSER Parser,
+    IN ULONG  ReportType,
+    IN USAGE  UsagePage,
+    OUT USAGE  *UsageList,
+    IN OUT PULONG UsageLength,
+    IN PCHAR  ReportDescriptor,
+    IN ULONG  ReportDescriptorLength)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+    ULONG Index;
+    PHID_REPORT Report;
+    ULONG ItemCount = 0;
+    USHORT CurrentUsagePage;
+    PHID_REPORT_ITEM ReportItem;
+    UCHAR Activated;
+    ULONG Data;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+    //
+    // sanity checks
+    //
+    ASSERT(ParserContext);
+
+    //
+    // FIXME support multiple top collecions
+    //
+    ASSERT(ParserContext->RootCollection->NodeCount == 1);
+
+    //
+    // get report
+    //
+    Report = HidParser_GetReportByType(Parser, ReportType);
+    if (!Report)
+    {
+        //
+        // no such report
+        //
+        return HIDPARSER_STATUS_REPORT_NOT_FOUND;
+    }
+
+    if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
+    {
+        //
+        // invalid report descriptor length
+        //
+        return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
+    }
+
+    for(Index = 0; Index < Report->ItemCount; Index++)
+    {
+        //
+        // get report item
+        //
+        ReportItem = Report->Items[Index];
+
+        //
+        // does it have data
+        //
+        if (!ReportItem->HasData)
+            continue;
+
+        //
+        // check usage page
+        //
+        CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
+
+        //
+        // does usage match
+        //
+        if (UsagePage != CurrentUsagePage)
+            continue;
+
+        //
+        // check if the specified usage is activated
+        //
+        ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
+        ASSERT(ReportItem->BitCount < 8);
+
+        //
+        // one extra shift for skipping the prepended report id
+        //
+        Data = ReportDescriptor[ReportItem->ByteOffset + 1];
+
+        //
+        // shift data
+        //
+        Data >>= ReportItem->Shift;
+
+        //
+        // clear unwanted bits
+        //
+        Data &= ReportItem->Mask;
+
+        //
+        // is it activated
+        //
+        Activated = (Data != 0);
+
+        if (!Activated)
+            continue;
+
+        //
+        // is there enough space for the usage
+        //
+        if (ItemCount >= *UsageLength)
+        {
+            ItemCount++;
+            continue;
+        }
+
+        //
+        // store item
+        //
+        UsageList[ItemCount] = (ReportItem->UsageMinimum & 0xFFFF);
+        ItemCount++;
+    }
+
+    if (ItemCount > *UsageLength)
+    {
+        //
+        // list too small
+        //
+        return HIDPARSER_STATUS_BUFFER_TOO_SMALL;
+    }
+
+    //
+    // success, clear rest of array
+    //
+    Parser->Zero(&UsageList[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE));
+
+    //
+    // store result size
+    //
+    *UsageLength = ItemCount;
+
+    //
+    // done
+    //
+    return HIDPARSER_STATUS_SUCCESS;
+}
+
+HIDPARSER_STATUS
+HidParser_GetScaledUsageValueWithReport(
+    IN PHID_PARSER Parser,
+    IN ULONG ReportType,
+    IN USAGE UsagePage,
+    IN USAGE  Usage,
+    OUT PLONG UsageValue,
+    IN PCHAR ReportDescriptor,
+    IN ULONG ReportDescriptorLength)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+    ULONG Index;
+    PHID_REPORT Report;
+    ULONG ItemCount = 0;
+    USHORT CurrentUsagePage;
+    PHID_REPORT_ITEM ReportItem;
+    ULONG Data;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+    //
+    // sanity checks
+    //
+    ASSERT(ParserContext);
+
+    //
+    // FIXME support multiple top collecions
+    //
+    ASSERT(ParserContext->RootCollection->NodeCount == 1);
+
+    //
+    // get report
+    //
+    Report = HidParser_GetReportByType(Parser, ReportType);
+    if (!Report)
+    {
+        //
+        // no such report
+        //
+        return HIDPARSER_STATUS_REPORT_NOT_FOUND;
+    }
+
+    if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
+    {
+        //
+        // invalid report descriptor length
+        //
+        return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
+    }
+
+    for(Index = 0; Index < Report->ItemCount; Index++)
+    {
+        //
+        // get report item
+        //
+        ReportItem = Report->Items[Index];
+
+        //
+        // check usage page
+        //
+        CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
+
+        //
+        // does usage page match
+        //
+        if (UsagePage != CurrentUsagePage)
+            continue;
+
+        //
+        // does the usage match
+        //
+        if (Usage != (ReportItem->UsageMinimum & 0xFFFF))
+            continue;
+
+        //
+        // check if the specified usage is activated
+        //
+        ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
+
+        //
+        // one extra shift for skipping the prepended report id
+        //
+        Data = 0;
+        Parser->Copy(&Data, &ReportDescriptor[ReportItem->ByteOffset +1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1)));
+        Data = ReportDescriptor[ReportItem->ByteOffset + 1];
+
+        //
+        // shift data
+        //
+        Data >>= ReportItem->Shift;
+
+        //
+        // clear unwanted bits
+        //
+        Data &= ReportItem->Mask;
+
+        if (ReportItem->Minimum > ReportItem->Maximum)
+        {
+            //
+            // logical boundaries are signed values
+            //
+            if ((Data & ~(ReportItem->Mask >> 1)) != 0)
+            {
+                Data |= ~ReportItem->Mask;
+            }
+        }
+
+        //
+        // store result
+        //
+        *UsageValue = Data;
+        return HIDPARSER_STATUS_SUCCESS;
+    }
+
+    //
+    // usage not found
+    //
+    return HIDPARSER_STATUS_USAGE_NOT_FOUND;
+}
diff --git a/lib/drivers/hidparser/hidparser.c b/lib/drivers/hidparser/hidparser.c
new file mode 100644 (file)
index 0000000..ddde2f7
--- /dev/null
@@ -0,0 +1,1083 @@
+/*
+ * PROJECT:     ReactOS HID Parser Library
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        lib/drivers/hidparser/hidparser.c
+ * PURPOSE:     HID Parser
+ * PROGRAMMERS:
+ *              Michael Martin (michael.martin@reactos.org)
+ *              Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+#include "parser.h"
+
+NTSTATUS
+TranslateHidParserStatus(
+    IN HIDPARSER_STATUS Status)
+{
+    UNIMPLEMENTED
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+HidParser_GetCollectionDescription(
+    IN PHID_PARSER Parser,
+    IN PHIDP_REPORT_DESCRIPTOR ReportDesc,
+    IN ULONG DescLength,
+    IN POOL_TYPE PoolType,
+    OUT PHIDP_DEVICE_DESC DeviceDescription)
+{
+    HIDPARSER_STATUS ParserStatus;
+    ULONG CollectionCount, ReportCount;
+    ULONG Index;
+
+    //
+    // first parse the report descriptor
+    //
+    ParserStatus = HidParser_ParseReportDescriptor(Parser, ReportDesc, DescLength);
+    if (ParserStatus != HIDPARSER_STATUS_SUCCESS)
+    {
+        //
+        // failed to parse report descriptor
+        //
+        Parser->Debug("[HIDPARSER] Failed to parse report descriptor with %x\n", ParserStatus);
+        return TranslateHidParserStatus(ParserStatus);
+    }
+
+    //
+    // get collection count
+    //
+    CollectionCount = HidParser_NumberOfTopCollections(Parser);
+
+    //
+    // FIXME: only one top level collection is supported
+    //
+    ASSERT(CollectionCount <= 1);
+    if (CollectionCount == 0)
+    {
+        //
+        // no top level collections found
+        //
+        return STATUS_NO_DATA_DETECTED;
+    }
+
+    //
+    // zero description
+    //
+    Parser->Zero(DeviceDescription, sizeof(HIDP_DEVICE_DESC));
+
+    //
+    // allocate collection
+    //
+    DeviceDescription->CollectionDesc = (PHIDP_COLLECTION_DESC)Parser->Alloc(sizeof(HIDP_COLLECTION_DESC) * CollectionCount);
+    if (!DeviceDescription->CollectionDesc)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // allocate report description
+    //
+    DeviceDescription->ReportIDs = (PHIDP_REPORT_IDS)Parser->Alloc(sizeof(HIDP_REPORT_IDS) * CollectionCount);
+    if (!DeviceDescription->ReportIDs)
+    {
+        //
+        // no memory
+        //
+        Parser->Free(DeviceDescription->CollectionDesc);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    for(Index = 0; Index < CollectionCount; Index++)
+    {
+        //
+        // init report description
+        //
+        DeviceDescription->ReportIDs[Index].CollectionNumber = Index + 1;
+        DeviceDescription->ReportIDs[Index].ReportID = Index; //FIXME
+        DeviceDescription->ReportIDs[Index].InputLength = HidParser_GetReportLength(Parser, HID_REPORT_TYPE_INPUT);
+        DeviceDescription->ReportIDs[Index].OutputLength = HidParser_GetReportLength(Parser, HID_REPORT_TYPE_OUTPUT);
+        DeviceDescription->ReportIDs[Index].FeatureLength = HidParser_GetReportLength(Parser, HID_REPORT_TYPE_FEATURE);
+
+        //
+        // init collection description
+        //
+        DeviceDescription->CollectionDesc[Index].CollectionNumber = Index + 1;
+
+        //
+        // get collection usage page
+        //
+        ParserStatus = HidParser_GetCollectionUsagePage(Parser, Index, &DeviceDescription->CollectionDesc[Index].Usage, &DeviceDescription->CollectionDesc[Index].UsagePage);
+
+        //
+        // windows seems to prepend the report id, regardless if it is required
+        //
+        DeviceDescription->CollectionDesc[Index].InputLength = (DeviceDescription->ReportIDs[Index].InputLength > 0 ? DeviceDescription->ReportIDs[Index].InputLength + 1 : 0);
+        DeviceDescription->CollectionDesc[Index].OutputLength = (DeviceDescription->ReportIDs[Index].OutputLength > 0 ? DeviceDescription->ReportIDs[Index].OutputLength + 1 : 0);
+        DeviceDescription->CollectionDesc[Index].FeatureLength = (DeviceDescription->ReportIDs[Index].FeatureLength > 0 ? DeviceDescription->ReportIDs[Index].FeatureLength + 1 : 0);
+
+        //
+        // set preparsed data length
+        //
+        DeviceDescription->CollectionDesc[Index].PreparsedDataLength = HidParser_GetContextSize(Parser);
+        DeviceDescription->CollectionDesc[Index].PreparsedData = Parser->Alloc(DeviceDescription->CollectionDesc[Index].PreparsedDataLength);
+        if (!DeviceDescription->CollectionDesc[Index].PreparsedData)
+        {
+            //
+            // no memory
+            //
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        //
+        // copy context
+        //
+        Parser->Copy(DeviceDescription->CollectionDesc[Index].PreparsedData, Parser->ParserContext, DeviceDescription->CollectionDesc[Index].PreparsedDataLength);
+    }
+
+    //
+    // store collection & report count
+    //
+    DeviceDescription->CollectionDescLength = CollectionCount;
+    DeviceDescription->ReportIDsLength = CollectionCount;
+
+    //
+    // done
+    //
+    return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+HidParser_FreeCollectionDescription(
+    IN PHID_PARSER Parser,
+    IN PHIDP_DEVICE_DESC   DeviceDescription)
+{
+    ULONG Index;
+
+    //
+    // first free all context
+    //
+    for(Index = 0; Index < DeviceDescription->CollectionDescLength; Index++)
+    {
+        //
+        // free parser context
+        //
+        HidParser_FreeContext(Parser, (PUCHAR)DeviceDescription->CollectionDesc[Index].PreparsedData, DeviceDescription->CollectionDesc[Index].PreparsedDataLength);
+    }
+
+    //
+    // now free collection description
+    //
+    Parser->Free(DeviceDescription->CollectionDesc);
+
+    //
+    // free report description
+    //
+    ExFreePool(DeviceDescription->ReportIDs);
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetCaps(
+    IN PHID_PARSER Parser,
+    OUT PHIDP_CAPS  Capabilities)
+{
+    ULONG CollectionNumber;
+    //
+    // zero capabilities
+    //
+    Parser->Zero(Capabilities, sizeof(HIDP_CAPS));
+
+    //
+    // FIXME support multiple top level collections
+    //
+    CollectionNumber = 0;
+
+    //
+    // init capabilities
+    //
+    HidParser_GetCollectionUsagePage(Parser, CollectionNumber, &Capabilities->Usage, &Capabilities->UsagePage);
+    Capabilities->InputReportByteLength = HidParser_GetReportLength(Parser, HID_REPORT_TYPE_INPUT);
+    Capabilities->OutputReportByteLength = HidParser_GetReportLength(Parser, HID_REPORT_TYPE_OUTPUT);
+    Capabilities->FeatureReportByteLength = HidParser_GetReportLength(Parser, HID_REPORT_TYPE_FEATURE);
+
+    //
+    // always pre-prend report id
+    //
+    Capabilities->InputReportByteLength = (Capabilities->InputReportByteLength > 0 ? Capabilities->InputReportByteLength + 1 : 0);
+    Capabilities->OutputReportByteLength = (Capabilities->OutputReportByteLength > 0 ? Capabilities->OutputReportByteLength + 1 : 0);
+    Capabilities->FeatureReportByteLength = (Capabilities->FeatureReportByteLength > 0 ? Capabilities->FeatureReportByteLength + 1 : 0);
+
+    //
+    // get number of link collection nodes
+    //
+    Capabilities->NumberLinkCollectionNodes = HidParser_GetTotalCollectionCount(Parser);
+
+    //
+    // get data indices
+    //
+    Capabilities->NumberInputDataIndices = HidParser_GetReportItemTypeCountFromReportType(Parser, HID_REPORT_TYPE_INPUT, TRUE);
+    Capabilities->NumberOutputDataIndices = HidParser_GetReportItemTypeCountFromReportType(Parser, HID_REPORT_TYPE_OUTPUT, TRUE);
+    Capabilities->NumberFeatureDataIndices = HidParser_GetReportItemTypeCountFromReportType(Parser, HID_REPORT_TYPE_FEATURE, TRUE);
+
+    //
+    // get value caps
+    //
+    Capabilities->NumberInputValueCaps = HidParser_GetReportItemTypeCountFromReportType(Parser, HID_REPORT_TYPE_INPUT, FALSE);
+    Capabilities->NumberOutputValueCaps = HidParser_GetReportItemTypeCountFromReportType(Parser, HID_REPORT_TYPE_OUTPUT, FALSE);
+    Capabilities->NumberFeatureValueCaps = HidParser_GetReportItemTypeCountFromReportType(Parser, HID_REPORT_TYPE_FEATURE, FALSE);
+
+
+    //
+    // get button caps
+    //
+    Capabilities->NumberInputButtonCaps = HidParser_GetReportItemCountFromReportType(Parser, HID_REPORT_TYPE_INPUT);
+    Capabilities->NumberOutputButtonCaps = HidParser_GetReportItemCountFromReportType(Parser, HID_REPORT_TYPE_OUTPUT);
+    Capabilities->NumberFeatureButtonCaps = HidParser_GetReportItemCountFromReportType(Parser, HID_REPORT_TYPE_FEATURE);
+
+    //
+    // done
+    //
+    return HIDP_STATUS_SUCCESS;
+}
+
+HIDAPI
+ULONG
+NTAPI
+HidParser_MaxUsageListLength(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USAGE  UsagePage  OPTIONAL)
+{
+    //
+    // FIXME test what should be returned when usage page is not defined
+    //
+    if (UsagePage == HID_USAGE_PAGE_UNDEFINED)
+    {
+        //
+        // implement me
+        //
+        UNIMPLEMENTED
+
+        //
+        // invalid report
+        //
+        return 0;
+    }
+
+    if (ReportType == HidP_Input)
+    {
+        //
+        // input report
+        //
+        return HidParser_GetMaxUsageListLengthWithReportAndPage(Parser, HID_REPORT_TYPE_INPUT, UsagePage);
+    }
+    else if (ReportType == HidP_Output)
+    {
+        //
+        // input report
+        //
+        return HidParser_GetMaxUsageListLengthWithReportAndPage(Parser, HID_REPORT_TYPE_OUTPUT, UsagePage);
+    }
+    else if (ReportType == HidP_Feature)
+    {
+        //
+        // input report
+        //
+        return HidParser_GetMaxUsageListLengthWithReportAndPage(Parser, HID_REPORT_TYPE_FEATURE, UsagePage);
+    }
+    else
+    {
+        //
+        // invalid report type
+        //
+        return 0;
+    }
+}
+
+#undef HidParser_GetButtonCaps
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetButtonCaps(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE ReportType,
+    IN PHIDP_BUTTON_CAPS ButtonCaps,
+    IN PUSHORT ButtonCapsLength)
+{
+    return HidParser_GetSpecificButtonCaps(Parser, ReportType, HID_USAGE_PAGE_UNDEFINED, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_PAGE_UNDEFINED, ButtonCaps, (PULONG)ButtonCapsLength);
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetSpecificValueCaps(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USAGE  UsagePage,
+    IN USHORT  LinkCollection,
+    IN USAGE  Usage,
+    OUT PHIDP_VALUE_CAPS  ValueCaps,
+    IN OUT PULONG  ValueCapsLength)
+{
+    HIDPARSER_STATUS ParserStatus;
+
+    //
+    // FIXME: implement searching in specific collection
+    //
+    ASSERT(LinkCollection == HIDP_LINK_COLLECTION_UNSPECIFIED);
+
+    if (ReportType == HidP_Input)
+    {
+        //
+        // input report
+        //
+        ParserStatus = HidParser_GetSpecificValueCapsWithReport(Parser, HID_REPORT_TYPE_INPUT, UsagePage, Usage, ValueCaps, ValueCapsLength);
+    }
+    else if (ReportType == HidP_Output)
+    {
+        //
+        // input report
+        //
+        ParserStatus = HidParser_GetSpecificValueCapsWithReport(Parser, HID_REPORT_TYPE_OUTPUT, UsagePage, Usage, ValueCaps, ValueCapsLength);
+    }
+    else if (ReportType == HidP_Feature)
+    {
+        //
+        // input report
+        //
+        ParserStatus = HidParser_GetSpecificValueCapsWithReport(Parser, HID_REPORT_TYPE_FEATURE, UsagePage, Usage, ValueCaps, ValueCapsLength);
+    }
+    else
+    {
+        //
+        // invalid report type
+        //
+        return HIDP_STATUS_INVALID_REPORT_TYPE;
+    }
+
+
+    if (ParserStatus == HIDPARSER_STATUS_SUCCESS)
+    {
+        //
+        // success
+        //
+        return HIDP_STATUS_SUCCESS;
+    }
+
+    //
+    // translate error
+    //
+    return TranslateHidParserStatus(ParserStatus);
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_UsageListDifference(
+  IN PUSAGE  PreviousUsageList,
+  IN PUSAGE  CurrentUsageList,
+  OUT PUSAGE  BreakUsageList,
+  OUT PUSAGE  MakeUsageList,
+  IN ULONG  UsageListLength)
+{
+    ULONG Index, SubIndex, bFound, BreakUsageIndex = 0, MakeUsageIndex = 0;
+    USAGE CurrentUsage, Usage;
+
+    if (UsageListLength)
+    {
+        Index = 0;
+        do
+        {
+            /* get current usage */
+            CurrentUsage = PreviousUsageList[Index];
+
+            /* is the end of list reached? */
+            if (!CurrentUsage)
+                break;
+
+            /* start searching in current usage list */
+            SubIndex = 0;
+            bFound = FALSE;
+            do
+            {
+                /* get usage of current list */
+                Usage = CurrentUsageList[SubIndex];
+
+                /* end of list reached? */
+                if (!Usage)
+                    break;
+
+                /* check if it matches the current one */
+                if (CurrentUsage == Usage)
+                {
+                    /* it does */
+                    bFound = TRUE;
+                    break;
+                }
+
+                /* move to next usage */
+                SubIndex++;
+            }while(SubIndex < UsageListLength);
+
+            /* was the usage found ?*/
+            if (!bFound)
+            {
+                /* store it in the break usage list */
+                BreakUsageList[BreakUsageIndex] = CurrentUsage;
+                BreakUsageIndex++;
+            }
+
+            /* move to next usage */
+            Index++;
+
+        }while(Index < UsageListLength);
+
+        /* now process the new items */
+        Index = 0;
+        do
+        {
+            /* get current usage */
+            CurrentUsage = CurrentUsageList[Index];
+
+            /* is the end of list reached? */
+            if (!CurrentUsage)
+                break;
+
+            /* start searching in current usage list */
+            SubIndex = 0;
+            bFound = FALSE;
+            do
+            {
+                /* get usage of previous list */
+                Usage = PreviousUsageList[SubIndex];
+
+                /* end of list reached? */
+                if (!Usage)
+                    break;
+
+                /* check if it matches the current one */
+                if (CurrentUsage == Usage)
+                {
+                    /* it does */
+                    bFound = TRUE;
+                    break;
+                }
+
+                /* move to next usage */
+                SubIndex++;
+            }while(SubIndex < UsageListLength);
+
+            /* was the usage found ?*/
+            if (!bFound)
+            {
+                /* store it in the make usage list */
+                MakeUsageList[MakeUsageIndex] = CurrentUsage;
+                MakeUsageIndex++;
+            }
+
+            /* move to next usage */
+            Index++;
+
+        }while(Index < UsageListLength);
+    }
+
+    /* does the break list contain empty entries */
+    if (BreakUsageIndex < UsageListLength)
+    {
+        /* zeroize entries */
+        RtlZeroMemory(&BreakUsageList[BreakUsageIndex], sizeof(USAGE) * (UsageListLength - BreakUsageIndex));
+    }
+
+    /* does the make usage list contain empty entries */
+    if (MakeUsageIndex < UsageListLength)
+    {
+        /* zeroize entries */
+        RtlZeroMemory(&MakeUsageList[MakeUsageIndex], sizeof(USAGE) * (UsageListLength - MakeUsageIndex));
+    }
+
+    /* done */
+    return HIDP_STATUS_SUCCESS;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetUsages(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USAGE  UsagePage,
+    IN USHORT  LinkCollection  OPTIONAL,
+    OUT USAGE  *UsageList,
+    IN OUT PULONG UsageLength,
+    IN PCHAR  Report,
+    IN ULONG  ReportLength)
+{
+    HIDPARSER_STATUS ParserStatus;
+
+    //
+    // FIXME: implement searching in specific collection
+    //
+    ASSERT(LinkCollection == HIDP_LINK_COLLECTION_UNSPECIFIED);
+
+    if (ReportType == HidP_Input)
+    {
+        //
+        // input report
+        //
+        ParserStatus = HidParser_GetUsagesWithReport(Parser, HID_REPORT_TYPE_INPUT, UsagePage, UsageList, UsageLength, Report, ReportLength);
+    }
+    else if (ReportType == HidP_Output)
+    {
+        //
+        // input report
+        //
+        ParserStatus = HidParser_GetUsagesWithReport(Parser, HID_REPORT_TYPE_OUTPUT, UsagePage, UsageList, UsageLength, Report, ReportLength);
+    }
+    else if (ReportType == HidP_Feature)
+    {
+        //
+        // input report
+        //
+        ParserStatus = HidParser_GetUsagesWithReport(Parser, HID_REPORT_TYPE_FEATURE, UsagePage, UsageList, UsageLength, Report, ReportLength);
+    }
+    else
+    {
+        //
+        // invalid report type
+        //
+        return HIDP_STATUS_INVALID_REPORT_TYPE;
+    }
+
+    if (ParserStatus == HIDPARSER_STATUS_SUCCESS)
+    {
+        //
+        // success
+        //
+        return HIDP_STATUS_SUCCESS;
+    }
+
+    //
+    // translate error
+    //
+    return TranslateHidParserStatus(ParserStatus);
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetScaledUsageValue(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USAGE  UsagePage,
+    IN USHORT  LinkCollection  OPTIONAL,
+    IN USAGE  Usage,
+    OUT PLONG  UsageValue,
+    IN PCHAR  Report,
+    IN ULONG  ReportLength)
+{
+    HIDPARSER_STATUS ParserStatus;
+
+    //
+    // FIXME: implement searching in specific collection
+    //
+    ASSERT(LinkCollection == HIDP_LINK_COLLECTION_UNSPECIFIED);
+
+    if (ReportType == HidP_Input)
+    {
+        //
+        // input report
+        //
+        ParserStatus = HidParser_GetScaledUsageValueWithReport(Parser, HID_REPORT_TYPE_INPUT, UsagePage, Usage, UsageValue, Report, ReportLength);
+    }
+    else if (ReportType == HidP_Output)
+    {
+        //
+        // input report
+        //
+        ParserStatus = HidParser_GetScaledUsageValueWithReport(Parser, HID_REPORT_TYPE_OUTPUT, UsagePage, Usage, UsageValue, Report, ReportLength);
+    }
+    else if (ReportType == HidP_Feature)
+    {
+        //
+        // input report
+        //
+        ParserStatus = HidParser_GetScaledUsageValueWithReport(Parser, HID_REPORT_TYPE_FEATURE,  UsagePage, Usage, UsageValue, Report, ReportLength);
+    }
+    else
+    {
+        //
+        // invalid report type
+        //
+        return HIDP_STATUS_INVALID_REPORT_TYPE;
+    }
+
+    if (ParserStatus == HIDPARSER_STATUS_SUCCESS)
+    {
+        //
+        // success
+        //
+        return HIDP_STATUS_SUCCESS;
+    }
+
+    //
+    // translate error
+    //
+    return TranslateHidParserStatus(ParserStatus);
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetUsagesEx(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USHORT  LinkCollection,
+    OUT PUSAGE_AND_PAGE  ButtonList,
+    IN OUT ULONG  *UsageLength,
+    IN PCHAR  Report,
+    IN ULONG  ReportLength)
+{
+    return HidParser_GetUsages(Parser, ReportType, HID_USAGE_PAGE_UNDEFINED, LinkCollection, (PUSAGE)ButtonList, UsageLength, Report, ReportLength);
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_UsageAndPageListDifference(
+   IN PUSAGE_AND_PAGE  PreviousUsageList,
+   IN PUSAGE_AND_PAGE  CurrentUsageList,
+   OUT PUSAGE_AND_PAGE  BreakUsageList,
+   OUT PUSAGE_AND_PAGE  MakeUsageList,
+   IN ULONG  UsageListLength)
+{
+    ULONG Index, SubIndex, BreakUsageListIndex = 0, MakeUsageListIndex = 0, bFound;
+    PUSAGE_AND_PAGE CurrentUsage, Usage;
+
+    if (UsageListLength)
+    {
+        /* process removed usages */
+        Index = 0;
+        do
+        {
+            /* get usage from current index */
+            CurrentUsage = &PreviousUsageList[Index];
+
+            /* end of list reached? */
+            if (CurrentUsage->Usage == 0 && CurrentUsage->UsagePage == 0)
+                break;
+
+            /* search in current list */
+            SubIndex = 0;
+            bFound = FALSE;
+            do
+            {
+                /* get usage */
+                Usage = &CurrentUsageList[SubIndex];
+
+                /* end of list reached? */
+                if (Usage->Usage == 0 && Usage->UsagePage == 0)
+                    break;
+
+                /* does it match */
+                if (Usage->Usage == CurrentUsage->Usage && Usage->UsagePage == CurrentUsage->UsagePage)
+                {
+                    /* found match */
+                    bFound = TRUE;
+                }
+
+                /* move to next index */
+                SubIndex++;
+
+            }while(SubIndex < UsageListLength);
+
+            if (!bFound)
+            {
+                /* store it in break usage list */
+                BreakUsageList[BreakUsageListIndex].Usage = CurrentUsage->Usage;
+                BreakUsageList[BreakUsageListIndex].UsagePage = CurrentUsage->UsagePage;
+                BreakUsageListIndex++;
+            }
+
+            /* move to next index */
+            Index++;
+
+        }while(Index < UsageListLength);
+
+        /* process new usages */
+        Index = 0;
+        do
+        {
+            /* get usage from current index */
+            CurrentUsage = &CurrentUsageList[Index];
+
+            /* end of list reached? */
+            if (CurrentUsage->Usage == 0 && CurrentUsage->UsagePage == 0)
+                break;
+
+            /* search in current list */
+            SubIndex = 0;
+            bFound = FALSE;
+            do
+            {
+                /* get usage */
+                Usage = &PreviousUsageList[SubIndex];
+
+                /* end of list reached? */
+                if (Usage->Usage == 0 && Usage->UsagePage == 0)
+                    break;
+
+                /* does it match */
+                if (Usage->Usage == CurrentUsage->Usage && Usage->UsagePage == CurrentUsage->UsagePage)
+                {
+                    /* found match */
+                    bFound = TRUE;
+                }
+
+                /* move to next index */
+                SubIndex++;
+
+            }while(SubIndex < UsageListLength);
+
+            if (!bFound)
+            {
+                /* store it in break usage list */
+                MakeUsageList[MakeUsageListIndex].Usage = CurrentUsage->Usage;
+                MakeUsageList[MakeUsageListIndex].UsagePage = CurrentUsage->UsagePage;
+                MakeUsageListIndex++;
+            }
+
+            /* move to next index */
+            Index++;
+        }while(Index < UsageListLength);
+    }
+
+    /* are there remaining free list entries */
+    if (BreakUsageListIndex < UsageListLength)
+    {
+        /* zero them */
+        RtlZeroMemory(&BreakUsageList[BreakUsageListIndex], (UsageListLength - BreakUsageListIndex) * sizeof(USAGE_AND_PAGE));
+    }
+
+    /* are there remaining free list entries */
+    if (MakeUsageListIndex < UsageListLength)
+    {
+        /* zero them */
+        RtlZeroMemory(&MakeUsageList[MakeUsageListIndex], (UsageListLength - MakeUsageListIndex) * sizeof(USAGE_AND_PAGE));
+    }
+
+    /* done */
+    return HIDP_STATUS_SUCCESS;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetSpecificButtonCaps(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USAGE  UsagePage,
+    IN USHORT  LinkCollection,
+    IN USAGE  Usage,
+    OUT PHIDP_BUTTON_CAPS  ButtonCaps,
+    IN OUT PULONG  ButtonCapsLength)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetData(
+  IN HIDP_REPORT_TYPE  ReportType,
+  OUT PHIDP_DATA  DataList,
+  IN OUT PULONG  DataLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN PCHAR  Report,
+  IN ULONG  ReportLength)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetExtendedAttributes(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USHORT  DataIndex,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  OUT PHIDP_EXTENDED_ATTRIBUTES  Attributes,
+  IN OUT PULONG  LengthAttributes)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetLinkCollectionNodes(
+    OUT PHIDP_LINK_COLLECTION_NODE  LinkCollectionNodes,
+    IN OUT PULONG  LinkCollectionNodesLength,
+    IN PHIDP_PREPARSED_DATA  PreparsedData)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetUsageValue(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection,
+  IN USAGE  Usage,
+  OUT PULONG  UsageValue,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN PCHAR  Report,
+  IN ULONG  ReportLength)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS
+NTAPI
+HidParser_SysPowerEvent (
+    IN PCHAR HidPacket,
+    IN USHORT HidPacketLength,
+    IN PHIDP_PREPARSED_DATA Ppd,
+    OUT PULONG OutputBuffer)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+HidParser_SysPowerCaps (
+    IN PHIDP_PREPARSED_DATA Ppd,
+    OUT PULONG OutputBuffer)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetUsageValueArray(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection  OPTIONAL,
+  IN USAGE  Usage,
+  OUT PCHAR  UsageValue,
+  IN USHORT  UsageValueByteLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN PCHAR  Report,
+  IN ULONG  ReportLength)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_UnsetUsages(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection,
+  IN PUSAGE  UsageList,
+  IN OUT PULONG  UsageLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN OUT PCHAR  Report,
+  IN ULONG  ReportLength)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_TranslateUsagesToI8042ScanCodes(
+  IN PUSAGE  ChangedUsageList,
+  IN ULONG  UsageListLength,
+  IN HIDP_KEYBOARD_DIRECTION  KeyAction,
+  IN OUT PHIDP_KEYBOARD_MODIFIER_STATE  ModifierState,
+  IN PHIDP_INSERT_SCANCODES  InsertCodesProcedure,
+  IN PVOID  InsertCodesContext)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_TranslateUsageAndPagesToI8042ScanCodes(
+   IN PUSAGE_AND_PAGE  ChangedUsageList,
+   IN ULONG  UsageListLength,
+   IN HIDP_KEYBOARD_DIRECTION  KeyAction,
+   IN OUT PHIDP_KEYBOARD_MODIFIER_STATE  ModifierState,
+   IN PHIDP_INSERT_SCANCODES  InsertCodesProcedure,
+   IN PVOID  InsertCodesContext)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_SetUsages(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection,
+  IN PUSAGE  UsageList,
+  IN OUT PULONG  UsageLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN OUT PCHAR  Report,
+  IN ULONG  ReportLength)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_SetUsageValueArray(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection  OPTIONAL,
+  IN USAGE  Usage,
+  IN PCHAR  UsageValue,
+  IN USHORT  UsageValueByteLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  OUT PCHAR  Report,
+  IN ULONG  ReportLength)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_SetUsageValue(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection,
+  IN USAGE  Usage,
+  IN ULONG  UsageValue,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN OUT PCHAR  Report,
+  IN ULONG  ReportLength)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_SetScaledUsageValue(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection  OPTIONAL,
+  IN USAGE  Usage,
+  IN LONG  UsageValue,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN OUT PCHAR  Report,
+  IN ULONG  ReportLength)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_SetData(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN PHIDP_DATA  DataList,
+  IN OUT PULONG  DataLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN OUT PCHAR  Report,
+  IN ULONG  ReportLength)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+ULONG
+NTAPI
+HidParser_MaxDataListLength(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN PHIDP_PREPARSED_DATA  PreparsedData)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_InitializeReportForID(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN UCHAR  ReportID,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN OUT PCHAR  Report,
+  IN ULONG  ReportLength)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+#undef HidParser_GetValueCaps
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetValueCaps(
+  HIDP_REPORT_TYPE ReportType,
+  PHIDP_VALUE_CAPS ValueCaps,
+  PULONG ValueCapsLength,
+  PHIDP_PREPARSED_DATA PreparsedData)
+{
+    UNIMPLEMENTED
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
diff --git a/lib/drivers/hidparser/hidparser.h b/lib/drivers/hidparser/hidparser.h
new file mode 100644 (file)
index 0000000..f305c22
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * PROJECT:     ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        lib/drivers/hidparser/hidparser.c
+ * PURPOSE:     HID Parser
+ * PROGRAMMERS:
+ *              Michael Martin (michael.martin@reactos.org)
+ *              Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+#pragma once
+
+#define _HIDPI_
+#define _HIDPI_NO_FUNCTION_MACROS_
+#include <ntddk.h>
+#include <hidpddi.h>
+#include <hidpi.h>
+#include <debug.h>
+
+//
+// function prototypes
+//
+typedef PVOID (NTAPI *PHIDPARSER_ALLOC_FUNCTION)(ULONG Size);
+typedef VOID (NTAPI *PHIDPARSER_FREE_FUNCTION)(PVOID Item);
+typedef VOID (NTAPI *PHIDPARSER_ZERO_FUNCTION)(PVOID Item, ULONG Size);
+typedef VOID (NTAPI *PHIDPARSER_COPY_FUNCTION)(PVOID Target, PVOID Source, ULONG Size);
+typedef VOID (NTAPI *PHIDPARSER_DEBUG_FUNCTION)(LPCSTR Src, ...);
+
+//
+// status code
+//
+typedef long HIDPARSER_STATUS;
+
+//
+// result codes
+//
+typedef enum
+{
+    HIDPARSER_STATUS_SUCCESS = 0,
+    HIDPARSER_STATUS_INSUFFICIENT_RESOURCES = -1,
+    HIDPARSER_STATUS_NOT_IMPLEMENTED = -2,
+    HIDPARSER_STATUS_REPORT_NOT_FOUND = -3,
+    HIDPARSER_STATUS_COLLECTION_NOT_FOUND = -4,
+    HIDPARSER_STATUS_INVALID_REPORT_LENGTH = -5,
+    HIDPARSER_STATUS_INVALID_REPORT_TYPE = -6,
+    HIDPARSER_STATUS_BUFFER_TOO_SMALL = -7,
+    HIDPARSER_STATUS_USAGE_NOT_FOUND = 8
+}HIDPARSER_STATUS_CODES;
+
+typedef struct
+{
+    //
+    // size of struct
+    //
+    unsigned long Size;
+
+    //
+    // allocation function
+    //
+    PHIDPARSER_ALLOC_FUNCTION Alloc;
+
+    //
+    // free function
+    //
+    PFREE_FUNCTION Free;
+
+    //
+    // zero function
+    //
+    PHIDPARSER_ZERO_FUNCTION Zero;
+
+    //
+    // copy function
+    //
+    PHIDPARSER_COPY_FUNCTION Copy;
+
+    //
+    // debug function
+    //
+    PHIDPARSER_DEBUG_FUNCTION Debug;
+
+    //
+    // parser context
+    //
+    void * ParserContext;
+
+}HID_PARSER, *PHID_PARSER;
+
+HIDPARSER_STATUS
+HidParser_AllocateParser(
+    IN PHIDPARSER_ALLOC_FUNCTION AllocFunction,
+    IN PHIDPARSER_FREE_FUNCTION FreeFunction,
+    IN PHIDPARSER_ZERO_FUNCTION ZeroFunction,
+    IN PHIDPARSER_COPY_FUNCTION CopyFunction,
+    IN PHIDPARSER_DEBUG_FUNCTION DebugFunction,
+    OUT PHID_PARSER *OutParser);
+
+VOID
+HidParser_InitParser(
+    IN PHIDPARSER_ALLOC_FUNCTION AllocFunction,
+    IN PHIDPARSER_FREE_FUNCTION FreeFunction,
+    IN PHIDPARSER_ZERO_FUNCTION ZeroFunction,
+    IN PHIDPARSER_COPY_FUNCTION CopyFunction,
+    IN PHIDPARSER_DEBUG_FUNCTION DebugFunction,
+    IN PVOID ParserContext,
+    OUT PHID_PARSER Parser);
+
+NTSTATUS
+NTAPI
+HidParser_GetCollectionDescription(
+    IN PHID_PARSER Parser,
+    IN PHIDP_REPORT_DESCRIPTOR ReportDesc,
+    IN ULONG DescLength,
+    IN POOL_TYPE PoolType,
+    OUT PHIDP_DEVICE_DESC DeviceDescription);
+
+VOID
+NTAPI
+HidParser_FreeCollectionDescription(
+    IN PHID_PARSER Parser,
+    IN PHIDP_DEVICE_DESC   DeviceDescription);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetCaps(
+    IN PHID_PARSER Parser,
+    OUT PHIDP_CAPS  Capabilities);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetSpecificValueCaps(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USAGE  UsagePage,
+    IN USHORT  LinkCollection,
+    IN USAGE  Usage,
+    OUT PHIDP_VALUE_CAPS  ValueCaps,
+    IN OUT PULONG  ValueCapsLength);
+
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetButtonCaps(
+    IN PHID_PARSER Parser,
+    HIDP_REPORT_TYPE ReportType,
+    PHIDP_BUTTON_CAPS ButtonCaps,
+    PUSHORT ButtonCapsLength);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetSpecificButtonCaps(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USAGE  UsagePage,
+    IN USHORT  LinkCollection,
+    IN USAGE  Usage,
+    OUT PHIDP_BUTTON_CAPS  ButtonCaps,
+    IN OUT PULONG  ButtonCapsLength);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetScaledUsageValue(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USAGE  UsagePage,
+    IN USHORT  LinkCollection  OPTIONAL,
+    IN USAGE  Usage,
+    OUT PLONG  UsageValue,
+    IN PCHAR  Report,
+    IN ULONG  ReportLength);
+
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetData(
+  IN HIDP_REPORT_TYPE  ReportType,
+  OUT PHIDP_DATA  DataList,
+  IN OUT PULONG  DataLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN PCHAR  Report,
+  IN ULONG  ReportLength);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetExtendedAttributes(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USHORT  DataIndex,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  OUT PHIDP_EXTENDED_ATTRIBUTES  Attributes,
+  IN OUT PULONG  LengthAttributes);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetLinkCollectionNodes(
+    OUT PHIDP_LINK_COLLECTION_NODE  LinkCollectionNodes,
+    IN OUT PULONG  LinkCollectionNodesLength,
+    IN PHIDP_PREPARSED_DATA  PreparsedData);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetUsageValue(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection,
+  IN USAGE  Usage,
+  OUT PULONG  UsageValue,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN PCHAR  Report,
+  IN ULONG  ReportLength);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_UsageListDifference(
+  IN PUSAGE  PreviousUsageList,
+  IN PUSAGE  CurrentUsageList,
+  OUT PUSAGE  BreakUsageList,
+  OUT PUSAGE  MakeUsageList,
+  IN ULONG  UsageListLength);
+
+
+HIDAPI
+ULONG
+NTAPI
+HidParser_MaxUsageListLength(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USAGE  UsagePage  OPTIONAL);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetUsages(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USAGE  UsagePage,
+    IN USHORT  LinkCollection  OPTIONAL,
+    OUT USAGE  *UsageList,
+    IN OUT ULONG  *UsageLength,
+    IN PCHAR  Report,
+    IN ULONG  ReportLength);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetUsagesEx(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USHORT  LinkCollection,
+    OUT PUSAGE_AND_PAGE  ButtonList,
+    IN OUT ULONG  *UsageLength,
+    IN PCHAR  Report,
+    IN ULONG  ReportLength);
+
+
+NTSTATUS
+NTAPI
+HidParser_SysPowerEvent (
+    IN PCHAR HidPacket,
+    IN USHORT HidPacketLength,
+    IN PHIDP_PREPARSED_DATA Ppd,
+    OUT PULONG OutputBuffer);
+
+NTSTATUS
+NTAPI
+HidParser_SysPowerCaps (
+    IN PHIDP_PREPARSED_DATA Ppd,
+    OUT PULONG OutputBuffer);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetUsageValueArray(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection  OPTIONAL,
+  IN USAGE  Usage,
+  OUT PCHAR  UsageValue,
+  IN USHORT  UsageValueByteLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN PCHAR  Report,
+  IN ULONG  ReportLength);
+
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_UsageAndPageListDifference(
+   IN PUSAGE_AND_PAGE  PreviousUsageList,
+   IN PUSAGE_AND_PAGE  CurrentUsageList,
+   OUT PUSAGE_AND_PAGE  BreakUsageList,
+   OUT PUSAGE_AND_PAGE  MakeUsageList,
+   IN ULONG  UsageListLength);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_UnsetUsages(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection,
+  IN PUSAGE  UsageList,
+  IN OUT PULONG  UsageLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN OUT PCHAR  Report,
+  IN ULONG  ReportLength);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_TranslateUsagesToI8042ScanCodes(
+  IN PUSAGE  ChangedUsageList,
+  IN ULONG  UsageListLength,
+  IN HIDP_KEYBOARD_DIRECTION  KeyAction,
+  IN OUT PHIDP_KEYBOARD_MODIFIER_STATE  ModifierState,
+  IN PHIDP_INSERT_SCANCODES  InsertCodesProcedure,
+  IN PVOID  InsertCodesContext);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_TranslateUsageAndPagesToI8042ScanCodes(
+   IN PUSAGE_AND_PAGE  ChangedUsageList,
+   IN ULONG  UsageListLength,
+   IN HIDP_KEYBOARD_DIRECTION  KeyAction,
+   IN OUT PHIDP_KEYBOARD_MODIFIER_STATE  ModifierState,
+   IN PHIDP_INSERT_SCANCODES  InsertCodesProcedure,
+   IN PVOID  InsertCodesContext);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_SetUsages(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection,
+  IN PUSAGE  UsageList,
+  IN OUT PULONG  UsageLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN OUT PCHAR  Report,
+  IN ULONG  ReportLength);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_SetUsageValueArray(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection  OPTIONAL,
+  IN USAGE  Usage,
+  IN PCHAR  UsageValue,
+  IN USHORT  UsageValueByteLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  OUT PCHAR  Report,
+  IN ULONG  ReportLength);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_SetUsageValue(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection,
+  IN USAGE  Usage,
+  IN ULONG  UsageValue,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN OUT PCHAR  Report,
+  IN ULONG  ReportLength);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_SetScaledUsageValue(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN USAGE  UsagePage,
+  IN USHORT  LinkCollection  OPTIONAL,
+  IN USAGE  Usage,
+  IN LONG  UsageValue,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN OUT PCHAR  Report,
+  IN ULONG  ReportLength);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_SetData(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN PHIDP_DATA  DataList,
+  IN OUT PULONG  DataLength,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN OUT PCHAR  Report,
+  IN ULONG  ReportLength);
+
+HIDAPI
+ULONG
+NTAPI
+HidParser_MaxDataListLength(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN PHIDP_PREPARSED_DATA  PreparsedData);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_InitializeReportForID(
+  IN HIDP_REPORT_TYPE  ReportType,
+  IN UCHAR  ReportID,
+  IN PHIDP_PREPARSED_DATA  PreparsedData,
+  IN OUT PCHAR  Report,
+  IN ULONG  ReportLength);
+
+HIDAPI
+NTSTATUS
+NTAPI
+HidParser_GetValueCaps(
+  HIDP_REPORT_TYPE ReportType,
+  PHIDP_VALUE_CAPS ValueCaps,
+  PULONG ValueCapsLength,
+  PHIDP_PREPARSED_DATA PreparsedData);
diff --git a/lib/drivers/hidparser/parser.c b/lib/drivers/hidparser/parser.c
new file mode 100644 (file)
index 0000000..d86b6df
--- /dev/null
@@ -0,0 +1,1347 @@
+/*
+ * PROJECT:     ReactOS HID Parser Library
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        lib/drivers/hidparser/parser.c
+ * PURPOSE:     HID Parser
+ * PROGRAMMERS:
+ *              Michael Martin (michael.martin@reactos.org)
+ *              Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+
+#include "parser.h"
+
+static UCHAR ItemSize[4] = { 0, 1, 2, 4 };
+
+VOID
+HidParser_DeleteReport(
+    IN PHID_PARSER Parser,
+    IN PHID_REPORT Report)
+{
+    //
+    // not implemented
+    //
+}
+
+VOID
+HidParser_FreeCollection(
+    IN PHID_PARSER Parser,
+    IN PHID_COLLECTION Collection)
+{
+    //
+    // not implemented
+    //
+}
+
+HIDPARSER_STATUS
+HidParser_AllocateCollection(
+    IN PHID_PARSER Parser,
+    IN PHID_COLLECTION ParentCollection,
+    IN UCHAR Type,
+    IN PLOCAL_ITEM_STATE LocalItemState,
+    OUT PHID_COLLECTION * OutCollection)
+{
+    PHID_COLLECTION Collection;
+    USAGE_VALUE UsageValue;
+
+    //
+    // first allocate the collection
+    //
+    Collection = (PHID_COLLECTION)Parser->Alloc(sizeof(HID_COLLECTION));
+    if (!Collection)
+    {
+        //
+        // no memory
+        //
+        return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // init collection
+    //
+    Collection->Root = ParentCollection;
+    Collection->Type = Type;
+    Collection->StringID = LocalItemState->StringIndex;
+    Collection->PhysicalID = LocalItemState->DesignatorIndex;
+
+    //
+    // set Usage
+    //
+    ASSERT(LocalItemState);
+    ASSERT(LocalItemState->UsageStack);
+
+    if (LocalItemState->UsageStackUsed > 0)
+    {
+        //
+        // usage value from first local stack item
+        //
+        UsageValue.u.Extended = LocalItemState->UsageStack[0].u.Extended;
+    }
+    else if (LocalItemState->UsageMinimumSet)
+    {
+        //
+        // use value from minimum
+        //
+        UsageValue.u.Extended = LocalItemState->UsageMinimum.u.Extended;
+    }
+    else if (LocalItemState->UsageMaximumSet)
+    {
+        //
+        // use value from maximum
+        //
+        UsageValue.u.Extended = LocalItemState->UsageMaximum.u.Extended;
+    }
+    else if (Type == COLLECTION_LOGICAL)
+    {
+        //
+        // root collection
+        //
+        UsageValue.u.Extended = 0;
+    }
+    else
+    {
+        //
+        // no usage set
+        //
+        Parser->Debug("HIDPARSE] No usage set\n");
+        UsageValue.u.Extended = 0;
+    }
+
+    //
+    // store usage
+    //
+    Collection->Usage = UsageValue.u.Extended;
+
+    //
+    // store result
+    //
+    *OutCollection = Collection;
+
+    //
+    // done
+    // 
+    return HIDPARSER_STATUS_SUCCESS;
+}
+
+
+VOID
+HidParser_ResetParser(
+    OUT PHID_PARSER Parser)
+{
+    ULONG Index;
+    PHID_PARSER_CONTEXT ParserContext;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+
+
+    //
+    // delete all reports
+    //
+    for(Index = 0; Index < ParserContext->ReportCount; Index++)
+    {
+        //
+        // delete report
+        //
+        HidParser_DeleteReport(Parser, ParserContext->Reports[Index]);
+    }
+
+    if (ParserContext->ReportCount && ParserContext->Reports)
+    {
+        //
+        // free report array
+        //
+       Parser->Free(ParserContext->Reports);
+    }
+
+    if (ParserContext->RootCollection)
+    {
+        //
+        // delete root collection
+        //
+        HidParser_FreeCollection(Parser, ParserContext->RootCollection);
+    }
+
+    //
+    // reinit parser
+    //
+    ParserContext->ReportCount = 0;
+    ParserContext->Reports = NULL;
+    ParserContext->RootCollection = NULL;
+    ParserContext->UseReportIDs = FALSE;
+
+    //
+    // zero item states
+    //
+    Parser->Zero(&ParserContext->GlobalItemState, sizeof(GLOBAL_ITEM_STATE));
+    Parser->Zero(&ParserContext->LocalItemState, sizeof(LOCAL_ITEM_STATE));
+}
+
+HIDPARSER_STATUS
+HidParser_AddCollection(
+    IN PHID_PARSER Parser,
+    IN PHID_COLLECTION CurrentCollection,
+    IN PHID_COLLECTION NewCollection)
+{
+    PHID_COLLECTION * NewAllocCollection;
+    ULONG CollectionCount;
+
+    //
+    // increment collection array
+    //
+    CollectionCount = CurrentCollection->NodeCount + 1;
+
+    //
+    // allocate new collection
+    //
+    NewAllocCollection = (PHID_COLLECTION*)Parser->Alloc(sizeof(PHID_COLLECTION) * CollectionCount);
+    if (!NewAllocCollection)
+    {
+        //
+        // no memory
+        //
+        return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    if (CurrentCollection->NodeCount)
+    {
+        //
+        // copy old array
+        //
+        Parser->Copy(NewAllocCollection, CurrentCollection->Nodes, CurrentCollection->NodeCount * sizeof(PHID_COLLECTION));
+
+        //
+        // delete old array
+        //
+        Parser->Free(CurrentCollection->Nodes);
+    }
+
+    //
+    // insert new item
+    //
+    NewAllocCollection[CurrentCollection->NodeCount] = (struct __HID_COLLECTION__*)NewCollection;
+
+
+    //
+    // store new array
+    //
+    CurrentCollection->Nodes = NewAllocCollection;
+    CurrentCollection->NodeCount++;
+
+    //
+    // done
+    //
+    return HIDPARSER_STATUS_SUCCESS;
+}
+
+HIDPARSER_STATUS
+HidParser_FindReport(
+    IN PHID_PARSER Parser,
+    IN UCHAR ReportType,
+    IN UCHAR ReportID,
+    OUT PHID_REPORT *OutReport)
+{
+    PHID_PARSER_CONTEXT ParserContext;
+    ULONG Index;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+    ASSERT(ParserContext);
+
+    for(Index = 0; Index < ParserContext->ReportCount; Index++)
+    {
+        if (ParserContext->Reports[Index]->Type == ReportType && ParserContext->Reports[Index]->ReportID == ReportID)
+        {
+            //
+            // found report
+            //
+            *OutReport = ParserContext->Reports[Index];
+            return HIDPARSER_STATUS_SUCCESS;
+        }
+    }
+
+    //
+    // no such report found
+    //
+    *OutReport = NULL;
+    return HIDPARSER_STATUS_REPORT_NOT_FOUND;
+}
+
+HIDPARSER_STATUS
+HidParser_AllocateReport(
+    IN PHID_PARSER Parser,
+    IN UCHAR ReportType,
+    IN UCHAR ReportID,
+    OUT PHID_REPORT *OutReport)
+{
+    PHID_REPORT Report;
+
+    //
+    // allocate report
+    //
+    Report = (PHID_REPORT)Parser->Alloc(sizeof(HID_REPORT));
+    if (!Report)
+    {
+        //
+        // no memory
+        //
+        return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // init report
+    //
+    Report->ReportID = ReportID;
+    Report->Type = ReportType;
+
+    //
+    // done
+    //
+    *OutReport = Report;
+    return HIDPARSER_STATUS_SUCCESS;
+}
+
+HIDPARSER_STATUS
+HidParser_AddReport(
+    IN PHID_PARSER Parser,
+    IN PHID_REPORT NewReport)
+{
+    PHID_REPORT * NewReportArray;
+    PHID_PARSER_CONTEXT ParserContext;
+
+    //
+    // get parser context
+    //
+    ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
+    ASSERT(ParserContext);
+
+    //
+    // allocate new report array
+    //
+    NewReportArray = (PHID_REPORT*)Parser->Alloc(sizeof(PHID_REPORT) * (ParserContext->ReportCount + 1));
+    if (!NewReportArray)
+    {
+        //
+        // no memory
+        //
+        return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    if (ParserContext->ReportCount)
+    {
+        //
+        // copy old array contents
+        //
+        Parser->Copy(NewReportArray, ParserContext->Reports, sizeof(PHID_REPORT) * ParserContext->ReportCount);
+
+        //
+        // free old array
+        //
+        Parser->Free(ParserContext->Reports);
+    }
+
+    //
+    // store result
+    //
+    NewReportArray[ParserContext->ReportCount] = NewReport;
+    ParserContext->Reports = NewReportArray;
+    ParserContext->ReportCount++;
+
+    //
+    // completed successfully
+    //
+    return HIDPARSER_STATUS_SUCCESS;
+}
+
+HIDPARSER_STATUS
+HidParser_GetReport(
+    IN PHID_PARSER Parser,
+    IN UCHAR ReportType,
+    IN UCHAR ReportID,
+    IN UCHAR CreateIfNotExists,
+    OUT PHID_REPORT *OutReport)
+{
+    HIDPARSER_STATUS Status;
+
+    //
+    // try finding existing report
+    //
+    Status = HidParser_FindReport(Parser, ReportType, ReportID, OutReport);
+    if (Status == HIDPARSER_STATUS_SUCCESS || CreateIfNotExists == FALSE)
+    {
+        //
+        // founed report
+        //
+        return Status;
+    }
+
+    //
+    // allocate new report
+    //
+    Status = HidParser_AllocateReport(Parser, ReportType, ReportID, OutReport);
+    if (Status != HIDPARSER_STATUS_SUCCESS)
+    {
+        //
+        // failed to allocate report
+        //
+        return Status;
+    }
+
+    //
+    // add report
+    //
+    Status = HidParser_AddReport(Parser, *OutReport);
+    if (Status != HIDPARSER_STATUS_SUCCESS)
+    {
+        //
+        // failed to allocate report
+        //
+        Parser->Free(*OutReport);
+    }
+
+    //
+    // done
+    //
+    return Status;
+}
+
+
+HIDPARSER_STATUS
+HidParser_ReserveCollectionItems(
+    IN PHID_PARSER Parser,
+    IN PHID_COLLECTION Collection,
+    IN ULONG ReportCount)
+{
+    PHID_REPORT_ITEM * NewReportArray;
+
+    if (Collection->ItemCount + ReportCount <= Collection->ItemCountAllocated)
+    {
+        //
+        // enough space for the next items
+        //
+        return HIDPARSER_STATUS_SUCCESS;
+    }
+
+    //
+    // allocate report array
+    //
+    NewReportArray = (PHID_REPORT_ITEM*)Parser->Alloc(sizeof(PHID_REPORT) * (Collection->ItemCountAllocated + ReportCount));
+    if (!NewReportArray)
+    {
+        //
+        // no memory
+        //
+        return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // are there any items
+    //
+    if (Collection->ItemCount)
+    {
+        //
+        // copy old items
+        //
+        Parser->Copy(NewReportArray, Collection->Items, sizeof(PHID_REPORT_ITEM) * Collection->ItemCount);
+
+        //
+        // free old item
+        //
+        Parser->Free(Collection->Items);
+    }
+
+    //
+    // replace array
+    //
+    Collection->Items = NewReportArray;
+    Collection->ItemCountAllocated += ReportCount;
+
+    //
+    // completed sucessfully
+    //
+    return HIDPARSER_STATUS_SUCCESS;
+}
+
+
+HIDPARSER_STATUS
+HidParser_ReserveReportItems(
+    IN PHID_PARSER Parser,
+    IN PHID_REPORT Report,
+    IN ULONG ReportCount)
+{
+    PHID_REPORT_ITEM * NewReportArray;
+
+    if (Report->ItemCount + ReportCount <= Report->ItemAllocated)
+    {
+        //
+        // enough space for the next items
+        //
+        return HIDPARSER_STATUS_SUCCESS;
+    }
+
+    //
+    // allocate report array
+    //
+    NewReportArray = (PHID_REPORT_ITEM*)Parser->Alloc(sizeof(PHID_REPORT_ITEM) * (Report->ItemAllocated + ReportCount));
+    if (!NewReportArray)
+    {
+        //
+        // no memory
+        //
+        return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // are there any items
+    //
+    if (Report->ItemCount)
+    {
+        //
+        // copy old items
+        //
+        Parser->Copy(NewReportArray, Report->Items, sizeof(PHID_REPORT_ITEM) * Report->ItemCount);
+
+        //
+        // free old item
+        //
+        Parser->Free(Report->Items);
+    }
+
+    //
+    // replace array
+    //
+    Report->Items = NewReportArray;
+    Report->ItemAllocated += ReportCount;
+
+    //
+    // completed sucessfully
+    //
+    return HIDPARSER_STATUS_SUCCESS;
+}
+
+HIDPARSER_STATUS
+HidParser_AllocateReportItem(
+    IN PHID_PARSER Parser,
+    OUT PHID_REPORT_ITEM * OutReportItem)
+{
+    PHID_REPORT_ITEM ReportItem;
+
+    //
+    // allocate report item
+    //
+    ReportItem = (PHID_REPORT_ITEM)Parser->Alloc(sizeof(HID_REPORT_ITEM));
+    if (!ReportItem)
+    {
+        //
+        // no memory
+        //
+        return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // store result
+    //
+    *OutReportItem = ReportItem;
+    return HIDPARSER_STATUS_SUCCESS;
+}
+
+VOID
+HidParser_AddReportItemToReport(
+    IN OUT PHID_REPORT Report,
+    IN PHID_REPORT_ITEM ReportItem)
+{
+    //
+    // there should be space in item array
+    //
+    ASSERT(Report->ItemCount + 1 <= Report->ItemAllocated);
+
+    //
+    // store item
+    //
+    Report->Items[Report->ItemCount] = ReportItem;
+    Report->ItemCount++;
+}
+
+VOID
+HidParser_AddReportItemToCollection(
+    IN OUT PHID_COLLECTION Collection,
+    IN PHID_REPORT_ITEM ReportItem)
+{
+    //
+    // there should be space in item array
+    //
+    ASSERT(Collection->ItemCount + 1 <= Collection->ItemCountAllocated);
+
+    //
+    // store item
+    //
+    Collection->Items[Collection->ItemCount] = ReportItem;
+    Collection->ItemCount++;
+}
+
+VOID
+HidParser_SignRange(
+    IN ULONG Minimum,
+    IN ULONG Maximum,
+    OUT PULONG NewMinimum,
+    OUT PULONG NewMaximum)
+{
+    ULONG Mask = 0x80000000;
+    ULONG Index;
+
+    for (Index = 0; Index < 4; Index++)
+    {
+        if (Minimum & Mask) 
+        {
+            Minimum |= Mask;
+            if (Maximum & Mask)
+                Maximum |= Mask;
+            return;
+        }
+
+        Mask >>= 8;
+        Mask |= 0xff000000;
+    }
+
+    *NewMinimum = Minimum;
+    *NewMaximum = Maximum;
+}
+
+HIDPARSER_STATUS
+HidParser_InitReportItem(
+    IN PHID_REPORT Report,
+    IN PHID_REPORT_ITEM ReportItem,
+    IN PGLOBAL_ITEM_STATE GlobalItemState,
+    IN PLOCAL_ITEM_STATE LocalItemState,
+    IN PMAIN_ITEM_DATA ItemData,
+    IN ULONG ReportItemIndex)
+{
+    ULONG LogicalMinimum;
+    ULONG LogicalMaximum;
+    ULONG PhysicalMinimum;
+    ULONG PhysicalMaximum;
+    ULONG UsageMinimum;
+    ULONG UsageMaximum;
+    USAGE_VALUE UsageValue;
+
+    //
+    // get logical bounds
+    //
+    LogicalMinimum = GlobalItemState->LogicalMinimum;
+    LogicalMaximum = GlobalItemState->LogicialMaximum;
+    if (LogicalMinimum > LogicalMaximum)
+    {
+        //
+        // make them signed
+        //
+        HidParser_SignRange(LogicalMinimum, LogicalMaximum, &LogicalMinimum, &LogicalMaximum);
+    }
+    //ASSERT(LogicalMinimum <= LogicalMaximum);
+
+    //
+    // get physical bounds
+    //
+    PhysicalMinimum = GlobalItemState->PhysicalMinimum;
+    PhysicalMaximum = GlobalItemState->PhysicalMaximum;
+    if (PhysicalMinimum > PhysicalMaximum)
+    {
+        //
+        // make them signed
+        //
+        HidParser_SignRange(PhysicalMinimum, PhysicalMaximum, &PhysicalMinimum, &PhysicalMaximum);
+    }
+    //ASSERT(PhysicalMinimum <= PhysicalMaximum);
+
+    //
+    // get usage bounds
+    //
+    UsageMinimum = 0;
+    UsageMaximum = 0;
+    if (ItemData->ArrayVariable == FALSE)
+    {
+        //
+        // get usage bounds
+        //
+        UsageMinimum = LocalItemState->UsageMinimum.u.Extended;
+        UsageMaximum = LocalItemState->UsageMaximum.u.Extended;
+    }
+    else
+    {
+        //
+        // get usage value from stack
+        //
+        if (ReportItemIndex < LocalItemState->UsageStackUsed)
+        {
+            //
+            // use stack item
+            //
+            UsageValue = LocalItemState->UsageStack[ReportItemIndex];
+        }
+        else
+        {
+            //
+            // get usage minimum from local state
+            //
+            UsageValue = LocalItemState->UsageMinimum;
+            ASSERT(LocalItemState->UsageMinimumSet);
+            ASSERT(LocalItemState->UsageMaximumSet);
+
+            //
+            // append item index
+            //
+            UsageValue.u.Extended += ReportItemIndex;
+
+            if (UsageValue.u.Extended > LocalItemState->UsageMaximum.u.Extended)
+            {
+                //
+                // maximum reached
+                //
+                UsageValue.u.Extended = LocalItemState->UsageMaximum.u.Extended;
+            }
+        }
+
+        //
+        // usage usage bounds
+        //
+        UsageMinimum = UsageMaximum = UsageValue.u.Extended;
+    }
+
+    //
+    // now store all values
+    //
+    ReportItem->ByteOffset = (Report->ReportSize / 8);
+    ReportItem->Shift = (Report->ReportSize % 8);
+    ReportItem->Mask = ~(0xFFFFFFFF << GlobalItemState->ReportSize);
+    ReportItem->BitCount = GlobalItemState->ReportSize;
+    ReportItem->HasData = (ItemData->DataConstant == FALSE);
+    ReportItem->Array = (ItemData->ArrayVariable == 0);
+    ReportItem->Relative = (ItemData->Relative == TRUE);
+    ReportItem->Minimum = LogicalMinimum;
+    ReportItem->Maximum = LogicalMaximum;
+    ReportItem->UsageMinimum = UsageMinimum;
+    ReportItem->UsageMaximum = UsageMaximum;
+
+    //
+    // increment report size
+    //
+    Report->ReportSize += GlobalItemState->ReportSize;
+
+    //
+    // completed successfully
+    //
+    return HIDPARSER_STATUS_SUCCESS;
+}
+
+HIDPARSER_STATUS
+HidParser_AddMainItem(
+    IN PHID_PARSER Parser,
+    IN PHID_REPORT Report,
+    IN PGLOBAL_ITEM_STATE GlobalItemState,
+    IN PLOCAL_ITEM_STATE LocalItemState,
+    IN PMAIN_ITEM_DATA ItemData,
+    IN PHID_COLLECTION Collection)
+{
+    PHID_REPORT_ITEM ReportItem;
+    HIDPARSER_STATUS Status;
+    ULONG Index;
+
+    //
+    // first grow report item array
+    //
+    Status = HidParser_ReserveReportItems(Parser, Report, GlobalItemState->ReportCount);
+    if (Status != HIDPARSER_STATUS_SUCCESS)
+    {
+        //
+        // failed to allocate memory
+        //
+        return Status;
+    }
+
+    //
+    // grow collection item array
+    //
+    Status = HidParser_ReserveCollectionItems(Parser, Collection, GlobalItemState->ReportCount);
+    if (Status != HIDPARSER_STATUS_SUCCESS)
+    {
+        //
+        // failed to allocate memory
+        //
+        return Status;
+    }
+
+
+
+    for(Index = 0; Index < GlobalItemState->ReportCount; Index++)
+    {
+        //
+        // create report item
+        //
+        Status = HidParser_AllocateReportItem(Parser, &ReportItem);
+        if (Status != HIDPARSER_STATUS_SUCCESS)
+        {
+            //
+            // failed to allocate memory
+            //
+            return Status;
+        }
+
+        Status = HidParser_InitReportItem(Report, ReportItem, GlobalItemState, LocalItemState, ItemData, Index);
+        if (Status != HIDPARSER_STATUS_SUCCESS)
+        {
+            //
+            // failed to init report item
+            //
+            return Status;
+        }
+
+        //
+        // add report item
+        //
+        HidParser_AddReportItemToReport(Report, ReportItem);
+        HidParser_AddReportItemToCollection(Collection, ReportItem);
+    }
+
+    //
+    // done
+    //
+    return HIDPARSER_STATUS_SUCCESS;
+}
+
+HIDPARSER_STATUS
+HidParser_ParseReportDescriptor(
+    IN PHID_PARSER Parser,
+    IN PUCHAR ReportDescriptor,
+    IN ULONG ReportLength)
+{
+    PGLOBAL_ITEM_STATE LinkedGlobalItemState, NextLinkedGlobalItemState;
+    ULONG Index;
+    PUSAGE_VALUE NewUsageStack, UsageValue;
+    HIDPARSER_STATUS Status;
+    PHID_COLLECTION CurrentCollection, NewCollection;
+    PUCHAR CurrentOffset, ReportEnd;
+    PITEM_PREFIX CurrentItem;
+    ULONG CurrentItemSize;
+    PLONG_ITEM CurrentLongItem;
+    PSHORT_ITEM CurrentShortItem;
+    ULONG Data;
+    UCHAR ReportType;
+    PHID_REPORT Report;
+    PMAIN_ITEM_DATA MainItemData;
+    PHID_PARSER_CONTEXT ParserContext;
+
+    //
+    // reset parser
+    //
+    HidParser_ResetParser(Parser);
+
+    //
+    // get parser context
+    //
+    ParserContext =(PHID_PARSER_CONTEXT)Parser->ParserContext;
+    ASSERT(ParserContext);
+
+    //
+    // allocate usage stack
+    //
+    ParserContext->LocalItemState.UsageStackAllocated = 10;
+    ParserContext->LocalItemState.UsageStack = (PUSAGE_VALUE)Parser->Alloc(ParserContext->LocalItemState.UsageStackAllocated * sizeof(USAGE_VALUE));
+    if (!ParserContext->LocalItemState.UsageStack)
+    {
+        //
+        // no memory
+        //
+        return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // now allocate root collection
+    //
+    Status = HidParser_AllocateCollection(Parser, NULL, COLLECTION_LOGICAL, &ParserContext->LocalItemState, &ParserContext->RootCollection);
+    if (Status != HIDPARSER_STATUS_SUCCESS)
+    {
+        //
+        // no memory
+        //
+        Parser->Free(ParserContext->LocalItemState.UsageStack);
+        ParserContext->LocalItemState.UsageStack = NULL;
+        return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // start parsing
+    //
+    CurrentCollection = ParserContext->RootCollection;
+    CurrentOffset = ReportDescriptor;
+    ReportEnd = ReportDescriptor + ReportLength;
+
+    do
+    {
+        //
+        // get current item
+        //
+        CurrentItem = (PITEM_PREFIX)CurrentOffset;
+
+        //
+        // get item size
+        //
+        CurrentItemSize = ItemSize[CurrentItem->Size];
+        Data = 0;
+
+        if (CurrentItem->Type == ITEM_TYPE_LONG)
+        {
+            //
+            // increment item size with size of data item
+            //
+            CurrentLongItem = (PLONG_ITEM)CurrentItem;
+            CurrentItemSize += CurrentLongItem->DataSize;
+        }
+        else
+        {
+            //
+            // get short item
+            //
+            CurrentShortItem = (PSHORT_ITEM)CurrentItem;
+
+            //
+            // get associated data
+            //
+            //ASSERT(CurrentItemSize == 1 || CurrentItemSize == 2 || CurrentItemSize == 4);
+            if (CurrentItemSize == 1)
+                Data = CurrentShortItem->Data.UData8[0];
+            else if (CurrentItemSize == 2)
+                Data = CurrentShortItem->Data.UData16[0];
+            else if (CurrentItemSize == 4)
+                Data = CurrentShortItem->Data.UData32;
+            else
+            {
+                //
+                // invalid item size
+                //
+                //Parser->Debug("CurrentItem invalid item size %lu\n", CurrentItemSize);
+            }
+
+        }
+
+        //
+        // handle items
+        //
+        ASSERT(CurrentItem->Type >= ITEM_TYPE_MAIN && CurrentItem->Type <= ITEM_TYPE_LONG);
+        switch(CurrentItem->Type)
+        {
+            case ITEM_TYPE_MAIN:
+            {
+                // preprocess the local state if relevant (usages for
+                // collections and report items)
+                if (CurrentItem->Tag != ITEM_TAG_MAIN_END_COLLECTION) 
+                {
+                    // make all usages extended for easier later processing
+                    for (Index = 0; Index < ParserContext->LocalItemState.UsageStackUsed; Index++) 
+                    {
+                        //
+                        // is it already extended
+                        //
+                        if (ParserContext->LocalItemState.UsageStack[Index].IsExtended)
+                            continue;
+
+                        //
+                        // extend usage item
+                        //
+                        ParserContext->LocalItemState.UsageStack[Index].u.s.UsagePage = ParserContext->GlobalItemState.UsagePage;
+                        ParserContext->LocalItemState.UsageStack[Index].IsExtended = TRUE;
+                    }
+
+                    if (!ParserContext->LocalItemState.UsageMinimum.IsExtended) {
+                        // the specs say if one of them is extended they must
+                        // both be extended, so if the minimum isn't, the
+                        // maximum mustn't either.
+                        ParserContext->LocalItemState.UsageMinimum.u.s.UsagePage
+                            = ParserContext->LocalItemState.UsageMaximum.u.s.UsagePage
+                                = ParserContext->GlobalItemState.UsagePage;
+                        ParserContext->LocalItemState.UsageMinimum.IsExtended
+                            = ParserContext->LocalItemState.UsageMaximum.IsExtended = TRUE;
+                    }
+
+                    //LocalItemState.usage_stack = usageStack;
+                    //ParserContext->LocalItemState.UsageStackUsed = UsageStackUsed;
+                }
+
+                if (CurrentItem->Tag == ITEM_TAG_MAIN_COLLECTION) {
+
+                    //
+                    // allocate new collection
+                    //
+                    Status = HidParser_AllocateCollection(Parser, CurrentCollection, (UCHAR)Data, &ParserContext->LocalItemState, &NewCollection);
+                    ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
+
+                    //
+                    // add new collection to current collection
+                    //
+                    Status = HidParser_AddCollection(Parser, CurrentCollection, NewCollection);
+                    ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
+
+                    //
+                    // make new collection current
+                    //
+                    CurrentCollection = NewCollection;
+                } 
+                else if (CurrentItem->Tag == ITEM_TAG_MAIN_END_COLLECTION) 
+                {
+                    //
+                    // assert on ending the root collection
+                    //
+                    ASSERT(CurrentCollection != ParserContext->RootCollection);
+
+                    //
+                    // use parent of current collection
+                    //
+                    CurrentCollection = CurrentCollection->Root;
+                    ASSERT(CurrentCollection);
+                } 
+                else 
+                {
+                    ReportType = HID_REPORT_TYPE_ANY;
+
+                    switch (CurrentItem->Tag) {
+                        case ITEM_TAG_MAIN_INPUT:
+                            ReportType = HID_REPORT_TYPE_INPUT;
+                            break;
+
+                        case ITEM_TAG_MAIN_OUTPUT:
+                            ReportType = HID_REPORT_TYPE_OUTPUT;
+                            break;
+
+                        case ITEM_TAG_MAIN_FEATURE:
+                            ReportType = HID_REPORT_TYPE_FEATURE;
+                            break;
+
+                        default:
+                            Parser->Debug("[HIDPARSE] Unknown ReportType %x\n", CurrentItem->Tag);
+                            ASSERT(FALSE);
+                            break;
+                    }
+
+                    if (ReportType == HID_REPORT_TYPE_ANY)
+                        break;
+
+                    //
+                    // get report
+                    //
+                    Status = HidParser_GetReport(Parser, ReportType, ParserContext->GlobalItemState.ReportId, TRUE, &Report);
+                    ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
+
+                    // fill in a sensible default if the index isn't set
+                    if (!ParserContext->LocalItemState.DesignatorIndexSet) {
+                        ParserContext->LocalItemState.DesignatorIndex
+                            = ParserContext->LocalItemState.DesignatorMinimum;
+                    }
+
+                    if (!ParserContext->LocalItemState.StringIndexSet)
+                        ParserContext->LocalItemState.StringIndex = ParserContext->LocalItemState.StringMinimum;
+
+                    //
+                    // get main item data
+                    //
+                    MainItemData = (PMAIN_ITEM_DATA)&Data;
+
+                    //
+                    // add states & data to the report
+                    //
+                    Status = HidParser_AddMainItem(Parser, Report, &ParserContext->GlobalItemState, &ParserContext->LocalItemState, MainItemData, CurrentCollection);
+                    ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
+                }
+
+                //
+                // backup stack
+                //
+                Index = ParserContext->LocalItemState.UsageStackAllocated;
+                NewUsageStack = ParserContext->LocalItemState.UsageStack;
+
+                //
+                // reset the local item state and clear the usage stack
+                //
+                Parser->Zero(&ParserContext->LocalItemState, sizeof(LOCAL_ITEM_STATE));
+
+                //
+                // restore stack
+                //
+                ParserContext->LocalItemState.UsageStack = NewUsageStack;
+                ParserContext->LocalItemState.UsageStackAllocated = Index;
+                break;
+            }
+            case ITEM_TYPE_GLOBAL:
+            {
+                switch (CurrentItem->Tag) {
+                    case ITEM_TAG_GLOBAL_USAGE_PAGE:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_USAGE_PAGE %x\n", Data);
+                        ParserContext->GlobalItemState.UsagePage = Data;
+                        break;
+                    case ITEM_TAG_GLOBAL_LOGICAL_MINIMUM:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_LOGICAL_MINIMUM %x\n", Data);
+                        ParserContext->GlobalItemState.LogicalMinimum = Data;
+                        break;
+
+                    case ITEM_TAG_GLOBAL_LOGICAL_MAXIMUM:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_LOCAL_MAXIMUM %x\n", Data);
+                        ParserContext->GlobalItemState.LogicialMaximum = Data;
+                        break;
+
+                    case ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM %x\n", Data);
+                        ParserContext->GlobalItemState.PhysicalMinimum = Data;
+                        break;
+
+                    case ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM %x\n", Data);
+                        ParserContext->GlobalItemState.PhysicalMaximum = Data;
+                        break;
+
+                    case ITEM_TAG_GLOBAL_UNIT_EXPONENT:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT_EXPONENT %x\n", Data);
+                        ParserContext->GlobalItemState.UnitExponent = Data;
+                        break;
+
+                    case ITEM_TAG_GLOBAL_UNIT:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT %x\n", Data);
+                        ParserContext->GlobalItemState.Unit = Data;
+                        break;
+
+                    case ITEM_TAG_GLOBAL_REPORT_SIZE:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_SIZE %x\n", Data);
+                        ParserContext->GlobalItemState.ReportSize = Data;
+                        break;
+
+                    case ITEM_TAG_GLOBAL_REPORT_ID:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_ID %x\n", Data);
+                        ParserContext->GlobalItemState.ReportId = Data;
+                        ParserContext->UseReportIDs = TRUE;
+                        break;
+
+                    case ITEM_TAG_GLOBAL_REPORT_COUNT:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_COUNT %x\n", Data);
+                        ParserContext->GlobalItemState.ReportCount = Data;
+                        break;
+
+                    case ITEM_TAG_GLOBAL_PUSH:
+                    {
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PUSH\n");
+                        //
+                        // allocate global item state
+                        //
+                        LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)Parser->Alloc(sizeof(GLOBAL_ITEM_STATE));
+                        ASSERT(LinkedGlobalItemState);
+
+                        //
+                        // copy global item state
+                        //
+                        Parser->Copy(LinkedGlobalItemState, &ParserContext->GlobalItemState, sizeof(GLOBAL_ITEM_STATE));
+
+                        //
+                        // store pushed item in link member
+                        //
+                        ParserContext->GlobalItemState.Next = (struct __GLOBAL_ITEM_STATE__*)LinkedGlobalItemState;
+                        break;
+                    }
+                    case ITEM_TAG_GLOBAL_POP:
+                    {
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_POP\n");
+                        if (ParserContext->GlobalItemState.Next == NULL) 
+                        {
+                            //
+                            // pop without push
+                            //
+                            ASSERT(FALSE);
+                            break;
+                        }
+
+                        //
+                        // get link
+                        //
+                        LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)ParserContext->GlobalItemState.Next;
+
+                        //
+                        // replace current item with linked one
+                        //
+                        Parser->Copy(&ParserContext->GlobalItemState, LinkedGlobalItemState, sizeof(GLOBAL_ITEM_STATE));
+
+                        //
+                        // free item
+                        //
+                        Parser->Free(LinkedGlobalItemState);
+                        break;
+                    }
+
+                    default:
+                        //
+                        // unknown  / unsupported tag
+                        //
+                        ASSERT(FALSE);
+                        break;
+                }
+
+                break;
+            }
+            case ITEM_TYPE_LOCAL:
+            {
+                switch (CurrentItem->Tag) 
+                {
+                    case ITEM_TAG_LOCAL_USAGE:
+                    {
+                        if (ParserContext->LocalItemState.UsageStackUsed >= ParserContext->LocalItemState.UsageStackAllocated)
+                        {
+                            //
+                            // increment stack size
+                            //
+                            ParserContext->LocalItemState.UsageStackAllocated += 10;
+
+                            //
+                            // build new usage stack
+                            //
+                            NewUsageStack = (PUSAGE_VALUE)Parser->Alloc(sizeof(USAGE_VALUE) * ParserContext->LocalItemState.UsageStackAllocated);
+                            ASSERT(NewUsageStack);
+
+                            //
+                            // copy old usage stack
+                            //
+                            Parser->Copy(NewUsageStack, ParserContext->LocalItemState.UsageStack, sizeof(USAGE_VALUE) * (ParserContext->LocalItemState.UsageStackAllocated - 10));
+
+                            //
+                            // free old usage stack
+                            //
+                            Parser->Free(ParserContext->LocalItemState.UsageStack);
+
+                            //
+                            // replace with new usage stack
+                            //
+                            ParserContext->LocalItemState.UsageStack = NewUsageStack;
+                        }
+
+                        //
+                        // get fresh usage value
+                        //
+                        UsageValue = &ParserContext->LocalItemState.UsageStack[ParserContext->LocalItemState.UsageStackUsed];
+
+                        //
+                        // init usage stack
+                        //
+                        UsageValue->IsExtended = CurrentItemSize == sizeof(ULONG);
+                        UsageValue->u.Extended = Data;
+
+                        //
+                        // increment usage stack usage count
+                        //
+                        ParserContext->LocalItemState.UsageStackUsed++;
+                        break;
+                    }
+
+                    case ITEM_TAG_LOCAL_USAGE_MINIMUM:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MINIMUM Data %x\n", Data);
+                        ParserContext->LocalItemState.UsageMinimum.u.Extended = Data;
+                        ParserContext->LocalItemState.UsageMinimum.IsExtended
+                            = CurrentItemSize == sizeof(ULONG);
+                        ParserContext->LocalItemState.UsageMinimumSet = TRUE;
+                        break;
+
+                    case ITEM_TAG_LOCAL_USAGE_MAXIMUM:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MAXIMUM Data %x\n", Data);
+                        ParserContext->LocalItemState.UsageMaximum.u.Extended = Data;
+                        ParserContext->LocalItemState.UsageMaximum.IsExtended
+                            = CurrentItemSize == sizeof(ULONG);
+                        ParserContext->LocalItemState.UsageMaximumSet = TRUE;
+                        break;
+
+                    case ITEM_TAG_LOCAL_DESIGNATOR_INDEX:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_INDEX Data %x\n", Data);
+                        ParserContext->LocalItemState.DesignatorIndex = Data;
+                        ParserContext->LocalItemState.DesignatorIndexSet = TRUE;
+                        break;
+
+                    case ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM Data %x\n", Data);
+                        ParserContext->LocalItemState.DesignatorMinimum = Data;
+                        break;
+
+                    case ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM Data %x\n", Data);
+                        ParserContext->LocalItemState.DesignatorMaximum = Data;
+                        break;
+
+                    case ITEM_TAG_LOCAL_STRING_INDEX:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_INDEX Data %x\n", Data);
+                        ParserContext->LocalItemState.StringIndex = Data;
+                        ParserContext->LocalItemState.StringIndexSet = TRUE;
+                        break;
+
+                    case ITEM_TAG_LOCAL_STRING_MINIMUM:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MINIMUM Data %x\n", Data);
+                        ParserContext->LocalItemState.StringMinimum = Data;
+                        break;
+
+                    case ITEM_TAG_LOCAL_STRING_MAXIMUM:
+                        Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MAXIMUM Data %x\n", Data);
+                        ParserContext->LocalItemState.StringMaximum = Data;
+                        break;
+
+                    default:
+                        Parser->Debug("Unknown Local Item Tag %x\n", CurrentItem->Tag);
+                        ASSERT(FALSE);
+                        break;
+                }
+                break;
+            }
+
+            case ITEM_TYPE_LONG:
+            {
+                CurrentLongItem = (PLONG_ITEM)CurrentItem;
+                Parser->Debug("Unsupported ITEM_TYPE_LONG Tag %x\n", CurrentLongItem->LongItemTag);
+                break;
+            }
+        }
+
+        //
+        // move to next item
+        //
+        CurrentOffset += CurrentItemSize + sizeof(ITEM_PREFIX);
+
+
+    }while(CurrentOffset < ReportEnd);
+
+
+    //
+    // cleanup global stack
+    //
+    LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)ParserContext->GlobalItemState.Next;
+    while(LinkedGlobalItemState != NULL)
+    {
+        Parser->Debug("[HIDPARSE] Freeing GlobalState %p\n", LinkedGlobalItemState);
+        //
+        // free global item state
+        //
+        NextLinkedGlobalItemState = (PGLOBAL_ITEM_STATE)LinkedGlobalItemState->Next;
+
+        //
+        // free state
+        //
+        Parser->Free(LinkedGlobalItemState);
+
+        //
+        // move to next global state
+        //
+        LinkedGlobalItemState = NextLinkedGlobalItemState;
+    }
+
+    //
+    // free usage stack
+    //
+    Parser->Free(ParserContext->LocalItemState.UsageStack);
+    ParserContext->LocalItemState.UsageStack = NULL;
+
+    //
+    // done
+    //
+    return HIDPARSER_STATUS_SUCCESS;
+}
+
diff --git a/lib/drivers/hidparser/parser.h b/lib/drivers/hidparser/parser.h
new file mode 100644 (file)
index 0000000..95b1050
--- /dev/null
@@ -0,0 +1,362 @@
+
+#pragma once
+#include <ntddk.h>
+#include <assert.h>
+#include <pshpack1.h>
+#include "hidparser.h"
+
+ /*
+  * Copyright 2007, Haiku, Inc. All Rights Reserved.
+  * Distributed under the terms of the MIT License.
+  */
+
+#define HID_REPORT_TYPE_ANY                    0x07
+
+
+#define ITEM_TYPE_MAIN                                         0x0
+#define ITEM_TYPE_GLOBAL                                       0x1
+#define ITEM_TYPE_LOCAL                                                0x2
+#define ITEM_TYPE_LONG                                         0x3
+
+#define ITEM_TAG_MAIN_INPUT                                    0x8
+#define ITEM_TAG_MAIN_OUTPUT                           0x9
+#define ITEM_TAG_MAIN_FEATURE                          0xb
+#define ITEM_TAG_MAIN_COLLECTION                       0xa
+#define ITEM_TAG_MAIN_END_COLLECTION           0xc
+
+#define ITEM_TAG_GLOBAL_USAGE_PAGE                     0x0
+#define ITEM_TAG_GLOBAL_LOGICAL_MINIMUM                0x1
+#define ITEM_TAG_GLOBAL_LOGICAL_MAXIMUM                0x2
+#define ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM       0x3
+#define ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM       0x4
+#define ITEM_TAG_GLOBAL_UNIT_EXPONENT          0x5
+#define ITEM_TAG_GLOBAL_UNIT                           0x6
+#define ITEM_TAG_GLOBAL_REPORT_SIZE                    0x7
+#define ITEM_TAG_GLOBAL_REPORT_ID                      0x8
+#define ITEM_TAG_GLOBAL_REPORT_COUNT           0x9
+#define ITEM_TAG_GLOBAL_PUSH                           0xa
+#define ITEM_TAG_GLOBAL_POP                                    0xb
+
+#define ITEM_TAG_LOCAL_USAGE                           0x0
+#define ITEM_TAG_LOCAL_USAGE_MINIMUM           0x1
+#define ITEM_TAG_LOCAL_USAGE_MAXIMUM           0x2
+#define ITEM_TAG_LOCAL_DESIGNATOR_INDEX                0x3
+#define ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM      0x4
+#define ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM      0x5
+#define ITEM_TAG_LOCAL_STRING_INDEX                    0x7
+#define ITEM_TAG_LOCAL_STRING_MINIMUM          0x8
+#define ITEM_TAG_LOCAL_STRING_MAXIMUM          0x9
+#define ITEM_TAG_LOCAL_DELIMITER                       0xa
+
+#define ITEM_TAG_LONG                                          0xf
+
+#define COLLECTION_PHYSICAL                                    0x00
+#define COLLECTION_APPLICATION                         0x01
+#define COLLECTION_LOGICAL                                     0x02
+#define COLLECTION_REPORT                                      0x03
+#define COLLECTION_NAMED_ARRAY                         0x04
+#define COLLECTION_USAGE_SWITCH                                0x05
+#define COLLECTION_USAGE_MODIFIER                      0x06
+#define COLLECTION_ALL                                         0xff
+
+#define UNIT_SYSTEM                                                    0x0
+#define UNIT_LENGTH                                                    0x1
+#define UNIT_MASS                                                      0x2
+#define UNIT_TIME                                                      0x3
+#define UNIT_TEMPERATURE                                       0x4
+#define UNIT_CURRENT                                           0x5
+#define UNIT_LUMINOUS_INTENSITY                                0x6
+
+#define USAGE_PAGE_SHIFT                                       16
+#define USAGE_PAGE_MASK                                                0xffff
+#define USAGE_ID_SHIFT                                         0
+#define USAGE_ID_MASK                                          0xffff
+
+typedef struct
+{
+    UCHAR Size:2;
+    UCHAR Type:2;
+    UCHAR Tag:4;
+}ITEM_PREFIX, *PITEM_PREFIX;
+
+typedef struct
+{
+    ITEM_PREFIX Prefix;
+
+    union
+    {
+        UCHAR UData8[4];
+        CHAR  SData8[4];
+        USHORT UData16[2];
+        SHORT SData16[2];
+        ULONG UData32;
+        LONG SData32;
+    }Data;
+
+}SHORT_ITEM, *PSHORT_ITEM;
+
+typedef struct
+{
+    ITEM_PREFIX Prefix;
+    UCHAR DataSize;
+    UCHAR LongItemTag;
+    UCHAR Data[0];
+
+}LONG_ITEM,*PLONG_ITEM;
+
+
+#define  LBITFIELD9(b1,b2,b3,b4,b5,b6,b7,b8,b9)    USHORT b9,b8,b7,b6,b5,b4,b3,b2,b1
+typedef struct
+{
+    USHORT DataConstant:1;
+    USHORT ArrayVariable:1;
+    USHORT Relative:1;
+    USHORT Wrap:1;
+    USHORT NonLinear:1;
+    USHORT NoPreferred:1;
+    USHORT NullState:1;
+    USHORT IsVolatile:1;
+    USHORT BitsBytes:1;
+    UCHAR    reserved[2];
+
+}MAIN_ITEM_DATA, *PMAIN_ITEM_DATA;
+
+typedef struct __GLOBAL_ITEM_STATE_
+{
+    USHORT UsagePage;
+    ULONG  LogicalMinimum;
+    ULONG  LogicialMaximum;
+    ULONG  PhysicalMinimum;
+    ULONG  PhysicalMaximum;
+    UCHAR  UnitExponent;
+    UCHAR  Unit;
+    ULONG  ReportSize;
+    ULONG  ReportCount;
+    UCHAR  ReportId;
+    struct __GLOBAL_ITEM_STATE__ * Next;
+}GLOBAL_ITEM_STATE, *PGLOBAL_ITEM_STATE;
+
+
+typedef struct usage_value 
+{
+    union 
+    {
+        struct {
+            USHORT UsageId;
+            USHORT UsagePage;
+        }s;
+        ULONG  Extended;
+    }u;
+
+   UCHAR IsExtended;
+}USAGE_VALUE, *PUSAGE_VALUE;
+
+
+typedef struct
+{
+    PUSAGE_VALUE    UsageStack;
+    ULONG           UsageStackUsed;
+    ULONG           UsageStackAllocated;
+
+    USAGE_VALUE     UsageMinimum;
+    USAGE_VALUE     UsageMaximum;
+
+    UCHAR           UsageMinimumSet;
+    UCHAR           UsageMaximumSet;
+
+    ULONG           DesignatorIndex;
+    UCHAR           DesignatorIndexSet;
+
+    ULONG           DesignatorMinimum;
+    ULONG           DesignatorMaximum;
+
+    UCHAR           StringIndex;
+    UCHAR           StringIndexSet;
+    UCHAR           StringMinimum;
+    UCHAR           StringMaximum;
+
+}LOCAL_ITEM_STATE, *PLOCAL_ITEM_STATE;
+
+typedef struct
+{
+    ULONG ByteOffset;
+    UCHAR Shift;
+    ULONG Mask;
+    UCHAR BitCount;
+    UCHAR HasData;
+    UCHAR Array;
+    UCHAR Relative;
+    ULONG Minimum;
+    ULONG Maximum;
+    ULONG UsageMinimum;
+    ULONG UsageMaximum;
+    ULONG Data;
+    UCHAR Valid;
+}HID_REPORT_ITEM, *PHID_REPORT_ITEM;
+
+struct HID_REPORT;
+
+typedef struct __HID_COLLECTION__
+{
+    struct __HID_COLLECTION__ * Root;
+
+    UCHAR Type;
+    ULONG Usage;
+    UCHAR StringID;
+    UCHAR PhysicalID;
+    ULONG NodeCount;
+    struct __HID_COLLECTION__ ** Nodes;
+
+    ULONG ItemCount;
+    ULONG ItemCountAllocated;
+    PHID_REPORT_ITEM * Items;
+
+    //ULONG ReportCount;
+    //struct HID_REPORT ** Reports; 
+
+}HID_COLLECTION, *PHID_COLLECTION;
+
+typedef struct
+{
+    UCHAR Type;
+    UCHAR ReportID;
+    ULONG ReportSize;
+
+    ULONG ItemCount;
+    ULONG ItemAllocated;
+    PHID_REPORT_ITEM *Items;
+
+    ULONG ReportStatus;
+    UCHAR * CurrentReport;
+    ULONG BusyCount;
+}HID_REPORT, *PHID_REPORT;
+
+typedef struct
+{
+    //
+    // global item state
+    //
+    GLOBAL_ITEM_STATE GlobalItemState;
+
+    //
+    // local item state
+    //
+    LOCAL_ITEM_STATE LocalItemState;
+
+    //
+    // root collection
+    //
+    PHID_COLLECTION RootCollection;
+
+    //
+    // report count
+    //
+    ULONG ReportCount;
+
+    //
+    // reports
+    //
+    PHID_REPORT * Reports;
+
+    //
+    // uses report ids
+    //
+    UCHAR UseReportIDs;
+
+}HID_PARSER_CONTEXT, *PHID_PARSER_CONTEXT;
+
+HIDPARSER_STATUS
+HidParser_ParseReportDescriptor(
+    PHID_PARSER Parser,
+    PUCHAR Report,
+    ULONG ReportSize);
+
+ULONG
+HidParser_NumberOfTopCollections(
+    IN PHID_PARSER Parser);
+
+#define HID_REPORT_TYPE_INPUT          0x01
+#define HID_REPORT_TYPE_OUTPUT         0x02
+#define HID_REPORT_TYPE_FEATURE                0x04
+
+ULONG
+HidParser_NumberOfReports(
+    IN PHID_PARSER Parser,
+    IN ULONG ReportType);
+
+HIDPARSER_STATUS
+HidParser_GetCollectionUsagePage(
+    IN PHID_PARSER Parser,
+    IN ULONG CollectionNumber,
+    OUT PUSHORT Usage,
+    OUT PUSHORT UsagePage);
+
+ULONG
+HidParser_GetReportLength(
+    IN PHID_PARSER Parser,
+    IN ULONG ReportType);
+
+UCHAR
+HidParser_IsReportIDUsed(
+    IN PHID_PARSER Parser);
+
+ULONG
+HidParser_GetReportItemCountFromReportType(
+    IN PHID_PARSER Parser,
+    IN ULONG ReportType);
+
+ULONG
+HidParser_GetReportItemTypeCountFromReportType(
+    IN PHID_PARSER Parser,
+    IN ULONG ReportType,
+    IN ULONG bData);
+
+ULONG
+HidParser_GetContextSize(
+    IN PHID_PARSER Parser);
+
+VOID
+HidParser_FreeContext(
+    IN PHID_PARSER Parser,
+    IN PUCHAR Context,
+    IN ULONG ContextLength);
+
+ULONG
+HidParser_GetTotalCollectionCount(
+    IN PHID_PARSER Parser);
+
+ULONG
+HidParser_GetMaxUsageListLengthWithReportAndPage(
+    IN PHID_PARSER Parser,
+    IN ULONG  ReportType,
+    IN USAGE  UsagePage  OPTIONAL);
+
+HIDPARSER_STATUS
+HidParser_GetSpecificValueCapsWithReport(
+    IN PHID_PARSER Parser,
+    IN ULONG ReportType,
+    IN USHORT UsagePage,
+    IN USHORT Usage,
+    OUT PHIDP_VALUE_CAPS  ValueCaps,
+    IN OUT PULONG  ValueCapsLength);
+
+
+HIDPARSER_STATUS
+HidParser_GetUsagesWithReport(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USAGE  UsagePage,
+    OUT USAGE  *UsageList,
+    IN OUT PULONG UsageLength,
+    IN PCHAR  ReportDescriptor,
+    IN ULONG  ReportDescriptorLength);
+
+HIDPARSER_STATUS
+HidParser_GetScaledUsageValueWithReport(
+    IN PHID_PARSER Parser,
+    IN HIDP_REPORT_TYPE  ReportType,
+    IN USAGE  UsagePage,
+    IN USAGE  Usage,
+    OUT PLONG  UsageValue,
+    IN PCHAR  ReportDescriptor,
+    IN ULONG  ReportDescriptorLength);
\ No newline at end of file