mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:23:37 +00:00
Merge "CEC: Add support for multiple ports to default HdmiCec" am: 63a8152f8e am: bfd12e9bf5 am: db777a32de
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1773889 Change-Id: I49899980442854cbea7f4472504734a7e956056e
This commit is contained in:
@@ -15,6 +15,7 @@ cc_library_shared {
|
||||
srcs: [
|
||||
"HdmiCec.cpp",
|
||||
"HdmiCecDefault.cpp",
|
||||
"HdmiCecPort.cpp",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
|
||||
@@ -19,15 +19,19 @@
|
||||
#include <android-base/properties.h>
|
||||
|
||||
#include <cutils/properties.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <poll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "HdmiCecDefault.h"
|
||||
|
||||
#define PROPERTY_DEVICE_TYPE "ro.hdmi.device_type"
|
||||
#define MIN_PORT_ID 0
|
||||
#define MAX_PORT_ID 15
|
||||
#define INVALID_PHYSICAL_ADDRESS 0xFFFF
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace tv {
|
||||
@@ -36,10 +40,10 @@ namespace V1_0 {
|
||||
namespace implementation {
|
||||
|
||||
using android::base::GetUintProperty;
|
||||
using std::stoi;
|
||||
using std::string;
|
||||
|
||||
HdmiCecDefault::HdmiCecDefault() {
|
||||
mCecFd = -1;
|
||||
mExitFd = -1;
|
||||
mCecEnabled = false;
|
||||
mWakeupEnabled = false;
|
||||
mCecControlEnabled = false;
|
||||
@@ -58,7 +62,7 @@ Return<Result> HdmiCecDefault::addLogicalAddress(CecLogicalAddress addr) {
|
||||
}
|
||||
|
||||
cec_log_addrs cecLogAddrs;
|
||||
int ret = ioctl(mCecFd, CEC_ADAP_G_LOG_ADDRS, &cecLogAddrs);
|
||||
int ret = ioctl(mHdmiCecPorts[MIN_PORT_ID]->mCecFd, CEC_ADAP_G_LOG_ADDRS, &cecLogAddrs);
|
||||
if (ret) {
|
||||
LOG(ERROR) << "Add logical address failed, Error = " << strerror(errno);
|
||||
return Result::FAILURE_BUSY;
|
||||
@@ -124,27 +128,36 @@ Return<Result> HdmiCecDefault::addLogicalAddress(CecLogicalAddress addr) {
|
||||
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 failure only if add logical address fails for all the ports
|
||||
Return<Result> result = Result::FAILURE_BUSY;
|
||||
for (int i = 0; i < mHdmiCecPorts.size(); i++) {
|
||||
ret = ioctl(mHdmiCecPorts[i]->mCecFd, CEC_ADAP_S_LOG_ADDRS, &cecLogAddrs);
|
||||
if (ret) {
|
||||
LOG(ERROR) << "Add logical address failed for port " << mHdmiCecPorts[i]->mPortId
|
||||
<< ", Error = " << strerror(errno);
|
||||
} else {
|
||||
result = Result::SUCCESS;
|
||||
}
|
||||
}
|
||||
return Result::SUCCESS;
|
||||
return result;
|
||||
}
|
||||
|
||||
Return<void> HdmiCecDefault::clearLogicalAddress() {
|
||||
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);
|
||||
for (int i = 0; i < mHdmiCecPorts.size(); i++) {
|
||||
int ret = ioctl(mHdmiCecPorts[i]->mCecFd, CEC_ADAP_S_LOG_ADDRS, &cecLogAddrs);
|
||||
if (ret) {
|
||||
LOG(ERROR) << "Clear logical Address failed for port " << mHdmiCecPorts[i]->mPortId
|
||||
<< ", Error = " << strerror(errno);
|
||||
}
|
||||
}
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> HdmiCecDefault::getPhysicalAddress(getPhysicalAddress_cb callback) {
|
||||
uint16_t addr;
|
||||
int ret = ioctl(mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr);
|
||||
int ret = ioctl(mHdmiCecPorts[MIN_PORT_ID]->mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr);
|
||||
if (ret) {
|
||||
LOG(ERROR) << "Get physical address failed, Error = " << strerror(errno);
|
||||
callback(Result::FAILURE_INVALID_STATE, addr);
|
||||
@@ -171,27 +184,25 @@ Return<SendMessageResult> HdmiCecDefault::sendMessage(const CecMessage& message)
|
||||
}
|
||||
cecMsg.len = message.body.size() + 1;
|
||||
|
||||
int ret = ioctl(mCecFd, CEC_TRANSMIT, &cecMsg);
|
||||
// Return failure only if send message fails for all the ports
|
||||
Return<SendMessageResult> result = SendMessageResult::FAIL;
|
||||
for (int i = 0; i < mHdmiCecPorts.size(); i++) {
|
||||
int ret = ioctl(mHdmiCecPorts[i]->mCecFd, CEC_TRANSMIT, &cecMsg);
|
||||
|
||||
if (ret) {
|
||||
LOG(ERROR) << "Send message failed, Error = " << strerror(errno);
|
||||
return SendMessageResult::FAIL;
|
||||
}
|
||||
if (ret) {
|
||||
LOG(ERROR) << "Send message failed, Error = " << strerror(errno);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cecMsg.tx_status != CEC_TX_STATUS_OK) {
|
||||
LOG(ERROR) << "Send message tx_status = " << cecMsg.tx_status;
|
||||
}
|
||||
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;
|
||||
if (result != SendMessageResult::SUCCESS) {
|
||||
result = getSendMessageResult(cecMsg.tx_status);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Return<void> HdmiCecDefault::setCallback(const sp<IHdmiCecCallback>& callback) {
|
||||
@@ -216,19 +227,25 @@ Return<uint32_t> HdmiCecDefault::getVendorId() {
|
||||
}
|
||||
|
||||
Return<void> 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);
|
||||
hidl_vec<HdmiPortInfo> portInfos(mHdmiCecPorts.size());
|
||||
for (int i = 0; i < mHdmiCecPorts.size(); i++) {
|
||||
uint16_t addr = INVALID_PHYSICAL_ADDRESS;
|
||||
int ret = ioctl(mHdmiCecPorts[i]->mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr);
|
||||
if (ret) {
|
||||
LOG(ERROR) << "Get port info failed for port : " << mHdmiCecPorts[i]->mPortId
|
||||
<< ", Error = " << strerror(errno);
|
||||
}
|
||||
HdmiPortType type = HdmiPortType::INPUT;
|
||||
uint32_t deviceType = GetUintProperty<uint32_t>(PROPERTY_DEVICE_TYPE, CEC_DEVICE_PLAYBACK);
|
||||
if (deviceType != CEC_DEVICE_TV && i == MIN_PORT_ID) {
|
||||
type = HdmiPortType::OUTPUT;
|
||||
}
|
||||
portInfos[i] = {.type = type,
|
||||
.portId = mHdmiCecPorts[i]->mPortId,
|
||||
.cecSupported = true,
|
||||
.arcSupported = false,
|
||||
.physicalAddress = addr};
|
||||
}
|
||||
|
||||
uint32_t type = GetUintProperty<uint32_t>("ro.hdmi.device_type", CEC_DEVICE_PLAYBACK);
|
||||
hidl_vec<HdmiPortInfo> 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();
|
||||
}
|
||||
@@ -259,9 +276,9 @@ Return<void> HdmiCecDefault::enableAudioReturnChannel(int32_t /*portId*/, bool /
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<bool> HdmiCecDefault::isConnected(int32_t /*portId*/) {
|
||||
Return<bool> HdmiCecDefault::isConnected(int32_t portId) {
|
||||
uint16_t addr;
|
||||
int ret = ioctl(mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr);
|
||||
int ret = ioctl(mHdmiCecPorts[portId]->mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr);
|
||||
if (ret) {
|
||||
LOG(ERROR) << "Is connected failed, Error = " << strerror(errno);
|
||||
return false;
|
||||
@@ -272,46 +289,44 @@ Return<bool> HdmiCecDefault::isConnected(int32_t /*portId*/) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initialise the cec file descriptor
|
||||
int getPortId(string cecFilename) {
|
||||
int portId = stoi(cecFilename.substr(3));
|
||||
if (portId >= MIN_PORT_ID && portId <= MAX_PORT_ID) {
|
||||
return portId;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise the cec file descriptors
|
||||
Return<Result> 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;
|
||||
const char* parentPath = "/dev/";
|
||||
DIR* dir = opendir(parentPath);
|
||||
const char* cecFilename = "cec";
|
||||
|
||||
while (struct dirent* dirEntry = readdir(dir)) {
|
||||
string filename = dirEntry->d_name;
|
||||
if (filename.compare(0, 3, cecFilename, 0, 3) == 0) {
|
||||
int portId = getPortId(filename);
|
||||
if (portId == -1) {
|
||||
continue;
|
||||
}
|
||||
shared_ptr<HdmiCecPort> hdmiCecPort(new HdmiCecPort(portId));
|
||||
string filepath = parentPath + filename;
|
||||
Result result = hdmiCecPort->init(filepath.c_str());
|
||||
if (result != Result::SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
thread eventThread(&HdmiCecDefault::event_thread, this, hdmiCecPort.get());
|
||||
mEventThreads.push_back(std::move(eventThread));
|
||||
mHdmiCecPorts.push_back(std::move(hdmiCecPort));
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the CEC device supports required capabilities
|
||||
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();
|
||||
if (mHdmiCecPorts.empty()) {
|
||||
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 | CEC_MODE_EXCL_FOLLOWER_PASSTHRU;
|
||||
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;
|
||||
}
|
||||
|
||||
mEventThread = thread(&HdmiCecDefault::event_thread, this);
|
||||
|
||||
mCecEnabled = true;
|
||||
mWakeupEnabled = true;
|
||||
mCecControlEnabled = true;
|
||||
@@ -319,31 +334,25 @@ Return<Result> HdmiCecDefault::init() {
|
||||
}
|
||||
|
||||
Return<void> HdmiCecDefault::release() {
|
||||
if (mExitFd > 0) {
|
||||
uint64_t tmp = 1;
|
||||
write(mExitFd, &tmp, sizeof(tmp));
|
||||
if (mEventThread.joinable()) {
|
||||
mEventThread.join();
|
||||
}
|
||||
}
|
||||
if (mExitFd > 0) {
|
||||
close(mExitFd);
|
||||
}
|
||||
if (mCecFd > 0) {
|
||||
close(mCecFd);
|
||||
}
|
||||
mCecEnabled = false;
|
||||
mWakeupEnabled = false;
|
||||
mCecControlEnabled = false;
|
||||
for (thread& eventThread : mEventThreads) {
|
||||
if (eventThread.joinable()) {
|
||||
eventThread.join();
|
||||
}
|
||||
}
|
||||
setCallback(nullptr);
|
||||
mHdmiCecPorts.clear();
|
||||
mEventThreads.clear();
|
||||
return Void();
|
||||
}
|
||||
|
||||
void HdmiCecDefault::event_thread() {
|
||||
pollfd ufds[3] = {
|
||||
{mCecFd, POLLIN, 0},
|
||||
{mCecFd, POLLERR, 0},
|
||||
{mExitFd, POLLIN, 0},
|
||||
void HdmiCecDefault::event_thread(HdmiCecPort* hdmiCecPort) {
|
||||
struct pollfd ufds[3] = {
|
||||
{hdmiCecPort->mCecFd, POLLIN, 0},
|
||||
{hdmiCecPort->mCecFd, POLLERR, 0},
|
||||
{hdmiCecPort->mExitFd, POLLIN, 0},
|
||||
};
|
||||
|
||||
while (1) {
|
||||
@@ -363,7 +372,7 @@ void HdmiCecDefault::event_thread() {
|
||||
|
||||
if (ufds[1].revents == POLLERR) { /* CEC Event */
|
||||
cec_event ev;
|
||||
ret = ioctl(mCecFd, CEC_DQEVENT, &ev);
|
||||
ret = ioctl(hdmiCecPort->mCecFd, CEC_DQEVENT, &ev);
|
||||
|
||||
if (ret) {
|
||||
LOG(ERROR) << "CEC_DQEVENT failed, Error = " << strerror(errno);
|
||||
@@ -378,7 +387,7 @@ void HdmiCecDefault::event_thread() {
|
||||
if (mCallback != nullptr) {
|
||||
HotplugEvent hotplugEvent{
|
||||
.connected = (ev.state_change.phys_addr != CEC_PHYS_ADDR_INVALID),
|
||||
.portId = 1};
|
||||
.portId = hdmiCecPort->mPortId};
|
||||
mCallback->onHotplugEvent(hotplugEvent);
|
||||
} else {
|
||||
LOG(ERROR) << "No event callback for hotplug";
|
||||
@@ -388,7 +397,7 @@ void HdmiCecDefault::event_thread() {
|
||||
|
||||
if (ufds[0].revents == POLLIN) { /* CEC Driver */
|
||||
cec_msg msg = {};
|
||||
ret = ioctl(mCecFd, CEC_RECEIVE, &msg);
|
||||
ret = ioctl(hdmiCecPort->mCecFd, CEC_RECEIVE, &msg);
|
||||
|
||||
if (ret) {
|
||||
LOG(ERROR) << "CEC_RECEIVE failed, Error = " << strerror(errno);
|
||||
@@ -489,6 +498,19 @@ bool HdmiCecDefault::isPowerUICommand(cec_msg message) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Return<SendMessageResult> HdmiCecDefault::getSendMessageResult(int tx_status) {
|
||||
switch (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;
|
||||
}
|
||||
}
|
||||
} // namespace implementation
|
||||
} // namespace V1_0
|
||||
} // namespace cec
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
|
||||
#include <hardware/hdmi_cec.h>
|
||||
#include <linux/cec.h>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include "HdmiCecPort.h"
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
@@ -26,7 +26,9 @@ namespace cec {
|
||||
namespace V1_0 {
|
||||
namespace implementation {
|
||||
|
||||
using std::shared_ptr;
|
||||
using std::thread;
|
||||
using std::vector;
|
||||
|
||||
class HdmiCecDefault : public IHdmiCec, public hidl_death_recipient {
|
||||
public:
|
||||
@@ -54,14 +56,16 @@ class HdmiCecDefault : public IHdmiCec, public hidl_death_recipient {
|
||||
Return<void> release();
|
||||
|
||||
private:
|
||||
void event_thread();
|
||||
void event_thread(HdmiCecPort* hdmiCecPort);
|
||||
static int getOpcode(cec_msg message);
|
||||
static int getFirstParam(cec_msg message);
|
||||
static bool isWakeupMessage(cec_msg message);
|
||||
static bool isTransferableInSleep(cec_msg message);
|
||||
static bool isPowerUICommand(cec_msg message);
|
||||
static Return<SendMessageResult> getSendMessageResult(int tx_status);
|
||||
|
||||
thread mEventThread;
|
||||
vector<thread> mEventThreads;
|
||||
vector<shared_ptr<HdmiCecPort>> mHdmiCecPorts;
|
||||
|
||||
// When set to false, all the CEC commands are discarded. True by default after initialization.
|
||||
bool mCecEnabled;
|
||||
@@ -78,9 +82,6 @@ class HdmiCecDefault : public IHdmiCec, public hidl_death_recipient {
|
||||
*/
|
||||
bool mCecControlEnabled;
|
||||
sp<IHdmiCecCallback> mCallback;
|
||||
|
||||
int mCecFd;
|
||||
int mExitFd;
|
||||
};
|
||||
} // namespace implementation
|
||||
} // namespace V1_0
|
||||
|
||||
101
tv/cec/1.0/default/HdmiCecPort.cpp
Executable file
101
tv/cec/1.0/default/HdmiCecPort.cpp
Executable file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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 <android-base/logging.h>
|
||||
#include <errno.h>
|
||||
#include <linux/cec.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "HdmiCecPort.h"
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace tv {
|
||||
namespace cec {
|
||||
namespace V1_0 {
|
||||
namespace implementation {
|
||||
|
||||
HdmiCecPort::HdmiCecPort(unsigned int portId) {
|
||||
mPortId = portId;
|
||||
mCecFd = -1;
|
||||
mExitFd = -1;
|
||||
}
|
||||
|
||||
HdmiCecPort::~HdmiCecPort() {
|
||||
release();
|
||||
}
|
||||
|
||||
// Initialise the cec file descriptor
|
||||
Return<Result> HdmiCecPort::init(const char* path) {
|
||||
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 | CEC_MODE_EXCL_FOLLOWER_PASSTHRU;
|
||||
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<void> HdmiCecPort::release() {
|
||||
if (mExitFd > 0) {
|
||||
uint64_t tmp = 1;
|
||||
write(mExitFd, &tmp, sizeof(tmp));
|
||||
}
|
||||
if (mExitFd > 0) {
|
||||
close(mExitFd);
|
||||
}
|
||||
if (mCecFd > 0) {
|
||||
close(mCecFd);
|
||||
}
|
||||
return Void();
|
||||
}
|
||||
} // namespace implementation
|
||||
} // namespace V1_0
|
||||
} // namespace cec
|
||||
} // namespace tv
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
42
tv/cec/1.0/default/HdmiCecPort.h
Executable file
42
tv/cec/1.0/default/HdmiCecPort.h
Executable file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 <android/hardware/tv/cec/1.0/IHdmiCec.h>
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace tv {
|
||||
namespace cec {
|
||||
namespace V1_0 {
|
||||
namespace implementation {
|
||||
|
||||
class HdmiCecPort {
|
||||
public:
|
||||
HdmiCecPort(unsigned int portId);
|
||||
~HdmiCecPort();
|
||||
Return<Result> init(const char* path);
|
||||
Return<void> release();
|
||||
|
||||
unsigned int mPortId;
|
||||
int mCecFd;
|
||||
int mExitFd;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V1_0
|
||||
} // namespace cec
|
||||
} // namespace tv
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
Reference in New Issue
Block a user