mirror of
https://github.com/reactos/reactos.git
synced 2024-08-06 11:24:58 +00:00
954 lines
19 KiB
C
954 lines
19 KiB
C
![]() |
/*
|
||
|
* 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;
|
||
|
}
|