Merge remote-tracking branch 'warped-rudi/cubox-stable' into development. Closes #50
authorLars Op den Kamp <lars@opdenkamp.eu>
Mon, 8 Oct 2012 18:24:03 +0000 (20:24 +0200)
committerLars Op den Kamp <lars@opdenkamp.eu>
Mon, 8 Oct 2012 18:24:03 +0000 (20:24 +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..9bf87861cffd4ba81ac7e702b8b81a90ecb437fa 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 a combined HDMI tranceiver / CEC controller by NXP. The
+device driver for it is based on an SDK by the chip vendor and is compiled into
+the Linux kernel. The following options for 'configure' have been introduced:
+
+To enable support for the CuBox:
+--enable-cubox
+
+To specify the path to the SDK part of the kernel driver:
+--with-tda995x-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 2962a1562b979c7c24706cbf6e5cb1a2ae0311c5..967699255c51c1085d056f5f7276cb4f5061b6dc 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_tda995x=$enableval],
+  [use_tda995x=no])
+
+## Optional path to the tda995x dev toolkit
+AC_ARG_WITH([tda995x-toolkit-path],
+  [AS_HELP_STRING([--with-tda995x-toolkit-path],
+    [location of the TDA995x driver toolkit (default is ./nxp_hdmi)])],
+  [TDA995X_CFLAGS="-I$withval/inc"],
+  [TDA995X_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_tda995x" != "xno"; then
+  AC_DEFINE([HAVE_TDA995X_API],[1],[Define to 1 to include CuBox support])
+  AM_CONDITIONAL(USE_TDA995X_API, true)
+  features="$features\n  CuBox support :\t\t\tyes"
+  LIB_INFO="$LIB_INFO 'CuBox'"
+  CPPFLAGS="$CPPFLAGS $TDA995X_CFLAGS"
+else
+  AM_CONDITIONAL(USE_TDA995X_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 58b6ef4cc97bd0ff44df0d5d6bfcf6de9fee3605..2af86437c726152708000c6cb77b3b8422aa2d11 100644 (file)
@@ -274,6 +274,16 @@ namespace CEC {
  */
 #define CEC_RPI_VIRTUAL_COM            "RPI"
 
+/*!
+ * the path to use for the TDA995x's CEC wire
+ */
+#define CEC_TDA995x_PATH               "/dev/hdmicec"
+
+/*!
+ * the name of the virtual COM port to use for the TDA995x's CEC wire
+ */
+#define CEC_TDA995x_VIRTUAL_COM                "CuBox"
+
 /*!
  * Mimimum client version
  */
@@ -299,6 +309,7 @@ namespace CEC {
 #define MSGESC                       0xFD
 #define ESCOFFSET                    3
 
+
 typedef enum cec_abort_reason
 {
   CEC_ABORT_REASON_UNRECOGNIZED_OPCODE            = 0,//!< CEC_ABORT_REASON_UNRECOGNIZED_OPCODE
@@ -830,7 +841,8 @@ typedef enum cec_adapter_type
   ADAPTERTYPE_UNKNOWN          = 0,
   ADAPTERTYPE_P8_EXTERNAL      = 0x1,
   ADAPTERTYPE_P8_DAUGHTERBOARD = 0x2,
-  ADAPTERTYPE_RPI              = 0x100
+  ADAPTERTYPE_RPI              = 0x100,
+  ADAPTERTYPE_TDA995x          = 0x200
 } cec_adapter_type;
 
 typedef struct cec_menu_language
index 45a62b63d5ffe51d45d7d85d919f45e9264101b4..6662182f50802be831d67e4f6174686fa842b766 100644 (file)
@@ -805,6 +805,8 @@ namespace CEC
         return "Pulse-Eight USB-CEC Daughterboard";
       case ADAPTERTYPE_RPI:
         return "Raspberry Pi";
+      case ADAPTERTYPE_TDA995x:
+        return "TDA995x";
       default:
         return "unknown";
       }
index 7ea1e99dd5bf742a66149f82c2d624369b535c4a..b88b02baf1ac1be7f3389fc07ada17d64ee0274c 100644 (file)
@@ -50,4 +50,11 @@ libcec_la_SOURCES += adapter/RPi/RPiCECAdapterDetection.cpp \
                      adapter/RPi/RPiCECAdapterMessageQueue.cpp
 endif
 
+## CuBox (NXP) support
+if USE_TDA995X_API
+libcec_la_SOURCES += adapter/CuBox/NxpCECAdapterDetection.cpp \
+                     adapter/CuBox/NxpCECAdapterCommunication.cpp
+endif
+
+
 libcec_la_LDFLAGS = @LIBS_LIBCEC@ -version-info @VERSION@
index 9ee9cc7c664516b51782ef06fcd8b38952fb2763..d1dae84ac69b0de80e7f0ceebcbaeefe272277ab 100644 (file)
 #include "RPi/RPiCECAdapterCommunication.h"
 #endif
 
+#if defined(HAVE_TDA995X_API)
+#include "CuBox/NxpCECAdapterDetection.h"
+#include "CuBox/NxpCECAdapterCommunication.h"
+#endif
+
 using namespace std;
 using namespace CEC;
 
@@ -75,7 +80,16 @@ int8_t CAdapterFactory::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize,
   }
 #endif
 
-#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB)
+#if defined(HAVE_TDA995X_API)
+  if (iAdaptersFound < iBufSize && CNxpCECAdapterDetection::FindAdapter() &&
+      (!strDevicePath || !strcmp(strDevicePath, CEC_TDA995x_VIRTUAL_COM)))
+  {
+    snprintf(deviceList[iAdaptersFound].path, 1024, CEC_TDA995x_PATH);
+    snprintf(deviceList[iAdaptersFound++].comm, 1024, CEC_TDA995x_VIRTUAL_COM);
+  }
+#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
 
@@ -84,6 +98,11 @@ int8_t CAdapterFactory::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize,
 
 IAdapterCommunication *CAdapterFactory::GetInstance(const char *strPort, uint16_t iBaudRate)
 {
+#if defined(HAVE_TDA995X_API)
+  if (!strcmp(strPort, CEC_TDA995x_VIRTUAL_COM))
+    return new CNxpCECAdapterCommunication(m_lib->m_cec);
+#endif
+
 #if defined(HAVE_RPI_API)
   if (!strcmp(strPort, CEC_RPI_VIRTUAL_COM))
     return new CRPiCECAdapterCommunication(m_lib->m_cec);
@@ -93,7 +112,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_TDA995X_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..d17f344
--- /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..e46f94e
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * 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_TDA995X_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()
+
+// 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) :
+    IAdapterCommunication(callback),
+    m_bLogicalAddressChanged(false)
+{ 
+  CLockObject lock(m_mutex);
+
+  m_iNextMessage = 0;
+  m_logicalAddresses.Clear();
+  m_dev = new CCDevSocket(CEC_TDA995x_PATH);
+}
+
+
+CNxpCECAdapterCommunication::~CNxpCECAdapterCommunication(void)
+{
+  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 UNUSED(bSkipChecks), bool 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)
+{
+  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;
+
+  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;
+    }
+    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);
+  
+  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; 
+  }
+  
+  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; 
+  }
+  
+  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;
+  }
+
+  return m_logicalAddresses;
+}
+
+
+bool CNxpCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses)
+{
+  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 UNUSED(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);
+      
+      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_TDA995X_API
diff --git a/src/lib/adapter/CuBox/NxpCECAdapterCommunication.h b/src/lib/adapter/CuBox/NxpCECAdapterCommunication.h
new file mode 100644 (file)
index 0000000..066c032
--- /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_TDA995X_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);
+    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_TDA995x; }
+    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..b4b7495
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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_TDA995X_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)
+{
+  return access(CEC_TDA995x_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 06df1e45888af8b5ba26037755808501fd571032..739c6a71823d76ee002f306fb11888325775010e 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;
+      }
+  };
+
+};
+