From 6407418d7cfd07ebe01087f314622863310b7a32 Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Thu, 30 Aug 2012 20:06:36 +0200 Subject: [PATCH] added device detection support for composite usb devices on windows. needs the windows ddk, and it's expected to be found in C:\WinDDK\7600.16385.1 --- project/libcec.vcxproj | 4 + .../Pulse-Eight/USBCECAdapterDetection.cpp | 112 +++++++++++++++--- 2 files changed, 99 insertions(+), 17 deletions(-) diff --git a/project/libcec.vcxproj b/project/libcec.vcxproj index 3c26ad7..dd529e1 100644 --- a/project/libcec.vcxproj +++ b/project/libcec.vcxproj @@ -159,19 +159,23 @@ $(SolutionDir)..\include;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\win7\i386;$(LibraryPath) $(SolutionDir)..\include;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\win7\amd64;$(LibraryPath) $(SolutionDir)..\build\ libcec $(SolutionDir)..\include;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\win7\i386;$(LibraryPath) $(SolutionDir)..\build\ $(ProjectName).x64 $(SolutionDir)..\include;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\win7\amd64;$(LibraryPath) diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp index 04daf46..4d408ad 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp @@ -46,10 +46,14 @@ #elif defined(__WINDOWS__) #pragma comment(lib, "advapi32.lib") #pragma comment(lib, "setupapi.lib") +#pragma comment(lib, "cfgmgr32.lib") #include +#include // the virtual COM port only shows up when requesting devices with the raw device guid! -static GUID USB_RAW_GUID = { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } }; +static GUID USB_RAW_GUID = { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } }; +static GUID USB_CDC_GUID = { 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }; + #elif defined(HAVE_LIBUDEV) #include #include @@ -126,6 +130,78 @@ bool CUSBCECAdapterDetection::CanAutodetect(void) #endif } +#if defined(__WINDOWS__) +static bool GetComPortFromHandle(HDEVINFO hDevHandle, PSP_DEVINFO_DATA devInfoData, char* strPortName, unsigned int iSize) +{ + bool bReturn(false); + TCHAR strRegPortName[256]; + strRegPortName[0] = _T('\0'); + DWORD dwSize = sizeof(strRegPortName); + DWORD dwType = 0; + + HKEY hDeviceKey = SetupDiOpenDevRegKey(hDevHandle, devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE); + if (!hDeviceKey) + return bReturn; + + // locate the PortName + if ((RegQueryValueEx(hDeviceKey, _T("PortName"), NULL, &dwType, reinterpret_cast(strRegPortName), &dwSize) == ERROR_SUCCESS) && + (dwType == REG_SZ) && + _tcslen(strRegPortName) > 3 && + _tcsnicmp(strRegPortName, _T("COM"), 3) == 0 && + _ttoi(&(strRegPortName[3])) > 0) + { + // return the port name + snprintf(strPortName, iSize, "%s", strRegPortName); + bReturn = true; + } + + RegCloseKey(hDeviceKey); + + return bReturn; +} + +static bool FindComPortForComposite(const char* strLocation, char* strPortName, unsigned int iSize) +{ + bool bReturn(false); + + // find all devices of the CDC class + HDEVINFO hDevHandle = SetupDiGetClassDevs(&USB_CDC_GUID, NULL, NULL, DIGCF_PRESENT); + if (hDevHandle == INVALID_HANDLE_VALUE) + return bReturn; + + // check all devices, whether they match the location or not + char strId[512]; + bool bGetNext(true); + for (int iPtr = 0; !bReturn && bGetNext && iPtr < 1024 ; iPtr++) + { + strId[0] = 0; + + SP_DEVINFO_DATA devInfoData; + devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + + // no more devices + if (!SetupDiEnumDeviceInfo(hDevHandle, iPtr, &devInfoData)) + bGetNext = false; + else + { + // check if the location of the _parent_ device matches + DEVINST parentDevInst; + if (CM_Get_Parent(&parentDevInst, devInfoData.DevInst, 0) == CR_SUCCESS) + { + CM_Get_Device_ID(parentDevInst, strId, 512, 0); + + // match + if (!strncmp(strId, strLocation, strlen(strLocation))) + bReturn = GetComPortFromHandle(hDevHandle, &devInfoData, strPortName, iSize); + } + } + } + + SetupDiDestroyDeviceInfoList(hDevHandle); + return bReturn; +} +#endif + uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */) { uint8_t iFound(0); @@ -258,6 +334,7 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i SP_DEVINFO_DATA devInfoData; devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + // find all devices if ((hDevHandle = SetupDiGetClassDevs(&USB_RAW_GUID, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)) == INVALID_HANDLE_VALUE) return iFound; @@ -273,6 +350,7 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i if(!bResult) { + // no (more) results SetupDiDestroyDeviceInfoList(hDevHandle); delete []buffer; buffer = NULL; @@ -301,9 +379,11 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i if(!bDetailResult) continue; + // check whether the path matches, if a path was given if (strDevicePath && strcmp(strDevicePath, devicedetailData->DevicePath) != 0) continue; + // get the vid and pid CStdString strVendorId; CStdString strProductId; CStdString strTmp(devicedetailData->DevicePath); @@ -315,30 +395,28 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i int iVendor, iProduct; sscanf(strVendorId, "%x", &iVendor); sscanf(strProductId, "%x", &iProduct); - if (iVendor != CEC_VID || (iProduct != CEC_PID && iProduct != CEC_PID2)) - continue; - HKEY hDeviceKey = SetupDiOpenDevRegKey(hDevHandle, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE); - if (!hDeviceKey) + // no match + if (iVendor != CEC_VID || (iProduct != CEC_PID && iProduct != CEC_PID2)) continue; - TCHAR strPortName[256]; - strPortName[0] = _T('\0'); - DWORD dwSize = sizeof(strPortName); - DWORD dwType = 0; - /* search the registry */ - if ((RegQueryValueEx(hDeviceKey, _T("PortName"), NULL, &dwType, reinterpret_cast(strPortName), &dwSize) == ERROR_SUCCESS) && (dwType == REG_SZ)) + if (iProduct == CEC_PID2) { - if (_tcslen(strPortName) > 3 && _tcsnicmp(strPortName, _T("COM"), 3) == 0 && - _ttoi(&(strPortName[3])) > 0) + // the 1002 pid indicates a composite device, that needs special treatment + char strId[512]; + CM_Get_Device_ID(devInfoData.DevInst, strId, 512, 0); + if (FindComPortForComposite(strId, deviceList[iFound].comm, sizeof(deviceList[iFound].comm))) { - snprintf(deviceList[iFound ].path, sizeof(deviceList[iFound].path), "%s", devicedetailData->DevicePath); - snprintf(deviceList[iFound++].comm, sizeof(deviceList[iFound].path), "%s", strPortName); + snprintf(deviceList[iFound].path, sizeof(deviceList[iFound].path), "%s", devicedetailData->DevicePath); + iFound++; } } - - RegCloseKey(hDeviceKey); + else if (GetComPortFromHandle(hDevHandle, &devInfoData, deviceList[iFound].comm, sizeof(deviceList[iFound].comm))) + { + snprintf(deviceList[iFound].path, sizeof(deviceList[iFound].path), "%s", devicedetailData->DevicePath); + iFound++; + } } #elif defined(__FreeBSD__) char devicePath[PATH_MAX + 1]; -- 2.34.1