mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
527f2f9057
* Create a branch for some evul shell experiments. svn path=/branches/shell-experiments/; revision=61927
1229 lines
33 KiB
C
1229 lines
33 KiB
C
/*
|
|
* 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"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
NTSTATUS
|
|
TranslateHidParserStatus(
|
|
IN HIDPARSER_STATUS Status)
|
|
{
|
|
switch(Status)
|
|
{
|
|
case HIDPARSER_STATUS_INSUFFICIENT_RESOURCES:
|
|
return HIDP_STATUS_INTERNAL_ERROR;
|
|
case HIDPARSER_STATUS_NOT_IMPLEMENTED:
|
|
return HIDP_STATUS_NOT_IMPLEMENTED;
|
|
case HIDPARSER_STATUS_REPORT_NOT_FOUND:
|
|
return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
|
|
case HIDPARSER_STATUS_INVALID_REPORT_LENGTH:
|
|
return HIDP_STATUS_INVALID_REPORT_LENGTH;
|
|
case HIDPARSER_STATUS_INVALID_REPORT_TYPE:
|
|
return HIDP_STATUS_INVALID_REPORT_TYPE;
|
|
case HIDPARSER_STATUS_BUFFER_TOO_SMALL:
|
|
return HIDP_STATUS_BUFFER_TOO_SMALL;
|
|
case HIDPARSER_STATUS_USAGE_NOT_FOUND:
|
|
return HIDP_STATUS_USAGE_NOT_FOUND;
|
|
case HIDPARSER_STATUS_I8042_TRANS_UNKNOWN:
|
|
return HIDP_STATUS_I8042_TRANS_UNKNOWN;
|
|
case HIDPARSER_STATUS_COLLECTION_NOT_FOUND:
|
|
return HIDP_STATUS_NOT_IMPLEMENTED; //FIXME
|
|
case HIDPARSER_STATUS_BAD_LOG_PHY_VALUES:
|
|
return HIDP_STATUS_BAD_LOG_PHY_VALUES;
|
|
}
|
|
DPRINT1("TranslateHidParserStatus Status %ld not implemented\n", Status);
|
|
return HIDP_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;
|
|
ULONG Index;
|
|
PVOID ParserContext;
|
|
|
|
//
|
|
// first parse the report descriptor
|
|
//
|
|
ParserStatus = HidParser_ParseReportDescriptor(Parser, ReportDesc, DescLength, &ParserContext);
|
|
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(ParserContext);
|
|
if (CollectionCount == 0)
|
|
{
|
|
//
|
|
// no top level collections found
|
|
//
|
|
ASSERT(FALSE);
|
|
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++)
|
|
{
|
|
//
|
|
// set preparsed data length
|
|
//
|
|
DeviceDescription->CollectionDesc[Index].PreparsedDataLength = HidParser_GetContextSize(Parser, ParserContext, Index);
|
|
ParserStatus = HidParser_BuildContext(Parser, ParserContext, Index, DeviceDescription->CollectionDesc[Index].PreparsedDataLength, (PVOID*)&DeviceDescription->CollectionDesc[Index].PreparsedData);
|
|
if (ParserStatus != HIDPARSER_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return TranslateHidParserStatus(ParserStatus);
|
|
}
|
|
|
|
//
|
|
// init report description
|
|
//
|
|
DeviceDescription->ReportIDs[Index].CollectionNumber = Index + 1;
|
|
DeviceDescription->ReportIDs[Index].ReportID = Index; //FIXME
|
|
DeviceDescription->ReportIDs[Index].InputLength = HidParser_GetReportLength((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_INPUT);
|
|
DeviceDescription->ReportIDs[Index].OutputLength = HidParser_GetReportLength((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_OUTPUT);
|
|
DeviceDescription->ReportIDs[Index].FeatureLength = HidParser_GetReportLength((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_FEATURE);
|
|
|
|
|
|
DeviceDescription->ReportIDs[Index].InputLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_INPUT) == TRUE ? 1 : 0);
|
|
DeviceDescription->ReportIDs[Index].OutputLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_OUTPUT) == TRUE ? 1 : 0);
|
|
DeviceDescription->ReportIDs[Index].FeatureLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_FEATURE) == TRUE ? 1 : 0);
|
|
|
|
|
|
//
|
|
// init collection description
|
|
//
|
|
DeviceDescription->CollectionDesc[Index].CollectionNumber = Index + 1;
|
|
|
|
//
|
|
// get collection usage page
|
|
//
|
|
ParserStatus = HidParser_GetCollectionUsagePage((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, &DeviceDescription->CollectionDesc[Index].Usage, &DeviceDescription->CollectionDesc[Index].UsagePage);
|
|
|
|
//
|
|
// windows seems to prepend the report id, regardless if it is required
|
|
//
|
|
DeviceDescription->CollectionDesc[Index].CollectionNumber = Index + 1;
|
|
DeviceDescription->CollectionDesc[Index].InputLength = DeviceDescription->ReportIDs[Index].InputLength;
|
|
DeviceDescription->CollectionDesc[Index].OutputLength = DeviceDescription->ReportIDs[Index].OutputLength;
|
|
DeviceDescription->CollectionDesc[Index].FeatureLength = DeviceDescription->ReportIDs[Index].FeatureLength;
|
|
|
|
DeviceDescription->CollectionDesc[Index].InputLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_INPUT) == FALSE ? 1 : 0);
|
|
DeviceDescription->CollectionDesc[Index].OutputLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_OUTPUT) == FALSE ? 1 : 0);
|
|
DeviceDescription->CollectionDesc[Index].FeatureLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_FEATURE) == FALSE ? 1 : 0);
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// 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 collection context
|
|
//
|
|
Parser->Free(DeviceDescription->CollectionDesc[Index].PreparsedData);
|
|
}
|
|
|
|
//
|
|
// now free collection description
|
|
//
|
|
Parser->Free(DeviceDescription->CollectionDesc);
|
|
|
|
//
|
|
// free report description
|
|
//
|
|
Parser->Free(DeviceDescription->ReportIDs);
|
|
}
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_GetCaps(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
OUT PHIDP_CAPS Capabilities)
|
|
{
|
|
//
|
|
// zero capabilities
|
|
//
|
|
Parser->Zero(Capabilities, sizeof(HIDP_CAPS));
|
|
|
|
//
|
|
// init capabilities
|
|
//
|
|
HidParser_GetCollectionUsagePage(CollectionContext, &Capabilities->Usage, &Capabilities->UsagePage);
|
|
Capabilities->InputReportByteLength = HidParser_GetReportLength(CollectionContext, HID_REPORT_TYPE_INPUT);
|
|
Capabilities->OutputReportByteLength = HidParser_GetReportLength(CollectionContext, HID_REPORT_TYPE_OUTPUT);
|
|
Capabilities->FeatureReportByteLength = HidParser_GetReportLength(CollectionContext, 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(CollectionContext);
|
|
|
|
//
|
|
// get data indices
|
|
//
|
|
Capabilities->NumberInputDataIndices = HidParser_GetReportItemTypeCountFromReportType(CollectionContext, HID_REPORT_TYPE_INPUT, TRUE);
|
|
Capabilities->NumberOutputDataIndices = HidParser_GetReportItemTypeCountFromReportType(CollectionContext, HID_REPORT_TYPE_OUTPUT, TRUE);
|
|
Capabilities->NumberFeatureDataIndices = HidParser_GetReportItemTypeCountFromReportType(CollectionContext, HID_REPORT_TYPE_FEATURE, TRUE);
|
|
|
|
//
|
|
// get value caps
|
|
//
|
|
Capabilities->NumberInputValueCaps = HidParser_GetReportItemTypeCountFromReportType(CollectionContext, HID_REPORT_TYPE_INPUT, FALSE);
|
|
Capabilities->NumberOutputValueCaps = HidParser_GetReportItemTypeCountFromReportType(CollectionContext, HID_REPORT_TYPE_OUTPUT, FALSE);
|
|
Capabilities->NumberFeatureValueCaps = HidParser_GetReportItemTypeCountFromReportType(CollectionContext, HID_REPORT_TYPE_FEATURE, FALSE);
|
|
|
|
|
|
//
|
|
// get button caps
|
|
//
|
|
Capabilities->NumberInputButtonCaps = HidParser_GetReportItemCountFromReportType(CollectionContext, HID_REPORT_TYPE_INPUT);
|
|
Capabilities->NumberOutputButtonCaps = HidParser_GetReportItemCountFromReportType(CollectionContext, HID_REPORT_TYPE_OUTPUT);
|
|
Capabilities->NumberFeatureButtonCaps = HidParser_GetReportItemCountFromReportType(CollectionContext, HID_REPORT_TYPE_FEATURE);
|
|
|
|
//
|
|
// done
|
|
//
|
|
return HIDP_STATUS_SUCCESS;
|
|
}
|
|
|
|
HIDAPI
|
|
ULONG
|
|
NTAPI
|
|
HidParser_MaxUsageListLength(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
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(CollectionContext, HID_REPORT_TYPE_INPUT, UsagePage);
|
|
}
|
|
else if (ReportType == HidP_Output)
|
|
{
|
|
//
|
|
// input report
|
|
//
|
|
return HidParser_GetMaxUsageListLengthWithReportAndPage(CollectionContext, HID_REPORT_TYPE_OUTPUT, UsagePage);
|
|
}
|
|
else if (ReportType == HidP_Feature)
|
|
{
|
|
//
|
|
// input report
|
|
//
|
|
return HidParser_GetMaxUsageListLengthWithReportAndPage(CollectionContext, HID_REPORT_TYPE_FEATURE, UsagePage);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// invalid report type
|
|
//
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#undef HidParser_GetButtonCaps
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_GetButtonCaps(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
IN PHIDP_BUTTON_CAPS ButtonCaps,
|
|
IN PUSHORT ButtonCapsLength)
|
|
{
|
|
return HidParser_GetSpecificButtonCaps(Parser, CollectionContext, 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 PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
IN USAGE UsagePage,
|
|
IN USHORT LinkCollection,
|
|
IN USAGE Usage,
|
|
OUT PHIDP_VALUE_CAPS ValueCaps,
|
|
IN OUT PUSHORT 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, CollectionContext, HID_REPORT_TYPE_INPUT, UsagePage, Usage, ValueCaps, ValueCapsLength);
|
|
}
|
|
else if (ReportType == HidP_Output)
|
|
{
|
|
//
|
|
// input report
|
|
//
|
|
ParserStatus = HidParser_GetSpecificValueCapsWithReport(Parser, CollectionContext, HID_REPORT_TYPE_OUTPUT, UsagePage, Usage, ValueCaps, ValueCapsLength);
|
|
}
|
|
else if (ReportType == HidP_Feature)
|
|
{
|
|
//
|
|
// input report
|
|
//
|
|
ParserStatus = HidParser_GetSpecificValueCapsWithReport(Parser, CollectionContext, 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 PVOID CollectionContext,
|
|
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, CollectionContext, HID_REPORT_TYPE_INPUT, UsagePage, UsageList, UsageLength, Report, ReportLength);
|
|
}
|
|
else if (ReportType == HidP_Output)
|
|
{
|
|
//
|
|
// input report
|
|
//
|
|
ParserStatus = HidParser_GetUsagesWithReport(Parser, CollectionContext, HID_REPORT_TYPE_OUTPUT, UsagePage, UsageList, UsageLength, Report, ReportLength);
|
|
}
|
|
else if (ReportType == HidP_Feature)
|
|
{
|
|
//
|
|
// input report
|
|
//
|
|
ParserStatus = HidParser_GetUsagesWithReport(Parser, CollectionContext, 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 PVOID CollectionContext,
|
|
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, CollectionContext, HID_REPORT_TYPE_INPUT, UsagePage, Usage, UsageValue, Report, ReportLength);
|
|
}
|
|
else if (ReportType == HidP_Output)
|
|
{
|
|
//
|
|
// input report
|
|
//
|
|
ParserStatus = HidParser_GetScaledUsageValueWithReport(Parser, CollectionContext, HID_REPORT_TYPE_OUTPUT, UsagePage, Usage, UsageValue, Report, ReportLength);
|
|
}
|
|
else if (ReportType == HidP_Feature)
|
|
{
|
|
//
|
|
// input report
|
|
//
|
|
ParserStatus = HidParser_GetScaledUsageValueWithReport(Parser, CollectionContext, 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_TranslateUsageAndPagesToI8042ScanCodes(
|
|
IN PHID_PARSER Parser,
|
|
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)
|
|
{
|
|
ULONG Index;
|
|
HIDPARSER_STATUS Status = HIDPARSER_STATUS_SUCCESS;
|
|
|
|
for(Index = 0; Index < UsageListLength; Index++)
|
|
{
|
|
//
|
|
// check current usage
|
|
//
|
|
if (ChangedUsageList[Index].UsagePage == HID_USAGE_PAGE_KEYBOARD)
|
|
{
|
|
//
|
|
// process keyboard usage
|
|
//
|
|
Status = HidParser_TranslateKbdUsage(Parser, ChangedUsageList[Index].Usage, KeyAction, ModifierState, InsertCodesProcedure, InsertCodesContext);
|
|
}
|
|
else if (ChangedUsageList[Index].UsagePage == HID_USAGE_PAGE_CONSUMER)
|
|
{
|
|
//
|
|
// process consumer usage
|
|
//
|
|
Status = HidParser_TranslateCustUsage(Parser, ChangedUsageList[Index].Usage, KeyAction, ModifierState, InsertCodesProcedure, InsertCodesContext);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// invalid page / end of usage list page
|
|
//
|
|
return HIDP_STATUS_I8042_TRANS_UNKNOWN;
|
|
}
|
|
|
|
//
|
|
// check status
|
|
//
|
|
if (Status != HIDPARSER_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// failed
|
|
//
|
|
return TranslateHidParserStatus(Status);
|
|
}
|
|
}
|
|
|
|
if (Status != HIDPARSER_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// failed
|
|
//
|
|
return TranslateHidParserStatus(Status);
|
|
}
|
|
|
|
//
|
|
// done
|
|
//
|
|
return HIDP_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_GetUsagesEx(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
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, CollectionContext, 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 PVOID CollectionContext,
|
|
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 PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
OUT PHIDP_DATA DataList,
|
|
IN OUT PULONG DataLength,
|
|
IN PCHAR Report,
|
|
IN ULONG ReportLength)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_GetExtendedAttributes(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
IN USHORT DataIndex,
|
|
OUT PHIDP_EXTENDED_ATTRIBUTES Attributes,
|
|
IN OUT PULONG LengthAttributes)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_GetLinkCollectionNodes(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
OUT PHIDP_LINK_COLLECTION_NODE LinkCollectionNodes,
|
|
IN OUT PULONG LinkCollectionNodesLength)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_GetUsageValue(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
IN USAGE UsagePage,
|
|
IN USHORT LinkCollection,
|
|
IN USAGE Usage,
|
|
OUT PULONG 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_GetUsageValueWithReport(Parser, CollectionContext, HID_REPORT_TYPE_INPUT, UsagePage, Usage, UsageValue, Report, ReportLength);
|
|
}
|
|
else if (ReportType == HidP_Output)
|
|
{
|
|
//
|
|
// input report
|
|
//
|
|
ParserStatus = HidParser_GetUsageValueWithReport(Parser, CollectionContext, HID_REPORT_TYPE_OUTPUT, UsagePage, Usage, UsageValue, Report, ReportLength);
|
|
}
|
|
else if (ReportType == HidP_Feature)
|
|
{
|
|
//
|
|
// input report
|
|
//
|
|
ParserStatus = HidParser_GetUsageValueWithReport(Parser, CollectionContext, 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);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_SysPowerEvent(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN PCHAR HidPacket,
|
|
IN USHORT HidPacketLength,
|
|
OUT PULONG OutputBuffer)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_SysPowerCaps (
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
OUT PULONG OutputBuffer)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_GetUsageValueArray(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
IN USAGE UsagePage,
|
|
IN USHORT LinkCollection OPTIONAL,
|
|
IN USAGE Usage,
|
|
OUT PCHAR UsageValue,
|
|
IN USHORT UsageValueByteLength,
|
|
IN PCHAR Report,
|
|
IN ULONG ReportLength)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_UnsetUsages(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
IN USAGE UsagePage,
|
|
IN USHORT LinkCollection,
|
|
IN PUSAGE UsageList,
|
|
IN OUT PULONG UsageLength,
|
|
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_SetUsages(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
IN USAGE UsagePage,
|
|
IN USHORT LinkCollection,
|
|
IN PUSAGE UsageList,
|
|
IN OUT PULONG UsageLength,
|
|
IN OUT PCHAR Report,
|
|
IN ULONG ReportLength)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_SetUsageValueArray(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
IN USAGE UsagePage,
|
|
IN USHORT LinkCollection OPTIONAL,
|
|
IN USAGE Usage,
|
|
IN PCHAR UsageValue,
|
|
IN USHORT UsageValueByteLength,
|
|
OUT PCHAR Report,
|
|
IN ULONG ReportLength)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_SetUsageValue(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
IN USAGE UsagePage,
|
|
IN USHORT LinkCollection,
|
|
IN USAGE Usage,
|
|
IN ULONG UsageValue,
|
|
IN OUT PCHAR Report,
|
|
IN ULONG ReportLength)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_SetScaledUsageValue(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
IN USAGE UsagePage,
|
|
IN USHORT LinkCollection OPTIONAL,
|
|
IN USAGE Usage,
|
|
IN LONG UsageValue,
|
|
IN OUT PCHAR Report,
|
|
IN ULONG ReportLength)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_SetData(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
IN PHIDP_DATA DataList,
|
|
IN OUT PULONG DataLength,
|
|
IN OUT PCHAR Report,
|
|
IN ULONG ReportLength)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
HIDAPI
|
|
ULONG
|
|
NTAPI
|
|
HidParser_MaxDataListLength(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_InitializeReportForID(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
IN UCHAR ReportID,
|
|
IN OUT PCHAR Report,
|
|
IN ULONG ReportLength)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
#undef HidParser_GetValueCaps
|
|
|
|
HIDAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
HidParser_GetValueCaps(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID CollectionContext,
|
|
HIDP_REPORT_TYPE ReportType,
|
|
PHIDP_VALUE_CAPS ValueCaps,
|
|
PULONG ValueCapsLength)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|