Merge PR #31
authorLars Op den Kamp <lars@opdenkamp.eu>
Fri, 24 Oct 2014 19:40:44 +0000 (21:40 +0200)
committerLars Op den Kamp <lars@opdenkamp.eu>
Fri, 24 Oct 2014 19:40:44 +0000 (21:40 +0200)
20 files changed:
configure.ac
include/cectypes.h
src/lib/Makefile.am
src/lib/adapter/AdapterFactory.cpp
src/lib/adapter/Exynos/ExynosCEC.h [new file with mode: 0644]
src/lib/adapter/Exynos/ExynosCECAdapterCommunication.cpp [new file with mode: 0644]
src/lib/adapter/Exynos/ExynosCECAdapterCommunication.h [new file with mode: 0644]
src/lib/adapter/Exynos/ExynosCECAdapterDetection.cpp [new file with mode: 0644]
src/lib/adapter/Exynos/ExynosCECAdapterDetection.h [new file with mode: 0644]
src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp
src/lib/adapter/RPi/RPiCECAdapterCommunication.h
src/lib/adapter/RPi/RPiCECAdapterMessageQueue.cpp
src/lib/adapter/RPi/RPiCECAdapterMessageQueue.h
src/lib/implementations/ANCommandHandler.cpp
src/lib/implementations/ANCommandHandler.h
src/lib/implementations/CECCommandHandler.cpp
src/lib/implementations/CECCommandHandler.h
src/lib/platform/X11/randr-edid.cpp [new file with mode: 0644]
src/lib/platform/X11/randr-edid.h [new file with mode: 0644]
src/lib/platform/posix/os-edid.cpp

index 510d851ccdac9d91d6bb6363944ff7e828ec39b4..cb952f376033b67f18b8b98fb9989739ffe3655b 100644 (file)
@@ -57,6 +57,13 @@ AC_ARG_WITH([tda995x-toolkit-path],
   [TDA995X_CFLAGS="-I$withval/inc"],
   [TDA995X_CFLAGS="-I\$(abs_top_srcdir)/nxp_hdmi/inc"])
 
+## Exynos support
+AC_ARG_ENABLE([exynos],
+  [AS_HELP_STRING([--enable-exynos],
+  [enable support for the Exynos (default is yes)])],
+  [use_exynos=$enableval],
+  [use_exynos=yes])
+
 ## Raspberry Pi support
 AC_ARG_ENABLE([rpi],
   [AS_HELP_STRING([--enable-rpi],
@@ -206,6 +213,20 @@ case "${host}" in
         LIBS="$libs_pre_rpi"
       fi
     fi
+    ## search for X11/xrandr
+    libs_tmp="$LIBS"
+    use_x11_xrandr="yes"
+    AC_CHECK_HEADER(X11/Xlib.h,,[use_x11_xrandr="no"])
+    AC_CHECK_HEADER(X11/Xatom.h,,[use_x11_xrandr="no"])
+    AC_CHECK_HEADER(X11/extensions/Xrandr.h,,[use_x11_xrandr="no"])
+    AC_CHECK_LIB(X11,XOpenDisplay,,[use_x11_xrandr="no"])
+    AC_CHECK_LIB(Xrandr,XRRGetScreenResources,,[use_x11_xrandr="no"])
+    if test "x$use_x11_xrandr" = "xyes"; then
+      AC_DEFINE([HAVE_RANDR],[1],[Define to 1 to include support for the X11 randr extension])
+      AM_CONDITIONAL(USE_X11_RANDR, true)
+    else
+      LIBS="$libs_tmp"
+    fi
     ;;
   *-apple-darwin*)
     AC_CHECK_HEADER(mach/mach_time.h,,AC_MSG_ERROR($msg_required_header_missing))
@@ -270,6 +291,19 @@ else
   features="$features\n  TDA995x support :\t\t\tno"
 fi
 
+## mark Exynos support as available
+if test "x$use_exynos" != "xno"; then
+  AC_DEFINE([HAVE_EXYNOS_API],[1],[Define to 1 to include Exynos support])
+  AM_CONDITIONAL(USE_EXYNOS_API, true)
+  features="$features\n  Exynos support :\t\t\tyes"
+  LIB_INFO="$LIB_INFO 'EXYNOS'"
+  CPPFLAGS="$CPPFLAGS $EXYNOS_CFLAGS"
+else
+  AM_CONDITIONAL(USE_EXYNOS_API, false)
+  features="$features\n  EXYNOS support :\t\t\tno"
+fi
+
+
 ## check if our build system is complete
 AC_CHECK_HEADER(algorithm,,AC_MSG_ERROR($msg_required_header_missing))
 AC_CHECK_HEADER(ctype.h,,AC_MSG_ERROR($msg_required_header_missing))
index 929d85ccd3d6bafad7ee16ff373da9d005f6b2ec..bb1015dbec6b282361026609b826a1b0128aac26 100644 (file)
@@ -294,6 +294,16 @@ namespace CEC {
  */
 #define CEC_TDA995x_VIRTUAL_COM                "CuBox"
 
+/*!
+ * the path to use for the Exynos HDMI CEC device
+ */
+#define CEC_EXYNOS_PATH                "/dev/CEC"
+
+/*!
+ * the name of the virtual COM port to use for the EXYNOS' CEC wire
+ */
+#define CEC_EXYNOS_VIRTUAL_COM         "Exynos"
+
 /*!
  * Mimimum client version
  */
@@ -859,7 +869,8 @@ typedef enum cec_adapter_type
   ADAPTERTYPE_P8_EXTERNAL      = 0x1,
   ADAPTERTYPE_P8_DAUGHTERBOARD = 0x2,
   ADAPTERTYPE_RPI              = 0x100,
-  ADAPTERTYPE_TDA995x          = 0x200
+  ADAPTERTYPE_TDA995x          = 0x200,
+  ADAPTERTYPE_EXYNOS           = 0x300
 } cec_adapter_type;
 
 typedef struct cec_menu_language
index 9117d8ebf3ce8fb7e9880b8b3497b4b8e3b946aa..bd9598fdaeefe4256fce22cbbd34462368a232ef 100644 (file)
@@ -44,6 +44,10 @@ libcec_la_SOURCES += adapter/Pulse-Eight/USBCECAdapterMessage.cpp \
                      platform/posix/os-edid.cpp \
                      platform/adl/adl-edid.cpp \
                      platform/nvidia/nv-edid.cpp
+if USE_X11_RANDR
+libcec_la_SOURCES += platform/X11/randr-edid.cpp
+endif
+
 endif
 
 ## Raspberry Pi support
@@ -59,5 +63,10 @@ libcec_la_SOURCES += adapter/TDA995x/TDA995xCECAdapterDetection.cpp \
                      adapter/TDA995x/TDA995xCECAdapterCommunication.cpp
 endif
 
+## Exynos support
+if USE_EXYNOS_API
+libcec_la_SOURCES += adapter/Exynos/ExynosCECAdapterDetection.cpp \
+                     adapter/Exynos/ExynosCECAdapterCommunication.cpp
+endif
 
 libcec_la_LDFLAGS = @LIBS_LIBCEC@ -version-info @VERSION@
index 42cdd0beacb7b088cd3a8935c09d9ad38d536121..d585154212245e87332eed7bc7e63a861a2a07a4 100644 (file)
 #include "TDA995x/TDA995xCECAdapterCommunication.h"
 #endif
 
+#if defined(HAVE_EXYNOS_API)
+#include "Exynos/ExynosCECAdapterDetection.h"
+#include "Exynos/ExynosCECAdapterCommunication.h"
+#endif
+
 using namespace std;
 using namespace CEC;
 
@@ -109,6 +114,19 @@ int8_t CAdapterFactory::DetectAdapters(cec_adapter_descriptor *deviceList, uint8
   }
 #endif
 
+#if defined(HAVE_EXYNOS_API)
+  if (iAdaptersFound < iBufSize && CExynosCECAdapterDetection::FindAdapter())
+  {
+    snprintf(deviceList[iAdaptersFound].strComPath, sizeof(deviceList[iAdaptersFound].strComPath), CEC_EXYNOS_PATH);
+    snprintf(deviceList[iAdaptersFound].strComName, sizeof(deviceList[iAdaptersFound].strComName), CEC_EXYNOS_VIRTUAL_COM);
+    deviceList[iAdaptersFound].iVendorId = 0;
+    deviceList[iAdaptersFound].iProductId = 0;
+    deviceList[iAdaptersFound].adapterType = ADAPTERTYPE_EXYNOS;
+    iAdaptersFound++;
+  }
+#endif
+
+
 #if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) && !defined(HAVE_TDA995X_API)
 #error "libCEC doesn't have support for any type of adapter. please check your build system or configuration"
 #endif
@@ -123,6 +141,11 @@ IAdapterCommunication *CAdapterFactory::GetInstance(const char *strPort, uint16_
     return new CTDA995xCECAdapterCommunication(m_lib->m_cec);
 #endif
 
+#if defined(HAVE_EXYNOS_API)
+  if (!strcmp(strPort, CEC_EXYNOS_VIRTUAL_COM))
+    return new CExynosCECAdapterCommunication(m_lib->m_cec);
+#endif
+
 #if defined(HAVE_RPI_API)
   if (!strcmp(strPort, CEC_RPI_VIRTUAL_COM))
     return new CRPiCECAdapterCommunication(m_lib->m_cec);
@@ -132,7 +155,7 @@ IAdapterCommunication *CAdapterFactory::GetInstance(const char *strPort, uint16_
   return new CUSBCECAdapterCommunication(m_lib->m_cec, strPort, iBaudRate);
 #endif
 
-#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) && !defined(HAVE_TDA995X_API)
+#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) && !defined(HAVE_TDA995X_API) && !defined(HAVE_EXYNOS_API)
   return NULL;
 #endif
 }
diff --git a/src/lib/adapter/Exynos/ExynosCEC.h b/src/lib/adapter/Exynos/ExynosCEC.h
new file mode 100644 (file)
index 0000000..55e1eec
--- /dev/null
@@ -0,0 +1,39 @@
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC Exynos Code is Copyright (C) 2014 Valentin Manea
+ * 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.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+
+#define CEC_DEFAULT_PADDR   0x1000
+#define CEC_PADDR_NAME      "/sys/module/s5p_hdmi/parameters/source_phy_addr"
+#define CEC_IOC_SETLADDR    _IOW('c', 0, unsigned int)
+#define CEC_MAX_FRAME_SIZE  16
diff --git a/src/lib/adapter/Exynos/ExynosCECAdapterCommunication.cpp b/src/lib/adapter/Exynos/ExynosCECAdapterCommunication.cpp
new file mode 100644 (file)
index 0000000..86e306b
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC Exynos Code is Copyright (C) 2014 Valentin Manea
+ * 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.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+
+#if defined(HAVE_EXYNOS_API)
+#include "ExynosCEC.h"
+#include "ExynosCECAdapterCommunication.h"
+
+#include "lib/CECTypeUtils.h"
+#include "lib/LibCEC.h"
+#include "lib/platform/util/StdString.h"
+#include "lib/platform/util/buffer.h"
+
+using namespace std;
+using namespace CEC;
+using namespace PLATFORM;
+
+#define LIB_CEC m_callback->GetLib()
+
+
+CExynosCECAdapterCommunication::CExynosCECAdapterCommunication(IAdapterCommunicationCallback *callback) :
+    IAdapterCommunication(callback),
+    m_bLogicalAddressChanged(false)
+{ 
+  CLockObject lock(m_mutex);
+
+  m_logicalAddresses.Clear();
+  m_fd = INVALID_SOCKET_VALUE;
+}
+
+
+CExynosCECAdapterCommunication::~CExynosCECAdapterCommunication(void)
+{
+  Close();
+}
+
+
+bool CExynosCECAdapterCommunication::IsOpen(void)
+{
+  return IsInitialised() && m_fd != INVALID_SOCKET_VALUE;
+}
+
+
+bool CExynosCECAdapterCommunication::Open(uint32_t UNUSED(iTimeoutMs), bool UNUSED(bSkipChecks), bool bStartListening)
+{
+  if (m_fd != INVALID_SOCKET_VALUE)
+    close(m_fd);
+
+  if ((m_fd = open(CEC_EXYNOS_PATH, O_RDWR)) > 0)
+  {
+    if (!bStartListening || CreateThread()) {
+        return true;
+    }
+    close(m_fd);
+  }
+  return false;
+}
+
+
+void CExynosCECAdapterCommunication::Close(void)
+{
+  StopThread(0);
+
+  close(m_fd);
+  m_fd = INVALID_SOCKET_VALUE;
+}
+
+
+std::string CExynosCECAdapterCommunication::GetError(void) const
+{
+  std::string strError(m_strError);
+  return strError;
+}
+
+
+cec_adapter_message_state CExynosCECAdapterCommunication::Write(
+  const cec_command &data, bool &UNUSED(bRetry), uint8_t UNUSED(iLineTimeout), bool UNUSED(bIsReply))
+{
+  uint8_t buffer[CEC_MAX_FRAME_SIZE];
+  int32_t size = 1;
+  cec_adapter_message_state rc = ADAPTER_MESSAGE_STATE_ERROR;
+
+  if (!IsOpen())
+    return rc;
+
+  if ((size_t)data.parameters.size + data.opcode_set > sizeof(buffer))
+  {
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: data size too large !", __func__);
+    return ADAPTER_MESSAGE_STATE_ERROR;
+  }
+  buffer[0] = (data.initiator << 4) | (data.destination & 0x0f);
+
+  if (data.opcode_set)
+  {
+    buffer[1] = data.opcode;
+    size++;
+
+    memcpy(&buffer[size], data.parameters.data, data.parameters.size);
+    size += data.parameters.size;
+  }
+
+  if (write(m_fd, (void *)buffer, size) == size)
+  {
+    rc = ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  }
+  else
+  {
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: write failed !", __func__);
+  }
+
+  return rc;
+}
+
+
+uint16_t CExynosCECAdapterCommunication::GetFirmwareVersion(void)
+{
+  return 0;
+}
+
+
+cec_vendor_id CExynosCECAdapterCommunication::GetVendorId(void)
+{
+  return cec_vendor_id(CEC_VENDOR_SAMSUNG);
+}
+
+
+uint16_t CExynosCECAdapterCommunication::GetPhysicalAddress(void)
+{
+  uint16_t phys_addr = CEC_DEFAULT_PADDR;
+
+  FILE *f = fopen(CEC_PADDR_NAME, "r");
+  if(f) {
+    if(fscanf(f, "%hu", &phys_addr) != 1)
+      phys_addr = CEC_DEFAULT_PADDR;
+
+    fclose(f);
+  }
+  return phys_addr;
+}
+
+
+cec_logical_addresses CExynosCECAdapterCommunication::GetLogicalAddresses(void)
+{
+  return m_logicalAddresses;
+}
+
+
+bool CExynosCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses)
+{
+  unsigned int log_addr = addresses.primary;
+  CLockObject lock(m_mutex);
+
+  if (!IsOpen())
+    return false;
+
+  if (ioctl(m_fd, CEC_IOC_SETLADDR, &log_addr))
+  {
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: IOCTL SetLogicalAddr failed !", __func__);
+    return false;
+  }
+  m_logicalAddresses = addresses;
+  m_bLogicalAddressChanged = true;
+
+  return true;
+}
+
+
+void CExynosCECAdapterCommunication::HandleLogicalAddressLost(cec_logical_address UNUSED(oldAddress))
+{
+  unsigned int log_addr = CECDEVICE_BROADCAST;
+  if (ioctl(m_fd, CEC_IOC_SETLADDR, &log_addr))
+  {
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: IOCTL SetLogicalAddr failed !", __func__);
+  }
+}
+
+
+void *CExynosCECAdapterCommunication::Process(void)
+{
+  uint8_t buffer[CEC_MAX_FRAME_SIZE];
+  uint32_t size;
+  fd_set rfds;
+  cec_logical_address initiator, destination;
+
+  if (!IsOpen())
+    return 0;
+
+  FD_ZERO(&rfds);
+  FD_SET(m_fd, &rfds);
+
+  while (!IsStopped())
+  {
+    if (select(m_fd + 1, &rfds, NULL, NULL, NULL) >= 0 )
+    {
+      size = read(m_fd, buffer, CEC_MAX_FRAME_SIZE);
+
+      if (size > 0)
+      {
+          initiator = cec_logical_address(buffer[0] >> 4);
+          destination = cec_logical_address(buffer[0] & 0x0f);
+
+          cec_command cmd;
+
+          cec_command::Format(
+            cmd, initiator, destination,
+            ( size > 1 ) ? cec_opcode(buffer[1]) : CEC_OPCODE_NONE);
+
+          for( uint8_t i = 2; i < size; i++ )
+            cmd.parameters.PushBack(buffer[i]);
+
+          if (!IsStopped())
+            m_callback->OnCommandReceived(cmd);
+      }
+    }
+
+  }
+
+  return 0;
+}
+
+#endif // HAVE_EXYNOS_API
diff --git a/src/lib/adapter/Exynos/ExynosCECAdapterCommunication.h b/src/lib/adapter/Exynos/ExynosCECAdapterCommunication.h
new file mode 100644 (file)
index 0000000..e23487d
--- /dev/null
@@ -0,0 +1,101 @@
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC Exynos Code is Copyright (C) 2014 Valentin Manea
+ * 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.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#if defined(HAVE_EXYNOS_API)
+
+#include "lib/platform/threads/mutex.h"
+#include "lib/platform/threads/threads.h"
+#include "lib/adapter/AdapterCommunication.h"
+#include <map>
+
+namespace CEC
+{
+  class CExynosCECAdapterCommunication : public IAdapterCommunication, public PLATFORM::CThread
+  {
+  public:
+    /*!
+     * @brief Create a new Exynos HDMI CEC communication handler.
+     * @param callback The callback to use for incoming CEC commands.
+     */
+    CExynosCECAdapterCommunication(IAdapterCommunicationCallback *callback);
+    virtual ~CExynosCECAdapterCommunication(void);
+
+    /** @name IAdapterCommunication implementation */
+    ///{
+    bool Open(uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT, bool bSkipChecks = false, bool bStartListening = true);
+    void Close(void);
+    bool IsOpen(void);
+    std::string GetError(void) const;
+    cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply);
+
+    bool SetLineTimeout(uint8_t UNUSED(iTimeout)) { return true; }
+    bool StartBootloader(void) { return false; }
+    bool SetLogicalAddresses(const cec_logical_addresses &addresses);
+    cec_logical_addresses GetLogicalAddresses(void);
+    bool PingAdapter(void) { return IsInitialised(); }
+    uint16_t GetFirmwareVersion(void);
+    uint32_t GetFirmwareBuildDate(void) { return 0; }
+    bool IsRunningLatestFirmware(void) { return true; }
+    bool PersistConfiguration(const libcec_configuration & UNUSED(configuration)) { return false; }
+    bool GetConfiguration(libcec_configuration & UNUSED(configuration)) { return false; }
+    std::string GetPortName(void) { return std::string("EXYNOS"); }
+    uint16_t GetPhysicalAddress(void);
+    bool SetControlledMode(bool UNUSED(controlled)) { return true; }
+    cec_vendor_id GetVendorId(void);
+    bool SupportsSourceLogicalAddress(const cec_logical_address address) { return address > CECDEVICE_TV && address <= CECDEVICE_BROADCAST; }
+    cec_adapter_type GetAdapterType(void) { return ADAPTERTYPE_EXYNOS; }
+    uint16_t GetAdapterVendorId(void) const { return 1; }
+    uint16_t GetAdapterProductId(void) const { return 1; }
+    void HandleLogicalAddressLost(cec_logical_address oldAddress);
+    void SetActiveSource(bool UNUSED(bSetTo), bool UNUSED(bClientUnregistered)) {}
+    ///}
+
+    /** @name PLATFORM::CThread implementation */
+    ///{
+    void *Process(void);
+    ///}
+
+  private:
+    bool IsInitialised(void) const { return 1; };
+
+    std::string                 m_strError; /**< current error message */
+
+    bool                        m_bLogicalAddressChanged;
+    cec_logical_addresses       m_logicalAddresses;
+
+    PLATFORM::CMutex            m_mutex;
+    int                         m_fd;
+  };
+};
+#endif
diff --git a/src/lib/adapter/Exynos/ExynosCECAdapterDetection.cpp b/src/lib/adapter/Exynos/ExynosCECAdapterDetection.cpp
new file mode 100644 (file)
index 0000000..4daf191
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC Exynos Code is Copyright (C) 2014 Valentin Manea
+ * 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.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <stdio.h>
+
+#if defined(HAVE_EXYNOS_API)
+#include "ExynosCECAdapterDetection.h"
+#include "ExynosCEC.h"
+
+using namespace CEC;
+
+bool CExynosCECAdapterDetection::FindAdapter(void)
+{
+  return access(CEC_EXYNOS_PATH, 0) == 0;
+}
+
+#endif
diff --git a/src/lib/adapter/Exynos/ExynosCECAdapterDetection.h b/src/lib/adapter/Exynos/ExynosCECAdapterDetection.h
new file mode 100644 (file)
index 0000000..901496b
--- /dev/null
@@ -0,0 +1,42 @@
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC Exynos Code is Copyright (C) 2014 Valentin Manea
+ * 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.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+namespace CEC
+{
+  class CExynosCECAdapterDetection
+  {
+  public:
+    static bool FindAdapter(void);
+  };
+}
index 76c61b3bb5a2fb922cf206cc7cbafd011d5c9c62..9af5357602ae5b32597c383ff0b4845f7d3a66e6 100644 (file)
@@ -78,7 +78,9 @@ CRPiCECAdapterCommunication::CRPiCECAdapterCommunication(IAdapterCommunicationCa
 CRPiCECAdapterCommunication::~CRPiCECAdapterCommunication(void)
 {
   delete(m_queue);
+  UnregisterLogicalAddress();
   Close();
+  vc_cec_set_passive(false);
 }
 
 const char *ToString(const VC_CEC_ERROR_T error)
@@ -212,6 +214,7 @@ void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, u
       {
         m_bLogicalAddressChanged = true;
         m_logicalAddress = (cec_logical_address)(p0 & 0xF);
+        m_bLogicalAddressRegistered = true;
         LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address changed to %s (%x)", LIB_CEC->ToString(m_logicalAddress), m_logicalAddress);
       }
       else
@@ -224,8 +227,9 @@ void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, u
     break;
   case VC_CEC_LOGICAL_ADDR_LOST:
     {
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical %s (%x) address lost", LIB_CEC->ToString(m_logicalAddress), m_logicalAddress);
       // the logical address was taken by another device
-      cec_logical_address previousAddress = m_logicalAddress == CECDEVICE_BROADCAST ? m_previousLogicalAddress : m_logicalAddress;
+      cec_logical_address previousAddress = m_logicalAddress == CECDEVICE_FREEUSE ? m_previousLogicalAddress : m_logicalAddress;
       m_logicalAddress = CECDEVICE_UNKNOWN;
 
       // notify libCEC that we lost our LA when the connection was initialised
@@ -305,23 +309,18 @@ bool CRPiCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONN
     vc_cec_register_callback(rpi_cec_callback, (void*)this);
     vc_tv_register_callback(rpi_tv_callback, (void*)this);
 
-    // release previous LA
-    vc_cec_release_logical_address();
-    if (!m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged, iTimeoutMs))
-    {
-      LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to release the previous LA");
-      return false;
-    }
-
     // register LA "freeuse"
-    if (RegisterLogicalAddress(CECDEVICE_FREEUSE))
+    if (RegisterLogicalAddress(CECDEVICE_FREEUSE, iTimeoutMs))
     {
       LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - vc_cec initialised", __FUNCTION__);
       CLockObject lock(m_mutex);
       m_bInitialised = true;
     }
     else
+    {
       LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - vc_cec could not be initialised", __FUNCTION__);
+      return false;
+    }
   }
 
   return true;
@@ -346,19 +345,10 @@ uint16_t CRPiCECAdapterCommunication::GetPhysicalAddress(void)
 
 void CRPiCECAdapterCommunication::Close(void)
 {
-  {
-    CLockObject lock(m_mutex);
-    if (m_bInitialised)
-      m_bInitialised = false;
-    else
-      return;
+  if (m_bInitialised) {
+    vc_tv_unregister_callback(rpi_tv_callback);
+    m_bInitialised = false;
   }
-  vc_tv_unregister_callback(rpi_tv_callback);
-
-  UnregisterLogicalAddress();
-
-  // disable passive mode
-  vc_cec_set_passive(false);
 
   if (!g_bHostInited)
   {
@@ -373,22 +363,16 @@ std::string CRPiCECAdapterCommunication::GetError(void) const
   return strError;
 }
 
-cec_adapter_message_state CRPiCECAdapterCommunication::Write(const cec_command &data, bool &UNUSED(bRetry), uint8_t UNUSED(iLineTimeout), bool bIsReply)
+cec_adapter_message_state CRPiCECAdapterCommunication::Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply)
 {
-  // ensure that the source LA is registered
-  if (!RegisterLogicalAddress(data.initiator))
-  {
-    LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to register logical address %s (%X)", CCECTypeUtils::ToString(data.initiator), data.initiator);
-    return (data.initiator == data.destination) ? ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED : ADAPTER_MESSAGE_STATE_ERROR;
-  }
-
-  if (!data.opcode_set && data.initiator == data.destination)
-  {
-    // registration of the logical address would have failed
-    return ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
-  }
+  VC_CEC_ERROR_T vcAnswer;
+  uint32_t iTimeout = (data.transmit_timeout ? data.transmit_timeout : iLineTimeout*1000);
 
-  return m_queue->Write(data, bIsReply) ? ADAPTER_MESSAGE_STATE_SENT_ACKED : ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+  cec_adapter_message_state rc = m_queue->Write(data, bRetry, iTimeout, bIsReply, vcAnswer);
+#ifdef CEC_DEBUGGING
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: result %s", ToString(vcAnswer));
+#endif
+  return rc;
 }
 
 uint16_t CRPiCECAdapterCommunication::GetFirmwareVersion(void)
@@ -398,22 +382,15 @@ uint16_t CRPiCECAdapterCommunication::GetFirmwareVersion(void)
 
 cec_logical_address CRPiCECAdapterCommunication::GetLogicalAddress(void)
 {
-  {
-    CLockObject lock(m_mutex);
-    if (m_logicalAddress != CECDEVICE_UNKNOWN)
-      return m_logicalAddress;
-  }
+  CLockObject lock(m_mutex);
 
-  CEC_AllDevices_T address;
-  return (vc_cec_get_logical_address(&address) == VCHIQ_SUCCESS) ?
-      (cec_logical_address)address : CECDEVICE_UNKNOWN;
+  return m_logicalAddress;
 }
 
 bool CRPiCECAdapterCommunication::UnregisterLogicalAddress(void)
 {
   CLockObject lock(m_mutex);
-  if (m_logicalAddress == CECDEVICE_UNKNOWN ||
-      m_logicalAddress == CECDEVICE_BROADCAST)
+  if (!m_bInitialised)
     return true;
 
   LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - releasing previous logical address", __FUNCTION__);
@@ -428,34 +405,25 @@ bool CRPiCECAdapterCommunication::UnregisterLogicalAddress(void)
   return m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged);
 }
 
-bool CRPiCECAdapterCommunication::RegisterLogicalAddress(const cec_logical_address address)
+bool CRPiCECAdapterCommunication::RegisterLogicalAddress(const cec_logical_address address, uint32_t iTimeoutMs)
 {
   {
     CLockObject lock(m_mutex);
-    if (m_logicalAddress == address)
+    if ((m_logicalAddress == address) && m_bLogicalAddressRegistered)
       return true;
   }
 
-  if (!UnregisterLogicalAddress())
-    return false;
-
-  LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - registering address %x", __FUNCTION__, address);
-
-  CLockObject lock(m_mutex);
   m_bLogicalAddressChanged = false;
-  vc_cec_poll_address((CEC_AllDevices_T)address);
 
   // register the new LA
   int iRetval = vc_cec_set_logical_address((CEC_AllDevices_T)address, (CEC_DEVICE_TYPE_T)CCECTypeUtils::GetType(address), CEC_VENDOR_ID_BROADCOM);
   if (iRetval != VCHIQ_SUCCESS)
   {
     LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - vc_cec_set_logical_address(%X) returned %s (%d)", __FUNCTION__, address, ToString((VC_CEC_ERROR_T)iRetval), iRetval);
-    return false;
+    UnregisterLogicalAddress();
   }
-
-  if (m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged))
+  else if (m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged, iTimeoutMs))
   {
-    m_bLogicalAddressRegistered = true;
     return true;
   }
   return false;
@@ -464,9 +432,8 @@ bool CRPiCECAdapterCommunication::RegisterLogicalAddress(const cec_logical_addre
 cec_logical_addresses CRPiCECAdapterCommunication::GetLogicalAddresses(void)
 {
   cec_logical_addresses addresses; addresses.Clear();
-  cec_logical_address current = GetLogicalAddress();
-  if (current != CECDEVICE_UNKNOWN)
-    addresses.Set(current);
+  if (m_bLogicalAddressRegistered)
+    addresses.primary = GetLogicalAddress();
 
   return addresses;
 }
index 7fbc1052f7793f3fa576e10d9c5d1374b8329f50..e6a644645ec210fa6b3633a0ec4b2e4d7aef0a2a 100644 (file)
@@ -97,7 +97,7 @@ namespace CEC
   private:
     cec_logical_address GetLogicalAddress(void);
     bool UnregisterLogicalAddress(void);
-    bool RegisterLogicalAddress(const cec_logical_address address);
+    bool RegisterLogicalAddress(const cec_logical_address address, uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT);
     int InitHostCEC(void);
 
     bool m_bInitialised;   /**< true when the connection is initialised, false otherwise */
index aa9701d3ec260c26139fc15bc15bd712de4fa051..cb9fed01f8f9cc179b2b949cea72389f1167ae40 100644 (file)
@@ -71,9 +71,12 @@ void CRPiCECAdapterMessageQueueEntry::Broadcast(void)
 
 bool CRPiCECAdapterMessageQueueEntry::MessageReceived(cec_opcode opcode, cec_logical_address initiator, cec_logical_address destination, uint32_t response)
 {
-  if ((!m_command.opcode_set || m_command.opcode == opcode) &&
-      m_command.initiator == initiator &&
-      m_command.destination == destination)
+  if ((m_command.opcode_set && m_command.opcode == opcode &&
+     m_command.initiator == initiator &&
+     m_command.destination == destination)
+     ||
+     (!m_command.opcode_set && 
+     m_command.destination == destination))
   {
     CLockObject lock(m_mutex);
     m_retval = response;
@@ -93,9 +96,6 @@ bool CRPiCECAdapterMessageQueueEntry::Wait(uint32_t iTimeout)
     CLockObject lock(m_mutex);
     bReturn = m_bSucceeded ? true : m_condition.Wait(m_mutex, m_bSucceeded, iTimeout);
     m_bWaiting = false;
-
-    if (bReturn)
-      bReturn = m_retval == VCHIQ_SUCCESS;
   }
   return bReturn;
 }
@@ -124,7 +124,12 @@ void CRPiCECAdapterMessageQueue::MessageReceived(cec_opcode opcode, cec_logical_
     LIB_CEC->AddLog(CEC_LOG_WARNING, "unhandled response received: opcode=%x initiator=%x destination=%x response=%x", (int)opcode, (int)initiator, (int)destination, response);
 }
 
-bool CRPiCECAdapterMessageQueue::Write(const cec_command &command, bool bIsReply)
+uint32_t CRPiCECAdapterMessageQueueEntry::Result() const
+{
+  return m_retval;
+}
+
+cec_adapter_message_state CRPiCECAdapterMessageQueue::Write(const cec_command &command, bool &bRetry, uint32_t iLineTimeout, bool bIsReply, VC_CEC_ERROR_T &vcReply)
 {
   CRPiCECAdapterMessageQueueEntry *entry = new CRPiCECAdapterMessageQueueEntry(this, command);
   uint64_t iEntryId(0);
@@ -182,24 +187,43 @@ bool CRPiCECAdapterMessageQueue::Write(const cec_command &command, bool bIsReply
   LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: %s", strDump.c_str());
 #endif
 
-   int iReturn = vc_cec_send_message((uint32_t)command.destination, (uint8_t*)&payload, iLength, bIsReply);
+  int iReturn = vc_cec_send_message((uint32_t)command.destination, command.opcode_set ? (uint8_t*)&payload : NULL, iLength, bIsReply);
 #endif
 
+  bRetry = false;
   if (iReturn != VCHIQ_SUCCESS)
   {
     LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending command '%s' failed (%d)", command.opcode_set ? CCECTypeUtils::ToString(command.opcode) : "POLL", iReturn);
     delete (entry);
-    return false;
+    return ADAPTER_MESSAGE_STATE_ERROR;
   }
 
-  bool bReturn(true);
+  cec_adapter_message_state bReturn(ADAPTER_MESSAGE_STATE_ERROR);
   if (entry)
   {
-    if (!entry->Wait(CEC_DEFAULT_TRANSMIT_WAIT))
+    if (entry->Wait(iLineTimeout))
     {
-      LIB_CEC->AddLog(CEC_LOG_DEBUG, "command '%s' was not acked by the controller", command.opcode_set ? CCECTypeUtils::ToString(command.opcode) : "POLL");
-      bReturn = false;
+      int status = entry->Result();
+
+      if (status == VC_CEC_ERROR_NO_ACK)
+        bReturn = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+      else if (status == VC_CEC_SUCCESS)
+        bReturn = ADAPTER_MESSAGE_STATE_SENT_ACKED;
+      else
+        bReturn = ADAPTER_MESSAGE_STATE_SENT;
     }
+    else
+    {
+      if (command.opcode_set)
+      {
+        bRetry = true;
+        LIB_CEC->AddLog(CEC_LOG_DEBUG, "command '%s' timeout", command.opcode_set ? CCECTypeUtils::ToString(command.opcode) : "POLL");
+        sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
+      }
+      bReturn = ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT;
+    }
+
+    vcReply = (VC_CEC_ERROR_T)entry->Result();
 
     CLockObject lock(m_mutex);
     m_messages.erase(iEntryId);
index af5756b68aa5588815f19344f74d3aa66434b9e8..a6f4d7eb59881a43cbad6ac38e0f293178df983e 100644 (file)
 
 #include "lib/platform/util/buffer.h"
 #include <map>
+#include "lib/adapter/AdapterCommunication.h"
+
+extern "C" {
+#include <interface/vmcs_host/vc_cecservice.h>
+#include <interface/vchiq_arm/vchiq_if.h>
+}
 
 namespace CEC
 {
@@ -64,6 +70,11 @@ namespace CEC
      */
     bool IsWaiting(void);
 
+    /*!
+     * @brief Query result from worker thread
+     */
+    uint32_t Result() const;
+
     /*!
      * @return The command that was sent in human readable form.
      */
@@ -106,7 +117,7 @@ namespace CEC
 
     void MessageReceived(cec_opcode opcode, cec_logical_address initiator, cec_logical_address destination, uint32_t response);
 
-    bool Write(const cec_command &command, bool bIsReply);
+    cec_adapter_message_state Write(const cec_command &command, bool &bRetry, uint32_t iLineTimeout, bool bIsReply, VC_CEC_ERROR_T &vcReply);
 
   private:
     CRPiCECAdapterCommunication *                             m_com;                    /**< the communication handler */
index 7e0e9b9062eb977d4278c68613e98476f9acdc7a..93e8c92147df584f2cf771c46b9e6629082c6dc3 100644 (file)
@@ -116,3 +116,13 @@ int CANCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &comman
   }
   return CEC_ABORT_REASON_INVALID_OPERAND;
 }
+
+int CANCommandHandler::HandleSetMenuLanguage(const cec_command &command)
+{
+  if (m_processor->CECInitialised() && command.initiator == CECDEVICE_TV && command.destination == CECDEVICE_BROADCAST)
+  {
+    m_processor->GetDevice(command.initiator)->SetPowerStatus(CEC_POWER_STATUS_ON);
+  }
+
+  return CCECCommandHandler::HandleSetMenuLanguage(command);
+}
index 595170ac887101088f5627b9db9f8c2a300bfba3..73d3caef9779df589c241f826d448a59073ba6fa 100644 (file)
@@ -47,6 +47,7 @@ namespace CEC
 
     int HandleVendorRemoteButtonDown(const cec_command &command);
     int HandleDeviceVendorCommandWithId(const cec_command &command);
+    int HandleSetMenuLanguage(const cec_command &command);
 
   protected:
     bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
index 29d1ffbcc7444b9725555de8f7f76d7d1b28fa58..a89ebe6c27ee2bc5fb632a6b26ee29749af3331c 100644 (file)
@@ -592,12 +592,15 @@ int CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
     CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamAddress);
     if (device)
     {
-      if (device->IsHandledByLibCEC() && !device->IsActiveSource())
-        device->ActivateSource();
-      else
+      if (device->IsHandledByLibCEC())
       {
-        device->MarkAsActiveSource();
-        device->TransmitActiveSource(true);
+        if (!device->IsActiveSource())
+          device->ActivateSource();
+        else
+        {
+          device->MarkAsActiveSource();
+          device->TransmitActiveSource(true);
+        }
       }
       return COMMAND_HANDLED;
     }
index aeace0233a3ae673ed1a71977b858c29689b915e..e94851e30426a4d49a0a1b0d5186587bd38dae07 100644 (file)
@@ -58,7 +58,7 @@ namespace CEC
     virtual bool HandleCommand(const cec_command &command);
     virtual cec_vendor_id GetVendorId(void) { return m_vendorId; };
     virtual void SetVendorId(cec_vendor_id vendorId) { m_vendorId = vendorId; }
-    static bool HasSpecificHandler(cec_vendor_id vendorId) { return vendorId == CEC_VENDOR_LG || vendorId == CEC_VENDOR_SAMSUNG || vendorId == CEC_VENDOR_PANASONIC || vendorId == CEC_VENDOR_PHILIPS || vendorId == CEC_VENDOR_SHARP;}
+    static bool HasSpecificHandler(cec_vendor_id vendorId) { return vendorId == CEC_VENDOR_LG || vendorId == CEC_VENDOR_SAMSUNG || vendorId == CEC_VENDOR_PANASONIC || vendorId == CEC_VENDOR_PHILIPS || vendorId == CEC_VENDOR_SHARP || vendorId == CEC_VENDOR_TOSHIBA || vendorId == CEC_VENDOR_TOSHIBA2 || vendorId == CEC_VENDOR_ONKYO;}
 
     virtual bool InitHandler(void) { return true; }
     virtual bool ActivateSource(bool bTransmitDelayedCommandsOnly = false);
diff --git a/src/lib/platform/X11/randr-edid.cpp b/src/lib/platform/X11/randr-edid.cpp
new file mode 100644 (file)
index 0000000..4de17e4
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * 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.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing     <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+#include "lib/platform/os.h"
+#include "randr-edid.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrandr.h>
+
+#include <stdlib.h>
+
+using namespace PLATFORM;
+
+static const char * const edid_names[] = 
+{ 
+#if (RANDR_MAJOR > 1) || (RANDR_MAJOR == 1 && RANDR_MINOR >2) 
+  RR_PROPERTY_RANDR_EDID,
+#else
+  "EDID",
+#endif
+  "EDID_DATA",
+  "XFree86_DDC_EDID1_RAWDATA"
+};
+
+#define EDID_NAME_COUNT (sizeof(edid_names)/sizeof(*edid_names))
+
+uint16_t CRandrEdidParser::GetPhysicalAddress(void)
+{
+  uint16_t physical_address = 0;
+
+  /* open default X11 DISPLAY */
+  Display *disp = XOpenDisplay(NULL);
+  if( disp )
+  {
+    int event_base, error_base;
+    int maj, min;
+
+    if( XRRQueryExtension(disp, &event_base, &error_base)
+     && XRRQueryVersion(disp, &maj, &min) )
+    {
+      int version = (maj << 8) | min;
+        
+      if( version >= 0x0102 )
+      {
+        size_t atom_avail = 0;
+        Atom edid_atoms[EDID_NAME_COUNT];
+
+        if( XInternAtoms(disp, (char **)edid_names, EDID_NAME_COUNT, True, edid_atoms) )
+        {
+          /* remove missing some atoms */
+          atom_avail = 0;
+          for(size_t atom_count=0; atom_count<EDID_NAME_COUNT; ++atom_count)
+          {
+            Atom edid_atom = edid_atoms[atom_count];
+            if( None != edid_atom )
+            {
+              if( atom_avail < atom_count )
+              {
+                edid_atoms[atom_avail] = edid_atom;
+              }
+              ++atom_avail;
+            }
+          }
+        }
+
+        if( atom_avail > 0 )
+        {
+          int scr_count = ScreenCount(disp);
+          int screen;
+
+          for(screen=0; screen<scr_count; ++screen)
+          {
+            XRRScreenResources *rsrc = NULL;
+            Window root = RootWindow(disp, screen);
+
+#if (RANDR_MAJOR > 1) || (RANDR_MAJOR == 1 && RANDR_MINOR >=3) 
+            if( version >= 0x0103 )
+            {
+              /* get cached resources if they are available */
+              rsrc = XRRGetScreenResourcesCurrent(disp, root);
+            }
+
+            if( NULL == rsrc )
+#endif
+              rsrc = XRRGetScreenResources(disp, root);
+
+            if( NULL != rsrc )
+            {
+              int output_id;
+              for( output_id=0; 0 == physical_address && output_id < rsrc->noutput; ++output_id )
+              {
+                RROutput rr_output_id = rsrc->outputs[output_id];
+                XRROutputInfo *output_info = XRRGetOutputInfo(disp, rsrc, rr_output_id);
+                if( NULL != output_info )
+                {
+                  if( RR_Connected == output_info->connection )
+                  {
+                    for(size_t atom_count=0; 0 == physical_address && atom_count<atom_avail; ++atom_count)
+                    {
+                      Atom actual_type;
+                      int actual_format;
+                      unsigned long nitems;
+                      unsigned long bytes_after;
+                      unsigned char *data;
+                      int status;
+
+                      status = XRRGetOutputProperty(disp, rr_output_id, edid_atoms[atom_count], 0, 128, False, False,
+                            AnyPropertyType, &actual_type, &actual_format,
+                            &nitems, &bytes_after, &data);
+                      if( Success == status )
+                      {
+                        if((actual_type == XA_INTEGER) && (actual_format == 8) )
+                        {
+                          physical_address = CEDIDParser::GetPhysicalAddressFromEDID(data, nitems);
+                        }
+                        XFree(data);
+                      }
+                    }
+                  }
+                  XRRFreeOutputInfo(output_info);
+                }
+                else
+                  break;  /* problem ? */
+              }
+              XRRFreeScreenResources(rsrc);
+            }
+          }
+        }
+      }
+    }
+    XCloseDisplay(disp);
+  }
+  return physical_address;
+}
diff --git a/src/lib/platform/X11/randr-edid.h b/src/lib/platform/X11/randr-edid.h
new file mode 100644 (file)
index 0000000..b415002
--- /dev/null
@@ -0,0 +1,46 @@
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * 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.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "lib/platform/util/edid.h"
+
+namespace PLATFORM
+{
+  class CRandrEdidParser
+  {
+  public:
+    CRandrEdidParser(void) {};
+    virtual ~CRandrEdidParser(void) {};
+
+    uint16_t GetPhysicalAddress(void);
+  };
+}
index 4347688ca5ac43fafabd53d8c614ebb6cebeefa7..51dc92fd76ffda551b12fb7bfe4324855c51978e 100644 (file)
 
 #include "env.h"
 #include "lib/platform/util/edid.h"
+#include "lib/platform/X11/randr-edid.h"
 
 using namespace PLATFORM;
 
 uint16_t CEDIDParser::GetPhysicalAddress(void)
 {
+#if HAVE_RANDR
+  return CRandrEdidParser().GetPhysicalAddress();    
+#else
   // TODO
   return 0;
+#endif
 }