diff --git a/packages/devel/libcec/package.mk b/packages/devel/libcec/package.mk index 215bac45d0..0306c667f5 100644 --- a/packages/devel/libcec/package.mk +++ b/packages/devel/libcec/package.mk @@ -43,6 +43,12 @@ else EXTRA_CMAKE_OPTS="-DHAVE_IMX_API=0" fi +if [ "$KODIPLAYER_DRIVER" = "libamcodec" ]; then + EXTRA_CMAKE_OPTS="-DHAVE_AMLOGIC_API=1" +else + EXTRA_CMAKE_OPTS="-DHAVE_AMLOGIC_API=0" +fi + configure_target() { if [ "$KODIPLAYER_DRIVER" = "bcm2835-driver" ]; then export CXXFLAGS="$CXXFLAGS \ diff --git a/packages/devel/libcec/patches/libcec-03-amlogic-support.patch b/packages/devel/libcec/patches/libcec-03-amlogic-support.patch new file mode 100644 index 0000000000..8d58b75439 --- /dev/null +++ b/packages/devel/libcec/patches/libcec-03-amlogic-support.patch @@ -0,0 +1,733 @@ +diff -Nur -x .cproject -x .project -x .settings libcec-3.0.1/include/cectypes.h libcec-3.0.1-with-amlogic-adapter/include/cectypes.h +--- libcec-3.0.1/include/cectypes.h 2016-02-21 01:11:20.791177759 +0100 ++++ libcec-3.0.1-with-amlogic-adapter/include/cectypes.h 2016-02-10 13:45:19.057046951 +0100 +@@ -320,6 +320,16 @@ + + + /*! ++ * the path to use for the Amlogic HDMI CEC device ++ */ ++#define CEC_AMLOGIC_PATH "/dev/AmlogicCEC" ++ ++/*! ++ * the name of the virtual COM port to use for the AMLOGIC' CEC wire ++ */ ++#define CEC_AMLOGIC_VIRTUAL_COM "Amlogic" ++ ++/*! + * Mimimum client version + */ + #define CEC_MIN_LIB_VERSION 3 +@@ -888,7 +898,8 @@ + ADAPTERTYPE_RPI = 0x100, + ADAPTERTYPE_TDA995x = 0x200, + ADAPTERTYPE_EXYNOS = 0x300, +- ADAPTERTYPE_IMX = 0x400 ++ ADAPTERTYPE_IMX = 0x400, ++ ADAPTERTYPE_AMLOGIC = 0x500 + } cec_adapter_type; + + /** force exporting through swig */ +diff -Nur -x .cproject -x .project -x .settings libcec-3.0.1/README.md libcec-3.0.1-with-amlogic-adapter/README.md +--- libcec-3.0.1/README.md 2015-07-03 19:20:49.000000000 +0200 ++++ libcec-3.0.1-with-amlogic-adapter/README.md 2016-02-10 12:03:54.517523977 +0100 +@@ -58,6 +58,12 @@ + cmake -DHAVE_EXYNOS_API=1 .. + ``` + ++### Amlogic ++To compile in support for Amlogic devices, you have to pass the argument -DHAVE_AMLOGIC_API=1 to cmake: ++``` ++cmake -DHAVE_AMLOGIC_API=1 .. ++``` ++ + ## TDA995x ## + To compile in support for TDA995x devices, you have to pass the argument -DHAVE_TDA995X_API=1 to cmake: + ``` +diff -Nur -x .cproject -x .project -x .settings libcec-3.0.1/src/libcec/adapter/AdapterFactory.cpp libcec-3.0.1-with-amlogic-adapter/src/libcec/adapter/AdapterFactory.cpp +--- libcec-3.0.1/src/libcec/adapter/AdapterFactory.cpp 2016-02-21 01:11:12.579266950 +0100 ++++ libcec-3.0.1-with-amlogic-adapter/src/libcec/adapter/AdapterFactory.cpp 2016-02-10 12:41:44.252060917 +0100 +@@ -63,6 +63,11 @@ + #include "IMX/IMXCECAdapterCommunication.h" + #endif + ++#if defined(HAVE_AMLOGIC_API) ++#include "Amlogic/AmlogicCECAdapterDetection.h" ++#include "Amlogic/AmlogicCECAdapterCommunication.h" ++#endif ++ + using namespace CEC; + + int8_t CAdapterFactory::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */) +@@ -131,6 +136,18 @@ + } + #endif + ++#if defined(HAVE_AMLOGIC_API) ++ if (iAdaptersFound < iBufSize && CAmlogicCECAdapterDetection::FindAdapter()) ++ { ++ snprintf(deviceList[iAdaptersFound].strComPath, sizeof(deviceList[iAdaptersFound].strComPath), CEC_AMLOGIC_PATH); ++ snprintf(deviceList[iAdaptersFound].strComName, sizeof(deviceList[iAdaptersFound].strComName), CEC_AMLOGIC_VIRTUAL_COM); ++ deviceList[iAdaptersFound].iVendorId = 0; ++ deviceList[iAdaptersFound].iProductId = 0; ++ deviceList[iAdaptersFound].adapterType = ADAPTERTYPE_AMLOGIC; ++ iAdaptersFound++; ++ } ++#endif ++ + + + #if defined(HAVE_IMX_API) +@@ -166,6 +183,11 @@ + return new CExynosCECAdapterCommunication(m_lib->m_cec); + #endif + ++#if defined(HAVE_AMLOGIC_API) ++ if (!strcmp(strPort, CEC_AMLOGIC_VIRTUAL_COM)) ++ return new CAmlogicCECAdapterCommunication(m_lib->m_cec); ++#endif ++ + #if defined(HAVE_RPI_API) + if (!strcmp(strPort, CEC_RPI_VIRTUAL_COM)) + return new CRPiCECAdapterCommunication(m_lib->m_cec); +@@ -180,7 +202,7 @@ + return new CUSBCECAdapterCommunication(m_lib->m_cec, strPort, iBaudRate); + #endif + +-#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) && !defined(HAVE_TDA995X_API) && !defined(HAVE_EXYNOS_API) && !defined(HAVE_IMX_API) ++#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) && !defined(HAVE_TDA995X_API) && !defined(HAVE_EXYNOS_API) && !defined(HAVE_IMX_API) && !defined(HAVE_AMLOGIC_API) + return NULL; + #endif + } +diff -Nur -x .cproject -x .project -x .settings libcec-3.0.1/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.cpp libcec-3.0.1-with-amlogic-adapter/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.cpp +--- libcec-3.0.1/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ libcec-3.0.1-with-amlogic-adapter/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.cpp 2016-02-28 12:31:26.771045268 +0100 +@@ -0,0 +1,298 @@ ++/* ++ * This file is part of the libCEC(R) library. ++ * ++ * libCEC Amlogic Code Copyright (C) 2016 Gerald Dachs ++ * based heavily on: ++ * libCEC Exynos Code Copyright (C) 2014 Valentin Manea ++ * libCEC(R) is Copyright (C) 2011-2015 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 ++ * http://www.pulse-eight.com/ ++ * http://www.pulse-eight.net/ ++ */ ++ ++#include "env.h" ++#include ++#include ++ ++ ++#if defined(HAVE_AMLOGIC_API) ++#include "AmlogicCEC.h" ++#include "AmlogicCECAdapterCommunication.h" ++ ++#include "CECTypeUtils.h" ++#include "LibCEC.h" ++#include ++ ++using namespace CEC; ++using namespace PLATFORM; ++ ++#define LIB_CEC m_callback->GetLib() ++ ++ ++CAmlogicCECAdapterCommunication::CAmlogicCECAdapterCommunication(IAdapterCommunicationCallback *callback) : ++ IAdapterCommunication(callback), ++ m_bLogicalAddressChanged(false) ++{ ++ CLockObject lock(m_mutex); ++ ++ m_logicalAddresses.Clear(); ++ m_fd = INVALID_SOCKET_VALUE; ++} ++ ++ ++CAmlogicCECAdapterCommunication::~CAmlogicCECAdapterCommunication(void) ++{ ++ Close(); ++} ++ ++ ++bool CAmlogicCECAdapterCommunication::IsOpen(void) ++{ ++ CLockObject lock(m_mutex); ++ return IsInitialised() && m_fd != INVALID_SOCKET_VALUE; ++} ++ ++ ++bool CAmlogicCECAdapterCommunication::Open(uint32_t UNUSED(iTimeoutMs), bool UNUSED(bSkipChecks), bool bStartListening) ++{ ++ if (IsOpen()) ++ Close(); ++ ++ CLockObject lock(m_mutex); ++ ++ if ((m_fd = open(CEC_AMLOGIC_PATH, O_RDWR)) > 0) ++ { ++ if (!bStartListening || CreateThread()) { ++ return true; ++ } ++ close(m_fd); ++ m_fd = INVALID_SOCKET_VALUE; ++ } ++ return false; ++} ++ ++ ++void CAmlogicCECAdapterCommunication::Close(void) ++{ ++ StopThread(0); ++ ++ CLockObject lock(m_mutex); ++ ++ close(m_fd); ++ m_fd = INVALID_SOCKET_VALUE; ++} ++ ++ ++std::string CAmlogicCECAdapterCommunication::GetError(void) const ++{ ++ std::string strError(m_strError); ++ return strError; ++} ++ ++int CAmlogicCECAdapterCommunication::getFileDescriptor(void) ++{ ++ CLockObject lock(m_mutex); ++ ++ return m_fd; ++} ++ ++ ++ ++cec_adapter_message_state CAmlogicCECAdapterCommunication::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; ++ ++ CLockObject lock(m_mutex); ++ ++ 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 CAmlogicCECAdapterCommunication::GetFirmwareVersion(void) ++{ ++ return 0; ++} ++ ++ ++cec_vendor_id CAmlogicCECAdapterCommunication::GetVendorId(void) ++{ ++ return cec_vendor_id(CEC_VENDOR_UNKNOWN); ++} ++ ++ ++uint16_t CAmlogicCECAdapterCommunication::GetPhysicalAddress(void) ++{ ++ int phys_addr = CEC_DEFAULT_PADDR; ++ ++ if (!IsOpen()) ++ return (uint16_t)phys_addr; ++ ++ CLockObject lock(m_mutex); ++ ++ if ((phys_addr = ioctl(m_fd, CEC_IOC_GETPADDR)) < 0) ++ { ++ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: IOCTL GetPhysicalAddr failed !", __func__); ++ phys_addr = CEC_DEFAULT_PADDR; ++ } ++ return (uint16_t)phys_addr; ++} ++ ++ ++cec_logical_addresses CAmlogicCECAdapterCommunication::GetLogicalAddresses(void) ++{ ++ return m_logicalAddresses; ++} ++ ++ ++bool CAmlogicCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses) ++{ ++ unsigned int log_addr = addresses.primary; ++ if (!IsOpen()) ++ return false; ++ ++ CLockObject lock(m_mutex); ++ ++ 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 CAmlogicCECAdapterCommunication::HandleLogicalAddressLost(cec_logical_address UNUSED(oldAddress)) ++{ ++ unsigned int log_addr = CECDEVICE_BROADCAST; ++ ++ if (!IsOpen()) ++ return; ++ ++ CLockObject lock(m_mutex); ++ ++ if (ioctl(m_fd, CEC_IOC_SETLADDR, &log_addr)) ++ { ++ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: IOCTL SetLogicalAddr failed !", __func__); ++ } ++} ++ ++ ++void *CAmlogicCECAdapterCommunication::Process(void) ++{ ++ uint8_t buffer[CEC_MAX_FRAME_SIZE]; ++ uint32_t size; ++ fd_set rfds; ++ cec_logical_address initiator, destination; ++ ++ if (!IsOpen()) ++ return 0; ++ ++ while (!IsStopped()) ++ { ++ int fd = getFileDescriptor(); ++ ++ if (fd == INVALID_SOCKET_VALUE) ++ { ++ break; ++ } ++ ++ FD_ZERO(&rfds); ++ FD_SET(fd, &rfds); ++ ++ if (select(fd + 1, &rfds, NULL, NULL, NULL) >= 0 ) ++ { ++ size = read(fd, buffer, CEC_MAX_FRAME_SIZE); ++ ++ if (size > 0) ++ { ++ if (buffer[0] == 0xff) // driver wants us to reread the physical address ++ { ++ if (!IsStopped()) ++ { ++ uint16_t iNewAddress = GetPhysicalAddress(); ++ m_callback->HandlePhysicalAddressChanged(iNewAddress); ++ } ++ continue; ++ } ++ ++ 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_AMLOGIC_API +diff -Nur -x .cproject -x .project -x .settings libcec-3.0.1/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.h libcec-3.0.1-with-amlogic-adapter/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.h +--- libcec-3.0.1/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.h 1970-01-01 01:00:00.000000000 +0100 ++++ libcec-3.0.1-with-amlogic-adapter/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.h 2016-02-28 12:16:30.985474428 +0100 +@@ -0,0 +1,105 @@ ++#pragma once ++/* ++ * This file is part of the libCEC(R) library. ++ * ++ * libCEC Amlogic Code Copyright (C) 2016 Gerald Dachs ++ * based heavily on: ++ * libCEC Exynos Code Copyright (C) 2014 Valentin Manea ++ * libCEC(R) is Copyright (C) 2011-2015 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 ++ * http://www.pulse-eight.com/ ++ * http://www.pulse-eight.net/ ++ */ ++ ++#include "env.h" ++ ++#if defined(HAVE_AMLOGIC_API) ++ ++#include ++#include ++#include "../AdapterCommunication.h" ++#include ++ ++namespace CEC ++{ ++ class CAmlogicCECAdapterCommunication : 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. ++ */ ++ CAmlogicCECAdapterCommunication(IAdapterCommunicationCallback *callback); ++ virtual ~CAmlogicCECAdapterCommunication(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("AMLOGIC"); } ++ 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_AMLOGIC; } ++ 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; }; ++ int getFileDescriptor(void); ++ ++ std::string m_strError; /**< current error message */ ++ ++ bool m_bLogicalAddressChanged; ++ cec_logical_addresses m_logicalAddresses; ++ PLATFORM::CMutex m_mutex; ++ int m_fd; ++ }; ++}; ++#endif +diff -Nur -x .cproject -x .project -x .settings libcec-3.0.1/src/libcec/adapter/Amlogic/AmlogicCECAdapterDetection.cpp libcec-3.0.1-with-amlogic-adapter/src/libcec/adapter/Amlogic/AmlogicCECAdapterDetection.cpp +--- libcec-3.0.1/src/libcec/adapter/Amlogic/AmlogicCECAdapterDetection.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ libcec-3.0.1-with-amlogic-adapter/src/libcec/adapter/Amlogic/AmlogicCECAdapterDetection.cpp 2016-02-10 11:57:58.445532459 +0100 +@@ -0,0 +1,50 @@ ++/* ++ * This file is part of the libCEC(R) library. ++ * ++ * libCEC Amlogic Code Copyright (C) 2016 Gerald Dachs ++ * based heavily on: ++ * libCEC Exynos Code Copyright (C) 2014 Valentin Manea ++ * libCEC(R) is Copyright (C) 2011-2015 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 ++ * http://www.pulse-eight.com/ ++ * http://www.pulse-eight.net/ ++ */ ++ ++#include "env.h" ++#include ++ ++#if defined(HAVE_AMLOGIC_API) ++#include "AmlogicCECAdapterDetection.h" ++#include "AmlogicCEC.h" ++ ++using namespace CEC; ++ ++bool CAmlogicCECAdapterDetection::FindAdapter(void) ++{ ++ return access(CEC_AMLOGIC_PATH, 0) == 0; ++} ++ ++#endif +diff -Nur -x .cproject -x .project -x .settings libcec-3.0.1/src/libcec/adapter/Amlogic/AmlogicCECAdapterDetection.h libcec-3.0.1-with-amlogic-adapter/src/libcec/adapter/Amlogic/AmlogicCECAdapterDetection.h +--- libcec-3.0.1/src/libcec/adapter/Amlogic/AmlogicCECAdapterDetection.h 1970-01-01 01:00:00.000000000 +0100 ++++ libcec-3.0.1-with-amlogic-adapter/src/libcec/adapter/Amlogic/AmlogicCECAdapterDetection.h 2016-02-10 11:57:58.445532459 +0100 +@@ -0,0 +1,46 @@ ++#pragma once ++/* ++ * This file is part of the libCEC(R) library. ++ * ++ * libCEC Amlogic Code Copyright (C) 2016 Gerald Dachs ++ * based heavily on: ++ * libCEC Exynos Code Copyright (C) 2014 Valentin Manea ++ * libCEC(R) is Copyright (C) 2011-2015 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 ++ * http://www.pulse-eight.com/ ++ * http://www.pulse-eight.net/ ++ */ ++ ++#include "env.h" ++ ++namespace CEC ++{ ++ class CAmlogicCECAdapterDetection ++ { ++ public: ++ static bool FindAdapter(void); ++ }; ++} +diff -Nur -x .cproject -x .project -x .settings libcec-3.0.1/src/libcec/adapter/Amlogic/AmlogicCEC.h libcec-3.0.1-with-amlogic-adapter/src/libcec/adapter/Amlogic/AmlogicCEC.h +--- libcec-3.0.1/src/libcec/adapter/Amlogic/AmlogicCEC.h 1970-01-01 01:00:00.000000000 +0100 ++++ libcec-3.0.1-with-amlogic-adapter/src/libcec/adapter/Amlogic/AmlogicCEC.h 2016-02-10 11:57:58.445532459 +0100 +@@ -0,0 +1,41 @@ ++#pragma once ++/* ++ * This file is part of the libCEC(R) library. ++ * ++ * libCEC Amlogic Code Copyright (C) 2016 Gerald Dachs ++ * based heavily on: ++ * libCEC Exynos Code Copyright (C) 2014 Valentin Manea ++ * libCEC(R) is Copyright (C) 2011-2015 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 ++ * http://www.pulse-eight.com/ ++ * http://www.pulse-eight.net/ ++ */ ++ ++ ++#define CEC_DEFAULT_PADDR 0x1000 ++#define CEC_IOC_SETLADDR _IOW('c', 0, unsigned int) ++#define CEC_IOC_GETPADDR _IO('c', 1) ++#define CEC_MAX_FRAME_SIZE 16 +diff -Nur -x .cproject -x .project -x .settings libcec-3.0.1/src/libcec/cmake/CheckPlatformSupport.cmake libcec-3.0.1-with-amlogic-adapter/src/libcec/cmake/CheckPlatformSupport.cmake +--- libcec-3.0.1/src/libcec/cmake/CheckPlatformSupport.cmake 2016-02-21 01:11:12.579266950 +0100 ++++ libcec-3.0.1-with-amlogic-adapter/src/libcec/cmake/CheckPlatformSupport.cmake 2016-02-10 13:18:20.847385373 +0100 +@@ -11,6 +11,7 @@ + # HAVE_IMX_API 1 if i.MX is supported + # HAVE_TDA995X_API 1 if TDA995X is supported + # HAVE_EXYNOS_API 1 if Exynos is supported ++# HAVE_AMLOGIC_API 1 if Amlogic is supported + # HAVE_P8_USB_DETECT 1 if Pulse-Eight devices can be auto-detected + # + +@@ -129,6 +130,18 @@ + else() + set(HAVE_EXYNOS_API 0) + endif() ++ ++ # Amlogic ++ if (${HAVE_AMLOGIC_API}) ++ set(LIB_INFO "${LIB_INFO}, Amlogic") ++ set(HAVE_AMLOGIC_API 1) ++ set(CEC_SOURCES_ADAPTER_AMLOGIC adapter/Amlogic/AmlogicCECAdapterDetection.cpp ++ adapter/Amlogic/AmlogicCECAdapterCommunication.cpp) ++ source_group("Source Files\\adapter\\Amlogic" FILES ${CEC_SOURCES_ADAPTER_AMLOGIC}) ++ list(APPEND CEC_SOURCES ${CEC_SOURCES_ADAPTER_AMLOGIC}) ++ else() ++ set(HAVE_AMLOGIC_API 0) ++ endif() + endif() + + # rt +diff -Nur -x .cproject -x .project -x .settings libcec-3.0.1/src/libcec/cmake/DisplayPlatformSupport.cmake libcec-3.0.1-with-amlogic-adapter/src/libcec/cmake/DisplayPlatformSupport.cmake +--- libcec-3.0.1/src/libcec/cmake/DisplayPlatformSupport.cmake 2016-02-21 01:11:12.579266950 +0100 ++++ libcec-3.0.1-with-amlogic-adapter/src/libcec/cmake/DisplayPlatformSupport.cmake 2016-02-10 12:47:10.380408360 +0100 +@@ -50,6 +50,12 @@ + message(STATUS "Exynos support: no") + endif() + ++if (HAVE_AMLOGIC_API) ++ message(STATUS "Amlogic support: yes") ++else() ++ message(STATUS "Amlogic support: no") ++endif() ++ + if (HAVE_PYTHON) + message(STATUS "Python support: version ${PYTHONLIBS_VERSION_STRING} (${PYTHON_VERSION})") + else() +diff -Nur -x .cproject -x .project -x .settings libcec-3.0.1/src/libcec/CMakeLists.txt libcec-3.0.1-with-amlogic-adapter/src/libcec/CMakeLists.txt +--- libcec-3.0.1/src/libcec/CMakeLists.txt 2015-07-03 19:20:49.000000000 +0200 ++++ libcec-3.0.1-with-amlogic-adapter/src/libcec/CMakeLists.txt 2016-02-10 11:57:58.445532459 +0100 +@@ -83,6 +83,9 @@ + adapter/Exynos/ExynosCEC.h + adapter/Exynos/ExynosCECAdapterDetection.h + adapter/Exynos/ExynosCECAdapterCommunication.h ++ adapter/Amlogic/AmlogicCEC.h ++ adapter/Amlogic/AmlogicCECAdapterDetection.h ++ adapter/Amlogic/AmlogicCECAdapterCommunication.h + adapter/Pulse-Eight/USBCECAdapterMessageQueue.h + adapter/Pulse-Eight/USBCECAdapterCommunication.h + adapter/Pulse-Eight/USBCECAdapterCommands.h +diff -Nur -x .cproject -x .project -x .settings libcec-3.0.1/src/libcec/env.h.in libcec-3.0.1-with-amlogic-adapter/src/libcec/env.h.in +--- libcec-3.0.1/src/libcec/env.h.in 2016-02-21 01:11:12.579266950 +0100 ++++ libcec-3.0.1-with-amlogic-adapter/src/libcec/env.h.in 2016-02-10 11:57:58.449532413 +0100 +@@ -69,6 +69,9 @@ + /* Define to 1 for Exynos support */ + #cmakedefine HAVE_EXYNOS_API @HAVE_EXYNOS_API@ + ++/* Define to 1 for Amlogic support */ ++#cmakedefine HAVE_AMLOGIC_API @HAVE_AMLOGIC_API@ ++ + /* Define to 1 for nVidia EDID parsing support (on selected models) */ + #cmakedefine HAVE_NVIDIA_EDID_PARSER @HAVE_NVIDIA_EDID_PARSER@ + diff --git a/projects/WeTek_Play/linux/linux.arm.conf b/projects/WeTek_Play/linux/linux.arm.conf index 274e2c074b..69e63b5fee 100644 --- a/projects/WeTek_Play/linux/linux.arm.conf +++ b/projects/WeTek_Play/linux/linux.arm.conf @@ -1232,6 +1232,7 @@ CONFIG_AM_HDMI_ONLY=y # CONFIG_AML_HDMI_TX_20 is not set CONFIG_AML_HDMI_TX=y # CONFIG_AML_HDMI_TX_HDCP is not set +CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER=y # CONFIG_TVIN is not set # CONFIG_AML_EXT_HDMIIN is not set # CONFIG_DEBUG_DRIVER is not set diff --git a/projects/WeTek_Play/patches/linux/080-amlogic-cec-driver.patch b/projects/WeTek_Play/patches/linux/080-amlogic-cec-driver.patch new file mode 100644 index 0000000000..84ddbaa9be --- /dev/null +++ b/projects/WeTek_Play/patches/linux/080-amlogic-cec-driver.patch @@ -0,0 +1,829 @@ +diff --git a/arch/arm/mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c b/arch/arm/mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c +index a2a78bd..762feba 100644 +--- a/arch/arm/mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c ++++ b/arch/arm/mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c +@@ -996,6 +996,7 @@ void cec_tx_irq_handle(void) + #endif + } + ++#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER + void cec_polling_online_dev(int log_addr, int *bool) + { + #ifdef AO_CEC +@@ -1005,7 +1006,7 @@ void cec_polling_online_dev(int log_addr, int *bool) + #endif + hdmi_print(INF, CEC "CEC: poll online logic device: 0x%x BOOL: %d\n", log_addr, *bool); + } +- ++#endif + + // DELETE LATER, TEST ONLY + void cec_test_(unsigned int cmd) +diff --git a/drivers/amlogic/hdmi/Kconfig b/drivers/amlogic/hdmi/Kconfig +index 71f6bf8..1bfc289 100755 +--- a/drivers/amlogic/hdmi/Kconfig ++++ b/drivers/amlogic/hdmi/Kconfig +@@ -24,4 +24,12 @@ config AML_HDMI_TX_HDCP + hdmitx hdcp enable, it should be enalbe if board burned hdmitx hdcp keys + endif + ++if AML_HDMI_TX ++config AML_HDMI_TX_NEW_CEC_DRIVER ++ bool "HDMI new CEC driver" ++ default n ++ help ++ hdmitx uses new CEC driver ++endif ++ + endmenu +diff --git a/drivers/amlogic/hdmi/hdmi_tx/Makefile b/drivers/amlogic/hdmi/hdmi_tx/Makefile +index 7a944cd..f74ec1f 100755 +--- a/drivers/amlogic/hdmi/hdmi_tx/Makefile ++++ b/drivers/amlogic/hdmi/hdmi_tx/Makefile +@@ -1,5 +1,11 @@ + obj-$(CONFIG_AML_HDMI_TX) += hdmitx.o + +-hdmitx-objs := hdmi_tx.o hdmi_tx_cec.o hdmi_cec_key.o hdmi_tx_video.o hdmi_tx_audio.o hdmi_tx_edid.o hdmi_tx_audio.o hdmi_tx_hdcp.o hdmi_tx_compliance.o ++hdmitx-objs := hdmi_tx.o hdmi_tx_video.o hdmi_tx_audio.o hdmi_tx_edid.o hdmi_tx_audio.o hdmi_tx_hdcp.o hdmi_tx_compliance.o ++ ++ifdef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER ++ hdmitx-objs += amlogic_cec.o ++else ++ hdmitx-objs += hdmi_tx_cec.o hdmi_cec_key.o ++endif + + #EXTRA_CFLAGS += -O2 +diff --git a/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c b/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c +new file mode 100644 +index 0000000..7d8992a +--- /dev/null ++++ b/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c +@@ -0,0 +1,603 @@ ++/* linux/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c ++ * ++ * Copyright (c) 2016 Gerald Dachs ++ * ++ * CEC interface file for Amlogic ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define CONFIG_TV_DEBUG // for verbose output ++//#undef CONFIG_TV_DEBUG ++unsigned long amlogic_cec_debug_flag = 1; ++ ++MODULE_AUTHOR("Gerald Dachs"); ++MODULE_DESCRIPTION("Amlogic CEC driver"); ++MODULE_LICENSE("GPL"); ++ ++//unused, only left to satisfy the linker ++bool cec_msg_dbg_en = 1; ++ ++#define DRV_NAME "amlogic_cec" ++#ifndef amlogic_cec_log_dbg ++#define amlogic_cec_log_dbg(fmt, ...) \ ++ if (amlogic_cec_debug_flag) \ ++ printk(KERN_INFO "[%s] %s(): " fmt, DRV_NAME, __func__, ##__VA_ARGS__) ++#endif ++ ++#define CEC_IOC_MAGIC 'c' ++#define CEC_IOC_SETLADDR _IOW(CEC_IOC_MAGIC, 0, unsigned int) ++#define CEC_IOC_GETPADDR _IO(CEC_IOC_MAGIC, 1) ++ ++#define VERSION "0.0.1" /* Driver version number */ ++#define CEC_MINOR 243 /* Major 10, Minor 242, /dev/cec */ ++ ++/* CEC Rx buffer size */ ++#define CEC_RX_BUFF_SIZE 16 ++/* CEC Tx buffer size */ ++#define CEC_TX_BUFF_SIZE 16 ++ ++struct cec_rx_list { ++ u8 buffer[CEC_RX_BUFF_SIZE]; ++ unsigned char size; ++ struct list_head list; ++}; ++ ++struct cec_rx_struct { ++ spinlock_t lock; ++ wait_queue_head_t waitq; ++ atomic_t state; ++ struct list_head list; ++}; ++ ++struct cec_tx_struct { ++ spinlock_t lock; ++ wait_queue_head_t waitq; ++ atomic_t state; ++}; ++ ++enum cec_state { ++ STATE_RX, ++ STATE_TX, ++ STATE_DONE, ++ STATE_ERROR ++}; ++ ++static char banner[] __initdata = ++ "Amlogic CEC Driver, (c) 2016 Gerald Dachs"; ++ ++static struct cec_rx_struct cec_rx_struct; ++ ++static struct cec_tx_struct cec_tx_struct; ++ ++static atomic_t hdmi_on = ATOMIC_INIT(0); ++ ++cec_global_info_t cec_global_info; ++ ++static hdmitx_dev_t* hdmitx_device = NULL; ++ ++static void amlogic_cec_set_rx_state(enum cec_state state) ++{ ++ atomic_set(&cec_rx_struct.state, state); ++} ++ ++static void amlogic_cec_set_tx_state(enum cec_state state) ++{ ++ atomic_set(&cec_tx_struct.state, state); ++} ++ ++static void amlogic_cec_msg_dump(char * msg_tag, const unsigned char *data, unsigned char count) ++{ ++ int i; ++ int pos; ++ unsigned char msg_log_buf[128] = { 0 }; ++ ++ if (amlogic_cec_debug_flag == 1) ++ { ++ pos = 0; ++ pos += sprintf(msg_log_buf + pos, "msg %s len: %d dat: ", msg_tag, count); ++ for (i = 0; i < count; ++i) ++ { ++ pos += sprintf(msg_log_buf + pos, "%02x ", data[i]); ++ } ++ pos += sprintf(msg_log_buf + pos, "\n"); ++ msg_log_buf[pos] = '\0'; ++ hdmi_print(INF, "[amlogic_cec] dump: %s", msg_log_buf); ++ } ++} ++ ++static unsigned int amlogic_cec_read_reg(unsigned int reg) ++{ ++#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 ++ return hdmi_rd_reg(CEC0_BASE_ADDR + reg); ++#endif ++#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 ++ return aocec_rd_reg(reg); ++#endif ++} ++ ++static void amlogic_cec_write_reg(unsigned int reg, unsigned int value) ++{ ++#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 ++ hdmi_wr_reg(CEC0_BASE_ADDR + reg, value); ++#endif ++#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 ++ aocec_wr_reg(reg, value); ++#endif ++} ++ ++static int amlogic_cec_read_hw(unsigned char *data, unsigned char *count) ++{ ++ int ret = -1; ++ int valid_msg; ++ int rx_msg_status; ++ int rx_num_msg; ++ ++ rx_msg_status = amlogic_cec_read_reg(CEC_RX_MSG_STATUS); ++ rx_num_msg = amlogic_cec_read_reg(CEC_RX_NUM_MSG); ++ ++ amlogic_cec_log_dbg("amlogic_cec_read_hw: enter: CEC_RX_MSG_STATUS %d, CEC_RX_NUM_MSG %d\n", rx_msg_status, rx_num_msg); ++ ++ valid_msg = (RX_DONE == rx_msg_status) && (1 == rx_num_msg); ++ ++ if (valid_msg) ++ { ++ int i; ++ ++ *count = amlogic_cec_read_reg(CEC_RX_MSG_LENGTH) + 1; ++ for (i = 0; i < (*count) && i < CEC_RX_BUFF_SIZE; ++i) ++ { ++ data[i]= amlogic_cec_read_reg(CEC_RX_MSG_0_HEADER + i); ++ } ++ ++ ret = RX_DONE; ++ } ++ ++ amlogic_cec_write_reg(CEC_RX_MSG_CMD, RX_ACK_CURRENT); ++ amlogic_cec_write_reg(CEC_RX_MSG_CMD, RX_NO_OP); ++ ++ if (valid_msg) ++ { ++ amlogic_cec_msg_dump("RX", data, *count); ++ } ++ ++ return ret; ++} ++ ++ ++static void amlogic_cec_write_hw(const char *data, size_t count) ++{ ++ int i; ++ ++ for (i = 0; i < count; ++i) ++ { ++ amlogic_cec_write_reg(CEC_TX_MSG_0_HEADER + i, data[i]); ++ } ++ amlogic_cec_write_reg(CEC_TX_MSG_LENGTH, count - 1); ++ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_REQ_CURRENT); ++ ++ amlogic_cec_msg_dump("TX", data, count); ++} ++ ++unsigned short cec_log_addr_to_dev_type(unsigned char log_addr) ++{ ++// unused, just to satisfy the linker ++ return log_addr; ++} ++ ++void cec_node_init(hdmitx_dev_t* hdmitx_device) ++{ ++ unsigned long cec_phy_addr; ++ unsigned long spin_flags; ++ struct cec_rx_list *entry; ++ ++ amlogic_cec_log_dbg("cec node init: enter\n"); ++ ++ cec_phy_addr = (((hdmitx_device->hdmi_info.vsdb_phy_addr.a) & 0xf) << 12) ++ | (((hdmitx_device->hdmi_info.vsdb_phy_addr.b) & 0xf) << 8) ++ | (((hdmitx_device->hdmi_info.vsdb_phy_addr.c) & 0xf) << 4) ++ | (((hdmitx_device->hdmi_info.vsdb_phy_addr.d) & 0xf) << 0); ++ ++ // If VSDB is not valid,use last or default physical address. ++ if (hdmitx_device->hdmi_info.vsdb_phy_addr.valid == 0) ++ { ++ amlogic_cec_log_dbg("no valid cec physical address\n"); ++ if (aml_read_reg32(P_AO_DEBUG_REG1)) ++ { ++ amlogic_cec_log_dbg("use last physical address\n"); ++ } ++ else ++ { ++ aml_write_reg32(P_AO_DEBUG_REG1, 0x1000); ++ amlogic_cec_log_dbg("use default physical address\n"); ++ } ++ } ++ else ++ { ++ aml_write_reg32(P_AO_DEBUG_REG1, cec_phy_addr); ++ amlogic_cec_log_dbg("physical address:0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); ++ ++ if ((hdmitx_device->cec_init_ready != 0) && (hdmitx_device->hpd_state != 0)) ++ { ++ if ((entry = kmalloc(sizeof(struct cec_rx_list), GFP_ATOMIC)) == NULL) ++ { ++ amlogic_cec_log_dbg("can't alloc cec_rx_list\n"); ++ } ++ else ++ { ++ // let the libCEC ask for new physical Address ++ entry->buffer[0] = 0xff; ++ entry->size = 1; ++ INIT_LIST_HEAD(&entry->list); ++ ++ spin_lock_irqsave(&cec_rx_struct.lock, spin_flags); ++ list_add_tail(&entry->list, &cec_rx_struct.list); ++ amlogic_cec_set_rx_state(STATE_DONE); ++ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); ++ ++ amlogic_cec_log_dbg("trigger libCEC\n"); ++ wake_up_interruptible(&cec_rx_struct.waitq); ++ } ++ } ++ } ++ amlogic_cec_log_dbg("cec node init: cec features ok !\n"); ++} ++ ++static int amlogic_cec_open(struct inode *inode, struct file *file) ++{ ++ int ret = 0; ++ ++ if (atomic_read(&hdmi_on)) ++ { ++ amlogic_cec_log_dbg("do not allow multiple open for tvout cec\n"); ++ ret = -EBUSY; ++ } ++ else ++ { ++ atomic_inc(&hdmi_on); ++ } ++ return ret; ++} ++ ++static int amlogic_cec_release(struct inode *inode, struct file *file) ++{ ++ atomic_dec(&hdmi_on); ++ ++ return 0; ++} ++ ++static ssize_t amlogic_cec_read(struct file *file, char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t retval; ++ unsigned long spin_flags; ++ struct cec_rx_list* entry = NULL; ++ ++ amlogic_cec_log_dbg("amlogic_cec_read: enter\n"); ++ ++ if (wait_event_interruptible(cec_rx_struct.waitq, ++ atomic_read(&cec_rx_struct.state) == STATE_DONE)) ++ { ++ amlogic_cec_log_dbg("error during wait on state change\n"); ++ return -ERESTARTSYS; ++ } ++ ++ spin_lock_irqsave(&cec_rx_struct.lock, spin_flags); ++ ++ entry = list_first_entry_or_null(&cec_rx_struct.list, struct cec_rx_list, list); ++ ++ if (entry == NULL || entry->size > count) ++ { ++ amlogic_cec_log_dbg("entry is NULL, or empty\n"); ++ retval = -1; ++ goto error_exit; ++ } ++ ++ if (copy_to_user(buffer, entry->buffer, entry->size)) ++ { ++ printk(KERN_ERR " copy_to_user() failed!\n"); ++ ++ retval = -EFAULT; ++ goto error_exit; ++ } ++ ++ retval = entry->size; ++ ++ amlogic_cec_set_rx_state(STATE_RX); ++ ++error_exit: ++ if (entry != NULL) ++ { ++ list_del(&entry->list); ++ kfree(entry); ++ } ++ ++ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); ++ ++ amlogic_cec_log_dbg("amlogic_cec_read: leave\n"); ++ ++ return retval; ++} ++ ++static ssize_t amlogic_cec_write(struct file *file, const char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ char data[CEC_TX_BUFF_SIZE]; ++ amlogic_cec_log_dbg("amlogic_cec_write: enter\n"); ++ ++ /* check data size */ ++ if (count > CEC_TX_BUFF_SIZE || count == 0) ++ return -1; ++ ++ if (copy_from_user(data, buffer, count)) ++ { ++ printk(KERN_ERR " copy_from_user() failed!\n"); ++ return -EFAULT; ++ } ++ ++ amlogic_cec_set_tx_state(STATE_TX); ++ ++ amlogic_cec_write_hw(data, count); ++ ++ if (wait_event_interruptible_timeout(cec_tx_struct.waitq, ++ atomic_read(&cec_tx_struct.state) != STATE_TX, 2 * HZ) <= 0) ++ { ++ amlogic_cec_log_dbg("error during wait on state change, resetting\n"); ++ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n"); ++ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_ABORT); // stop cec tx for hw retry. ++ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_NO_OP); ++ return -ERESTARTSYS; ++ } ++ ++ if (atomic_read(&cec_tx_struct.state) != STATE_DONE) ++ { ++ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n"); ++ return -1; ++ } ++ ++ amlogic_cec_log_dbg("amlogic_cec_write: leave\n"); ++ ++ return count; ++} ++ ++static long amlogic_cec_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ unsigned char logical_addr; ++ amlogic_cec_log_dbg("amlogic_cec_ioctl: enter\n"); ++ ++ switch(cmd) { ++ case CEC_IOC_SETLADDR: ++ if (get_user(logical_addr, (unsigned char __user *)arg)) ++ { ++ amlogic_cec_log_dbg("Failed to get logical addr from user\n"); ++ return -EFAULT; ++ } ++ ++ amlogic_cec_write_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | logical_addr); ++ amlogic_cec_log_dbg("amlogic_cec_ioctl: Set logical address: %d\n", logical_addr); ++ return 0; ++ ++ case CEC_IOC_GETPADDR: ++ amlogic_cec_log_dbg("amlogic_cec_ioctl: return physical address 0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); ++ return aml_read_reg32(P_AO_DEBUG_REG1); ++ } ++ ++ return -EINVAL; ++} ++ ++static u32 amlogic_cec_poll(struct file *file, poll_table *wait) ++{ ++ poll_wait(file, &cec_rx_struct.waitq, wait); ++ ++ if (atomic_read(&cec_rx_struct.state) == STATE_DONE) ++ { ++ return POLLIN | POLLRDNORM; ++ } ++ return 0; ++} ++ ++static const struct file_operations cec_fops = { ++ .owner = THIS_MODULE, ++ .open = amlogic_cec_open, ++ .release = amlogic_cec_release, ++ .read = amlogic_cec_read, ++ .write = amlogic_cec_write, ++ .unlocked_ioctl = amlogic_cec_ioctl, ++ .poll = amlogic_cec_poll, ++}; ++ ++static struct miscdevice cec_misc_device = { ++ .minor = CEC_MINOR, ++ .name = "AmlogicCEC", ++ .fops = &cec_fops, ++}; ++ ++static irqreturn_t amlogic_cec_irq_handler(int irq, void *dummy) ++{ ++ unsigned long spin_flags; ++ struct cec_rx_list *entry; ++ unsigned int tx_msg_state; ++ unsigned int rx_msg_state; ++ ++ amlogic_cec_log_dbg("amlogic_cec_irq_handler: enter\n"); ++ ++ udelay(100); //Delay execution a little. This fixes an issue when HDMI CEC stops working after a while. ++ ++ tx_msg_state = amlogic_cec_read_reg(CEC_TX_MSG_STATUS); ++ rx_msg_state = amlogic_cec_read_reg(CEC_RX_MSG_STATUS); ++ ++ amlogic_cec_log_dbg("cec msg status: rx: 0x%x; tx: 0x%x\n", rx_msg_state, tx_msg_state); ++ ++ if ((tx_msg_state == TX_DONE) || (tx_msg_state == TX_ERROR)) ++ { ++ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_NO_OP); ++ ++ switch (tx_msg_state) { ++ case TX_ERROR : ++ amlogic_cec_set_tx_state(STATE_ERROR); ++ break; ++ case TX_DONE : ++ amlogic_cec_set_tx_state(STATE_DONE); ++ break; ++ default : ++ amlogic_cec_log_dbg("unexpected ts message state: 0x%x", tx_msg_state); ++ break; ++ } ++ wake_up_interruptible(&cec_tx_struct.waitq); ++ } ++ ++ if (rx_msg_state == RX_DONE) ++ { ++ ++ if ((entry = kmalloc(sizeof(struct cec_rx_list), GFP_ATOMIC)) == NULL) ++ { ++ amlogic_cec_log_dbg("can't alloc cec_rx_list\n"); ++ return IRQ_HANDLED; ++ } ++ ++ if ((-1) == amlogic_cec_read_hw(entry->buffer, &entry->size)) ++ { ++ kfree(entry); ++ amlogic_cec_log_dbg("amlogic_cec_irq_handler: nothing to read\n"); ++ return IRQ_HANDLED; ++ } ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ spin_lock_irqsave(&cec_rx_struct.lock, spin_flags); ++ list_add_tail(&entry->list, &cec_rx_struct.list); ++ amlogic_cec_set_rx_state(STATE_DONE); ++ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); ++ ++ wake_up_interruptible(&cec_rx_struct.waitq); ++ } ++ ++ amlogic_cec_log_dbg("amlogic_cec_irq_handler: leave\n"); ++ ++ return IRQ_HANDLED; ++} ++ ++static int amlogic_cec_init(void) ++{ ++ extern hdmitx_dev_t * get_hdmitx_device(void); ++ INIT_LIST_HEAD(&cec_rx_struct.list); ++ ++ printk("%s, Version: %s\n", banner, VERSION); ++ ++ hdmitx_device = get_hdmitx_device(); ++ amlogic_cec_log_dbg("CEC init\n"); ++#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 ++ hdmi_wr_reg(CEC0_BASE_ADDR+CEC_CLOCK_DIV_H, 0x00 ); ++ hdmi_wr_reg(CEC0_BASE_ADDR+CEC_CLOCK_DIV_L, 0xf0 ); ++#endif ++ ++#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 ++ if (request_irq(INT_HDMI_CEC, &amlogic_cec_irq_handler, ++ IRQF_SHARED, "amhdmitx-cec",(void *)hdmitx_device)) ++ { ++ amlogic_cec_log_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); ++ return -EFAULT; ++ } ++#endif ++#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 ++ if (request_irq(INT_AO_CEC, &amlogic_cec_irq_handler, ++ IRQF_SHARED, "amhdmitx-aocec",(void *)hdmitx_device)) ++ { ++ amlogic_cec_log_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); ++ return -EFAULT; ++ } ++#endif ++ ++ init_waitqueue_head(&cec_rx_struct.waitq); ++ ++ spin_lock_init(&cec_rx_struct.lock); ++ ++ init_waitqueue_head(&cec_tx_struct.waitq); ++ ++ spin_lock_init(&cec_tx_struct.lock); ++ ++ if (misc_register(&cec_misc_device)) ++ { ++ printk(KERN_WARNING " Couldn't register device 10, %d.\n", CEC_MINOR); ++ return -EBUSY; ++ } ++ ++#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 ++ cec_gpi_init(); ++#endif ++ ++#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 ++ aml_set_reg32_bits(P_PERIPHS_PIN_MUX_1, 1, 25, 1); ++ // Clear CEC Int. state and set CEC Int. mask ++ aml_write_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_STAT_CLR, aml_read_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_STAT_CLR) | (1 << 23)); // Clear the interrupt ++ aml_write_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_MASK, aml_read_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_MASK) | (1 << 23)); // Enable the hdmi cec interrupt ++ ++#endif ++#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 ++#if 1 // Please match with H/W cec config ++// GPIOAO_12 ++ aml_set_reg32_bits(P_AO_RTI_PIN_MUX_REG, 0, 14, 1); // bit[14]: AO_PWM_C pinmux //0xc8100014 ++ aml_set_reg32_bits(P_AO_RTI_PULL_UP_REG, 1, 12, 1); // bit[12]: enable AO_12 internal pull-up //0xc810002c ++ aml_set_reg32_bits(P_AO_RTI_PIN_MUX_REG, 1, 17, 1); // bit[17]: AO_CEC pinmux //0xc8100014 ++ ao_cec_init(); ++#else ++// GPIOH_3 ++ aml_set_reg32_bits(P_PAD_PULL_UP_EN_REG1, 0, 19, 1); // disable gpioh_3 internal pull-up ++ aml_set_reg32_bits(P_PERIPHS_PIN_MUX_1, 1, 23, 1); // gpioh_3 cec pinmux ++#endif ++ cec_arbit_bit_time_set(3, 0x118, 0); ++ cec_arbit_bit_time_set(5, 0x000, 0); ++ cec_arbit_bit_time_set(7, 0x2aa, 0); ++#endif ++ ++ hdmitx_device->cec_init_ready = 1; ++ ++ amlogic_cec_log_dbg("hdmitx_device->cec_init_ready:0x%x\n", hdmitx_device->cec_init_ready); ++ ++ return 0; ++} ++ ++static void amlogic_cec_exit(void) ++{ ++#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 ++ aml_write_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_MASK, aml_read_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_MASK) & ~(1 << 23)); // Disable the hdmi cec interrupt ++ free_irq(INT_HDMI_CEC, (void *)hdmitx_device); ++#endif ++#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 ++ free_irq(INT_AO_CEC, (void *)hdmitx_device); ++#endif ++ misc_deregister(&cec_misc_device); ++} ++ ++module_init(amlogic_cec_init); ++module_exit(amlogic_cec_exit); +diff --git a/drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c b/drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c +index 3e043bc..2b11c72 100755 +--- a/drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c ++++ b/drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c +@@ -542,6 +542,7 @@ static ssize_t store_disp_mode(struct device * dev, struct device_attribute *att + return 16; + } + ++#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER + /*cec attr*/ + static ssize_t show_cec(struct device * dev, struct device_attribute *attr, char * buf) + { +@@ -589,6 +590,20 @@ static ssize_t show_cec_lang_config(struct device * dev, struct device_attribute + pos+=snprintf(buf+pos, PAGE_SIZE, "%x\n",cec_global_info.cec_node_info[cec_global_info.my_node_index].menu_lang); + return pos; + } ++#else ++ ++extern unsigned long amlogic_cec_debug_flag; ++ ++static ssize_t show_amlogic_cec_debug_config(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ return snprintf(buf, PAGE_SIZE, "amlogic_cec_debug:%lu\n", amlogic_cec_debug_flag); ++} ++ ++static ssize_t store_amlogic_cec_debug_config(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ return kstrtoul(buf, 16, &amlogic_cec_debug_flag) ? 0 : count; ++} ++#endif + + /*aud_mode attr*/ + static ssize_t show_aud_mode(struct device * dev, struct device_attribute *attr, char * buf) +@@ -963,10 +978,14 @@ static DEVICE_ATTR(disp_cap_3d, S_IWUSR | S_IRUGO, show_disp_cap_3d, NULL); + static DEVICE_ATTR(hdcp_ksv_info, S_IWUSR | S_IRUGO, show_hdcp_ksv_info, NULL); + static DEVICE_ATTR(hpd_state, S_IWUSR | S_IRUGO, show_hpd_state, NULL); + static DEVICE_ATTR(support_3d, S_IWUSR | S_IRUGO, show_support_3d, NULL); ++#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER + static DEVICE_ATTR(cec, S_IWUSR | S_IRUGO, show_cec, store_cec); + static DEVICE_ATTR(cec_config, S_IWUSR | S_IRUGO | S_IWGRP, show_cec_config, store_cec_config); + //static DEVICE_ATTR(cec_config, S_IWUGO | S_IRUGO , NULL, store_cec_config); + static DEVICE_ATTR(cec_lang_config, S_IWUSR | S_IRUGO | S_IWGRP, show_cec_lang_config, store_cec_lang_config); ++#else ++static DEVICE_ATTR(amlogic_cec_debug_config, S_IWUSR | S_IRUGO | S_IWGRP, show_amlogic_cec_debug_config, store_amlogic_cec_debug_config); ++#endif + + /***************************** + * hdmitx display client interface +@@ -1582,7 +1601,9 @@ extern void register_hdmi_is_special_tv_func( int (*pfunc)(void) ); + + static int amhdmitx_probe(struct platform_device *pdev) + { ++#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER + extern struct switch_dev lang_dev; ++#endif + int r,ret=0; + + #ifdef CONFIG_USE_OF +@@ -1643,9 +1664,13 @@ static int amhdmitx_probe(struct platform_device *pdev) + ret=device_create_file(hdmitx_dev, &dev_attr_hdcp_ksv_info); + ret=device_create_file(hdmitx_dev, &dev_attr_hpd_state); + ret=device_create_file(hdmitx_dev, &dev_attr_support_3d); ++#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER + ret=device_create_file(hdmitx_dev, &dev_attr_cec); + ret=device_create_file(hdmitx_dev, &dev_attr_cec_config); + ret=device_create_file(hdmitx_dev, &dev_attr_cec_lang_config); ++#else ++ ret=device_create_file(hdmitx_dev, &dev_attr_amlogic_cec_debug_config); ++#endif + + if (hdmitx_dev == NULL) { + hdmi_print(ERR, SYS "device_create create error\n"); +@@ -1732,7 +1757,9 @@ static int amhdmitx_probe(struct platform_device *pdev) + } + #endif + switch_dev_register(&sdev); ++#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER + switch_dev_register(&lang_dev); ++#endif + + hdmitx_init_parameters(&hdmitx_device.hdmi_info); + HDMITX_Meson_Init(&hdmitx_device); +@@ -1771,8 +1798,9 @@ static int amhdmitx_remove(struct platform_device *pdev) + device_remove_file(hdmitx_dev, &dev_attr_disp_cap_3d); + device_remove_file(hdmitx_dev, &dev_attr_hpd_state); + device_remove_file(hdmitx_dev, &dev_attr_support_3d); ++#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER + device_remove_file(hdmitx_dev, &dev_attr_cec); +- ++#endif + cdev_del(&hdmitx_device.cdev); + + device_destroy(hdmitx_class, hdmitx_id); +diff --git a/drivers/amlogic/input/new_remote/remote_func.c b/drivers/amlogic/input/new_remote/remote_func.c +index e36e272..807c255 100755 +--- a/drivers/amlogic/input/new_remote/remote_func.c ++++ b/drivers/amlogic/input/new_remote/remote_func.c +@@ -525,6 +525,7 @@ int remote_hw_reprot_key(struct remote *remote_data) + mod_timer(&remote_data->timer, jiffies + msecs_to_jiffies(remote_data->release_delay[remote_data->map_num]+remote_data->repeat_delay[remote_data->map_num])); + } else if((remote_data->frame_status & REPEARTFLAG) && remote_data->enable_repeat_falg) { //repeate key + #ifdef CONFIG_AML_HDMI_TX ++#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER + extern int rc_long_press_pwr_key; + if((remote_data->repeat_release_code == 0x1a) && (!cec_repeat)) { + rc_long_press_pwr_key = 1; +@@ -534,6 +535,7 @@ int remote_hw_reprot_key(struct remote *remote_data) + cec_repeat--; + + #endif ++#endif + if (remote_data->repeat_enable) { + repeat_count++; + if (remote_data->repeat_tick < jiffies) { +@@ -618,6 +620,7 @@ int remote_hw_nec_rca_2in1_reprot_key(struct remote *remote_data) + mod_timer(&remote_data->timer, jiffies + msecs_to_jiffies(remote_data->release_delay[remote_data->map_num]+remote_data->repeat_delay[remote_data->map_num])); + } else if((remote_data->frame_status & REPEARTFLAG) && remote_data->enable_repeat_falg) { //repeate key + #ifdef CONFIG_AML_HDMI_TX ++#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER + extern int rc_long_press_pwr_key; + if((remote_data->repeat_release_code == 0x1a) && (!cec_repeat)) { + rc_long_press_pwr_key = 1; +@@ -627,6 +630,7 @@ int remote_hw_nec_rca_2in1_reprot_key(struct remote *remote_data) + cec_repeat--; + + #endif ++#endif + if (remote_data->repeat_enable) { + repeat_count++; + if (remote_data->repeat_tick < jiffies) { +@@ -700,6 +704,7 @@ int remote_hw_nec_toshiba_2in1_reprot_key(struct remote *remote_data) + mod_timer(&remote_data->timer, jiffies + msecs_to_jiffies(remote_data->release_delay[remote_data->map_num]+remote_data->repeat_delay[remote_data->map_num])); + } else if((remote_data->frame_status & REPEARTFLAG) && remote_data->enable_repeat_falg) { //repeate key + #ifdef CONFIG_AML_HDMI_TX ++#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER + extern int rc_long_press_pwr_key; + if((remote_data->repeat_release_code == 0x1a) && (!cec_repeat)) { + rc_long_press_pwr_key = 1; +@@ -709,6 +714,7 @@ int remote_hw_nec_toshiba_2in1_reprot_key(struct remote *remote_data) + cec_repeat--; + + #endif ++#endif + if (remote_data->repeat_enable) { + repeat_count++; + if (remote_data->repeat_tick < jiffies) { +diff --git a/drivers/amlogic/input/remote/am_remote.c b/drivers/amlogic/input/remote/am_remote.c +index c824efb..01f0bfb 100755 +--- a/drivers/amlogic/input/remote/am_remote.c ++++ b/drivers/amlogic/input/remote/am_remote.c +@@ -390,6 +390,7 @@ static inline int remote_hw_reprot_key(struct remote *remote_data) + } + #ifdef CONFIG_AML_HDMI_TX + #ifdef CONFIG_ARCH_MESON6 ++#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER + //printk("last_scan_code:%x\n", last_scan_code); + if((((scan_code >> 16) & 0xff) == 0x1a) && (!cec_repeat)) { + extern int rc_long_press_pwr_key; +@@ -401,6 +402,7 @@ static inline int remote_hw_reprot_key(struct remote *remote_data) + cec_repeat--; + #endif + #endif ++#endif + if (remote_data->repeat_enable) { + if ((remote_data->repeat_tick < jiffies)&&(repeat_flag == 1)) { + remote_send_key(remote_data->input, (scan_code >> 16) & 0xff, 2);