| WebNoteId: 20 Title: The ScanForHidDevice() function in USBHIDIO.c returns the incorrect device. | |||||||||
Summary: This web note describes how to correct the ScanForHidDevice() function from returning the incorrect device. | |||||||||
// ------------------------------------------------------ //
// ScanForHidDevice(VID,PID,TID,SID,ENUM,SHARE) - Scan thru all the HID device looking
// for a match on the VID, PID and optional TID (Type ID) and SID (Serial Number).
// Sets the hDevice handle varible if found and opens the device
// Parameters:
// VID The Vendor Indenification Number. Delcom VID = 0x0FC5;
// PID The Product Indenification Number. Typically 0xB080 (see PID_ALT)
// TID The Family type number. Zero=all, else only serachs for matching TID
// SID The Serial number. Zero=all, else only serachs for matching SID
// ENUM Eumeration. When non-zero list all matching device found. Does not leave open any device.
// SHARE Share Mode. When non-zero open device in shared mode.
// PID_ALT An alternate PID to search for. Tyipcally 0xA080.
//
// Return zero if found, else non-zero error code.
// 0 = Success - A matching device has been found and openned.
// 1 = No matching HID devices.
// NOTES
// Enum if set - prints all the devices found
// 02/06/2020 - Added check for Usage ID and Page, to make should we are connecting to the Delcom Vendor Defined Device and
// not one of the other HID types. Also now check of all api return failures. Added PID_ALT to serach for alt too, set to zero if not used.
// ------------------------------------------------------ //
unsigned int CUSBHIDIO::ScanForHIDDevice(unsigned int VID, unsigned int PID, unsigned int TID, unsigned int SID, unsigned int Enum, unsigned int ShareMode,unsigned int PID_ALT )
{
//Use a series of API calls to find a HID with a matching Vendor,Product, Type and Serial ID.
DelcomDeviceInfoStruct DelcomInfo;
PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData;
GUID HidGuid;
HANDLE hDevInfo;
ULONG Required;
HIDD_ATTRIBUTES Attributes;
SP_DEVICE_INTERFACE_DATA devInfoData;
bool LastDevice = FALSE;
int MemberIndex = 0;
bool MyDeviceDetected = FALSE;
LONG Result;
ULONG Length;
ULONG devcnt;
DWORD SHARE_MODE;
PHIDP_PREPARSED_DATA pPreparsedData;
PHIDP_CAPS pCaps;
// Variable init
devcnt=0;
Length = 0;
pDetailData = NULL;
hDevice=NULL;
MemberIndex = 0;
LastDevice = FALSE;
if(ShareMode) SHARE_MODE = FILE_SHARE_READ|FILE_SHARE_WRITE;
else SHARE_MODE = 0;
pCaps =(PHIDP_CAPS)malloc(sizeof(HIDP_CAPS));
// API function: HidD_GetHidGuid - Get the GUID for all system HIDs. Returns: the GUID in HidGuid.
HidD_GetHidGuid(&HidGuid);
// API function: SetupDiGetClassDevs -Returns: a handle to a device information set for all installed devices.
// Requires: the GUID returned by GetHidGuid.
hDevInfo=SetupDiGetClassDevs(&HidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
devInfoData.cbSize = sizeof(devInfoData);
//Step through the available devices looking for the one we want.
//Quit on detecting the desired device or checking all available devices without success.
do {
MyDeviceDetected=FALSE;
//API function: SetupDiEnumDeviceInterfaces - On return, MyDeviceInterfaceData contains the handle to a
// SP_DEVICE_INTERFACE_DATA structure for a detected device. Requires:
// The DeviceInfoSet returned in SetupDiGetClassDevs. The HidGuid returned in GetHidGuid. An index to specify a device.
Result=SetupDiEnumDeviceInterfaces(hDevInfo, 0, &HidGuid, MemberIndex, &devInfoData);
if (Result != 0)
{ //A device has been detected, so get more information about it.
// API function: SetupDiGetDeviceInterfaceDetail - Returns: an SP_DEVICE_INTERFACE_DETAIL_DATA structure
// containing information about a device. To retrieve the information, call this function twice.
// The first time returns the size of the structure in Length. The second time returns a pointer to the data in DeviceInfoSet.
// Requires: A DeviceInfoSet returned by SetupDiGetClassDevs The SP_DEVICE_INTERFACE_DATA structure returned by SetupDiEnumDeviceInterfaces.
// The final parameter is an optional pointer to an SP_DEV_INFO_DATA structure. This application does not retrieve or use the structure.
// If retrieving the structure, set MyDeviceInfoData.cbSize = length of MyDeviceInfoData.
// and pass the structures address.
//Get the Length value.
//The call will return with a "buffer too small" error which can be ignored.
Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, NULL, 0, &Length, NULL);
//Allocate memory for the hDevInfo structure, using the returned Length.
pDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(Length);
//Set cbSize in the detailData structure.
pDetailData -> cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
//Call the function again, this time passing it the returned buffer size.
Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, pDetailData, Length, &Required, NULL);
//Open a handle to the device.
// API function: CreateFile - Returns: a handle that enables reading and writing to the device.
// Requires: The DevicePath in the detailData structure returned by SetupDiGetDeviceInterfaceDetail.
// NOTES: details->DevicePath - holds the name of the device -
// NOTES: For file sharing set 3rd parameter to FILE_SHARE_READ|FILE_SHARE_WRITE
hDevice = INVALID_HANDLE_VALUE;
hDevice = CreateFile(pDetailData->DevicePath, GENERIC_READ|GENERIC_WRITE, SHARE_MODE,
(LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, 0, NULL);
if( hDevice != INVALID_HANDLE_VALUE )
{
// API function: HidD_GetAttributes - Requests information from the device.
// Requires: the handle returned by CreateFile. Returns: a HIDD_ATTRIBUTES structure containing
// the Vendor ID, Product ID, and Product Version Number. Use this information to decide if the detected device is
// the one we are looking for.
// To enable overlappedtransfer use: GetDeviceCapabilities() & PrepareForOverlappedTransfer()
// Get the Attributes(VID,PID)
Attributes.Size = sizeof(Attributes);
Result = HidD_GetAttributes(hDevice, &Attributes);
// Get Capabillities(USAGE ID & PAGE)pCaps->Usage = 0x0;
pCaps->UsagePage = 0x0;
if(HidD_GetPreparsedData(hDevice, &pPreparsedData) )
Result = HidP_GetCaps(pPreparsedData, pCaps);
//Is it the desired device?
if( Result && (Attributes.VendorID == VID) &&
((Attributes.ProductID == PID) ||(Attributes.ProductID == PID_ALT)) &&
(pCaps->UsagePage==0xFF00) && (pCaps->Usage==0x00) )
{ //Both the Product and Vendor IDs and Usage ID and Page match. Delcom vendor defined device found!
MyDeviceDetected = TRUE; // premark it found
_tcsncpy_s(DeviceName, sizeof(DeviceName), pDetailData->DevicePath, 512); // save the devicename
// At this point we have found a match device. If VID, PID or ENUM are set then check for them too.
if(TID || SID || Enum) { // Now check for TID SID and ENUM if non-zero
Result = GetDeviceInfo(&DelcomInfo); // TRY TO READ THE DEVICE
if(Result ) MyDeviceDetected = FALSE; // this function must succeed
else {
if(TID && (DelcomInfo.Family != TID)) MyDeviceDetected = FALSE;
if(SID && (DelcomInfo.Serial != SID)) MyDeviceDetected = FALSE;
if(Enum) { // if Enumerate mode enabled, just print the info and make MyDeviceDetected=FALSE so it scans all of them.
//_tprintf(L"Device Found(%u): TID=%u SID=%u VER=%d Usage(%x/%x).
%s
", ++devcnt, DelcomInfo.Family,DelcomInfo.Serial, DelcomInfo.Version, pCaps->UsagePage, pCaps->Usage, DeviceName);
_tprintf(L"Device Found(%u): TID=%u SID=%u VER=%d.
%s
", ++devcnt, DelcomInfo.Family,DelcomInfo.Serial, DelcomInfo.Version, DeviceName);
MyDeviceDetected = FALSE; // Mark false, so keeps scanning
}
} // end of TID or SID or
}
}
if(MyDeviceDetected == FALSE) CloseHandle(hDevice); // close the handle if device not found or enum mode
} // eof if hDevice is valid
//Free the memory used by the detailData structure (no longer needed).
free(pDetailData);
} //if (Result != 0)
else { // End of List - No HID devices detected!
LastDevice=TRUE; //SetupDiEnumDeviceInterfaces returned 0, so there are no more devices to check.
}
//If we have not found the device yet, and have not tried every available device,
//try the next one.
MemberIndex++;
} // loop till either end of deivce list or we find our device
while ((LastDevice == FALSE) && (MyDeviceDetected == FALSE));
SetupDiDestroyDeviceInfoList(hDevInfo); //Free the memory reserved for hDevInfo by SetupDiClassDevs.
free(pCaps);
if (MyDeviceDetected == FALSE) {
// Device not found
hDevice = 0;
return(1);
}
else {
// Device Found
HidD_SetNumInputBuffers(hDevice,1); //sets the maximum number of input reports that the HID class driver ring buffer can hold for a specified top-level collection.
return(0); // Success
}
}
| |||||||||