From 0c8a05440b273f9298af4e69971a314b49479a2a Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Fri, 4 Jun 2021 15:10:06 +0530 Subject: [PATCH] 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