Beispiel #1
0
HID_API_EXPORT hid_device* HID_API_CALL hid_open_path(const char *path)
{
	hid_device *dev;
	HIDP_CAPS caps;
	PHIDP_PREPARSED_DATA pp_data = NULL;
	BOOLEAN res;
	NTSTATUS nt_res;

	if (hid_init() < 0) {
		return NULL;
	}

	dev = new_hid_device();

	/* Open a handle to the device */
	dev->device_handle = open_device(path, FALSE);

	/* Check validity of write_handle. */
	if (dev->device_handle == INVALID_HANDLE_VALUE) {
		/* Unable to open the device. */
		register_error(dev, "CreateFile");
		goto err;
	}

	/* Set the Input Report buffer size to 64 reports. */
	res = HidD_SetNumInputBuffers(dev->device_handle, 64);
	if (!res) {
		register_error(dev, "HidD_SetNumInputBuffers");
		goto err;
	}

	/* Get the Input Report length for the device. */
	res = HidD_GetPreparsedData(dev->device_handle, &pp_data);
	if (!res) {
		register_error(dev, "HidD_GetPreparsedData");
		goto err;
	}

	nt_res = HidP_GetCaps(pp_data, &caps);
	if (nt_res != HIDP_STATUS_SUCCESS) {
		register_error(dev, "HidP_GetCaps");
		goto err_pp_data;
	}
	dev->output_report_length = caps.OutputReportByteLength;
	dev->input_report_length = caps.InputReportByteLength;
	HidD_FreePreparsedData(pp_data);

	dev->read_buf = (char*) malloc(dev->input_report_length);

	return dev;

err_pp_data:
		HidD_FreePreparsedData(pp_data);
err:
		free_hid_device(dev);
		return NULL;
}
Beispiel #2
0
BOOLEAN SwitchLogitech( __in LPTSTR lpDongleName, __in HANDLE hHidDevice, __in BOOL toHID )
{
	PHIDP_PREPARSED_DATA PreparsedData;

	if ( !HidD_GetPreparsedData( hHidDevice, &PreparsedData ) )
	{
		LbtReportFunctionError( TEXT("HidD_GetPreparsedData") );
		return FALSE;
	}

	HIDP_CAPS       HidCaps;

	if ( !HidP_GetCaps( PreparsedData, &HidCaps ) )
	{
		LbtReportFunctionError( TEXT("HidP_GetCaps") );
		HidD_FreePreparsedData(PreparsedData);
		return FALSE;
	}

	if ( HidCaps.UsagePage != 0xFF00 || HidCaps.Usage != 0x0001 )
	{
		HidD_FreePreparsedData(PreparsedData);
		return FALSE;
	}

	if ( HidCaps.OutputReportByteLength != sizeof(ToHCIReports[0]) )
	{
		HidD_FreePreparsedData(PreparsedData);
		return FALSE;
	}

	DWORD noReports = toHID ? sizeof(ToHCIReports) / sizeof(ToHCIReports[0]) :
		sizeof(ToHIDReports) / sizeof(ToHIDReports[0]);

	for (DWORD i = 0; i < noReports; i++ )
	{
		CHAR ReportBuffer[sizeof(ToHCIReports[0])];
		RtlCopyMemory( ReportBuffer, toHID ? ToHCIReports[i] : ToHIDReports[i], sizeof( ToHCIReports[0] ) );
		if (!HidD_SetOutputReport( hHidDevice, ReportBuffer, HidCaps.OutputReportByteLength ) )
		{
			LbtReportFunctionError( TEXT("HidD_SetOutputReport") );
			HidD_FreePreparsedData(PreparsedData);
			return FALSE;
		}
	}

	HidD_FreePreparsedData(PreparsedData);
	LbtReportDongleSwitch( lpDongleName, toHID );
	return TRUE;
}
void GetDeviceCapabilities(HANDLE DeviceHandle)
{
	//Get the Capabilities structure for the 

	PHIDP_PREPARSED_DATA	PreparsedData;

	/*
	  API function: HidD_GetPreparsedData
	  Returns: a pointer to a buffer containing the information about the device's capabilities.
	  Requires: A handle returned by CreateFile.
	  There's no need to access the buffer directly,
	  but HidP_GetCaps and other API functions require a pointer to the buffer.
	*/

	HidD_GetPreparsedData
		(DeviceHandle,
		 &PreparsedData);

	/*
	  API function: HidP_GetCaps
	  Learn the device's capabilities.
	  For standard devices such as joysticks, you can find out the specific
	  capabilities of the 
	  For a custom device, the software will probably know what the device is capable of,
	  and the call only verifies the information.
	  Requires: the pointer to the buffer returned by HidD_GetPreparsedData.
	  Returns: a Capabilities structure containing the information.
	*/

	HidP_GetCaps
		(PreparsedData,
		 &Capabilities);

	HidD_FreePreparsedData(PreparsedData);
}
Beispiel #4
0
int open_path(const char * path, int print) {

  int device = async_open_path(path, print);
  if(device >= 0) {
    HIDD_ATTRIBUTES attributes = { .Size = sizeof(HIDD_ATTRIBUTES) };
    if(HidD_GetAttributes(devices[device].handle, &attributes) == TRUE) {
        PHIDP_PREPARSED_DATA preparsedData;
        HIDP_CAPS hidCapabilities;
        if(HidD_GetPreparsedData(devices[device].handle, &preparsedData) == TRUE) {
            if(HidP_GetCaps(preparsedData, &hidCapabilities) == HIDP_STATUS_SUCCESS ) {
                devices[device].write.size = hidCapabilities.OutputReportByteLength;
                async_set_read_size(device, hidCapabilities.InputReportByteLength);
                devices[device].hidInfo.vendor_id = attributes.VendorID;
                devices[device].hidInfo.product_id = attributes.ProductID;
                devices[device].hidInfo.bcdDevice = attributes.VersionNumber;
            }
            else {
                if (print) {
                    ASYNC_PRINT_ERROR("HidP_GetCaps")
                }
                async_close(device);
                device = -1;
            }
            HidD_FreePreparsedData(preparsedData);
        }
        else {
            if (print) {
                ASYNC_PRINT_ERROR("HidD_GetPreparsedData")
            }
            async_close(device);
            device = -1;
        }
    }
Beispiel #5
0
void Controller::clearHidStructures(){
	if (_pPreparsedData != 0)
	{
		HidD_FreePreparsedData(_pPreparsedData);
		_pPreparsedData = 0;
	}
	if (_pCaps != nullptr)
	{
		free(_pCaps);
		_pCaps = 0;
	}
	if (_pButtonCaps != nullptr)
	{
		free(_pButtonCaps);
		_pButtonCaps = 0;
	}
	if (_pButtonUsages != nullptr)
	{
		free(_pButtonUsages);
		_pButtonUsages = 0;
	}
	if (_pInputReport != nullptr)
	{
		free(_pInputReport);
		_pInputReport = 0;
	}
}
Beispiel #6
0
int hs_hid_parse_descriptor(hs_handle *h, hs_hid_descriptor *rdesc)
{
    assert(h);
    assert(h->dev->type == HS_DEVICE_TYPE_HID);
    assert(rdesc);

    // semi-hidden Hungarian pointers? Really , Microsoft?
    PHIDP_PREPARSED_DATA pp;
    HIDP_CAPS caps;
    LONG ret;

    ret = HidD_GetPreparsedData(h->handle, &pp);
    if (!ret)
        return hs_error(HS_ERROR_SYSTEM, "HidD_GetPreparsedData() failed");

    // NTSTATUS and BOOL are both defined as LONG
    ret = HidP_GetCaps(pp, &caps);
    HidD_FreePreparsedData(pp);
    if (ret != HIDP_STATUS_SUCCESS)
        return hs_error(HS_ERROR_SYSTEM, "Invalid HID descriptor");

    rdesc->usage_page = caps.UsagePage;
    rdesc->usage = caps.Usage;

    return 0;
}
USBHIDDLL_API			 bool bWrite_ToHIDDevice(PHANDLE pWriteHandle, LPBYTE lpWriteBuff){

				 DWORD			dwNumberOfBytesWrite;
				 HIDP_CAPS		Capabilities;
				 PHIDP_PREPARSED_DATA		HidParsedData;

				 BOOL bResult = false;

				 if(*pWriteHandle != NULL){
					 HidD_GetPreparsedData(*pWriteHandle, &HidParsedData);

					 /* extract the capabilities info */
					 HidP_GetCaps( HidParsedData ,&Capabilities);

					 /* Free the memory allocated when getting the preparsed data */
					 HidD_FreePreparsedData(HidParsedData);

					 bResult = WriteFile(*pWriteHandle, 
						 lpWriteBuff, 
						 Capabilities.OutputReportByteLength, 
						 &dwNumberOfBytesWrite,
						 NULL);


				 }
				 return bResult;

			 }
Beispiel #8
0
BOOLEAN SwitchCSR(__in LPTSTR lpDongleName, __in HANDLE hHidDevice, __in BOOL toHID)
{
	PHIDP_PREPARSED_DATA PreparsedData;

	if (!HidD_GetPreparsedData(hHidDevice, &PreparsedData))
	{
		LbtReportFunctionError(TEXT("HidD_GetPreparsedData"));
		return FALSE;
	}

	HIDP_CAPS       HidCaps;

	if (!HidP_GetCaps(PreparsedData, &HidCaps))
	{
		LbtReportFunctionError(TEXT("HidP_GetCaps"));
		HidD_FreePreparsedData(PreparsedData);
		return FALSE;
	}

	if (HidCaps.UsagePage != 0xFF00 || HidCaps.Usage != 0x0001)
	{
//		HidD_FreePreparsedData(PreparsedData);
//		return FALSE;
	}

	if (HidCaps.FeatureReportByteLength != sizeof(ToHCICSRReports))
	{
//		HidD_FreePreparsedData(PreparsedData);
//		return FALSE;
	}

	CHAR ReportBuffer[sizeof(ToHCICSRReports)];
	RtlCopyMemory(ReportBuffer, ToHCICSRReports, sizeof(ToHCICSRReports));
	if (!HidD_SetFeature(hHidDevice, ReportBuffer, HidCaps.FeatureReportByteLength))
	{
		LbtReportFunctionError(TEXT("HidD_SetOutputReport"));
		HidD_FreePreparsedData(PreparsedData);
		return FALSE;
	}

	HidD_FreePreparsedData(PreparsedData);
	LbtReportDongleSwitch(lpDongleName, toHID);
	return TRUE;
}
Beispiel #9
0
BOOLEAN
CheckIfOurDevice(
    HANDLE file,
    USAGE myUsagePage,
    USAGE myUsage)
{
    PHIDP_PREPARSED_DATA Ppd = NULL; // The opaque parser info describing this device
    HIDD_ATTRIBUTES                 Attributes; // The Attributes of this hid device.
    HIDP_CAPS                       Caps; // The Capabilities of this hid device.
    BOOLEAN                         result = FALSE;

    if (!HidD_GetPreparsedData (file, &Ppd))
    {
        printf("Error: HidD_GetPreparsedData failed \n");
        goto cleanup;
    }

    if (!HidD_GetAttributes(file, &Attributes))
    {
        printf("Error: HidD_GetAttributes failed \n");
        goto cleanup;
    }

    if (Attributes.VendorID == vmultib_VID && Attributes.ProductID == vmultib_PID)
    {
        if (!HidP_GetCaps (Ppd, &Caps))
        {
            printf("Error: HidP_GetCaps failed \n");
            goto cleanup;
        }

        if ((Caps.UsagePage == myUsagePage) && (Caps.Usage == myUsage))
        {
            printf("Success: Found my device.. \n");
            result = TRUE;
        }
    }

cleanup:

    if (Ppd != NULL)
    {
        HidD_FreePreparsedData (Ppd);
    }

    return result;
}
bool HIDDeviceManager::initUsage(HANDLE hidDev, HIDDeviceDesc* desc) const
{
    bool                 result = false;
    HIDP_CAPS            caps;
    HIDP_PREPARSED_DATA* preparsedData = 0;

    if (!HidD_GetPreparsedData(hidDev, &preparsedData))
        return false;

    if (HidP_GetCaps(preparsedData, &caps) == HIDP_STATUS_SUCCESS)
    {
        desc->Usage                  = caps.Usage;
        desc->UsagePage              = caps.UsagePage;
        result = true;
    }
    HidD_FreePreparsedData(preparsedData);
    return result;
}
Beispiel #11
0
int RawInputPad::Open()
{
	PHIDP_PREPARSED_DATA pPreparsedData = NULL;

	//TODO Better place?
	LoadMappings(mapVector);

	memset(&this->ovl, 0, sizeof(OVERLAPPED));
	memset(&this->ovlW, 0, sizeof(OVERLAPPED));

	//this->padState.initStage = 0;
	this->doPassthrough = !!conf.DFPPass;//TODO per player
	this->usbHandle = INVALID_HANDLE_VALUE;
	std::wstring path;
	{
		CONFIGVARIANT var(N_JOYSTICK, CONFIG_TYPE_WCHAR);
		if (LoadSetting(mPort, APINAME, var))
			path = var.wstrValue;
		else
			return 1;
	}

	this->usbHandle = CreateFileW(path.c_str(), GENERIC_READ|GENERIC_WRITE,
		FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);

	if(this->usbHandle != INVALID_HANDLE_VALUE)
	{
		this->ovl.hEvent = CreateEvent(0, 0, 0, 0);
		this->ovlW.hEvent = CreateEvent(0, 0, 0, 0);

		HidD_GetAttributes(this->usbHandle, &(this->attr));
		HidD_GetPreparsedData(this->usbHandle, &pPreparsedData);
		HidP_GetCaps(pPreparsedData, &(this->caps));
		HidD_FreePreparsedData(pPreparsedData);
		return 0;
	}
	else
		fwprintf(stderr, L"Could not open device '%s'.\nPassthrough and FFB will not work.\n", path.c_str());

	return 1;
}
// 获取设备一些能力信息
USBHIDDLL_API void __stdcall USBHIDGetDeviceCapabilities(USBHANDLE handle, PHIDD_ATTRIBUTES attributes, PHIDP_CAPS caps)
{
    if (handle != INVALID_HANDLE_VALUE)
    {
        HidD_GetAttributes(handle, attributes);

        //Get the Capabilities structure for the device.

        PHIDP_PREPARSED_DATA	PreparsedData;

        /*
        API function: HidD_GetPreparsedData
        Returns: a pointer to a buffer containing the information about the device's capabilities.
        Requires: A handle returned by CreateFile.
        There's no need to access the buffer directly,
        but HidP_GetCaps and other API functions require a pointer to the buffer.
        */

        HidD_GetPreparsedData (handle, &PreparsedData);
        //DisplayLastError("HidD_GetPreparsedData: ");

        /*
        API function: HidP_GetCaps
        Learn the device's capabilities.
        For standard devices such as joysticks, you can find out the specific
        capabilities of the device.
        For a custom device, the software will probably know what the device is capable of,
        and the call only verifies the information.
        Requires: the pointer to the buffer returned by HidD_GetPreparsedData.
        Returns: a Capabilities structure containing the information.
        */

        HidP_GetCaps (PreparsedData, caps);

        //No need for PreparsedData any more, so free the memory it's using.
        HidD_FreePreparsedData(PreparsedData);
        //DisplayLastError("HidD_FreePreparsedData: ") ;
    }
}
Beispiel #13
0
void parse_info_from_path(hid_event* event, char* device_path) {
	auto write_handle = open_device(device_path, TRUE);

	/* Check validity of write_handle. */
	if (write_handle == INVALID_HANDLE_VALUE) {
		/* Unable to open the device. */
		//register_error(dev, "CreateFile");
		//goto cont_close;
		return;
	}

	//TODO: clean this shit up

	HIDD_ATTRIBUTES attrib;
	attrib.Size = sizeof(HIDD_ATTRIBUTES);

	HidD_GetAttributes(write_handle, &attrib);

	event->device_info->product_id = attrib.ProductID;
	event->device_info->vendor_id = attrib.VendorID;
	event->device_info->release_number = attrib.VersionNumber;

	PHIDP_PREPARSED_DATA pp_data = NULL;
	auto res = HidD_GetPreparsedData(write_handle, &pp_data);
	if (res) {
		HIDP_CAPS caps;
		auto nt_res = HidP_GetCaps(pp_data, &caps);
		if (nt_res == HIDP_STATUS_SUCCESS) {
			event->device_info->usage_page = caps.UsagePage;
			event->device_info->usage = caps.Usage;
		}

		HidD_FreePreparsedData(pp_data);
	}

	CloseHandle(write_handle);
}
USBHIDDLL_API			 DWORD dwRead_FromHIDDevice(PHANDLE pReadHandle, BYTE byReadBuff[], DWORD len){

				 DWORD			dwNumberOfBytesRead;
				 DWORD			dwResponseSW = 0;
				 HIDP_CAPS		Capabilities;
				 PHIDP_PREPARSED_DATA		HidParsedData;
				 OVERLAPPED		HidOverlapped;
				 HANDLE			hEvent;

				 LPBYTE	 lpReadBuff = (LPBYTE)malloc(0x21);


				 /* Create a new event for report capture */
				 hEvent = CreateEvent(NULL, TRUE, TRUE, "");

				 /* fill the HidOverlapped structure so that Windows knows which
				 event to cause when the device sends an IN report */
				 HidOverlapped.hEvent = hEvent;
				 HidOverlapped.Offset = 0;
				 HidOverlapped.OffsetHigh = 0;

				 BOOL bResult = false;

				 //			LPCOMMTIMEOUTS lpCommitTimes = (LPCOMMTIMEOUTS)malloc(sizeof(LPCOMMTIMEOUTS));

				 if(*pReadHandle != NULL){
					 HidD_GetPreparsedData(*pReadHandle, &HidParsedData);

					 /* extract the capabilities info */
					 HidP_GetCaps( HidParsedData ,&Capabilities);

					 /* Free the memory allocated when getting the preparsed data */
					 HidD_FreePreparsedData(HidParsedData);

					 bResult = ReadFile(*pReadHandle, 
						 lpReadBuff, 
						 Capabilities.InputReportByteLength,
						 &dwNumberOfBytesRead,
						 (LPOVERLAPPED)&HidOverlapped);


					 if ( bResult == 0 )
					 {
						 // 读取错误信息
						 DWORD dwResult = GetLastError();

						 // I/O端口繁忙
						 if ( dwResult == ERROR_IO_PENDING )
						 {

							 // 需挂起等待
							 dwResult = WaitForSingleObject ( HidOverlapped.hEvent, INFINITE );

							 // I/O端口正常
							 if ( dwResult == WAIT_OBJECT_0 )
							 {
								 // 去读取数据的正常返回值
								 GetOverlappedResult ( *pReadHandle, &HidOverlapped, &dwNumberOfBytesRead, FALSE );
							 }
							 else
							 {
								 //							BOOL bGetTime = GetCommTimeouts(*pReadHandle, lpCommitTimes);
								 free(lpReadBuff);
								 CloseHandle(hEvent);
								 return -1;	// 等待超时
							 }

						 }
						 else
						 {
							 return -1;	// 不明错误
						 }
					 }
				 }
				 for(int i = 0; i < (len + 2); i ++){
					 byReadBuff[i] = *(lpReadBuff + i + 1);
				 }
				 dwResponseSW |= byReadBuff[len];

				 dwResponseSW = (dwResponseSW << 8) | (byReadBuff[len + 1]);
				 free(lpReadBuff);
				 CloseHandle(hEvent);
				 return	dwResponseSW;
			 }
Beispiel #15
0
//  rawhid_open - open 1 or more devices
//
//    Inputs:
//	max = maximum number of devices to open
//	vid = Vendor ID, or -1 if any
//	pid = Product ID, or -1 if any
//	usage_page = top level usage page, or -1 if any
//	usage = top level usage number, or -1 if any
//    Output:
//	actual number of devices opened
//
int rawhid_open(int max, int vid, int pid, int usage_page, int usage)
{
        GUID guid;
        HDEVINFO info;
        DWORD index=0, reqd_size;
        SP_DEVICE_INTERFACE_DATA iface;
        SP_DEVICE_INTERFACE_DETAIL_DATA *details;
        HIDD_ATTRIBUTES attrib;
        PHIDP_PREPARSED_DATA hid_data;
        HIDP_CAPS capabilities;
        HANDLE h;
        BOOL ret;
	hid_t *hid;
	int count=0;

	if (first_hid) free_all_hid();
	if (max < 1) return 0;
	if (!rx_event) {
		rx_event = CreateEvent(NULL, TRUE, TRUE, NULL);
		tx_event = CreateEvent(NULL, TRUE, TRUE, NULL);
		InitializeCriticalSection(&rx_mutex);
		InitializeCriticalSection(&tx_mutex);
	}
	HidD_GetHidGuid(&guid);
	info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
	if (info == INVALID_HANDLE_VALUE) return 0;
	for (index=0; 1 ;index++) {
		iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
		ret = SetupDiEnumDeviceInterfaces(info, NULL, &guid, index, &iface);
		if (!ret) return count;
		SetupDiGetInterfaceDeviceDetail(info, &iface, NULL, 0, &reqd_size, NULL);
		details = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(reqd_size);
		if (details == NULL) continue;

		memset(details, 0, reqd_size);
		details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
		ret = SetupDiGetDeviceInterfaceDetail(info, &iface, details,
			reqd_size, NULL, NULL);
		if (!ret) {
			free(details);
			continue;
		}
		h = CreateFile(details->DevicePath, GENERIC_READ|GENERIC_WRITE,
			FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
			OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
		free(details);
		if (h == INVALID_HANDLE_VALUE) continue;
		attrib.Size = sizeof(HIDD_ATTRIBUTES);
		ret = HidD_GetAttributes(h, &attrib);
		//printf("vid: %4x\n", attrib.VendorID);
		if (!ret || (vid > 0 && attrib.VendorID != vid) ||
		  (pid > 0 && attrib.ProductID != pid) ||
		  !HidD_GetPreparsedData(h, &hid_data)) {
			CloseHandle(h);
			continue;
		}
		if (!HidP_GetCaps(hid_data, &capabilities) ||
		  (usage_page > 0 && capabilities.UsagePage != usage_page) ||
		  (usage > 0 && capabilities.Usage != usage)) {
			HidD_FreePreparsedData(hid_data);
			CloseHandle(h);
			continue;
		}
		HidD_FreePreparsedData(hid_data);
		hid = (struct hid_struct *)malloc(sizeof(struct hid_struct));
		if (!hid) {
			CloseHandle(h);
			continue;
		}
		hid->handle = h;
		hid->open = 1;
		add_hid(hid);
		count++;
		if (count >= max) return count;
	}
	return count;
}
Beispiel #16
0
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;
}
Beispiel #17
0
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);
}
bool CLCDConnectionLogitech::HIDInit()
{
	if (GetConnectionState() != CONNECTED ||
		m_pConnectedDevice->GetIndex() != LGLCD_DEVICE_BW) //LGLCD_DEVICE_FAMILY_KEYBOARD_G15)
		return false;

	// Logitech G15 
	int VendorID = 0x046d;
	int ProductID = 0xc222;

	//Use a series of API calls to find a HID with a specified Vendor IF and Product ID.

	HIDD_ATTRIBUTES						Attributes;
	SP_DEVICE_INTERFACE_DATA			devInfoData;
	bool								LastDevice = FALSE;
	int									MemberIndex = 0;
	LONG								Result;

	DWORD Length = 0;
	PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
	HANDLE hDevInfo = NULL;
	GUID HidGuid;
	ULONG Required = 0;

	bool MyDeviceDetected = false;

	/*
	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.

	MemberIndex = 0;
	LastDevice = FALSE;

	do
	{
		/*
		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 doesn't retrieve or use the structure.
			If retrieving the structure, set
			MyDeviceInfoData.cbSize = length of MyDeviceInfoData.
			and pass the structure's 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.

			detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(Length);

			//Set cbSize in the detailData structure.

			detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

			//Call the function again, this time passing it the returned buffer size.

			Result = SetupDiGetDeviceInterfaceDetail
				(hDevInfo,
				&devInfoData,
				detailData,
				Length,
				&Required,
				NULL);

			// Open a handle to the device.
			// To enable retrieving information about a system mouse or keyboard,
			// don't request Read or Write access for this handle.

			/*
			API function: CreateFile
			Returns: a handle that enables reading and writing to the device.
			Requires:
			The DevicePath in the detailData structure
			returned by SetupDiGetDeviceInterfaceDetail.
			*/

			m_hHIDDeviceHandle = CreateFile
				(detailData->DevicePath,
				FILE_GENERIC_READ | FILE_GENERIC_WRITE,
				FILE_SHARE_READ | FILE_SHARE_WRITE,
				(LPSECURITY_ATTRIBUTES)NULL,
				OPEN_EXISTING,
				FILE_FLAG_OVERLAPPED,
				NULL);

			/*
			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're looking for.
			*/

			//Set the Size to the number of bytes in the structure.

			Attributes.Size = sizeof(Attributes);

			Result = HidD_GetAttributes
				(m_hHIDDeviceHandle,
				&Attributes);

			//Is it the desired device?
			MyDeviceDetected = FALSE;

			if (Attributes.VendorID == VendorID)
			{
				if (Attributes.ProductID == ProductID)
				{
					//Both the Vendor ID and Product ID match.
					MyDeviceDetected = TRUE;
				}
				else
					CloseHandle(m_hHIDDeviceHandle);

			}
			else
				CloseHandle(m_hHIDDeviceHandle);

			//Free the memory used by the detailData structure (no longer needed).
			free(detailData);
		}

		else
			LastDevice = TRUE;

		MemberIndex = MemberIndex + 1;
	} //do
	while ((LastDevice == FALSE) && (MyDeviceDetected == FALSE));

	if (MyDeviceDetected)
	{
		PHIDP_PREPARSED_DATA	PreparsedData;

		HidD_GetPreparsedData
			(m_hHIDDeviceHandle,
			&PreparsedData);

		HidP_GetCaps
			(PreparsedData,
			&m_HIDCapabilities);

		HidD_FreePreparsedData(PreparsedData);
	}
	//Free the memory reserved for hDevInfo by SetupDiClassDevs.

	SetupDiDestroyDeviceInfoList(hDevInfo);

	return MyDeviceDetected;
}
//  open - open 1 or more devices
//
//    Inputs:
//      max = maximum number of devices to open
//      vid = Vendor ID, or -1 if any
//      pid = Product ID, or -1 if any
//      usage_page = top level usage page, or -1 if any
//      usage = top level usage number, or -1 if any
//    Output:
//      actual number of devices opened
//
int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage)
{
        GUID guid;
        HDEVINFO info;
        DWORD index=0, reqd_size;
        SP_DEVICE_INTERFACE_DATA iface;
        SP_DEVICE_INTERFACE_DETAIL_DATA *details;
        HIDD_ATTRIBUTES attrib;
        PHIDP_PREPARSED_DATA hid_data;
        HIDP_CAPS capabilities;
        HANDLE h;
        BOOL ret;
        hid_t *hid;

        int count=0;

        if (first_hid) free_all_hid();

        if (max < 1) return 0;

        if (!rx_event)
        {
                rx_event = CreateEvent(NULL, TRUE, TRUE, NULL);
                tx_event = CreateEvent(NULL, TRUE, TRUE, NULL);
                InitializeCriticalSection(&rx_mutex);
                InitializeCriticalSection(&tx_mutex);
    }

        HidD_GetHidGuid(&guid);

        info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
        if (info == INVALID_HANDLE_VALUE) return 0;

        for (index=0; 1 ;index++)
        {
                iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
                ret = SetupDiEnumDeviceInterfaces(info, NULL, &guid, index, &iface);
                if (!ret) return count;

                SetupDiGetInterfaceDeviceDetail(info, &iface, NULL, 0, &reqd_size, NULL);
                details = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(reqd_size);
                if (details == NULL) continue;

                memset(details, 0, reqd_size);
                details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
                ret = SetupDiGetDeviceInterfaceDetail(info, &iface, details, reqd_size, NULL, NULL);
                if (!ret)
                {
                        free(details);
                        continue;
                }

                h = CreateFile(details->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
                if (h == INVALID_HANDLE_VALUE)
                {
                        DWORD err = GetLastError();

                        // I get ERROR_ACCESS_DENIED with most/all my input devices (mice/trackballs/tablet).
                        // Let's not log it :)
                        if (err == ERROR_ACCESS_DENIED)
                        {
                                free(details);
                                continue;
                        }

                        // qDebug wipes the GetLastError() it seems, so do that after print_win32_err().
                        print_win32_err(err);
                        qDebug() << "Problem opening handle, path: " << QString().fromWCharArray(details->DevicePath);

                        free(details);
                        continue;
                }

                free(details);

                attrib.Size = sizeof(HIDD_ATTRIBUTES);
                ret = HidD_GetAttributes(h, &attrib);
                //printf("vid: %4x\n", attrib.VendorID);
                if (!ret || (vid > 0 && attrib.VendorID != vid) ||
              (pid > 0 && attrib.ProductID != pid) ||
                          !HidD_GetPreparsedData(h, &hid_data))
                {
                        CloseHandle(h);
                        continue;
                }

                if (!HidP_GetCaps(hid_data, &capabilities) ||
              (usage_page > 0 && capabilities.UsagePage != usage_page) ||
                          (usage > 0 && capabilities.Usage != usage))
                {
                        HidD_FreePreparsedData(hid_data);
                        CloseHandle(h);
                        continue;
                }

                HidD_FreePreparsedData(hid_data);

                hid = (struct hid_struct *)malloc(sizeof(struct hid_struct));
                if (!hid)
                {
                        CloseHandle(h);
                        continue;
                }

//              COMMTIMEOUTS CommTimeouts;
//              CommTimeouts.ReadIntervalTimeout = 100;                 // 100ms
//              CommTimeouts.ReadTotalTimeoutConstant = 5;              // ms
//              CommTimeouts.ReadTotalTimeoutMultiplier = 1;    //
//              CommTimeouts.WriteTotalTimeoutConstant = 5;             // ms
//              CommTimeouts.WriteTotalTimeoutMultiplier = 1;   //
//              if (!SetCommTimeouts(h, &CommTimeouts))
//              {
////                    DWORD err = GetLastError();
//
//              }

                qDebug("Open: Handle address: %li for num: %i", (long int) h, count);

                hid->handle = h;
                add_hid(hid);

                count++;
                if (count >= max) return count;
        }

        return count;
}
Beispiel #20
0
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
{
	BOOL res;
	struct hid_device_info *root = NULL; /* return object */
	struct hid_device_info *cur_dev = NULL;

	/* Windows objects for interacting with the driver. */
	GUID InterfaceClassGuid;
	HidD_GetHidGuid(&InterfaceClassGuid);
	SP_DEVINFO_DATA devinfo_data;
	SP_DEVICE_INTERFACE_DATA device_interface_data;
	SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
	HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
	int device_index = 0;
	int i;

	if (hid_init() < 0)
		return NULL;

	/* Initialize the Windows objects. */
	memset(&devinfo_data, 0x0, sizeof(devinfo_data));
	devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
	device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

	/* Get information for all the devices belonging to the HID class. */
	device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

	/* Iterate over each device in the HID class, looking for the right one. */

	for (;;) {
		HANDLE write_handle = INVALID_HANDLE_VALUE;
		DWORD required_size = 0;
		HIDD_ATTRIBUTES attrib;

		res = SetupDiEnumDeviceInterfaces(device_info_set,
			NULL,
			&InterfaceClassGuid,
			device_index,
			&device_interface_data);

		if (!res) {
			/* A return of FALSE from this function means that
			   there are no more devices. */
			break;
		}

		/* Call with 0-sized detail size, and let the function
		   tell us how long the detail struct needs to be. The
		   size is put in &required_size. */
		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
			&device_interface_data,
			NULL,
			0,
			&required_size,
			NULL);

		/* Allocate a long enough structure for device_interface_detail_data. */
		device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);
		device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);

		/* Get the detailed data for this device. The detail data gives us
		   the device path for this device, which is then passed into
		   CreateFile() to get a handle to the device. */
		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
			&device_interface_data,
			device_interface_detail_data,
			required_size,
			NULL,
			NULL);

		if (!res) {
			/* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");
			   Continue to the next device. */
			goto cont;
		}

		/* Make sure this device is of Setup Class "HIDClass" and has a
		   driver bound to it. */
		for (i = 0; ; i++) {
			char driver_name[256];

			/* Populate devinfo_data. This function will return failure
			   when there are no more interfaces left. */
			res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
			if (!res)
				goto cont;

			res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
			               SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
			if (!res)
				goto cont;

			if (strcmp(driver_name, "HIDClass") == 0) {
				/* See if there's a driver bound. */
				res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
				           SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
				if (res)
					break;
			}
		}

		//wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);

		/* Open a handle to the device */
		write_handle = open_device(device_interface_detail_data->DevicePath, TRUE);

		/* Check validity of write_handle. */
		if (write_handle == INVALID_HANDLE_VALUE) {
			/* Unable to open the device. */
			//register_error(dev, "CreateFile");
			goto cont_close;
		}


		/* Get the Vendor ID and Product ID for this device. */
		attrib.Size = sizeof(HIDD_ATTRIBUTES);
		HidD_GetAttributes(write_handle, &attrib);
		//wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);

		/* Check the VID/PID to see if we should add this
		   device to the enumeration list. */
		if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
		    (product_id == 0x0 || attrib.ProductID == product_id)) {

			#define WSTR_LEN 512
			const char *str;
			struct hid_device_info *tmp;
			PHIDP_PREPARSED_DATA pp_data = NULL;
			HIDP_CAPS caps;
			BOOLEAN res;
			NTSTATUS nt_res;
			wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
			size_t len;

			/* VID/PID match. Create the record. */
			tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
			if (cur_dev) {
				cur_dev->next = tmp;
			}
			else {
				root = tmp;
			}
			cur_dev = tmp;

			/* Get the Usage Page and Usage for this device. */
			res = HidD_GetPreparsedData(write_handle, &pp_data);
			if (res) {
				nt_res = HidP_GetCaps(pp_data, &caps);
				if (nt_res == HIDP_STATUS_SUCCESS) {
					cur_dev->usage_page = caps.UsagePage;
					cur_dev->usage = caps.Usage;
				}

				HidD_FreePreparsedData(pp_data);
			}

			/* Fill out the record */
			cur_dev->next = NULL;
			str = device_interface_detail_data->DevicePath;
			if (str) {
				len = strlen(str);
				cur_dev->path = (char*) calloc(len+1, sizeof(char));
				strncpy(cur_dev->path, str, len+1);
				cur_dev->path[len] = '\0';
			}
			else
				cur_dev->path = NULL;

			/* Serial Number */
			res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr));
			wstr[WSTR_LEN-1] = 0x0000;
			if (res) {
				cur_dev->serial_number = _wcsdup(wstr);
			}

			/* Manufacturer String */
			res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr));
			wstr[WSTR_LEN-1] = 0x0000;
			if (res) {
				cur_dev->manufacturer_string = _wcsdup(wstr);
			}

			/* Product String */
			res = HidD_GetProductString(write_handle, wstr, sizeof(wstr));
			wstr[WSTR_LEN-1] = 0x0000;
			if (res) {
				cur_dev->product_string = _wcsdup(wstr);
			}

			/* VID/PID */
			cur_dev->vendor_id = attrib.VendorID;
			cur_dev->product_id = attrib.ProductID;

			/* Release Number */
			cur_dev->release_number = attrib.VersionNumber;

			/* Interface Number. It can sometimes be parsed out of the path
			   on Windows if a device has multiple interfaces. See
			   http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or
			   search for "Hardware IDs for HID Devices" at MSDN. If it's not
			   in the path, it's set to -1. */
			cur_dev->interface_number = -1;
			if (cur_dev->path) {
				char *interface_component = strstr(cur_dev->path, "&mi_");
				if (interface_component) {
					char *hex_str = interface_component + 4;
					char *endptr = NULL;
					cur_dev->interface_number = strtol(hex_str, &endptr, 16);
					if (endptr == hex_str) {
						/* The parsing failed. Set interface_number to -1. */
						cur_dev->interface_number = -1;
					}
				}
			}
		}

cont_close:
		CloseHandle(write_handle);
cont:
		/* We no longer need the detail data. It can be freed */
		free(device_interface_detail_data);

		device_index++;

	}

	/* Close the device information handle. */
	SetupDiDestroyDeviceInfoList(device_info_set);

	return root;

}