X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2Fadapter%2FPulse-Eight%2FUSBCECAdapterDetection.cpp;h=58bf4a562abd17697a85c15e5fe6bf99e2d237e9;hb=c3b3656087901ec8446206f54410de62612afc88;hp=f9969d83c08c16955250c5e867641751a4eb4cad;hpb=2b44051cbfa70deafc30d9767323214debbc1a75;p=deb_libcec.git diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp index f9969d8..58bf4a5 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp @@ -1,7 +1,7 @@ /* * This file is part of the libCEC(R) library. * - * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved. * libCEC(R) is an original work, containing original code. * * libCEC(R) is a trademark of Pulse-Eight Limited. @@ -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 @@ -57,12 +61,15 @@ extern "C" { #include } #elif defined(__FreeBSD__) +#include +#include #include #include #endif -#define CEC_VID 0x2548 -#define CEC_PID 0x1001 +#define CEC_VID 0x2548 +#define CEC_PID 0x1001 +#define CEC_PID2 0x1002 using namespace CEC; using namespace std; @@ -125,7 +132,79 @@ bool CUSBCECAdapterDetection::CanAutodetect(void) #endif } -uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */) +#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_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */) { uint8_t iFound(0); @@ -180,17 +259,24 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i kresult = IORegistryEntryGetParentEntry(parent, kIOServicePlane, &parent); IOObjectRelease(oldparent); } - if (strlen(bsdPath) && iVendor == CEC_VID && iProduct == CEC_PID) + if (strlen(bsdPath) && iVendor == CEC_VID && (iProduct == CEC_PID || iProduct == CEC_PID2)) { if (!strDevicePath || !strcmp(bsdPath, strDevicePath)) { // on darwin, the device path is the same as the comm path. - snprintf(deviceList[iFound ].path, sizeof(deviceList[iFound].path), "%s", bsdPath); - snprintf(deviceList[iFound++].comm, sizeof(deviceList[iFound].path), "%s", bsdPath); + if (iFound == 0 || strcmp(deviceList[iFound-1].strComName, bsdPath)) + { + snprintf(deviceList[iFound].strComPath, sizeof(deviceList[iFound].strComPath), "%s", bsdPath); + snprintf(deviceList[iFound].strComName, sizeof(deviceList[iFound].strComName), "%s", bsdPath); + deviceList[iFound].iVendorId = iVendor; + deviceList[iFound].iProductId = iProduct; + deviceList[iFound].adapterType = ADAPTERTYPE_P8_EXTERNAL; // will be overridden when not doing a "quick scan" by the actual type + iFound++; + } } } } - IOObjectRelease(serialService); + IOObjectRelease(serialService); } } IOObjectRelease(serialPortIterator); @@ -225,16 +311,20 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i int iVendor, iProduct; sscanf(udev_device_get_sysattr_value(pdev, "idVendor"), "%x", &iVendor); sscanf(udev_device_get_sysattr_value(pdev, "idProduct"), "%x", &iProduct); - if (iVendor == CEC_VID && iProduct == CEC_PID) + if (iVendor == CEC_VID && (iProduct == CEC_PID || iProduct == CEC_PID2)) { CStdString strPath(udev_device_get_syspath(pdev)); if (!strDevicePath || !strcmp(strPath.c_str(), strDevicePath)) { CStdString strComm(strPath); - if (FindComPort(strComm)) + if (FindComPort(strComm) && (iFound == 0 || strcmp(deviceList[iFound-1].strComName, strComm.c_str()))) { - snprintf(deviceList[iFound ].path, sizeof(deviceList[iFound].path), "%s", strPath.c_str()); - snprintf(deviceList[iFound++].comm, sizeof(deviceList[iFound].path), "%s", strComm.c_str()); + snprintf(deviceList[iFound].strComPath, sizeof(deviceList[iFound].strComPath), "%s", strPath.c_str()); + snprintf(deviceList[iFound].strComName, sizeof(deviceList[iFound].strComName), "%s", strComm.c_str()); + deviceList[iFound].iVendorId = iVendor; + deviceList[iFound].iProductId = iProduct; + deviceList[iFound].adapterType = ADAPTERTYPE_P8_EXTERNAL; // will be overridden when not doing a "quick scan" by the actual type + iFound++; } } } @@ -254,6 +344,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; @@ -269,6 +360,7 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i if(!bResult) { + // no (more) results SetupDiDestroyDeviceInfoList(hDevHandle); delete []buffer; buffer = NULL; @@ -297,9 +389,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); @@ -311,51 +405,116 @@ 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) - 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].strComName, sizeof(deviceList[iFound].strComName))) { - snprintf(deviceList[iFound ].path, sizeof(deviceList[iFound].path), "%s", devicedetailData->DevicePath); - snprintf(deviceList[iFound++].comm, sizeof(deviceList[iFound].path), "%s", strPortName); + snprintf(deviceList[iFound].strComPath, sizeof(deviceList[iFound].strComPath), "%s", devicedetailData->DevicePath); + deviceList[iFound].iVendorId = (uint16_t)iVendor; + deviceList[iFound].iProductId = (uint16_t)iProduct; + deviceList[iFound].adapterType = ADAPTERTYPE_P8_EXTERNAL; // will be overridden when not doing a "quick scan" by the actual type + iFound++; } } - - RegCloseKey(hDeviceKey); + else if (GetComPortFromHandle(hDevHandle, &devInfoData, deviceList[iFound].strComName, sizeof(deviceList[iFound].strComName))) + { + snprintf(deviceList[iFound].strComPath, sizeof(deviceList[iFound].strComPath), "%s", devicedetailData->DevicePath); + deviceList[iFound].iVendorId = (uint16_t)iVendor; + deviceList[iFound].iProductId = (uint16_t)iProduct; + deviceList[iFound].adapterType = ADAPTERTYPE_P8_EXTERNAL; // will be overridden when not doing a "quick scan" by the actual type + iFound++; + } } #elif defined(__FreeBSD__) char devicePath[PATH_MAX + 1]; + char infos[512]; + char sysctlname[32]; + char ttyname[8]; + char *pos; + size_t infos_size = sizeof(infos); int i; - for (i = 0; i < 8; ++i) + for (i = 0; ; ++i) { - (void)snprintf(devicePath, sizeof(devicePath), "/dev/ttyU%d", i); - if (!access(devicePath, 0)) - { - snprintf(deviceList[iFound ].path, sizeof(deviceList[iFound].path), "%s", devicePath); - snprintf(deviceList[iFound++].comm, sizeof(deviceList[iFound].path), "%s", devicePath); + unsigned int iVendor, iProduct; + memset(infos, 0, sizeof(infos)); + (void)snprintf(sysctlname, sizeof(sysctlname), + "dev.umodem.%d.%%pnpinfo", i); + if (sysctlbyname(sysctlname, infos, &infos_size, + NULL, 0) != 0) + break; + pos = strstr(infos, "vendor="); + if (pos == NULL) + continue; + sscanf(pos, "vendor=%x ", &iVendor); + + pos = strstr(infos, "product="); + if (pos == NULL) + continue; + sscanf(pos, "product=%x ", &iProduct); + + if (iVendor != CEC_VID || (iProduct != CEC_PID && iProduct != CEC_PID2)) + continue; + + pos = strstr(infos, "ttyname="); + if (pos == NULL) + continue; + sscanf(pos, "ttyname=%s ", ttyname); + + (void)snprintf(devicePath, sizeof(devicePath), + "/dev/tty%s", ttyname); + + if (strDevicePath) { + char currStrDevicePath[512]; + int port = 0; + int devaddr = 0; + memset(currStrDevicePath, 0, sizeof(currStrDevicePath)); + memset(infos, 0, sizeof(infos)); + (void)snprintf(sysctlname, sizeof(sysctlname), + "dev.umodem.%d.%%location", i); + if (sysctlbyname(sysctlname, infos, &infos_size, + NULL, 0) != 0) + break; + + pos = strstr(infos, "port="); + if (pos == NULL) + continue; + sscanf(pos, "port=%d ", &port); + + pos = strstr(infos, "devaddr="); + if (pos == NULL) + continue; + sscanf(pos, "devaddr=%d ", &devaddr); + + (void)snprintf(currStrDevicePath, sizeof(currStrDevicePath), + "/dev/ugen%d.%d", port, devaddr); + + if (strcmp(currStrDevicePath, strDevicePath) != 0) + continue; } + snprintf(deviceList[iFound].strComPath, sizeof(deviceList[iFound].strComPath), "%s", devicePath); + snprintf(deviceList[iFound].strComName, sizeof(deviceList[iFound].strComName), "%s", devicePath); + deviceList[iFound].iVendorId = iVendor; + deviceList[iFound].iProductId = iProduct; + deviceList[iFound].adapterType = ADAPTERTYPE_P8_EXTERNAL; // will be overridden when not doing a "quick scan" by the actual type + iFound++; } #else //silence "unused" warnings - void *tmp = (void*)deviceList; - tmp = (void *)strDevicePath; + ((void)deviceList); + ((void) strDevicePath); #endif - iBufSize = 0; /* silence "unused" warning on linux/osx */ + iBufSize = 0; if(!iBufSize){} /* silence "unused" warning on linux/osx */ return iFound; }