cec: silence all 'unused' compiler warnings
[deb_libcec.git] / src / lib / AdapterDetection.cpp
index 747ea16d24565f882e1890a9cad50c07326007f5..f06809975abc49300558e06780b4445633f6dd6c 100644 (file)
  */
 
 #include "AdapterDetection.h"
-#include "libPlatform/os-dependent.h"
+#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
@@ -51,7 +62,7 @@ static GUID USB_RAW_GUID =  { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0x
 using namespace CEC;
 using namespace std;
 
-#if !defined(__WINDOWS__)
+#if defined(HAVE_LIBUDEV)
 bool TranslateComPort(CStdString &strString)
 {
   CStdString strTmp(strString);
@@ -100,18 +111,84 @@ bool FindComPort(CStdString &strLocation)
 }
 #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);
@@ -124,32 +201,27 @@ int CAdapterDetection::FindAdapters(vector<cec_adapter> &deviceList, const char
     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);
@@ -157,7 +229,7 @@ int CAdapterDetection::FindAdapters(vector<cec_adapter> &deviceList, const char
 
   udev_enumerate_unref(enumerate);
   udev_unref(udev);
-#else
+#elif defined(__WINDOWS__)
   HDEVINFO hDevHandle;
   DWORD    required = 0, iMemberIndex = 0;
   int      nBufferSize = 0;
@@ -174,7 +246,7 @@ int CAdapterDetection::FindAdapters(vector<cec_adapter> &deviceList, const char
   BOOL bResult = true;
   TCHAR *buffer = NULL;
   PSP_DEVICE_INTERFACE_DETAIL_DATA devicedetailData;
-  while(bResult)
+  while(bResult && iFound < iBufSize)
   {
     bResult = SetupDiEnumDeviceInfo(hDevHandle, iMemberIndex, &devInfoData);
 
@@ -217,8 +289,8 @@ int CAdapterDetection::FindAdapters(vector<cec_adapter> &deviceList, const char
     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;
 
@@ -243,11 +315,8 @@ int CAdapterDetection::FindAdapters(vector<cec_adapter> &deviceList, const char
       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);
       }
     }
 
@@ -255,5 +324,7 @@ int CAdapterDetection::FindAdapters(vector<cec_adapter> &deviceList, const char
   }
 #endif
 
+  iBufSize = 0; /* silence "unused" warning on linux/osx */
+
   return iFound;
 }