added support for CuBox (http://www.solid-run.com)
authorwarped-rudi <r.ihle@s-t.de>
Mon, 17 Sep 2012 14:55:54 +0000 (16:55 +0200)
committerwarped-rudi <r.ihle@s-t.de>
Mon, 17 Sep 2012 14:55:54 +0000 (16:55 +0200)
14 files changed:
README
configure.ac
include/cectypes.h
src/lib/CECTypeUtils.h
src/lib/Makefile.am
src/lib/adapter/AdapterFactory.cpp
src/lib/adapter/CuBox/AdapterMessageQueue.h [new file with mode: 0644]
src/lib/adapter/CuBox/NxpCECAdapterCommunication.cpp [new file with mode: 0644]
src/lib/adapter/CuBox/NxpCECAdapterCommunication.h [new file with mode: 0644]
src/lib/adapter/CuBox/NxpCECAdapterDetection.cpp [new file with mode: 0644]
src/lib/adapter/CuBox/NxpCECAdapterDetection.h [new file with mode: 0644]
src/lib/platform/posix/os-socket.h
src/lib/platform/posix/os-types.h
src/lib/platform/sockets/cdevsocket.h [new file with mode: 0644]

diff --git a/README b/README
index 5c7364b19882ad5b765448ab7097e4ef45ad2179..de118ea8befe2edd212a0f2fd247a68e7eb1186d 100644 (file)
--- a/README
+++ b/README
@@ -99,6 +99,23 @@ To specify the path of the Raspberry Pi's libraries, use the following option
 for 'configure':
 --with-rpi-lib-path="/path/to/libbcm_host.so"
 
+===============================================================================
+                           === CuBox ===
+===============================================================================
+
+Solid-Run's CuBox uses an HDMI tranceiver by NXP. The device driver for this,
+which is based on an SDK by the chip vendor, is built into the kernel. The
+following options for 'configure' have been introduced:
+
+To enable support for the CuBox:
+--enable-cubox
+
+To specify the path for the NXP SDK:
+--with-nxp-toolkit-path='path/to/linux/drivers/video/dovefb/nxp_hdmi'
+
+If the toolkit path is not specified, it is assumed that a directory named
+'nxp_hdmi' (or a link to it) exists in the top level of the source tree.
+
 ===============================================================================
                             === Debugging / Testing ===
 ===============================================================================
index 0d09d42144c5c47dd7ce635f4319617d14b8c396..e0252c9bc118cce5c51c2681fc8cd7483403660c 100644 (file)
@@ -43,6 +43,20 @@ AC_ARG_ENABLE([optimisation],
   [use_optimisation=$enableval],
   [use_optimisation=yes])
 
+## CuBox support
+AC_ARG_ENABLE([cubox],
+  [AS_HELP_STRING([--enable-cubox],
+  [enable support for the CuBox (default is no)])],
+  [use_nxp=$enableval],
+  [use_nxp=no])
+
+## Optional path to the NXP dev toolkit
+AC_ARG_WITH([nxp-toolkit-path],
+  [AS_HELP_STRING([--with-nxp-toolkit-path],
+    [location of the NXP HDMI toolkit (default is ./nxp_hdmi)])],
+  [NXP_CFLAGS="-I$withval/inc"],
+  [NXP_CFLAGS="-I\$(abs_top_srcdir)/nxp_hdmi/inc"])
+
 ## Raspberry Pi support
 AC_ARG_ENABLE([rpi],
   [AS_HELP_STRING([--enable-rpi],
@@ -235,6 +249,18 @@ else
   features="$features\n  Raspberry Pi support :\t\tno"
 fi
 
+## mark CuBox support as available
+if test "x$use_nxp" != "xno"; then
+  AC_DEFINE([HAVE_NXP_API],[1],[Define to 1 to include CuBox support])
+  AM_CONDITIONAL(USE_NXP_API, true)
+  features="$features\n  CuBox support :\t\t\tyes"
+  LIB_INFO="$LIB_INFO 'CuBox'"
+  CPPFLAGS="$CPPFLAGS $NXP_CFLAGS"
+else
+  AM_CONDITIONAL(USE_NXP_API, false)
+  features="$features\n  CuBox 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 291190ce31671abc9c47ea00d5a48fbaced0372a..0687c72c6cb2fe9f18ef8f2336c43d7382be4f26 100644 (file)
@@ -117,6 +117,9 @@ namespace CEC {
 #define CEC_RPI_VIRTUAL_PATH           "Raspberry Pi"
 #define CEC_RPI_VIRTUAL_COM            "RPI"
 
+#define CEC_NXP_PATH                   "/dev/hdmicec"
+#define CEC_NXP_VIRTUAL_COM            "NXP"
+
 #define CEC_MIN_LIB_VERSION          1
 #define CEC_LIB_VERSION_MAJOR        1
 #define CEC_LIB_VERSION_MAJOR_STR    "1"
@@ -652,7 +655,8 @@ typedef enum cec_adapter_type
   ADAPTERTYPE_UNKNOWN          = 0,
   ADAPTERTYPE_P8_EXTERNAL      = 0x1,
   ADAPTERTYPE_P8_DAUGHTERBOARD = 0x2,
-  ADAPTERTYPE_RPI              = 0x100
+  ADAPTERTYPE_RPI              = 0x100,
+  ADAPTERTYPE_NXP              = 0x101
 } cec_adapter_type;
 
 typedef struct cec_menu_language
index a79163473c6fdac5ad312b66b29e582d91628569..90b287a2897d1e276c45081f939849bb9981ab2c 100644 (file)
@@ -795,6 +795,8 @@ namespace CEC
         return "Pulse-Eight USB-CEC Daughterboard";
       case ADAPTERTYPE_RPI:
         return "Raspberry Pi";
+      case ADAPTERTYPE_NXP:
+        return "Cubox";
       default:
         return "unknown";
       }
index 7ea1e99dd5bf742a66149f82c2d624369b535c4a..b4afcd1bed0e069083f55990fa98529f36eaa52d 100644 (file)
@@ -50,4 +50,11 @@ libcec_la_SOURCES += adapter/RPi/RPiCECAdapterDetection.cpp \
                      adapter/RPi/RPiCECAdapterMessageQueue.cpp
 endif
 
+## CuBox (NXP) support
+if USE_NXP_API
+libcec_la_SOURCES += adapter/CuBox/NxpCECAdapterDetection.cpp \
+                     adapter/CuBox/NxpCECAdapterCommunication.cpp
+endif
+
+
 libcec_la_LDFLAGS = @LIBS_LIBCEC@ -version-info @VERSION@
index 9ee9cc7c664516b51782ef06fcd8b38952fb2763..8ade6ee1547306657d057b4e0dddc5d4c94058e6 100644 (file)
 #include "RPi/RPiCECAdapterCommunication.h"
 #endif
 
+#if defined(HAVE_NXP_API)
+#include "CuBox/NxpCECAdapterDetection.h"
+#include "CuBox/NxpCECAdapterCommunication.h"
+#endif
+
 using namespace std;
 using namespace CEC;
 
@@ -75,7 +80,15 @@ int8_t CAdapterFactory::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize,
   }
 #endif
 
-#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB)
+#if defined(HAVE_NXP_API)
+  if (iAdaptersFound < iBufSize && CNxpCECAdapterDetection::FindAdapter())
+  {
+    snprintf(deviceList[iAdaptersFound].path, 1024, CEC_NXP_PATH);
+    snprintf(deviceList[iAdaptersFound++].comm, 1024, CEC_NXP_VIRTUAL_COM);
+  }
+#endif
+
+#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) && !defined(HAVE_NXP_API)
 #error "libCEC doesn't have support for any type of adapter. please check your build system or configuration"
 #endif
 
@@ -84,6 +97,11 @@ int8_t CAdapterFactory::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize,
 
 IAdapterCommunication *CAdapterFactory::GetInstance(const char *strPort, uint16_t iBaudRate)
 {
+#if defined(HAVE_NXP_API)
+  if (!strcmp(strPort, CEC_NXP_VIRTUAL_COM))
+    return new CNxpCECAdapterCommunication(m_lib->m_cec, CEC_NXP_PATH);
+#endif
+
 #if defined(HAVE_RPI_API)
   if (!strcmp(strPort, CEC_RPI_VIRTUAL_COM))
     return new CRPiCECAdapterCommunication(m_lib->m_cec);
@@ -93,7 +111,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)
+#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) && !defined(HAVE_NXP_API)
   return NULL;
 #endif
 }
diff --git a/src/lib/adapter/CuBox/AdapterMessageQueue.h b/src/lib/adapter/CuBox/AdapterMessageQueue.h
new file mode 100644 (file)
index 0000000..7904084
--- /dev/null
@@ -0,0 +1,134 @@
+#pragma once
+/*
+ * 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 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/threads/mutex.h"
+
+namespace CEC
+{
+  using namespace PLATFORM;
+  
+  class CAdapterMessageQueueEntry
+  {
+  public:
+    CAdapterMessageQueueEntry(const cec_command &command)
+       : m_bWaiting(true), m_retval((uint32_t)-1), m_bSucceeded(false)
+    {
+      m_hash = hashValue(
+       uint32_t(command.opcode_set ? command.opcode : CEC_OPCODE_NONE),
+       command.initiator, command.destination);
+    }
+    
+    virtual ~CAdapterMessageQueueEntry(void) {}
+
+    /*!
+     * @brief Query result from worker thread
+     */
+    uint32_t Result() const
+    {
+      return m_retval;
+    }
+    
+    /*!
+     * @brief Signal waiting threads
+     */
+    void Broadcast(void)
+    {
+      CLockObject lock(m_mutex);
+      m_condition.Broadcast();
+    }
+
+    /*!
+     * @brief Signal waiting thread(s) when message matches this entry
+     */
+    bool CheckMatch(uint32_t opcode, cec_logical_address initiator, 
+                   cec_logical_address destination, uint32_t response)
+    {
+      uint32_t hash = hashValue(opcode, initiator, destination);
+      
+      if (hash == m_hash)
+      {
+        CLockObject lock(m_mutex);
+
+       m_retval = response;
+        m_bSucceeded = true;
+        m_condition.Signal();
+       return true;
+      }
+      
+      return false;
+    }
+
+    /*!
+     * @brief Wait for a response to this command.
+     * @param iTimeout The timeout to use while waiting.
+     * @return True when a response was received before the timeout passed, false otherwise.
+     */
+    bool Wait(uint32_t iTimeout)
+    {
+      CLockObject lock(m_mutex);
+      bool bReturn = m_bSucceeded ? true : m_condition.Wait(m_mutex, m_bSucceeded, iTimeout);
+
+      m_bWaiting = false;
+      return bReturn;
+    }
+
+    /*!
+     * @return True while a thread is waiting for a signal or isn't waiting yet, false otherwise.
+     */
+    bool IsWaiting(void)
+    {
+      CLockObject lock(m_mutex);
+      return m_bWaiting;
+    }
+
+    /*!
+     * @return Hash value for given cec_command
+     */
+    static uint32_t hashValue(uint32_t opcode, 
+                             cec_logical_address initiator,  
+                             cec_logical_address destination)
+    {
+      return 1 | ((uint32_t)initiator << 8) | 
+             ((uint32_t)destination << 16) | ((uint32_t)opcode << 16);
+    }
+    
+  private:    
+    bool                         m_bWaiting;     /**< true while a thread is waiting or when it hasn't started waiting yet */
+    PLATFORM::CCondition<bool>   m_condition;    /**< the condition to wait on */
+    PLATFORM::CMutex             m_mutex;        /**< mutex for changes to this class */
+    uint32_t                    m_hash;
+    uint32_t                     m_retval;
+    bool                         m_bSucceeded;
+  };
+};
diff --git a/src/lib/adapter/CuBox/NxpCECAdapterCommunication.cpp b/src/lib/adapter/CuBox/NxpCECAdapterCommunication.cpp
new file mode 100644 (file)
index 0000000..44912d2
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * 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 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"
+
+#if defined(HAVE_NXP_API)
+#include "NxpCECAdapterCommunication.h"
+
+#include "lib/CECTypeUtils.h"
+#include "lib/LibCEC.h"
+#include "lib/platform/sockets/cdevsocket.h"
+#include "lib/platform/util/StdString.h"
+#include "lib/platform/util/buffer.h"
+
+extern "C" {
+#define __cec_h__
+#include <../comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h>
+#include <../tda998x_ioctl.h>
+}
+
+using namespace std;
+using namespace CEC;
+using namespace PLATFORM;
+
+#include "AdapterMessageQueue.h"
+
+#define LIB_CEC m_callback->GetLib()
+
+#if 0
+  #define TRACE(a)     LIB_CEC->AddLog a
+#else
+  #define TRACE(a)
+#endif
+
+// these are defined in nxp private header file
+#define CEC_MSG_SUCCESS                        0x00    /*Message transmisson Succeed*/
+#define CEC_CSP_OFF_STATE              0x80    /*CSP in Off State*/
+#define CEC_BAD_REQ_SERVICE            0x81    /*Bad .req service*/
+#define CEC_MSG_FAIL_UNABLE_TO_ACCESS  0x82    /*Message transmisson failed: Unable to access CEC line*/
+#define CEC_MSG_FAIL_ARBITRATION_ERROR 0x83    /*Message transmisson failed: Arbitration error*/
+#define CEC_MSG_FAIL_BIT_TIMMING_ERROR 0x84    /*Message transmisson failed: Bit timming error*/
+#define CEC_MSG_FAIL_DEST_NOT_ACK      0x85    /*Message transmisson failed: Destination Address not aknowledged*/
+#define CEC_MSG_FAIL_DATA_NOT_ACK      0x86    /*Message transmisson failed: Databyte not acknowledged*/
+
+
+CNxpCECAdapterCommunication::CNxpCECAdapterCommunication(IAdapterCommunicationCallback *callback, const char *UNUSED(device)) :
+    IAdapterCommunication(callback),
+    m_bLogicalAddressChanged(false)
+{ 
+  TRACE((CEC_LOG_DEBUG, "%s called", __func__));
+  
+  CLockObject lock(m_mutex);
+
+  m_iNextMessage = 0;
+  m_logicalAddresses.Clear();
+  m_dev = new CCDevSocket(CEC_NXP_PATH);
+}
+
+
+CNxpCECAdapterCommunication::~CNxpCECAdapterCommunication(void)
+{
+  TRACE((CEC_LOG_DEBUG, "%s called", __func__));
+
+  Close();
+
+  CLockObject lock(m_mutex);
+  delete m_dev;
+  m_dev = 0;
+}
+
+
+bool CNxpCECAdapterCommunication::IsOpen(void)
+{
+  return IsInitialised() && m_dev->IsOpen();
+}
+
+    
+bool CNxpCECAdapterCommunication::Open(uint32_t iTimeoutMs, bool bSkipChecks, bool bStartListening)
+{
+  TRACE((CEC_LOG_DEBUG, "%s called (%d,%d,%d)", __func__, iTimeoutMs, bSkipChecks, bStartListening));
+
+  if (m_dev->Open(iTimeoutMs))
+  {
+    unsigned char raw_mode = 0xff;
+    
+    if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_MODE, &raw_mode) == 0)
+    {
+      raw_mode = 1;
+      if (m_dev->Ioctl(CEC_IOCTL_SET_RAW_MODE, &raw_mode) == 0)
+      {
+        if (!bStartListening || CreateThread())
+          return true;
+      }
+      else
+      {
+        LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_SET_RAW_MODE failed !", __func__);
+      }
+
+      raw_mode = 0;
+      m_dev->Ioctl(CEC_IOCTL_SET_RAW_MODE, &raw_mode);
+    }
+    else
+    {
+      LIB_CEC->AddLog(CEC_LOG_ERROR, 
+       "%s: CEC_IOCTL_GET_RAW_MODE not supported. Please update your kernel.", __func__);
+    }
+
+    m_dev->Close();
+  }
+
+  return false;
+}
+
+
+void CNxpCECAdapterCommunication::Close(void)
+{
+  TRACE((CEC_LOG_DEBUG, "%s called", __func__));
+
+  StopThread(0);
+
+  unsigned char raw_mode = 0;
+  m_dev->Ioctl(CEC_IOCTL_SET_RAW_MODE, &raw_mode);
+
+  m_dev->Close();
+}
+
+
+std::string CNxpCECAdapterCommunication::GetError(void) const
+{
+  std::string strError(m_strError);
+  return strError;
+}
+
+
+cec_adapter_message_state CNxpCECAdapterCommunication::Write(
+  const cec_command &data, bool &UNUSED(bRetry), uint8_t UNUSED(iLineTimeout), bool UNUSED(bIsReply))
+{
+  cec_frame frame;
+  CAdapterMessageQueueEntry *entry;
+  cec_adapter_message_state rc = ADAPTER_MESSAGE_STATE_ERROR;
+  
+  TRACE((CEC_LOG_DEBUG, "%s: %x->%x, %d,%d,%d OPC%02x TMO%d LEN%d [%02x,%02x,%02x,%02x...]", __func__,
+        data.initiator, data.destination, data.ack, data.eom, data.opcode_set, data.opcode, data.transmit_timeout,
+        data.parameters.size, data.parameters.data[0], data.parameters.data[1],data.parameters.data[2],data.parameters.data[3]));
+  
+  if ((size_t)data.parameters.size + data.opcode_set > sizeof(frame.data))
+  {
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: data size too large !", __func__);
+    return ADAPTER_MESSAGE_STATE_ERROR;
+  }
+  
+  frame.size    = 0;
+  frame.service = 0;
+  frame.addr    = (data.initiator << 4) | (data.destination & 0x0f);
+
+  if (data.opcode_set)
+  {
+    frame.data[0] = data.opcode;
+    frame.size++;
+
+    memcpy(&frame.data[frame.size], data.parameters.data, data.parameters.size);
+    frame.size += data.parameters.size;
+  }
+  
+  frame.size += 3;
+
+  entry = new CAdapterMessageQueueEntry(data);
+  
+  m_messageMutex.Lock();
+  uint32_t msgKey = ++m_iNextMessage;
+  m_messages.insert(make_pair(msgKey, entry));
+  if (m_dev->Write((char *)&frame, sizeof(frame)) == sizeof(frame))
+  {
+    m_messageMutex.Unlock();
+
+    if (entry->Wait(CEC_DEFAULT_TRANSMIT_WAIT))
+    {
+      uint32_t status = entry->Result();
+     
+      if (status == CEC_MSG_FAIL_DEST_NOT_ACK)
+        rc = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+      else if (status == CEC_MSG_SUCCESS)
+        rc = ADAPTER_MESSAGE_STATE_SENT_ACKED;
+      
+      TRACE((CEC_LOG_DEBUG, "%s: reply received (0x%02x)", __func__, status));
+    }
+    else
+      LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: command timed out !", __func__);
+    
+    m_messageMutex.Lock();
+  }
+  else
+     LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: write failed !", __func__);
+
+  m_messages.erase(msgKey);
+  m_messageMutex.Unlock();
+
+  delete entry;
+
+  return rc;
+}
+
+
+uint16_t CNxpCECAdapterCommunication::GetFirmwareVersion(void)
+{
+  cec_sw_version  vers = { 0 };
+
+  m_dev->Ioctl(CEC_IOCTL_GET_SW_VERSION, &vers);
+  
+  TRACE((CEC_LOG_DEBUG, 
+    "%s: %s comp: %08lX, major: %08lX, minor: %08lX", __func__,
+    m_dev->GetName().c_str(), vers.compatibilityNr, vers.majorVersionNr, vers.minorVersionNr));
+
+  return (vers.majorVersionNr * 100) + vers.minorVersionNr;
+}
+
+
+cec_vendor_id CNxpCECAdapterCommunication::GetVendorId(void)
+{
+  cec_raw_info info;
+  if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_INFO, &info) != 0)
+  {
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__);
+    return CEC_VENDOR_LG; 
+  }
+  
+  TRACE((CEC_LOG_DEBUG, "%s: Vendor=%08x", __func__, info.VendorID));
+
+  return cec_vendor_id(info.VendorID);
+}
+
+
+uint16_t CNxpCECAdapterCommunication::GetPhysicalAddress(void)
+{
+  cec_raw_info info;
+  if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_INFO, &info) != 0)
+  {
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__);
+    return CEC_INVALID_PHYSICAL_ADDRESS; 
+  }
+  
+  TRACE((CEC_LOG_DEBUG, "%s: PhysAddr=%x", __func__, info.PhysicalAddress));
+
+  return info.PhysicalAddress;
+}
+
+
+cec_logical_addresses CNxpCECAdapterCommunication::GetLogicalAddresses(void)
+{
+  CLockObject lock(m_mutex);
+
+  if (m_bLogicalAddressChanged || m_logicalAddresses.IsEmpty() )
+  {
+    cec_raw_info info;
+
+    m_logicalAddresses.Clear();
+
+    if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_INFO, &info) != 0)
+    {
+      LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__);
+    }
+    else if (info.LogicalAddress != CECDEVICE_UNREGISTERED)
+    {
+      m_logicalAddresses.Set(cec_logical_address(info.LogicalAddress));
+      
+      for (int la = CECDEVICE_TV; la < CECDEVICE_BROADCAST; la++)
+      {
+        m_logicalAddresses.Set(cec_logical_address(la));  
+      }
+    }
+
+    m_bLogicalAddressChanged = false;
+  }
+
+  TRACE((CEC_LOG_DEBUG, "%s: LogAddr=%d", __func__, (int)m_logicalAddresses.primary));
+
+  return m_logicalAddresses;
+}
+
+
+bool CNxpCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses)
+{
+  TRACE((CEC_LOG_DEBUG, "%s: LogAddr=%d", __func__, addresses.primary));
+
+  unsigned char log_addr = addresses.primary;
+  
+  if (m_dev->Ioctl(CEC_IOCTL_RX_ADDR, &log_addr) != 0)
+  {
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_RX_ADDR failed !", __func__);
+    return false;
+  }
+
+  cec_rx_mask all_addresses;
+  
+  all_addresses.SwitchOn  = addresses.AckMask() & 0x7fff;
+  all_addresses.SwitchOff = ~all_addresses.SwitchOn;
+  
+  if (all_addresses.SwitchOn != (1 << addresses.primary) &&
+      m_dev->Ioctl(CEC_IOCTL_SET_RX_ADDR_MASK, &all_addresses) != 0)
+  {
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_SET_RX_ADDR_MASK failed !", __func__);
+    return false;
+  }
+  
+  m_bLogicalAddressChanged = true;
+  
+  return true;
+}
+
+
+void CNxpCECAdapterCommunication::HandleLogicalAddressLost(cec_logical_address oldAddress)
+{
+  TRACE((CEC_LOG_DEBUG, "%s: LogAddr=%d", __func__, (int)oldAddress));
+
+  unsigned char log_addr = CECDEVICE_BROADCAST;
+
+  if (m_dev->Ioctl(CEC_IOCTL_RX_ADDR, &log_addr) != 0)
+  {
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_RX_ADDR failed !", __func__);
+  }
+}
+
+
+void *CNxpCECAdapterCommunication::Process(void)
+{
+  bool bHandled;
+  cec_frame frame;
+  uint32_t opcode, status;
+  cec_logical_address initiator, destination;
+
+  while (!IsStopped())
+  {
+    if (m_dev->Read((char *)&frame, sizeof(frame), 500) == sizeof(frame))
+    {
+      initiator = cec_logical_address(frame.addr >> 4);
+      destination = cec_logical_address(frame.addr & 0x0f);
+      
+      TRACE((CEC_LOG_DEBUG, 
+             "%s: frame received [%x->%x] (srvc=%d, len=%d)", 
+            __func__, initiator, destination, frame.service, frame.size));
+
+      if (frame.service == CEC_RX_PKT)
+      {
+       cec_command cmd;
+       
+       cec_command::Format(
+         cmd, initiator, destination,
+          ( frame.size > 3 ) ? cec_opcode(frame.data[0]) : CEC_OPCODE_NONE);
+       
+       for( uint8_t i = 1; i < frame.size-3; i++ )
+           cmd.parameters.PushBack(frame.data[i]);
+       
+        m_callback->OnCommandReceived(cmd);
+      }
+      else if (frame.service == CEC_ACK_PKT)
+      {
+        bHandled = false;
+       status = ( frame.size > 3 ) ? frame.data[0] : 255;
+        opcode = ( frame.size > 4 ) ? frame.data[1] : (uint32_t)CEC_OPCODE_NONE;
+
+        m_messageMutex.Lock();
+        for (map<uint32_t, CAdapterMessageQueueEntry *>::iterator it = m_messages.begin(); 
+            !bHandled && it != m_messages.end(); it++)
+       {
+          bHandled = it->second->CheckMatch(opcode, initiator, destination, status);
+       }
+        m_messageMutex.Unlock();
+      
+        if (!bHandled)
+          LIB_CEC->AddLog(CEC_LOG_WARNING, "%s: unhandled response received !", __func__);
+      }
+    }
+  }
+
+  return 0;
+}
+
+
+#endif // HAVE_NXP_API
+
diff --git a/src/lib/adapter/CuBox/NxpCECAdapterCommunication.h b/src/lib/adapter/CuBox/NxpCECAdapterCommunication.h
new file mode 100644 (file)
index 0000000..9a06e16
--- /dev/null
@@ -0,0 +1,113 @@
+#pragma once
+/*
+ * 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 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_NXP_API)
+
+#include "lib/platform/threads/mutex.h"
+#include "lib/platform/threads/threads.h"
+#include "lib/platform/sockets/socket.h"
+#include "lib/adapter/AdapterCommunication.h"
+#include <map>
+
+
+namespace PLATFORM
+{
+  class CCDevSocket;
+};
+
+
+namespace CEC
+{
+  class CAdapterMessageQueueEntry;
+
+  class CNxpCECAdapterCommunication : public IAdapterCommunication, public PLATFORM::CThread
+  {
+  public:
+    /*!
+     * @brief Create a new USB-CEC communication handler.
+     * @param callback The callback to use for incoming CEC commands.
+     */
+    CNxpCECAdapterCommunication(IAdapterCommunicationCallback *callback, const char *device);
+    virtual ~CNxpCECAdapterCommunication(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("NXP"); }
+    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_NXP; }
+    void HandleLogicalAddressLost(cec_logical_address oldAddress);
+    ///}
+
+    /** @name PLATFORM::CThread implementation */
+    ///{
+    void *Process(void);
+    ///}
+
+  private:
+    bool IsInitialised(void) const { return m_dev != 0; };
+
+    std::string                 m_strError; /**< current error message */
+
+    bool                        m_bLogicalAddressChanged;
+    cec_logical_addresses       m_logicalAddresses;
+
+    PLATFORM::CMutex            m_mutex;
+    PLATFORM::CCDevSocket      *m_dev; /**< the device connection */
+    
+    PLATFORM::CMutex            m_messageMutex;
+    uint32_t                    m_iNextMessage;
+    std::map<uint32_t, CAdapterMessageQueueEntry *> m_messages;
+  };
+  
+};
+
+#endif
diff --git a/src/lib/adapter/CuBox/NxpCECAdapterDetection.cpp b/src/lib/adapter/CuBox/NxpCECAdapterDetection.cpp
new file mode 100644 (file)
index 0000000..c4d1327
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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 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_NXP_API)
+#include "NxpCECAdapterDetection.h"
+
+extern "C" {
+#define __cec_h__
+#include <../comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h>
+#include <../tda998x_ioctl.h>
+}
+
+using namespace CEC;
+
+bool CNxpCECAdapterDetection::FindAdapter(void)
+{
+  /* NXP HDMI uses /dev/hdmicec and ioctl() communication */
+
+  return access(CEC_NXP_PATH, 0) == 0;
+}
+
+#endif
+
diff --git a/src/lib/adapter/CuBox/NxpCECAdapterDetection.h b/src/lib/adapter/CuBox/NxpCECAdapterDetection.h
new file mode 100644 (file)
index 0000000..dde82a2
--- /dev/null
@@ -0,0 +1,41 @@
+#pragma once
+/*
+ * 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 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 CNxpCECAdapterDetection
+  {
+  public:
+    static bool FindAdapter(void);
+  };
+}
index 7539aab3e6289e91ab594704399e04ddecebe67f..9d98d9ad9285f3646046597b9ef1a71bc35f08d9 100644 (file)
@@ -36,6 +36,7 @@
 #include "lib/platform/util/timeutils.h"
 #include <stdio.h>
 #include <fcntl.h>
+#include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
@@ -172,6 +173,20 @@ namespace PLATFORM
 
     return iBytesRead;
   }
+
+  inline int SocketIoctl(socket_t socket, int *iError, int request, void* data)
+  {
+    if (socket == INVALID_SOCKET_VALUE)
+    {
+      *iError = EINVAL;
+      return -1;
+    }
+
+    int iReturn = ioctl(socket, request, data);
+    if (iReturn < 0)
+      *iError = errno;
+    return iReturn;
+  }
   //@}
 
   // TCP
index a365635490f66d4a7b46e86211404abe4ac60de3..261dd035e6d6efdf893d0423c3a69cf5c1edbbc9 100644 (file)
@@ -56,3 +56,6 @@ typedef socket_t tcp_socket_t;
 #define INVALID_SOCKET_VALUE        (-1)
 typedef socket_t serial_socket_t;
 #define INVALID_SERIAL_SOCKET_VALUE (-1)
+typedef socket_t chardev_socket_t;
+#define INVALID_CHARDEV_SOCKET_VALUE (-1)
+
diff --git a/src/lib/platform/sockets/cdevsocket.h b/src/lib/platform/sockets/cdevsocket.h
new file mode 100644 (file)
index 0000000..0cb5486
--- /dev/null
@@ -0,0 +1,117 @@
+#pragma once
+/*
+ * 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 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/os.h"
+#include "lib/platform/util/buffer.h"
+
+#include <string>
+#include <stdint.h>
+
+#if !defined(__WINDOWS__)
+#include <termios.h>
+#endif
+
+#include "socket.h"
+
+namespace PLATFORM
+{
+  class CCDevSocket : public CCommonSocket<chardev_socket_t>
+  {
+    public:
+      CCDevSocket(const std::string &strName ) :
+        CCommonSocket<chardev_socket_t>(INVALID_CHARDEV_SOCKET_VALUE, strName)
+        #ifdef __WINDOWS__
+        ,m_iCurrentReadTimeout(MAXDWORD)
+        #endif
+      {}
+
+      virtual ~CCDevSocket(void) 
+      { 
+       Close(); 
+      }
+
+      virtual bool Open(uint64_t iTimeoutMs = 0)
+      {
+        (void)iTimeoutMs;
+
+       if (IsOpen())
+          return false;
+
+        m_socket = open(m_strName.c_str(), O_RDWR );
+
+        if (m_socket == INVALID_CHARDEV_SOCKET_VALUE)
+        {
+          m_strError = strerror(errno);
+          return false;
+        }
+
+        return true;
+      }
+      
+      virtual void Close(void)
+      {
+        if (IsOpen())
+        {
+          SocketClose(m_socket);
+          m_socket = INVALID_CHARDEV_SOCKET_VALUE;
+        }
+      }
+      
+      virtual void Shutdown(void)
+      {
+        SocketClose(m_socket);
+      }
+      
+      virtual int Ioctl(int request, void* data)
+      {
+        return IsOpen() ? SocketIoctl(m_socket, &m_iError, request, data) : -1;
+      }
+      
+      virtual ssize_t Write(void* data, size_t len)
+      {
+        return IsOpen() ? SocketWrite(m_socket, &m_iError, data, len) : -1;
+      }
+      
+      virtual ssize_t Read(void* data, size_t len, uint64_t iTimeoutMs = 0)
+      {
+        return IsOpen() ? SocketRead(m_socket, &m_iError, data, len, iTimeoutMs) : -1;
+      }
+
+      virtual bool IsOpen(void)
+      {
+        return m_socket != INVALID_CHARDEV_SOCKET_VALUE;
+      }
+  };
+
+};
+