You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
876 lines
25 KiB
876 lines
25 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pnp.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code
|
|
for finding, adding, removing, and identifying hid devices.
|
|
|
|
Environment:
|
|
|
|
User mode
|
|
|
|
@@BEGIN_DDKSPLIT
|
|
|
|
Revision History:
|
|
|
|
Nov-96 : Created by Kenneth D. Ray
|
|
|
|
@@END_DDKSPLIT
|
|
--*/
|
|
|
|
#include <basetyps.h>
|
|
#include <stdlib.h>
|
|
#include <wtypes.h>
|
|
#include <setupapi.h>
|
|
#include "hidsdi.h"
|
|
#include "hid.h"
|
|
#include <strsafe.h>
|
|
|
|
BOOLEAN
|
|
FindKnownHidDevices (
|
|
OUT PHID_DEVICE * HidDevices, // A array of struct _HID_DEVICE
|
|
OUT PULONG NumberDevices // the length of this array.
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Do the required PnP things in order to find all the HID devices in
|
|
the system at this time.
|
|
--*/
|
|
{
|
|
HDEVINFO hardwareDeviceInfo;
|
|
SP_DEVICE_INTERFACE_DATA deviceInfoData;
|
|
ULONG i;
|
|
BOOLEAN done;
|
|
PHID_DEVICE hidDeviceInst;
|
|
GUID hidGuid;
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA functionClassDeviceData = NULL;
|
|
ULONG predictedLength = 0;
|
|
ULONG requiredLength = 0;
|
|
PHID_DEVICE newHidDevices;
|
|
|
|
|
|
HidD_GetHidGuid (&hidGuid);
|
|
|
|
*HidDevices = NULL;
|
|
*NumberDevices = 0;
|
|
|
|
//
|
|
// Open a handle to the plug and play dev node.
|
|
//
|
|
hardwareDeviceInfo = SetupDiGetClassDevs ( &hidGuid,
|
|
NULL, // Define no enumerator (global)
|
|
NULL, // Define no
|
|
(DIGCF_PRESENT | // Only Devices present
|
|
DIGCF_DEVICEINTERFACE)); // Function class devices.
|
|
|
|
//
|
|
// Take a wild guess to start
|
|
//
|
|
|
|
*NumberDevices = 4;
|
|
done = FALSE;
|
|
deviceInfoData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
|
|
|
|
i=0;
|
|
while (!done)
|
|
{
|
|
*NumberDevices *= 2;
|
|
|
|
if (*HidDevices)
|
|
{
|
|
newHidDevices =
|
|
realloc (*HidDevices, (*NumberDevices * sizeof (HID_DEVICE)));
|
|
|
|
if (NULL == newHidDevices)
|
|
{
|
|
free(*HidDevices);
|
|
}
|
|
|
|
*HidDevices = newHidDevices;
|
|
}
|
|
else
|
|
{
|
|
*HidDevices = calloc (*NumberDevices, sizeof (HID_DEVICE));
|
|
}
|
|
|
|
if (NULL == *HidDevices)
|
|
{
|
|
SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
|
|
return FALSE;
|
|
}
|
|
|
|
hidDeviceInst = *HidDevices + i;
|
|
|
|
for (; i < *NumberDevices; i++, hidDeviceInst++)
|
|
{
|
|
if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo,
|
|
0, // No care about specific PDOs
|
|
&hidGuid,
|
|
i,
|
|
&deviceInfoData))
|
|
{
|
|
//
|
|
// allocate a function class device data structure to receive the
|
|
// goods about this particular device.
|
|
//
|
|
|
|
SetupDiGetDeviceInterfaceDetail (
|
|
hardwareDeviceInfo,
|
|
&deviceInfoData,
|
|
NULL, // probing so no output buffer yet
|
|
0, // probing so output buffer length of zero
|
|
&requiredLength,
|
|
NULL); // not interested in the specific dev-node
|
|
|
|
|
|
predictedLength = requiredLength;
|
|
|
|
functionClassDeviceData = malloc (predictedLength);
|
|
if (functionClassDeviceData)
|
|
{
|
|
functionClassDeviceData->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);
|
|
}
|
|
else
|
|
{
|
|
SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Retrieve the information from Plug and Play.
|
|
//
|
|
|
|
if (! SetupDiGetDeviceInterfaceDetail (
|
|
hardwareDeviceInfo,
|
|
&deviceInfoData,
|
|
functionClassDeviceData,
|
|
predictedLength,
|
|
&requiredLength,
|
|
NULL))
|
|
{
|
|
SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
|
|
free(functionClassDeviceData);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Open device with just generic query abilities to begin with
|
|
//
|
|
|
|
if (! OpenHidDevice (functionClassDeviceData -> DevicePath,
|
|
FALSE, // ReadAccess - none
|
|
FALSE, // WriteAccess - none
|
|
FALSE, // Overlapped - no
|
|
FALSE, // Exclusive - no
|
|
hidDeviceInst))
|
|
{
|
|
SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
|
|
free(functionClassDeviceData);
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if (ERROR_NO_MORE_ITEMS == GetLastError())
|
|
{
|
|
done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*NumberDevices = i;
|
|
|
|
SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
|
|
free(functionClassDeviceData);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
OpenHidDevice (
|
|
IN PCHAR DevicePath,
|
|
IN BOOL HasReadAccess,
|
|
IN BOOL HasWriteAccess,
|
|
IN BOOL IsOverlapped,
|
|
IN BOOL IsExclusive,
|
|
IN OUT PHID_DEVICE HidDevice
|
|
)
|
|
/*++
|
|
RoutineDescription:
|
|
Given the HardwareDeviceInfo, representing a handle to the plug and
|
|
play information, and deviceInfoData, representing a specific hid device,
|
|
open that device and fill in all the relivant information in the given
|
|
HID_DEVICE structure.
|
|
|
|
return if the open and initialization was successfull or not.
|
|
|
|
--*/
|
|
{
|
|
DWORD accessFlags = 0;
|
|
DWORD sharingFlags = 0;
|
|
BOOLEAN bSuccess;
|
|
INT iDevicePathSize;
|
|
HRESULT stringReturn;
|
|
|
|
iDevicePathSize = strlen(DevicePath) + 1;
|
|
|
|
HidDevice -> DevicePath = malloc(iDevicePathSize);
|
|
|
|
if (NULL == HidDevice -> DevicePath)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
stringReturn = StringCbCopy(HidDevice -> DevicePath, iDevicePathSize, DevicePath);
|
|
|
|
if (HasReadAccess)
|
|
{
|
|
accessFlags |= GENERIC_READ;
|
|
}
|
|
|
|
if (HasWriteAccess)
|
|
{
|
|
accessFlags |= GENERIC_WRITE;
|
|
}
|
|
|
|
if (!IsExclusive)
|
|
{
|
|
sharingFlags = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
|
}
|
|
|
|
//
|
|
// The hid.dll api's do not pass the overlapped structure into deviceiocontrol
|
|
// so to use them we must have a non overlapped device. If the request is for
|
|
// an overlapped device we will close the device below and get a handle to an
|
|
// overlapped device
|
|
//
|
|
|
|
HidDevice->HidDevice = CreateFile (DevicePath,
|
|
accessFlags,
|
|
sharingFlags,
|
|
NULL, // no SECURITY_ATTRIBUTES structure
|
|
OPEN_EXISTING, // No special create flags
|
|
0, // Open device as non-overlapped so we can get data
|
|
NULL); // No template file
|
|
|
|
if (INVALID_HANDLE_VALUE == HidDevice->HidDevice)
|
|
{
|
|
free(HidDevice -> DevicePath);
|
|
HidDevice -> DevicePath = INVALID_HANDLE_VALUE ;
|
|
return FALSE;
|
|
}
|
|
|
|
HidDevice -> OpenedForRead = HasReadAccess;
|
|
HidDevice -> OpenedForWrite = HasWriteAccess;
|
|
HidDevice -> OpenedOverlapped = IsOverlapped;
|
|
HidDevice -> OpenedExclusive = IsExclusive;
|
|
|
|
//
|
|
// If the device was not opened as overlapped, then fill in the rest of the
|
|
// HidDevice structure. However, if opened as overlapped, this handle cannot
|
|
// be used in the calls to the HidD_ exported functions since each of these
|
|
// functions does synchronous I/O.
|
|
//
|
|
|
|
if (!HidD_GetPreparsedData (HidDevice->HidDevice, &HidDevice->Ppd))
|
|
{
|
|
free(HidDevice -> DevicePath);
|
|
HidDevice -> DevicePath = NULL ;
|
|
CloseHandle(HidDevice -> HidDevice);
|
|
HidDevice -> HidDevice = INVALID_HANDLE_VALUE ;
|
|
return FALSE;
|
|
}
|
|
|
|
if (!HidD_GetAttributes (HidDevice->HidDevice, &HidDevice->Attributes))
|
|
{
|
|
free(HidDevice -> DevicePath);
|
|
HidDevice -> DevicePath = NULL;
|
|
CloseHandle(HidDevice -> HidDevice);
|
|
HidDevice -> HidDevice = INVALID_HANDLE_VALUE;
|
|
HidD_FreePreparsedData (HidDevice->Ppd);
|
|
HidDevice->Ppd = NULL;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (!HidP_GetCaps (HidDevice->Ppd, &HidDevice->Caps))
|
|
{
|
|
free(HidDevice -> DevicePath);
|
|
HidDevice -> DevicePath = NULL;
|
|
CloseHandle(HidDevice -> HidDevice);
|
|
HidDevice -> HidDevice = INVALID_HANDLE_VALUE;
|
|
HidD_FreePreparsedData (HidDevice->Ppd);
|
|
HidDevice->Ppd = NULL;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// At this point the client has a choice. It may chose to look at the
|
|
// Usage and Page of the top level collection found in the HIDP_CAPS
|
|
// structure. In this way it could just use the usages it knows about.
|
|
// If either HidP_GetUsages or HidP_GetUsageValue return an error then
|
|
// that particular usage does not exist in the report.
|
|
// This is most likely the preferred method as the application can only
|
|
// use usages of which it already knows.
|
|
// In this case the app need not even call GetButtonCaps or GetValueCaps.
|
|
//
|
|
// In this example, however, we will call FillDeviceInfo to look for all
|
|
// of the usages in the device.
|
|
//
|
|
|
|
bSuccess = FillDeviceInfo(HidDevice);
|
|
|
|
if (FALSE == bSuccess)
|
|
{
|
|
CloseHidDevice(HidDevice);
|
|
return (FALSE);
|
|
}
|
|
|
|
if (IsOverlapped)
|
|
{
|
|
CloseHandle(HidDevice->HidDevice);
|
|
|
|
HidDevice->HidDevice = CreateFile (DevicePath,
|
|
accessFlags,
|
|
sharingFlags,
|
|
NULL, // no SECURITY_ATTRIBUTES structure
|
|
OPEN_EXISTING, // No special create flags
|
|
FILE_FLAG_OVERLAPPED, // Now we open the device as overlapped
|
|
NULL); // No template file
|
|
|
|
if (INVALID_HANDLE_VALUE == HidDevice->HidDevice)
|
|
{
|
|
CloseHidDevice(HidDevice);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
BOOLEAN
|
|
FillDeviceInfo(
|
|
IN PHID_DEVICE HidDevice
|
|
)
|
|
{
|
|
USHORT numValues;
|
|
USHORT numCaps;
|
|
PHIDP_BUTTON_CAPS buttonCaps;
|
|
PHIDP_VALUE_CAPS valueCaps;
|
|
PHID_DATA data;
|
|
ULONG i;
|
|
USAGE usage;
|
|
|
|
//
|
|
// setup Input Data buffers.
|
|
//
|
|
|
|
//
|
|
// Allocate memory to hold on input report
|
|
//
|
|
|
|
HidDevice->InputReportBuffer = (PCHAR)
|
|
calloc (HidDevice->Caps.InputReportByteLength, sizeof (CHAR));
|
|
|
|
|
|
//
|
|
// Allocate memory to hold the button and value capabilities.
|
|
// NumberXXCaps is in terms of array elements.
|
|
//
|
|
|
|
HidDevice->InputButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS)
|
|
calloc (HidDevice->Caps.NumberInputButtonCaps, sizeof (HIDP_BUTTON_CAPS));
|
|
|
|
if (NULL == buttonCaps)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
HidDevice->InputValueCaps = valueCaps = (PHIDP_VALUE_CAPS)
|
|
calloc (HidDevice->Caps.NumberInputValueCaps, sizeof (HIDP_VALUE_CAPS));
|
|
|
|
if (NULL == valueCaps)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Have the HidP_X functions fill in the capability structure arrays.
|
|
//
|
|
|
|
numCaps = HidDevice->Caps.NumberInputButtonCaps;
|
|
|
|
HidP_GetButtonCaps (HidP_Input,
|
|
buttonCaps,
|
|
&numCaps,
|
|
HidDevice->Ppd);
|
|
|
|
numCaps = HidDevice->Caps.NumberInputValueCaps;
|
|
|
|
HidP_GetValueCaps (HidP_Input,
|
|
valueCaps,
|
|
&numCaps,
|
|
HidDevice->Ppd);
|
|
|
|
|
|
//
|
|
// Depending on the device, some value caps structures may represent more
|
|
// than one value. (A range). In the interest of being verbose, over
|
|
// efficient, we will expand these so that we have one and only one
|
|
// struct _HID_DATA for each value.
|
|
//
|
|
// To do this we need to count up the total number of values are listed
|
|
// in the value caps structure. For each element in the array we test
|
|
// for range if it is a range then UsageMax and UsageMin describe the
|
|
// usages for this range INCLUSIVE.
|
|
//
|
|
|
|
numValues = 0;
|
|
for (i = 0; i < HidDevice->Caps.NumberInputValueCaps; i++, valueCaps++)
|
|
{
|
|
if (valueCaps->IsRange)
|
|
{
|
|
numValues += valueCaps->Range.UsageMax - valueCaps->Range.UsageMin + 1;
|
|
}
|
|
else
|
|
{
|
|
numValues++;
|
|
}
|
|
}
|
|
valueCaps = HidDevice->InputValueCaps;
|
|
|
|
|
|
//
|
|
// Allocate a buffer to hold the struct _HID_DATA structures.
|
|
// One element for each set of buttons, and one element for each value
|
|
// found.
|
|
//
|
|
|
|
HidDevice->InputDataLength = HidDevice->Caps.NumberInputButtonCaps
|
|
+ numValues;
|
|
|
|
HidDevice->InputData = data = (PHID_DATA)
|
|
calloc (HidDevice->InputDataLength, sizeof (HID_DATA));
|
|
|
|
if (NULL == data)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Fill in the button data
|
|
//
|
|
|
|
for (i = 0;
|
|
i < HidDevice->Caps.NumberInputButtonCaps;
|
|
i++, data++, buttonCaps++)
|
|
{
|
|
data->IsButtonData = TRUE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = buttonCaps->UsagePage;
|
|
if (buttonCaps->IsRange)
|
|
{
|
|
data->ButtonData.UsageMin = buttonCaps -> Range.UsageMin;
|
|
data->ButtonData.UsageMax = buttonCaps -> Range.UsageMax;
|
|
}
|
|
else
|
|
{
|
|
data -> ButtonData.UsageMin = data -> ButtonData.UsageMax = buttonCaps -> NotRange.Usage;
|
|
}
|
|
|
|
data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength (
|
|
HidP_Input,
|
|
buttonCaps->UsagePage,
|
|
HidDevice->Ppd);
|
|
data->ButtonData.Usages = (PUSAGE)
|
|
calloc (data->ButtonData.MaxUsageLength, sizeof (USAGE));
|
|
|
|
data->ReportID = buttonCaps -> ReportID;
|
|
}
|
|
|
|
//
|
|
// Fill in the value data
|
|
//
|
|
|
|
for (i = 0; i < numValues; i++, valueCaps++)
|
|
{
|
|
if (valueCaps->IsRange)
|
|
{
|
|
for (usage = valueCaps->Range.UsageMin;
|
|
usage <= valueCaps->Range.UsageMax;
|
|
usage++)
|
|
{
|
|
data->IsButtonData = FALSE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = valueCaps->UsagePage;
|
|
data->ValueData.Usage = usage;
|
|
data->ReportID = valueCaps -> ReportID;
|
|
data++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
data->IsButtonData = FALSE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = valueCaps->UsagePage;
|
|
data->ValueData.Usage = valueCaps->NotRange.Usage;
|
|
data->ReportID = valueCaps -> ReportID;
|
|
data++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// setup Output Data buffers.
|
|
//
|
|
|
|
HidDevice->OutputReportBuffer = (PCHAR)
|
|
calloc (HidDevice->Caps.OutputReportByteLength, sizeof (CHAR));
|
|
|
|
HidDevice->OutputButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS)
|
|
calloc (HidDevice->Caps.NumberOutputButtonCaps, sizeof (HIDP_BUTTON_CAPS));
|
|
|
|
if (NULL == buttonCaps)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
HidDevice->OutputValueCaps = valueCaps = (PHIDP_VALUE_CAPS)
|
|
calloc (HidDevice->Caps.NumberOutputValueCaps, sizeof (HIDP_VALUE_CAPS));
|
|
|
|
if (NULL == valueCaps)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
numCaps = HidDevice->Caps.NumberOutputButtonCaps;
|
|
HidP_GetButtonCaps (HidP_Output,
|
|
buttonCaps,
|
|
&numCaps,
|
|
HidDevice->Ppd);
|
|
|
|
numCaps = HidDevice->Caps.NumberOutputValueCaps;
|
|
HidP_GetValueCaps (HidP_Output,
|
|
valueCaps,
|
|
&numCaps,
|
|
HidDevice->Ppd);
|
|
|
|
numValues = 0;
|
|
for (i = 0; i < HidDevice->Caps.NumberOutputValueCaps; i++, valueCaps++)
|
|
{
|
|
if (valueCaps->IsRange)
|
|
{
|
|
numValues += valueCaps->Range.UsageMax
|
|
- valueCaps->Range.UsageMin + 1;
|
|
}
|
|
else
|
|
{
|
|
numValues++;
|
|
}
|
|
}
|
|
valueCaps = HidDevice->OutputValueCaps;
|
|
|
|
HidDevice->OutputDataLength = HidDevice->Caps.NumberOutputButtonCaps
|
|
+ numValues;
|
|
|
|
HidDevice->OutputData = data = (PHID_DATA)
|
|
calloc (HidDevice->OutputDataLength, sizeof (HID_DATA));
|
|
|
|
if (NULL == data)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
for (i = 0;
|
|
i < HidDevice->Caps.NumberOutputButtonCaps;
|
|
i++, data++, buttonCaps++)
|
|
{
|
|
data->IsButtonData = TRUE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = buttonCaps->UsagePage;
|
|
|
|
if (buttonCaps->IsRange)
|
|
{
|
|
data->ButtonData.UsageMin = buttonCaps -> Range.UsageMin;
|
|
data->ButtonData.UsageMax = buttonCaps -> Range.UsageMax;
|
|
}
|
|
else
|
|
{
|
|
data -> ButtonData.UsageMin = data -> ButtonData.UsageMax = buttonCaps -> NotRange.Usage;
|
|
}
|
|
|
|
data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength (
|
|
HidP_Output,
|
|
buttonCaps->UsagePage,
|
|
HidDevice->Ppd);
|
|
|
|
data->ButtonData.Usages = (PUSAGE)
|
|
calloc (data->ButtonData.MaxUsageLength, sizeof (USAGE));
|
|
|
|
data->ReportID = buttonCaps -> ReportID;
|
|
}
|
|
|
|
for (i = 0; i < numValues; i++, valueCaps++)
|
|
{
|
|
if (valueCaps->IsRange)
|
|
{
|
|
for (usage = valueCaps->Range.UsageMin;
|
|
usage <= valueCaps->Range.UsageMax;
|
|
usage++)
|
|
{
|
|
data->IsButtonData = FALSE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = valueCaps->UsagePage;
|
|
data->ValueData.Usage = usage;
|
|
data->ReportID = valueCaps -> ReportID;
|
|
data++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
data->IsButtonData = FALSE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = valueCaps->UsagePage;
|
|
data->ValueData.Usage = valueCaps->NotRange.Usage;
|
|
data->ReportID = valueCaps -> ReportID;
|
|
data++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// setup Feature Data buffers.
|
|
//
|
|
|
|
HidDevice->FeatureReportBuffer = (PCHAR)
|
|
calloc (HidDevice->Caps.FeatureReportByteLength, sizeof (CHAR));
|
|
|
|
HidDevice->FeatureButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS)
|
|
calloc (HidDevice->Caps.NumberFeatureButtonCaps, sizeof (HIDP_BUTTON_CAPS));
|
|
|
|
if (NULL == buttonCaps)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
HidDevice->FeatureValueCaps = valueCaps = (PHIDP_VALUE_CAPS)
|
|
calloc (HidDevice->Caps.NumberFeatureValueCaps, sizeof (HIDP_VALUE_CAPS));
|
|
|
|
if (NULL == valueCaps)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
numCaps = HidDevice->Caps.NumberFeatureButtonCaps;
|
|
HidP_GetButtonCaps (HidP_Feature,
|
|
buttonCaps,
|
|
&numCaps,
|
|
HidDevice->Ppd);
|
|
|
|
numCaps = HidDevice->Caps.NumberFeatureValueCaps;
|
|
HidP_GetValueCaps (HidP_Feature,
|
|
valueCaps,
|
|
&numCaps,
|
|
HidDevice->Ppd);
|
|
|
|
numValues = 0;
|
|
for (i = 0; i < HidDevice->Caps.NumberFeatureValueCaps; i++, valueCaps++)
|
|
{
|
|
if (valueCaps->IsRange)
|
|
{
|
|
numValues += valueCaps->Range.UsageMax
|
|
- valueCaps->Range.UsageMin + 1;
|
|
}
|
|
else
|
|
{
|
|
numValues++;
|
|
}
|
|
}
|
|
valueCaps = HidDevice->FeatureValueCaps;
|
|
|
|
HidDevice->FeatureDataLength = HidDevice->Caps.NumberFeatureButtonCaps
|
|
+ numValues;
|
|
|
|
HidDevice->FeatureData = data = (PHID_DATA)
|
|
calloc (HidDevice->FeatureDataLength, sizeof (HID_DATA));
|
|
|
|
if (NULL == data)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
for (i = 0;
|
|
i < HidDevice->Caps.NumberFeatureButtonCaps;
|
|
i++, data++, buttonCaps++)
|
|
{
|
|
data->IsButtonData = TRUE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = buttonCaps->UsagePage;
|
|
|
|
if (buttonCaps->IsRange)
|
|
{
|
|
data->ButtonData.UsageMin = buttonCaps -> Range.UsageMin;
|
|
data->ButtonData.UsageMax = buttonCaps -> Range.UsageMax;
|
|
}
|
|
else
|
|
{
|
|
data -> ButtonData.UsageMin = data -> ButtonData.UsageMax = buttonCaps -> NotRange.Usage;
|
|
}
|
|
|
|
data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength (
|
|
HidP_Feature,
|
|
buttonCaps->UsagePage,
|
|
HidDevice->Ppd);
|
|
data->ButtonData.Usages = (PUSAGE)
|
|
calloc (data->ButtonData.MaxUsageLength, sizeof (USAGE));
|
|
|
|
data->ReportID = buttonCaps -> ReportID;
|
|
}
|
|
|
|
for (i = 0; i < numValues; i++, valueCaps++)
|
|
{
|
|
if (valueCaps->IsRange)
|
|
{
|
|
for (usage = valueCaps->Range.UsageMin;
|
|
usage <= valueCaps->Range.UsageMax;
|
|
usage++)
|
|
{
|
|
data->IsButtonData = FALSE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = valueCaps->UsagePage;
|
|
data->ValueData.Usage = usage;
|
|
data->ReportID = valueCaps -> ReportID;
|
|
data++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
data->IsButtonData = FALSE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = valueCaps->UsagePage;
|
|
data->ValueData.Usage = valueCaps->NotRange.Usage;
|
|
data->ReportID = valueCaps -> ReportID;
|
|
data++;
|
|
}
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
VOID
|
|
CloseHidDevices(
|
|
IN PHID_DEVICE HidDevices,
|
|
IN ULONG NumberDevices
|
|
)
|
|
{
|
|
ULONG Index;
|
|
|
|
for (Index = 0; Index < NumberDevices; Index++)
|
|
{
|
|
CloseHidDevice(HidDevices+Index);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
CloseHidDevice (
|
|
IN PHID_DEVICE HidDevice
|
|
)
|
|
{
|
|
free(HidDevice -> DevicePath);
|
|
|
|
if (INVALID_HANDLE_VALUE != HidDevice -> HidDevice)
|
|
{
|
|
CloseHandle(HidDevice -> HidDevice);
|
|
HidDevice -> HidDevice = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (NULL != HidDevice -> Ppd)
|
|
{
|
|
HidD_FreePreparsedData(HidDevice -> Ppd);
|
|
HidDevice -> Ppd = NULL;
|
|
}
|
|
|
|
if (NULL != HidDevice -> InputReportBuffer)
|
|
{
|
|
free(HidDevice -> InputReportBuffer);
|
|
HidDevice -> InputReportBuffer = NULL;
|
|
}
|
|
|
|
if (NULL != HidDevice -> InputData)
|
|
{
|
|
free(HidDevice -> InputData);
|
|
HidDevice -> InputData = NULL;
|
|
}
|
|
|
|
if (NULL != HidDevice -> InputButtonCaps)
|
|
{
|
|
free(HidDevice -> InputButtonCaps);
|
|
HidDevice -> InputButtonCaps = NULL;
|
|
}
|
|
|
|
if (NULL != HidDevice -> InputValueCaps)
|
|
{
|
|
free(HidDevice -> InputValueCaps);
|
|
HidDevice -> InputValueCaps = NULL;
|
|
}
|
|
|
|
if (NULL != HidDevice -> OutputReportBuffer)
|
|
{
|
|
free(HidDevice -> OutputReportBuffer);
|
|
HidDevice -> OutputReportBuffer = NULL;
|
|
}
|
|
|
|
if (NULL != HidDevice -> OutputData)
|
|
{
|
|
free(HidDevice -> OutputData);
|
|
HidDevice -> OutputData = NULL;
|
|
}
|
|
|
|
if (NULL != HidDevice -> OutputButtonCaps)
|
|
{
|
|
free(HidDevice -> OutputButtonCaps);
|
|
HidDevice -> OutputButtonCaps = NULL;
|
|
}
|
|
|
|
if (NULL != HidDevice -> OutputValueCaps)
|
|
{
|
|
free(HidDevice -> OutputValueCaps);
|
|
HidDevice -> OutputValueCaps = NULL;
|
|
}
|
|
|
|
if (NULL != HidDevice -> FeatureReportBuffer)
|
|
{
|
|
free(HidDevice -> FeatureReportBuffer);
|
|
HidDevice -> FeatureReportBuffer = NULL;
|
|
}
|
|
|
|
if (NULL != HidDevice -> FeatureData)
|
|
{
|
|
free(HidDevice -> FeatureData);
|
|
HidDevice -> FeatureData = NULL;
|
|
}
|
|
|
|
if (NULL != HidDevice -> FeatureButtonCaps)
|
|
{
|
|
free(HidDevice -> FeatureButtonCaps);
|
|
HidDevice -> FeatureButtonCaps = NULL;
|
|
}
|
|
|
|
if (NULL != HidDevice -> FeatureValueCaps)
|
|
{
|
|
free(HidDevice -> FeatureValueCaps);
|
|
HidDevice -> FeatureValueCaps = NULL;
|
|
}
|
|
|
|
return;
|
|
}
|