#include "platform/os-dependent.h"
#include "util/StdString.h"
-#if !defined(__WINDOWS__)
+#if defined(__APPLE__)
#include <dirent.h>
-#include <libudev.h>
-#include <poll.h>
-#else
+#include <sys/param.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOMessage.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/serial/IOSerialKeys.h>
+#include <CoreFoundation/CoreFoundation.h>
+#elif defined(__WINDOWS__)
#include <setupapi.h>
// 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 } };
+#elif defined(HAVE_LIBUDEV)
+#include <dirent.h>
+#include <poll.h>
+extern "C" {
+#include <libudev.h>
+}
#endif
#define CEC_VID 0x2548
using namespace CEC;
using namespace std;
-#if !defined(__WINDOWS__)
+#if defined(HAVE_LIBUDEV)
bool TranslateComPort(CStdString &strString)
{
CStdString strTmp(strString);
}
#endif
-int CAdapterDetection::FindAdapters(vector<cec_adapter> &deviceList, const char *strDevicePath /* = NULL */)
+uint8_t CAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
{
- int iFound(0);
+ uint8_t iFound(0);
+
+#if defined(__APPLE__)
+ kern_return_t kresult;
+ char bsdPath[MAXPATHLEN] = {0};
+ io_iterator_t serialPortIterator;
+
+ CFMutableDictionaryRef classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
+ if (classesToMatch)
+ {
+ CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDModemType));
+ kresult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, &serialPortIterator);
+ if (kresult == KERN_SUCCESS)
+ {
+ io_object_t serialService;
+ while ((serialService = IOIteratorNext(serialPortIterator)))
+ {
+ int iVendor = 0, iProduct = 0;
+ CFTypeRef bsdPathAsCFString;
-#if !defined(__WINDOWS__)
+ // fetch the device path.
+ bsdPathAsCFString = IORegistryEntryCreateCFProperty(serialService,
+ CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
+ if (bsdPathAsCFString)
+ {
+ // convert the path from a CFString to a C (NUL-terminated) string.
+ CFStringGetCString((CFStringRef)bsdPathAsCFString, bsdPath, MAXPATHLEN - 1, kCFStringEncodingUTF8);
+ CFRelease(bsdPathAsCFString);
+
+ // now walk up the hierarchy until we find the entry with vendor/product IDs
+ io_registry_entry_t parent;
+ CFTypeRef vendorIdAsCFNumber = NULL;
+ CFTypeRef productIdAsCFNumber = NULL;
+ kern_return_t kresult = IORegistryEntryGetParentEntry(serialService, kIOServicePlane, &parent);
+ while (kresult == KERN_SUCCESS)
+ {
+ vendorIdAsCFNumber = IORegistryEntrySearchCFProperty(parent,
+ kIOServicePlane, CFSTR(kUSBVendorID), kCFAllocatorDefault, 0);
+ productIdAsCFNumber = IORegistryEntrySearchCFProperty(parent,
+ kIOServicePlane, CFSTR(kUSBProductID), kCFAllocatorDefault, 0);
+ if (vendorIdAsCFNumber && productIdAsCFNumber)
+ {
+ CFNumberGetValue((CFNumberRef)vendorIdAsCFNumber, kCFNumberIntType, &iVendor);
+ CFRelease(vendorIdAsCFNumber);
+ CFNumberGetValue((CFNumberRef)productIdAsCFNumber, kCFNumberIntType, &iProduct);
+ CFRelease(productIdAsCFNumber);
+ IOObjectRelease(parent);
+ break;
+ }
+ io_registry_entry_t oldparent = parent;
+ kresult = IORegistryEntryGetParentEntry(parent, kIOServicePlane, &parent);
+ IOObjectRelease(oldparent);
+ }
+ if (strlen(bsdPath) && iVendor == CEC_VID && iProduct == CEC_PID)
+ {
+ 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);
+ }
+ }
+ }
+ IOObjectRelease(serialService);
+ }
+ }
+ IOObjectRelease(serialPortIterator);
+ }
+#elif defined(HAVE_LIBUDEV)
struct udev *udev;
if (!(udev = udev_new()))
return -1;
struct udev_enumerate *enumerate;
struct udev_list_entry *devices, *dev_list_entry;
- struct udev_device *dev;
+ struct udev_device *dev, *pdev;
enumerate = udev_enumerate_new(udev);
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
if (!dev)
continue;
- dev = udev_device_get_parent(udev_device_get_parent(dev));
- if (!dev)
- continue;
- if (!udev_device_get_sysattr_value(dev,"idVendor") || !udev_device_get_sysattr_value(dev, "idProduct"))
+ pdev = udev_device_get_parent(udev_device_get_parent(dev));
+ if (!pdev || !udev_device_get_sysattr_value(pdev,"idVendor") || !udev_device_get_sysattr_value(pdev, "idProduct"))
{
udev_device_unref(dev);
continue;
}
int iVendor, iProduct;
- sscanf(udev_device_get_sysattr_value(dev, "idVendor"), "%x", &iVendor);
- sscanf(udev_device_get_sysattr_value(dev, "idProduct"), "%x", &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)
{
- CStdString strPath(udev_device_get_syspath(dev));
- if (strDevicePath && strcmp(strPath.c_str(), strDevicePath))
- continue;
-
- CStdString strComm(strPath);
- if (FindComPort(strComm))
+ CStdString strPath(udev_device_get_syspath(pdev));
+ if (!strDevicePath || !strcmp(strPath.c_str(), strDevicePath))
{
- cec_adapter foundDev;
- foundDev.path = strPath;
- foundDev.comm = strComm;
- deviceList.push_back(foundDev);
- ++iFound;
+ CStdString strComm(strPath);
+ if (FindComPort(strComm))
+ {
+ snprintf(deviceList[iFound ].path, sizeof(deviceList[iFound].path), "%s", strPath.c_str());
+ snprintf(deviceList[iFound++].comm, sizeof(deviceList[iFound].path), "%s", strComm.c_str());
+ }
}
}
udev_device_unref(dev);
udev_enumerate_unref(enumerate);
udev_unref(udev);
-#else
+#elif defined(__WINDOWS__)
HDEVINFO hDevHandle;
DWORD required = 0, iMemberIndex = 0;
int nBufferSize = 0;
BOOL bResult = true;
TCHAR *buffer = NULL;
PSP_DEVICE_INTERFACE_DETAIL_DATA devicedetailData;
- while(bResult)
+ while(bResult && iFound < iBufSize)
{
bResult = SetupDiEnumDeviceInfo(hDevHandle, iMemberIndex, &devInfoData);
CStdString strVendorId;
CStdString strProductId;
CStdString strTmp(devicedetailData->DevicePath);
- strVendorId = strTmp.substr(strTmp.Find("vid_") + 4, 4);
- strProductId = strTmp.substr(strTmp.Find("pid_") + 4, 4);
+ strVendorId.assign(strTmp.substr(strTmp.Find("vid_") + 4, 4));
+ strProductId.assign(strTmp.substr(strTmp.Find("pid_") + 4, 4));
if (strTmp.Find("&mi_") >= 0 && strTmp.Find("&mi_00") < 0)
continue;
if (_tcslen(strPortName) > 3 && _tcsnicmp(strPortName, _T("COM"), 3) == 0 &&
_ttoi(&(strPortName[3])) > 0)
{
- cec_adapter foundDev;
- foundDev.path = devicedetailData->DevicePath;
- foundDev.comm = strPortName;
- deviceList.push_back(foundDev);
- ++iFound;
+ snprintf(deviceList[iFound ].path, sizeof(deviceList[iFound].path), "%s", devicedetailData->DevicePath);
+ snprintf(deviceList[iFound++].comm, sizeof(deviceList[iFound].path), "%s", strPortName);
}
}
}
#endif
+ iBufSize = 0; /* silence "unused" warning on linux/osx */
+
return iFound;
}