From f3a43c8d5e6b77ff11ec6c136747a058762237ff Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Thu, 27 May 2021 19:40:17 +0530 Subject: [PATCH 01/11] CEC: Initialise the HAL based on default implementation Bug: 185434120 Test: manual Change-Id: I4bbe5e799388b0f17c532108dca4c2f037f1ff33 --- tv/cec/1.0/default/Android.bp | 5 +- tv/cec/1.0/default/HdmiCec.cpp | 12 +- tv/cec/1.0/default/HdmiCecDefault.cpp | 156 ++++++++++++++++++++++++++ tv/cec/1.0/default/HdmiCecDefault.h | 57 ++++++++++ 4 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 tv/cec/1.0/default/HdmiCecDefault.cpp create mode 100644 tv/cec/1.0/default/HdmiCecDefault.h diff --git a/tv/cec/1.0/default/Android.bp b/tv/cec/1.0/default/Android.bp index fc4298d86c..d2ba95d91e 100644 --- a/tv/cec/1.0/default/Android.bp +++ b/tv/cec/1.0/default/Android.bp @@ -12,7 +12,10 @@ cc_library_shared { defaults: ["hidl_defaults"], vendor: true, relative_install_path: "hw", - srcs: ["HdmiCec.cpp"], + srcs: [ + "HdmiCec.cpp", + "HdmiCecDefault.cpp", + ], shared_libs: [ "libhidlbase", diff --git a/tv/cec/1.0/default/HdmiCec.cpp b/tv/cec/1.0/default/HdmiCec.cpp index 171bdfe04f..74de785e81 100644 --- a/tv/cec/1.0/default/HdmiCec.cpp +++ b/tv/cec/1.0/default/HdmiCec.cpp @@ -20,6 +20,7 @@ #include #include #include "HdmiCec.h" +#include "HdmiCecDefault.h" namespace android { namespace hardware { @@ -390,6 +391,15 @@ Return HdmiCec::isConnected(int32_t portId) { return mDevice->is_connected(mDevice, portId) > 0; } +IHdmiCec* getHdmiCecDefault() { + HdmiCecDefault* hdmiCecDefault = new HdmiCecDefault(); + Result result = hdmiCecDefault->init(); + if (result == Result::SUCCESS) { + return hdmiCecDefault; + } + LOG(ERROR) << "Failed to load default HAL."; + return nullptr; +} IHdmiCec* HIDL_FETCH_IHdmiCec(const char* hal) { hdmi_cec_device_t* hdmi_cec_device; @@ -410,7 +420,7 @@ IHdmiCec* HIDL_FETCH_IHdmiCec(const char* hal) { return new HdmiCec(hdmi_cec_device); } else { LOG(ERROR) << "Passthrough failed to load legacy HAL."; - return nullptr; + return getHdmiCecDefault(); } } diff --git a/tv/cec/1.0/default/HdmiCecDefault.cpp b/tv/cec/1.0/default/HdmiCecDefault.cpp new file mode 100644 index 0000000000..f32c5aa806 --- /dev/null +++ b/tv/cec/1.0/default/HdmiCecDefault.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "android.hardware.tv.cec@1.0-impl" +#include + +#include +#include +#include +#include +#include + +#include "HdmiCecDefault.h" + +namespace android { +namespace hardware { +namespace tv { +namespace cec { +namespace V1_0 { +namespace implementation { + +int mCecFd; +int mExitFd; + +HdmiCecDefault::HdmiCecDefault() { + mCecFd = -1; + mExitFd = -1; +} + +HdmiCecDefault::~HdmiCecDefault() { + release(); +} + +// Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow. +Return HdmiCecDefault::addLogicalAddress(CecLogicalAddress /*addr*/) { + return Result::FAILURE_UNKNOWN; +} + +Return HdmiCecDefault::clearLogicalAddress() { + return Void(); +} + +Return HdmiCecDefault::getPhysicalAddress(getPhysicalAddress_cb /*_hidl_cb*/) { + return Void(); +} + +Return HdmiCecDefault::sendMessage(const CecMessage& /*message*/) { + return SendMessageResult::FAIL; +} + +Return HdmiCecDefault::setCallback(const sp& /*callback*/) { + return Void(); +} + +Return HdmiCecDefault::getCecVersion() { + return 0; +} + +Return HdmiCecDefault::getVendorId() { + return 0; +} + +Return HdmiCecDefault::getPortInfo(getPortInfo_cb /*_hidl_cb*/) { + return Void(); +} + +Return HdmiCecDefault::setOption(OptionKey /*key*/, bool /*value*/) { + return Void(); +} + +Return HdmiCecDefault::setLanguage(const hidl_string& /*language*/) { + return Void(); +} + +Return HdmiCecDefault::enableAudioReturnChannel(int32_t /*portId*/, bool /*enable*/) { + return Void(); +} + +Return HdmiCecDefault::isConnected(int32_t /*portId*/) { + return false; +} + +// Initialise the cec file descriptor +Return HdmiCecDefault::init() { + const char* path = "/dev/cec0"; + mCecFd = open(path, O_RDWR); + if (mCecFd < 0) { + LOG(ERROR) << "Failed to open " << path << ", Error = " << strerror(errno); + return Result::FAILURE_NOT_SUPPORTED; + } + mExitFd = eventfd(0, EFD_NONBLOCK); + if (mExitFd < 0) { + LOG(ERROR) << "Failed to open eventfd, Error = " << strerror(errno); + release(); + return Result::FAILURE_NOT_SUPPORTED; + } + + // Ensure the CEC device supports required capabilities + struct cec_caps caps = {}; + int ret = ioctl(mCecFd, CEC_ADAP_G_CAPS, &caps); + if (ret) { + LOG(ERROR) << "Unable to query cec adapter capabilities, Error = " << strerror(errno); + release(); + return Result::FAILURE_NOT_SUPPORTED; + } + + if (!(caps.capabilities & (CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | CEC_CAP_PASSTHROUGH))) { + LOG(ERROR) << "Wrong cec adapter capabilities " << caps.capabilities; + release(); + return Result::FAILURE_NOT_SUPPORTED; + } + + uint32_t mode = CEC_MODE_INITIATOR; + ret = ioctl(mCecFd, CEC_S_MODE, &mode); + if (ret) { + LOG(ERROR) << "Unable to set initiator mode, Error = " << strerror(errno); + release(); + return Result::FAILURE_NOT_SUPPORTED; + } + + return Result::SUCCESS; +} + +Return HdmiCecDefault::release() { + if (mExitFd > 0) { + uint64_t tmp = 1; + write(mExitFd, &tmp, sizeof(tmp)); + } + if (mExitFd > 0) { + close(mExitFd); + } + if (mCecFd > 0) { + close(mCecFd); + } + setCallback(nullptr); + return Void(); +} +} // namespace implementation +} // namespace V1_0 +} // namespace cec +} // namespace tv +} // namespace hardware +} // namespace android diff --git a/tv/cec/1.0/default/HdmiCecDefault.h b/tv/cec/1.0/default/HdmiCecDefault.h new file mode 100644 index 0000000000..4812ecafea --- /dev/null +++ b/tv/cec/1.0/default/HdmiCecDefault.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace android { +namespace hardware { +namespace tv { +namespace cec { +namespace V1_0 { +namespace implementation { + +struct HdmiCecDefault : public IHdmiCec, public hidl_death_recipient { + HdmiCecDefault(); + ~HdmiCecDefault(); + // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow. + Return addLogicalAddress(CecLogicalAddress addr) override; + Return clearLogicalAddress() override; + Return getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) override; + Return sendMessage(const CecMessage& message) override; + Return setCallback(const sp& callback) override; + Return getCecVersion() override; + Return getVendorId() override; + Return getPortInfo(getPortInfo_cb _hidl_cb) override; + Return setOption(OptionKey key, bool value) override; + Return setLanguage(const hidl_string& language) override; + Return enableAudioReturnChannel(int32_t portId, bool enable) override; + Return isConnected(int32_t portId) override; + + virtual void serviceDied(uint64_t, const wp<::android::hidl::base::V1_0::IBase>&) { + setCallback(nullptr); + } + + Return init(); + Return release(); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace cec +} // namespace tv +} // namespace hardware +} // namespace android From 971853be154b482a29a537324fb4a3178e24d1ba Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Mon, 31 May 2021 16:28:23 +0530 Subject: [PATCH 02/11] CEC: Add implementation of SendMessage method to default HdmiCec Bug: 185434120 Test: manual Change-Id: Ic546bc45df5331b381406314f2ba797e607f301e --- tv/cec/1.0/default/HdmiCecDefault.cpp | 36 +++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/tv/cec/1.0/default/HdmiCecDefault.cpp b/tv/cec/1.0/default/HdmiCecDefault.cpp index f32c5aa806..f0b3750b78 100644 --- a/tv/cec/1.0/default/HdmiCecDefault.cpp +++ b/tv/cec/1.0/default/HdmiCecDefault.cpp @@ -57,8 +57,40 @@ Return HdmiCecDefault::getPhysicalAddress(getPhysicalAddress_cb /*_hidl_cb return Void(); } -Return HdmiCecDefault::sendMessage(const CecMessage& /*message*/) { - return SendMessageResult::FAIL; +Return HdmiCecDefault::sendMessage(const CecMessage& message) { + struct cec_msg cecMsg; + memset(&cecMsg, 0, sizeof(cec_msg)); + + int initiator = static_cast(message.initiator); + int destination = static_cast(message.destination); + + cecMsg.msg[0] = (initiator << 4) | destination; + for (size_t i = 0; i < message.body.size(); ++i) { + cecMsg.msg[i + 1] = message.body[i]; + } + cecMsg.len = message.body.size() + 1; + + int ret = ioctl(mCecFd, CEC_TRANSMIT, &cecMsg); + + if (ret) { + LOG(ERROR) << "Send message failed, Error = " << strerror(errno); + return SendMessageResult::FAIL; + } + + if (cecMsg.tx_status != CEC_TX_STATUS_OK) { + LOG(ERROR) << "Send message tx_status = " << cecMsg.tx_status; + } + + switch (cecMsg.tx_status) { + case CEC_TX_STATUS_OK: + return SendMessageResult::SUCCESS; + case CEC_TX_STATUS_ARB_LOST: + return SendMessageResult::BUSY; + case CEC_TX_STATUS_NACK: + return SendMessageResult::NACK; + default: + return SendMessageResult::FAIL; + } } Return HdmiCecDefault::setCallback(const sp& /*callback*/) { From 9b1e529ce8e1a37abe619edcf337ce532bc9a228 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Mon, 31 May 2021 16:38:38 +0530 Subject: [PATCH 03/11] CEC: Add implementation of getPhysicalAddress method to default HdmiCec Bug: 185434120 Test: manual Change-Id: I5e52a82a7e5966cfeab95005c1b454c45ce995b6 --- tv/cec/1.0/default/HdmiCecDefault.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tv/cec/1.0/default/HdmiCecDefault.cpp b/tv/cec/1.0/default/HdmiCecDefault.cpp index f0b3750b78..c50602d7a5 100644 --- a/tv/cec/1.0/default/HdmiCecDefault.cpp +++ b/tv/cec/1.0/default/HdmiCecDefault.cpp @@ -53,7 +53,15 @@ Return HdmiCecDefault::clearLogicalAddress() { return Void(); } -Return HdmiCecDefault::getPhysicalAddress(getPhysicalAddress_cb /*_hidl_cb*/) { +Return HdmiCecDefault::getPhysicalAddress(getPhysicalAddress_cb callback) { + uint16_t addr; + int ret = ioctl(mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr); + if (ret) { + LOG(ERROR) << "Get physical address failed, Error = " << strerror(errno); + callback(Result::FAILURE_INVALID_STATE, addr); + return Void(); + } + callback(Result::SUCCESS, addr); return Void(); } From 0dacc5cd5ce03312182f4e18e0c9fb047b92cb96 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Tue, 1 Jun 2021 10:32:22 +0530 Subject: [PATCH 04/11] CEC: Add implementation of clearLogicalAddress method to default HdmiCec Bug: 185434120 Test: manual Change-Id: Ia21b415f47bfabe9b429378da2319ab7aa543e26 --- tv/cec/1.0/default/HdmiCecDefault.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tv/cec/1.0/default/HdmiCecDefault.cpp b/tv/cec/1.0/default/HdmiCecDefault.cpp index c50602d7a5..7466c92a83 100644 --- a/tv/cec/1.0/default/HdmiCecDefault.cpp +++ b/tv/cec/1.0/default/HdmiCecDefault.cpp @@ -50,6 +50,12 @@ Return HdmiCecDefault::addLogicalAddress(CecLogicalAddress /*addr*/) { } Return HdmiCecDefault::clearLogicalAddress() { + struct cec_log_addrs cecLogAddrs; + memset(&cecLogAddrs, 0, sizeof(cecLogAddrs)); + int ret = ioctl(mCecFd, CEC_ADAP_S_LOG_ADDRS, &cecLogAddrs); + if (ret) { + LOG(ERROR) << "Clear logical Address failed, Error = " << strerror(errno); + } return Void(); } From 332541054ed11c143f24b3da4f031064c1dfa6d8 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Tue, 1 Jun 2021 13:29:47 +0530 Subject: [PATCH 05/11] CEC: Add implementation of getPortInfo method to default HdmiCec Bug: 185434120 Test: manual Change-Id: Icb12d161304559b12723900192482173c6280052 --- tv/cec/1.0/default/Android.bp | 1 + tv/cec/1.0/default/HdmiCecDefault.cpp | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/tv/cec/1.0/default/Android.bp b/tv/cec/1.0/default/Android.bp index d2ba95d91e..b4053dfe1d 100644 --- a/tv/cec/1.0/default/Android.bp +++ b/tv/cec/1.0/default/Android.bp @@ -21,6 +21,7 @@ cc_library_shared { "libhidlbase", "liblog", "libbase", + "libcutils", "libutils", "libhardware", "android.hardware.tv.cec@1.0", diff --git a/tv/cec/1.0/default/HdmiCecDefault.cpp b/tv/cec/1.0/default/HdmiCecDefault.cpp index 7466c92a83..c7fb31fcf2 100644 --- a/tv/cec/1.0/default/HdmiCecDefault.cpp +++ b/tv/cec/1.0/default/HdmiCecDefault.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "android.hardware.tv.cec@1.0-impl" #include +#include #include #include #include @@ -119,7 +120,21 @@ Return HdmiCecDefault::getVendorId() { return 0; } -Return HdmiCecDefault::getPortInfo(getPortInfo_cb /*_hidl_cb*/) { +Return HdmiCecDefault::getPortInfo(getPortInfo_cb callback) { + uint16_t addr; + int ret = ioctl(mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr); + if (ret) { + LOG(ERROR) << "Get port info failed, Error = " << strerror(errno); + } + + unsigned int type = property_get_int32("ro.hdmi.device_type", CEC_DEVICE_PLAYBACK); + hidl_vec portInfos(1); + portInfos[0] = {.type = (type == CEC_DEVICE_TV ? HdmiPortType::INPUT : HdmiPortType::OUTPUT), + .portId = 1, + .cecSupported = true, + .arcSupported = false, + .physicalAddress = addr}; + callback(portInfos); return Void(); } From 697e280bde0a066ee6945d7d4a734b04bc18b296 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Tue, 1 Jun 2021 16:20:10 +0530 Subject: [PATCH 06/11] CEC: Add implementation of getVendorId method to default HdmiCec Bug: 185434120 Test: manual Change-Id: Ie6b1f0d2551ca271d492c59be5897f77e18b0698 --- tv/cec/1.0/default/HdmiCecDefault.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tv/cec/1.0/default/HdmiCecDefault.cpp b/tv/cec/1.0/default/HdmiCecDefault.cpp index c7fb31fcf2..7b986de343 100644 --- a/tv/cec/1.0/default/HdmiCecDefault.cpp +++ b/tv/cec/1.0/default/HdmiCecDefault.cpp @@ -117,7 +117,7 @@ Return HdmiCecDefault::getCecVersion() { } Return HdmiCecDefault::getVendorId() { - return 0; + return property_get_int32("ro.hdmi.vendor_id", 0x000c03 /* HDMI LLC vendor ID */); } Return HdmiCecDefault::getPortInfo(getPortInfo_cb callback) { From 2120790ee6e142ed92177e154a5975e4671e9bd9 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Tue, 1 Jun 2021 16:35:07 +0530 Subject: [PATCH 07/11] CEC: Add implementation of isConnected method to default HdmiCec Bug: 185434120 Test: manual Change-Id: I245d52a7ef4e57852277fce655bd6383e0461f92 --- tv/cec/1.0/default/HdmiCecDefault.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tv/cec/1.0/default/HdmiCecDefault.cpp b/tv/cec/1.0/default/HdmiCecDefault.cpp index 7b986de343..b5f2ba7bf1 100644 --- a/tv/cec/1.0/default/HdmiCecDefault.cpp +++ b/tv/cec/1.0/default/HdmiCecDefault.cpp @@ -151,7 +151,16 @@ Return HdmiCecDefault::enableAudioReturnChannel(int32_t /*portId*/, bool / } Return HdmiCecDefault::isConnected(int32_t /*portId*/) { - return false; + uint16_t addr; + int ret = ioctl(mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr); + if (ret) { + LOG(ERROR) << "Is connected failed, Error = " << strerror(errno); + return false; + } + if (addr == CEC_PHYS_ADDR_INVALID) { + return false; + } + return true; } // Initialise the cec file descriptor From 105b1c3007c74862a13d99570c0ae2b4bbffb1a2 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Tue, 1 Jun 2021 18:45:21 +0530 Subject: [PATCH 08/11] CEC: Add implementation of getCecVersion method to default HdmiCec Bug: 185434120 Test: manual Change-Id: I019cb5cf68e73331b1468b60cbfb95be7a052522 --- tv/cec/1.0/default/HdmiCecDefault.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tv/cec/1.0/default/HdmiCecDefault.cpp b/tv/cec/1.0/default/HdmiCecDefault.cpp index b5f2ba7bf1..4bc5ef3c64 100644 --- a/tv/cec/1.0/default/HdmiCecDefault.cpp +++ b/tv/cec/1.0/default/HdmiCecDefault.cpp @@ -113,7 +113,7 @@ Return HdmiCecDefault::setCallback(const sp& /*callback* } Return HdmiCecDefault::getCecVersion() { - return 0; + return property_get_int32("ro.hdmi.cec_version", CEC_OP_CEC_VERSION_1_4); } Return HdmiCecDefault::getVendorId() { From d50fd04f4c7547243aa35c2f866c47d78be6943d Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Wed, 2 Jun 2021 09:35:53 +0530 Subject: [PATCH 09/11] CEC: Add implementation of addLogicalAddress method to default HdmiCec Bug: 185434120 Test: manual Change-Id: Ic8a65044434d3b8a4e0aead5ccf9534dab388d9e --- tv/cec/1.0/default/HdmiCecDefault.cpp | 81 ++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/tv/cec/1.0/default/HdmiCecDefault.cpp b/tv/cec/1.0/default/HdmiCecDefault.cpp index 4bc5ef3c64..2ec2d09b8a 100644 --- a/tv/cec/1.0/default/HdmiCecDefault.cpp +++ b/tv/cec/1.0/default/HdmiCecDefault.cpp @@ -46,8 +46,85 @@ HdmiCecDefault::~HdmiCecDefault() { } // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow. -Return HdmiCecDefault::addLogicalAddress(CecLogicalAddress /*addr*/) { - return Result::FAILURE_UNKNOWN; +Return HdmiCecDefault::addLogicalAddress(CecLogicalAddress addr) { + if (addr < CecLogicalAddress::TV || addr >= CecLogicalAddress::BROADCAST) { + LOG(ERROR) << "Add logical address failed, Invalid address"; + return Result::FAILURE_INVALID_ARGS; + } + + struct cec_log_addrs cecLogAddrs; + int ret = ioctl(mCecFd, CEC_ADAP_G_LOG_ADDRS, &cecLogAddrs); + if (ret) { + LOG(ERROR) << "Add logical address failed, Error = " << strerror(errno); + return Result::FAILURE_BUSY; + } + + cecLogAddrs.cec_version = getCecVersion(); + cecLogAddrs.vendor_id = getVendorId(); + + unsigned int logAddrType = CEC_LOG_ADDR_TYPE_UNREGISTERED; + unsigned int allDevTypes = 0; + unsigned int primDevType = 0xff; + switch (addr) { + case CecLogicalAddress::TV: + primDevType = CEC_OP_PRIM_DEVTYPE_TV; + logAddrType = CEC_LOG_ADDR_TYPE_TV; + allDevTypes = CEC_OP_ALL_DEVTYPE_TV; + break; + case CecLogicalAddress::RECORDER_1: + case CecLogicalAddress::RECORDER_2: + case CecLogicalAddress::RECORDER_3: + primDevType = CEC_OP_PRIM_DEVTYPE_RECORD; + logAddrType = CEC_LOG_ADDR_TYPE_RECORD; + allDevTypes = CEC_OP_ALL_DEVTYPE_RECORD; + break; + case CecLogicalAddress::TUNER_1: + case CecLogicalAddress::TUNER_2: + case CecLogicalAddress::TUNER_3: + case CecLogicalAddress::TUNER_4: + primDevType = CEC_OP_PRIM_DEVTYPE_TUNER; + logAddrType = CEC_LOG_ADDR_TYPE_TUNER; + allDevTypes = CEC_OP_ALL_DEVTYPE_TUNER; + break; + case CecLogicalAddress::PLAYBACK_1: + case CecLogicalAddress::PLAYBACK_2: + case CecLogicalAddress::PLAYBACK_3: + primDevType = CEC_OP_PRIM_DEVTYPE_PLAYBACK; + logAddrType = CEC_LOG_ADDR_TYPE_PLAYBACK; + allDevTypes = CEC_OP_ALL_DEVTYPE_PLAYBACK; + cecLogAddrs.flags |= CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU; + break; + case CecLogicalAddress::AUDIO_SYSTEM: + primDevType = CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM; + logAddrType = CEC_LOG_ADDR_TYPE_AUDIOSYSTEM; + allDevTypes = CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM; + break; + case CecLogicalAddress::FREE_USE: + primDevType = CEC_OP_PRIM_DEVTYPE_PROCESSOR; + logAddrType = CEC_LOG_ADDR_TYPE_SPECIFIC; + allDevTypes = CEC_OP_ALL_DEVTYPE_SWITCH; + break; + case CecLogicalAddress::UNREGISTERED: + cecLogAddrs.flags |= CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK; + break; + } + + int logAddrIndex = cecLogAddrs.num_log_addrs; + + cecLogAddrs.num_log_addrs += 1; + cecLogAddrs.log_addr[logAddrIndex] = static_cast(addr); + cecLogAddrs.log_addr_type[logAddrIndex] = logAddrType; + cecLogAddrs.primary_device_type[logAddrIndex] = primDevType; + cecLogAddrs.all_device_types[logAddrIndex] = allDevTypes; + cecLogAddrs.features[logAddrIndex][0] = 0; + cecLogAddrs.features[logAddrIndex][1] = 0; + + ret = ioctl(mCecFd, CEC_ADAP_S_LOG_ADDRS, &cecLogAddrs); + if (ret) { + LOG(ERROR) << "Add logical address failed, Error = " << strerror(errno); + return Result::FAILURE_BUSY; + } + return Result::SUCCESS; } Return HdmiCecDefault::clearLogicalAddress() { From 92fa8e926f8bf324ce8c3fc4f85d2a9785d1dce0 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Wed, 2 Jun 2021 12:11:26 +0530 Subject: [PATCH 10/11] CEC: Add implementation of setCallback method to default HdmiCec Bug: 185434120 Test: manual Change-Id: I280d142427ae49eca5abce01eded569efdaf8221 --- tv/cec/1.0/default/HdmiCecDefault.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tv/cec/1.0/default/HdmiCecDefault.cpp b/tv/cec/1.0/default/HdmiCecDefault.cpp index 2ec2d09b8a..7dc0d24d81 100644 --- a/tv/cec/1.0/default/HdmiCecDefault.cpp +++ b/tv/cec/1.0/default/HdmiCecDefault.cpp @@ -35,10 +35,12 @@ namespace implementation { int mCecFd; int mExitFd; +sp mCallback; HdmiCecDefault::HdmiCecDefault() { mCecFd = -1; mExitFd = -1; + mCallback = nullptr; } HdmiCecDefault::~HdmiCecDefault() { @@ -185,7 +187,16 @@ Return HdmiCecDefault::sendMessage(const CecMessage& message) } } -Return HdmiCecDefault::setCallback(const sp& /*callback*/) { +Return HdmiCecDefault::setCallback(const sp& callback) { + if (mCallback != nullptr) { + mCallback->unlinkToDeath(this); + mCallback = nullptr; + } + + if (callback != nullptr) { + mCallback = callback; + mCallback->linkToDeath(this, 0 /*cookie*/); + } return Void(); } From 0c8a05440b273f9298af4e69971a314b49479a2a Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Fri, 4 Jun 2021 15:10:06 +0530 Subject: [PATCH 11/11] CEC: Add event handler to default HdmiCec Event handler polls the file descriptor for CEC messages and events Bug: 185434120 Test: manual Change-Id: Iaaec9a0a74b264e5ec8625d7fce3d821208fd5ac --- tv/cec/1.0/default/HdmiCecDefault.cpp | 91 ++++++++++++++++++++++++++- tv/cec/1.0/default/HdmiCecDefault.h | 1 + 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/tv/cec/1.0/default/HdmiCecDefault.cpp b/tv/cec/1.0/default/HdmiCecDefault.cpp index 7dc0d24d81..c8dd511ff1 100644 --- a/tv/cec/1.0/default/HdmiCecDefault.cpp +++ b/tv/cec/1.0/default/HdmiCecDefault.cpp @@ -22,7 +22,10 @@ #include #include #include +#include +#include #include +#include #include "HdmiCecDefault.h" @@ -35,6 +38,7 @@ namespace implementation { int mCecFd; int mExitFd; +pthread_t mEventThread; sp mCallback; HdmiCecDefault::HdmiCecDefault() { @@ -281,7 +285,7 @@ Return HdmiCecDefault::init() { return Result::FAILURE_NOT_SUPPORTED; } - uint32_t mode = CEC_MODE_INITIATOR; + uint32_t mode = CEC_MODE_INITIATOR | CEC_MODE_EXCL_FOLLOWER_PASSTHRU; ret = ioctl(mCecFd, CEC_S_MODE, &mode); if (ret) { LOG(ERROR) << "Unable to set initiator mode, Error = " << strerror(errno); @@ -289,6 +293,13 @@ Return HdmiCecDefault::init() { return Result::FAILURE_NOT_SUPPORTED; } + /* thread loop for receiving cec messages and hotplug events*/ + if (pthread_create(&mEventThread, NULL, event_thread, NULL)) { + LOG(ERROR) << "Can't create event thread: " << strerror(errno); + release(); + return Result::FAILURE_NOT_SUPPORTED; + } + return Result::SUCCESS; } @@ -296,6 +307,7 @@ Return HdmiCecDefault::release() { if (mExitFd > 0) { uint64_t tmp = 1; write(mExitFd, &tmp, sizeof(tmp)); + pthread_join(mEventThread, NULL); } if (mExitFd > 0) { close(mExitFd); @@ -306,6 +318,83 @@ Return HdmiCecDefault::release() { setCallback(nullptr); return Void(); } + +void* HdmiCecDefault::event_thread(void*) { + struct pollfd ufds[3] = { + {mCecFd, POLLIN, 0}, + {mCecFd, POLLERR, 0}, + {mExitFd, POLLIN, 0}, + }; + + while (1) { + ufds[0].revents = 0; + ufds[1].revents = 0; + ufds[2].revents = 0; + + int ret = poll(ufds, /* size(ufds) = */ 3, /* timeout = */ -1); + + if (ret <= 0) { + continue; + } + + if (ufds[2].revents == POLLIN) { /* Exit */ + break; + } + + if (ufds[1].revents == POLLERR) { /* CEC Event */ + struct cec_event ev; + ret = ioctl(mCecFd, CEC_DQEVENT, &ev); + + if (ret) { + LOG(ERROR) << "CEC_DQEVENT failed, Error = " << strerror(errno); + continue; + } + + if (ev.event == CEC_EVENT_STATE_CHANGE) { + if (mCallback != nullptr) { + HotplugEvent hotplugEvent{ + .connected = (ev.state_change.phys_addr != CEC_PHYS_ADDR_INVALID), + .portId = 1}; + mCallback->onHotplugEvent(hotplugEvent); + } else { + LOG(ERROR) << "No event callback for hotplug"; + } + } + } + + if (ufds[0].revents == POLLIN) { /* CEC Driver */ + struct cec_msg msg = {}; + ret = ioctl(mCecFd, CEC_RECEIVE, &msg); + + if (ret) { + LOG(ERROR) << "CEC_RECEIVE failed, Error = " << strerror(errno); + continue; + } + + if (msg.rx_status != CEC_RX_STATUS_OK) { + LOG(ERROR) << "msg rx_status = " << msg.rx_status; + continue; + } + + if (mCallback != nullptr) { + size_t length = std::min(msg.len - 1, (uint32_t)MaxLength::MESSAGE_BODY); + CecMessage cecMessage{ + .initiator = static_cast(msg.msg[0] >> 4), + .destination = static_cast(msg.msg[0] & 0xf), + }; + cecMessage.body.resize(length); + for (size_t i = 0; i < length; ++i) { + cecMessage.body[i] = static_cast(msg.msg[i + 1]); + } + mCallback->onCecMessage(cecMessage); + } else { + LOG(ERROR) << "no event callback for message"; + } + } + } + return NULL; +} + } // namespace implementation } // namespace V1_0 } // namespace cec diff --git a/tv/cec/1.0/default/HdmiCecDefault.h b/tv/cec/1.0/default/HdmiCecDefault.h index 4812ecafea..c3682f7ea2 100644 --- a/tv/cec/1.0/default/HdmiCecDefault.h +++ b/tv/cec/1.0/default/HdmiCecDefault.h @@ -47,6 +47,7 @@ struct HdmiCecDefault : public IHdmiCec, public hidl_death_recipient { Return init(); Return release(); + static void* event_thread(void*); }; } // namespace implementation