blob: 7cd9bb70811522a6232b6d9126063760e90336ec [file] [log] [blame]
Venkatarama Avadhani820b5482022-05-18 15:19:04 +05301/*
2 * Copyright (C) 2022 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.hdmi"
18#include <android-base/logging.h>
19#include <fcntl.h>
20#include <utils/Log.h>
21
22#include "HdmiMock.h"
23
24using ndk::ScopedAStatus;
25
26namespace android {
27namespace hardware {
28namespace tv {
29namespace hdmi {
30namespace implementation {
31
32void HdmiMock::serviceDied(void* cookie) {
33 ALOGE("HdmiMock died");
34 auto hdmi = static_cast<HdmiMock*>(cookie);
35 hdmi->mHdmiThreadRun = false;
36}
37
38ScopedAStatus HdmiMock::getPortInfo(std::vector<HdmiPortInfo>* _aidl_return) {
39 *_aidl_return = mPortInfos;
40 return ScopedAStatus::ok();
41}
42
43ScopedAStatus HdmiMock::isConnected(int32_t portId, bool* _aidl_return) {
44 // Maintain port connection status and update on hotplug event
45 if (portId <= mTotalPorts && portId >= 1) {
46 *_aidl_return = mPortConnectionStatus[portId];
47 } else {
48 *_aidl_return = false;
49 }
50
51 return ScopedAStatus::ok();
52}
53
54ScopedAStatus HdmiMock::setCallback(const std::shared_ptr<IHdmiCallback>& callback) {
55 if (mCallback != nullptr) {
56 mCallback = nullptr;
57 }
58
59 if (callback != nullptr) {
60 mCallback = callback;
61 AIBinder_linkToDeath(this->asBinder().get(), mDeathRecipient.get(), 0 /* cookie */);
62
63 mInputFile = open(HDMI_MSG_IN_FIFO, O_RDWR | O_CLOEXEC);
64 pthread_create(&mThreadId, NULL, __threadLoop, this);
65 pthread_setname_np(mThreadId, "hdmi_loop");
66 }
67 return ScopedAStatus::ok();
68}
69
Venkatarama Avadhani04ee1a42022-11-09 16:21:55 +053070ScopedAStatus HdmiMock::setHpdSignal(HpdSignal signal) {
71 if (mHdmiThreadRun) {
72 mHpdSignal = signal;
73 return ScopedAStatus::ok();
74 } else {
75 return ScopedAStatus::fromServiceSpecificError(
76 static_cast<int32_t>(Result::FAILURE_INVALID_STATE));
77 }
78}
79
80ScopedAStatus HdmiMock::getHpdSignal(HpdSignal* _aidl_return) {
81 *_aidl_return = mHpdSignal;
82 return ScopedAStatus::ok();
83}
84
Venkatarama Avadhani820b5482022-05-18 15:19:04 +053085void* HdmiMock::__threadLoop(void* user) {
86 HdmiMock* const self = static_cast<HdmiMock*>(user);
87 self->threadLoop();
88 return 0;
89}
90
91int HdmiMock::readMessageFromFifo(unsigned char* buf, int msgCount) {
92 if (msgCount <= 0 || !buf) {
93 return 0;
94 }
95
96 int ret = -1;
97 // Maybe blocked at driver
98 ret = read(mInputFile, buf, msgCount);
99 if (ret < 0) {
100 ALOGE("[halimp_aidl] read :%s failed, ret:%d\n", HDMI_MSG_IN_FIFO, ret);
101 return -1;
102 }
103
104 return ret;
105}
106
107void HdmiMock::printEventBuf(const char* msg_buf, int len) {
108 int i, size = 0;
109 const int bufSize = MESSAGE_BODY_MAX_LENGTH * 3;
110 // Use 2 characters for each byte in the message plus 1 space
111 char buf[bufSize] = {0};
112
113 // Messages longer than max length will be truncated.
114 for (i = 0; i < len && size < bufSize; i++) {
115 size += sprintf(buf + size, " %02x", msg_buf[i]);
116 }
117 ALOGD("[halimp_aidl] %s, msg:%.*s", __FUNCTION__, size, buf);
118}
119
120void HdmiMock::handleHotplugMessage(unsigned char* msgBuf) {
121 bool connected = ((msgBuf[3]) & 0xf) > 0;
122 int32_t portId = static_cast<uint32_t>(msgBuf[0] & 0xf);
123
124 if (portId > static_cast<int32_t>(mPortInfos.size())) {
125 ALOGD("[halimp_aidl] ignore hot plug message, id %x does not exist", portId);
126 return;
127 }
128
129 ALOGD("[halimp_aidl] hot plug port id %x, is connected %x", (msgBuf[0] & 0xf),
130 (msgBuf[3] & 0xf));
131 mPortConnectionStatus[portId] = connected;
132 if (mPortInfos[portId].type == HdmiPortType::OUTPUT) {
133 mPhysicalAddress = (connected ? 0xffff : ((msgBuf[1] << 8) | (msgBuf[2])));
134 mPortInfos[portId].physicalAddress = mPhysicalAddress;
135 ALOGD("[halimp_aidl] hot plug physical address %x", mPhysicalAddress);
136 }
137
138 if (mCallback != nullptr) {
139 mCallback->onHotplugEvent(connected, portId);
140 }
141}
142
143void HdmiMock::threadLoop() {
144 ALOGD("[halimp_aidl] threadLoop start.");
145 unsigned char msgBuf[MESSAGE_BODY_MAX_LENGTH];
146 int r = -1;
147
148 // Open the input pipe
149 while (mInputFile < 0) {
150 usleep(1000 * 1000);
151 mInputFile = open(HDMI_MSG_IN_FIFO, O_RDONLY | O_CLOEXEC);
152 }
153 ALOGD("[halimp_aidl] file open ok, fd = %d.", mInputFile);
154
155 while (mHdmiThreadRun) {
156 memset(msgBuf, 0, sizeof(msgBuf));
157 // Try to get a message from dev.
158 // echo -n -e '\x04\x83' >> /dev/cec
159 r = readMessageFromFifo(msgBuf, MESSAGE_BODY_MAX_LENGTH);
160 if (r <= 1) {
161 // Ignore received ping messages
162 continue;
163 }
164
165 printEventBuf((const char*)msgBuf, r);
166
167 if (((msgBuf[0] >> 4) & 0xf) == 0xf) {
168 handleHotplugMessage(msgBuf);
169 }
170 }
171
172 ALOGD("[halimp_aidl] thread end.");
173}
174
175HdmiMock::HdmiMock() {
176 ALOGE("[halimp_aidl] Opening a virtual HDMI HAL for testing and virtual machine.");
177 mCallback = nullptr;
178 mPortInfos.resize(mTotalPorts);
179 mPortConnectionStatus.resize(mTotalPorts);
180 mPortInfos[0] = {.type = HdmiPortType::OUTPUT,
181 .portId = static_cast<uint32_t>(1),
182 .cecSupported = true,
183 .arcSupported = false,
Venkatarama Avadhani3d35efc2022-11-02 10:16:28 +0530184 .eArcSupported = false,
Venkatarama Avadhani820b5482022-05-18 15:19:04 +0530185 .physicalAddress = mPhysicalAddress};
186 mPortConnectionStatus[0] = false;
187 mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
188}
189
190} // namespace implementation
191} // namespace hdmi
192} // namespace tv
193} // namespace hardware
194} // namespace android