summaryrefslogtreecommitdiff
path: root/hwc2/common/devices/ExternalDevice.cpp (plain)
blob: a4c53d91ca3f6b4b7211c11052b624ab4a04e108
1/*
2// Copyright (c) 2014 Intel Corporation
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// This file is modified by Amlogic, Inc. 2017.01.17.
17*/
18
19#include <HwcTrace.h>
20#include <Drm.h>
21#include <DrmConfig.h>
22#include <Hwcomposer.h>
23#include <ExternalDevice.h>
24
25namespace android {
26namespace amlogic {
27
28ExternalDevice::ExternalDevice(Hwcomposer& hwc, DeviceControlFactory* controlFactory)
29 : PhysicalDevice(DEVICE_EXTERNAL, hwc, controlFactory),
30 mHdcpControl(NULL),
31 mAbortModeSettingCond(),
32 mPendingDrmMode(),
33 mHotplugEventPending(false),
34 mExpectedRefreshRate(0)
35{
36 CTRACE();
37}
38
39ExternalDevice::~ExternalDevice()
40{
41 CTRACE();
42}
43
44bool ExternalDevice::initialize()
45{
46 if (!PhysicalDevice::initialize()) {
47 DEINIT_AND_RETURN_FALSE("failed to initialize physical device");
48 }
49
50 mHdcpControl = mControlFactory->createHdcpControl();
51 if (!mHdcpControl) {
52 DEINIT_AND_RETURN_FALSE("failed to create HDCP control");
53 }
54
55 mHotplugEventPending = false;
56 if (mConnected) {
57 mHdcpControl->startHdcpAsync(HdcpLinkStatusListener, this);
58 }
59
60 UeventObserver *observer = Hwcomposer::getInstance().getUeventObserver();
61 if (observer) {
62 observer->registerListener(
63 DrmConfig::getHotplugString(),
64 hotplugEventListener,
65 this);
66 } else {
67 ETRACE("Uevent observer is NULL");
68 }
69
70 mDisplayHdmi = new DisplayHdmi(mId);
71 mDisplayHdmi->initialize();
72
73 return true;
74}
75
76void ExternalDevice::deinitialize()
77{
78 // abort mode settings if it is in the middle
79 mAbortModeSettingCond.signal();
80 if (mThread.get()) {
81 mThread->join();
82 mThread = NULL;
83 }
84
85 if (mHdcpControl) {
86 mHdcpControl->stopHdcp();
87 delete mHdcpControl;
88 mHdcpControl = 0;
89 }
90
91 mHotplugEventPending = false;
92 DEINIT_AND_DELETE_OBJ(mDisplayHdmi);
93 PhysicalDevice::deinitialize();
94}
95
96bool ExternalDevice::setDrmMode(drmModeModeInfo& value)
97{
98 if (!mConnected) {
99 WTRACE("external device is not connected");
100 return false;
101 }
102
103 if (mThread.get()) {
104 mThread->join();
105 mThread = NULL;
106 }
107
108 Drm *drm = Hwcomposer::getInstance().getDrm();
109 drmModeModeInfo mode;
110 drm->getModeInfo(mType, mode);
111 if (drm->isSameDrmMode(&value, &mode))
112 return true;
113
114 // any issue here by faking connection status?
115 mConnected = false;
116 mPendingDrmMode = value;
117
118 // setting mode in a working thread
119 mThread = new ModeSettingThread(this);
120 if (!mThread.get()) {
121 ETRACE("failed to create mode settings thread");
122 return false;
123 }
124
125 mThread->run("ModeSettingsThread", PRIORITY_URGENT_DISPLAY);
126 return true;
127}
128
129bool ExternalDevice::threadLoop()
130{
131 // one-time execution
132 setDrmMode();
133 return false;
134}
135
136void ExternalDevice::setDrmMode()
137{
138 ITRACE("start mode setting...");
139
140 Drm *drm = Hwcomposer::getInstance().getDrm();
141
142 mConnected = false;
143 mHwc.hotplug(mType, false);
144
145 {
146 Mutex::Autolock lock(mLock);
147 // TODO: make timeout value flexible, or wait until surface flinger
148 // acknowledges hot unplug event.
149 status_t err = mAbortModeSettingCond.waitRelative(mLock, milliseconds(20));
150 if (err != -ETIMEDOUT) {
151 ITRACE("Mode settings is interrupted");
152 mHwc.hotplug(mType, true);
153 return;
154 }
155 }
156
157 // TODO: potential threading issue with onHotplug callback
158 mHdcpControl->stopHdcp();
159 if (!drm->setDrmMode(mType, mPendingDrmMode)) {
160 ETRACE("failed to set Drm mode");
161 mHwc.hotplug(mType, true);
162 return;
163 }
164
165 if (!PhysicalDevice::updateDisplayConfigs()) {
166 ETRACE("failed to update display configs");
167 mHwc.hotplug(mType, true);
168 return;
169 }
170 mConnected = true;
171 mHotplugEventPending = true;
172 // delay sending hotplug event until HDCP is authenticated
173 if (mHdcpControl->startHdcpAsync(HdcpLinkStatusListener, this) == false) {
174 ETRACE("startHdcpAsync() failed; HDCP is not enabled");
175 mHotplugEventPending = false;
176 mHwc.hotplug(mType, true);
177 }
178 mExpectedRefreshRate = 0;
179}
180
181
182void ExternalDevice::HdcpLinkStatusListener(bool success, void *userData)
183{
184 if (userData == NULL) {
185 return;
186 }
187
188 ExternalDevice *p = (ExternalDevice*)userData;
189 p->HdcpLinkStatusListener(success);
190}
191
192void ExternalDevice::HdcpLinkStatusListener(bool success)
193{
194 if (!success) {
195 ETRACE("HDCP is not authenticated, disabling dynamic vsync");
196 mHwc.getVsyncManager()->enableDynamicVsync(false);
197 }
198
199 if (mHotplugEventPending) {
200 DTRACE("HDCP authentication status %d, sending hotplug event...", success);
201 mHwc.hotplug(mType, mConnected);
202 mHotplugEventPending = false;
203 }
204
205 if (success) {
206 ITRACE("HDCP authenticated, enabling dynamic vsync");
207 mHwc.getVsyncManager()->enableDynamicVsync(true);
208 }
209}
210
211void ExternalDevice::hotplugEventListener(void *data)
212{
213 ExternalDevice *pThis = (ExternalDevice*)data;
214 if (pThis) {
215 pThis->hotplugListener();
216 }
217}
218
219void ExternalDevice::hotplugListener()
220{
221 bool ret;
222
223 CTRACE();
224
225 // abort mode settings if it is in the middle
226 mAbortModeSettingCond.signal();
227
228 // remember the current connection status before detection
229 bool connected = mConnected;
230
231 // detect display configs
232 ret = detectDisplayConfigs();
233 if (ret == false) {
234 ETRACE("failed to detect display config");
235 return;
236 }
237
238 ITRACE("hotpug event: %d", mConnected);
239
240 if (connected == mConnected) {
241 WTRACE("same connection status detected, hotplug event ignored");
242 return;
243 }
244
245 if (mConnected == false) {
246 mHotplugEventPending = false;
247 mHwc.getVsyncManager()->resetVsyncSource();
248 mHdcpControl->stopHdcp();
249 mHwc.hotplug(mType, mConnected);
250 } else {
251 DTRACE("start HDCP asynchronously...");
252 // delay sending hotplug event till HDCP is authenticated.
253 mHotplugEventPending = true;
254 ret = mHdcpControl->startHdcpAsync(HdcpLinkStatusListener, this);
255 if (ret == false) {
256 ETRACE("failed to start HDCP");
257 mHotplugEventPending = false;
258 mHwc.hotplug(mType, mConnected);
259 }
260 }
261 mActiveDisplayConfig = 0;
262}
263
264int ExternalDevice::getRefreshRate()
265{
266 Drm *drm = Hwcomposer::getInstance().getDrm();
267 drmModeModeInfo mode;
268 if (!drm->getModeInfo(IDisplayDevice::DEVICE_EXTERNAL, mode))
269 return 0;
270 return mode.vrefresh;
271}
272
273void ExternalDevice::setRefreshRate(int hz)
274{
275 RETURN_VOID_IF_NOT_INIT();
276
277 ITRACE("setting refresh rate to %d", hz);
278
279 if (mBlank) {
280 WTRACE("external device is blank");
281 return;
282 }
283
284 Drm *drm = Hwcomposer::getInstance().getDrm();
285 drmModeModeInfo mode;
286 if (!drm->getModeInfo(IDisplayDevice::DEVICE_EXTERNAL, mode))
287 return;
288
289 if (hz == 0 && (mode.type & DRM_MODE_TYPE_PREFERRED))
290 return;
291
292 if (hz == (int)mode.vrefresh)
293 return;
294
295 if (mExpectedRefreshRate != 0 &&
296 mExpectedRefreshRate == hz && mHotplugEventPending) {
297 ITRACE("Ignore a new refresh setting event because there is a same event is handling");
298 return;
299 }
300 mExpectedRefreshRate = hz;
301
302 ITRACE("changing refresh rate from %d to %d", mode.vrefresh, hz);
303
304 mHwc.getVsyncManager()->enableDynamicVsync(false);
305
306 mHdcpControl->stopHdcp();
307
308 drm->setRefreshRate(IDisplayDevice::DEVICE_EXTERNAL, hz);
309
310 mHotplugEventPending = false;
311 mHdcpControl->startHdcpAsync(HdcpLinkStatusListener, this);
312 mHwc.getVsyncManager()->enableDynamicVsync(true);
313}
314
315int ExternalDevice::getActiveConfig()
316{
317 if (!mConnected) {
318 return 0;
319 }
320 return mActiveDisplayConfig;
321}
322
323bool ExternalDevice::setActiveConfig(int index)
324{
325 if (!mConnected) {
326 if (index == 0)
327 return true;
328 else
329 return false;
330 }
331
332 int ret = mDisplayHdmi->setActiveConfig(index);
333 if (ret < 0)
334 return false;
335
336 setRefreshRate(mDisplayHdmi->getActiveRefreshRate());
337 mActiveDisplayConfig = index;
338
339 return true;
340}
341
342} // namespace amlogic
343} // namespace android
344