blob: 7466c92a83e284d212a1b622b50f1aff2815c171 [file] [log] [blame]
Shraddha Basantwanif3a43c82021-05-27 19:40:17 +05301/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "android.hardware.tv.cec@1.0-impl"
18#include <android-base/logging.h>
19
20#include <errno.h>
21#include <fcntl.h>
22#include <linux/cec.h>
23#include <linux/ioctl.h>
24#include <sys/eventfd.h>
25
26#include "HdmiCecDefault.h"
27
28namespace android {
29namespace hardware {
30namespace tv {
31namespace cec {
32namespace V1_0 {
33namespace implementation {
34
35int mCecFd;
36int mExitFd;
37
38HdmiCecDefault::HdmiCecDefault() {
39 mCecFd = -1;
40 mExitFd = -1;
41}
42
43HdmiCecDefault::~HdmiCecDefault() {
44 release();
45}
46
47// Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
48Return<Result> HdmiCecDefault::addLogicalAddress(CecLogicalAddress /*addr*/) {
49 return Result::FAILURE_UNKNOWN;
50}
51
52Return<void> HdmiCecDefault::clearLogicalAddress() {
Shraddha Basantwani0dacc5c2021-06-01 10:32:22 +053053 struct cec_log_addrs cecLogAddrs;
54 memset(&cecLogAddrs, 0, sizeof(cecLogAddrs));
55 int ret = ioctl(mCecFd, CEC_ADAP_S_LOG_ADDRS, &cecLogAddrs);
56 if (ret) {
57 LOG(ERROR) << "Clear logical Address failed, Error = " << strerror(errno);
58 }
Shraddha Basantwanif3a43c82021-05-27 19:40:17 +053059 return Void();
60}
61
Shraddha Basantwani9b1e5292021-05-31 16:38:38 +053062Return<void> HdmiCecDefault::getPhysicalAddress(getPhysicalAddress_cb callback) {
63 uint16_t addr;
64 int ret = ioctl(mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr);
65 if (ret) {
66 LOG(ERROR) << "Get physical address failed, Error = " << strerror(errno);
67 callback(Result::FAILURE_INVALID_STATE, addr);
68 return Void();
69 }
70 callback(Result::SUCCESS, addr);
Shraddha Basantwanif3a43c82021-05-27 19:40:17 +053071 return Void();
72}
73
Shraddha Basantwani971853b2021-05-31 16:28:23 +053074Return<SendMessageResult> HdmiCecDefault::sendMessage(const CecMessage& message) {
75 struct cec_msg cecMsg;
76 memset(&cecMsg, 0, sizeof(cec_msg));
77
78 int initiator = static_cast<cec_logical_address_t>(message.initiator);
79 int destination = static_cast<cec_logical_address_t>(message.destination);
80
81 cecMsg.msg[0] = (initiator << 4) | destination;
82 for (size_t i = 0; i < message.body.size(); ++i) {
83 cecMsg.msg[i + 1] = message.body[i];
84 }
85 cecMsg.len = message.body.size() + 1;
86
87 int ret = ioctl(mCecFd, CEC_TRANSMIT, &cecMsg);
88
89 if (ret) {
90 LOG(ERROR) << "Send message failed, Error = " << strerror(errno);
91 return SendMessageResult::FAIL;
92 }
93
94 if (cecMsg.tx_status != CEC_TX_STATUS_OK) {
95 LOG(ERROR) << "Send message tx_status = " << cecMsg.tx_status;
96 }
97
98 switch (cecMsg.tx_status) {
99 case CEC_TX_STATUS_OK:
100 return SendMessageResult::SUCCESS;
101 case CEC_TX_STATUS_ARB_LOST:
102 return SendMessageResult::BUSY;
103 case CEC_TX_STATUS_NACK:
104 return SendMessageResult::NACK;
105 default:
106 return SendMessageResult::FAIL;
107 }
Shraddha Basantwanif3a43c82021-05-27 19:40:17 +0530108}
109
110Return<void> HdmiCecDefault::setCallback(const sp<IHdmiCecCallback>& /*callback*/) {
111 return Void();
112}
113
114Return<int32_t> HdmiCecDefault::getCecVersion() {
115 return 0;
116}
117
118Return<uint32_t> HdmiCecDefault::getVendorId() {
119 return 0;
120}
121
122Return<void> HdmiCecDefault::getPortInfo(getPortInfo_cb /*_hidl_cb*/) {
123 return Void();
124}
125
126Return<void> HdmiCecDefault::setOption(OptionKey /*key*/, bool /*value*/) {
127 return Void();
128}
129
130Return<void> HdmiCecDefault::setLanguage(const hidl_string& /*language*/) {
131 return Void();
132}
133
134Return<void> HdmiCecDefault::enableAudioReturnChannel(int32_t /*portId*/, bool /*enable*/) {
135 return Void();
136}
137
138Return<bool> HdmiCecDefault::isConnected(int32_t /*portId*/) {
139 return false;
140}
141
142// Initialise the cec file descriptor
143Return<Result> HdmiCecDefault::init() {
144 const char* path = "/dev/cec0";
145 mCecFd = open(path, O_RDWR);
146 if (mCecFd < 0) {
147 LOG(ERROR) << "Failed to open " << path << ", Error = " << strerror(errno);
148 return Result::FAILURE_NOT_SUPPORTED;
149 }
150 mExitFd = eventfd(0, EFD_NONBLOCK);
151 if (mExitFd < 0) {
152 LOG(ERROR) << "Failed to open eventfd, Error = " << strerror(errno);
153 release();
154 return Result::FAILURE_NOT_SUPPORTED;
155 }
156
157 // Ensure the CEC device supports required capabilities
158 struct cec_caps caps = {};
159 int ret = ioctl(mCecFd, CEC_ADAP_G_CAPS, &caps);
160 if (ret) {
161 LOG(ERROR) << "Unable to query cec adapter capabilities, Error = " << strerror(errno);
162 release();
163 return Result::FAILURE_NOT_SUPPORTED;
164 }
165
166 if (!(caps.capabilities & (CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | CEC_CAP_PASSTHROUGH))) {
167 LOG(ERROR) << "Wrong cec adapter capabilities " << caps.capabilities;
168 release();
169 return Result::FAILURE_NOT_SUPPORTED;
170 }
171
172 uint32_t mode = CEC_MODE_INITIATOR;
173 ret = ioctl(mCecFd, CEC_S_MODE, &mode);
174 if (ret) {
175 LOG(ERROR) << "Unable to set initiator mode, Error = " << strerror(errno);
176 release();
177 return Result::FAILURE_NOT_SUPPORTED;
178 }
179
180 return Result::SUCCESS;
181}
182
183Return<void> HdmiCecDefault::release() {
184 if (mExitFd > 0) {
185 uint64_t tmp = 1;
186 write(mExitFd, &tmp, sizeof(tmp));
187 }
188 if (mExitFd > 0) {
189 close(mExitFd);
190 }
191 if (mCecFd > 0) {
192 close(mCecFd);
193 }
194 setCallback(nullptr);
195 return Void();
196}
197} // namespace implementation
198} // namespace V1_0
199} // namespace cec
200} // namespace tv
201} // namespace hardware
202} // namespace android