• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <HwcTrace.h>
17 #include <DrmConfig.h>
18 #include <Hwcomposer.h>
19 #include <DisplayQuery.h>
20 #include <common/DrmControl.h>
21 #include <common/HdcpControl.h>
22 #include <cutils/properties.h>
23 
24 
25 namespace android {
26 namespace intel {
27 
HdcpControl()28 HdcpControl::HdcpControl()
29     : mCallback(NULL),
30       mUserData(NULL),
31       mCallbackState(CALLBACK_PENDING),
32       mMutex(),
33       mStoppedCondition(),
34       mCompletedCondition(),
35       mWaitForCompletion(false),
36       mStopped(true),
37       mAuthenticated(false),
38       mActionDelay(0),
39       mAuthRetryCount(0)
40 {
41 }
42 
~HdcpControl()43 HdcpControl::~HdcpControl()
44 {
45 }
46 
startHdcp()47 bool HdcpControl::startHdcp()
48 {
49     // this is a blocking and synchronous call
50     Mutex::Autolock lock(mMutex);
51 
52     char prop[PROPERTY_VALUE_MAX];
53     if (property_get("debug.hwc.hdcp.enable", prop, "1") > 0) {
54         if (atoi(prop) == 0) {
55             WTRACE("HDCP is disabled");
56             return false;
57         }
58     }
59 
60     if (!mStopped) {
61         WTRACE("HDCP has been started");
62         return true;
63     }
64 
65     mStopped = false;
66     mAuthenticated = false;
67     mWaitForCompletion = false;
68 
69     mThread = new HdcpControlThread(this);
70     if (!mThread.get()) {
71         ETRACE("failed to create hdcp control thread");
72         return false;
73     }
74 
75     if (!runHdcp()) {
76         ETRACE("failed to run HDCP");
77         mStopped = true;
78         mThread = NULL;
79         return false;
80     }
81 
82     mAuthRetryCount = 0;
83     mWaitForCompletion = !mAuthenticated;
84     if (mAuthenticated) {
85         mActionDelay = HDCP_VERIFICATION_DELAY_MS;
86     } else {
87         mActionDelay = HDCP_AUTHENTICATION_SHORT_DELAY_MS;
88     }
89 
90     mThread->run("HdcpControl", PRIORITY_NORMAL);
91 
92     if (!mWaitForCompletion) {
93         // HDCP is authenticated.
94         return true;
95     }
96     status_t err = mCompletedCondition.waitRelative(mMutex, milliseconds(HDCP_AUTHENTICATION_TIMEOUT_MS));
97     if (err == -ETIMEDOUT) {
98         WTRACE("timeout waiting for completion");
99     }
100     mWaitForCompletion = false;
101     return mAuthenticated;
102 }
103 
startHdcpAsync(HdcpStatusCallback cb,void * userData)104 bool HdcpControl::startHdcpAsync(HdcpStatusCallback cb, void *userData)
105 {
106     char prop[PROPERTY_VALUE_MAX];
107     if (property_get("debug.hwc.hdcp.enable", prop, "1") > 0) {
108         if (atoi(prop) == 0) {
109             WTRACE("HDCP is disabled");
110             return false;
111         }
112     }
113 
114     if (cb == NULL || userData == NULL) {
115         ETRACE("invalid callback or user data");
116         return false;
117     }
118 
119     Mutex::Autolock lock(mMutex);
120 
121     if (!mStopped) {
122         WTRACE("HDCP has been started");
123         return true;
124     }
125 
126     mThread = new HdcpControlThread(this);
127     if (!mThread.get()) {
128         ETRACE("failed to create hdcp control thread");
129         return false;
130     }
131 
132     mAuthRetryCount = 0;
133     mCallback = cb;
134     mUserData = userData;
135     mCallbackState = CALLBACK_PENDING;
136     mWaitForCompletion = false;
137     mAuthenticated = false;
138     mStopped = false;
139     mActionDelay = HDCP_ASYNC_START_DELAY_MS;
140     mThread->run("HdcpControl", PRIORITY_NORMAL);
141 
142     return true;
143 }
144 
stopHdcp()145 bool HdcpControl::stopHdcp()
146 {
147     do {
148         Mutex::Autolock lock(mMutex);
149         if (mStopped) {
150             return true;
151         }
152 
153         mStopped = true;
154         mStoppedCondition.signal();
155 
156         mAuthenticated = false;
157         mWaitForCompletion = false;
158         mCallback = NULL;
159         mUserData = NULL;
160         disableAuthentication();
161     } while (0);
162 
163     if (mThread.get()) {
164         mThread->requestExitAndWait();
165         mThread = NULL;
166     }
167 
168     return true;
169 }
170 
enableAuthentication()171 bool HdcpControl::enableAuthentication()
172 {
173     int fd = Hwcomposer::getInstance().getDrm()->getDrmFd();
174     int ret = drmCommandNone(fd, DRM_PSB_ENABLE_HDCP);
175     if (ret != 0) {
176         ETRACE("failed to enable HDCP authentication");
177         return false;
178     }
179     return true;
180 }
181 
disableAuthentication()182 bool HdcpControl::disableAuthentication()
183 {
184     int fd = Hwcomposer::getInstance().getDrm()->getDrmFd();
185     int ret = drmCommandNone(fd, DRM_PSB_DISABLE_HDCP);
186     if (ret != 0) {
187         ETRACE("failed to stop disable authentication");
188         return false;
189     }
190     return true;
191 }
192 
enableOverlay()193 bool HdcpControl::enableOverlay()
194 {
195     return true;
196 }
197 
disableOverlay()198 bool HdcpControl::disableOverlay()
199 {
200     return true;
201 }
202 
enableDisplayIED()203 bool HdcpControl::enableDisplayIED()
204 {
205     int fd = Hwcomposer::getInstance().getDrm()->getDrmFd();
206     int ret = drmCommandNone(fd, DRM_PSB_HDCP_DISPLAY_IED_ON);
207     if (ret != 0) {
208         ETRACE("failed to enable overlay IED");
209         return false;
210     }
211     return true;
212 }
213 
disableDisplayIED()214 bool HdcpControl::disableDisplayIED()
215 {
216     int fd = Hwcomposer::getInstance().getDrm()->getDrmFd();
217     int ret = drmCommandNone(fd, DRM_PSB_HDCP_DISPLAY_IED_OFF);
218     if (ret != 0) {
219         ETRACE("failed to disable overlay IED");
220         return false;
221     }
222     return true;
223 }
224 
isHdcpSupported()225 bool HdcpControl::isHdcpSupported()
226 {
227     int fd = Hwcomposer::getInstance().getDrm()->getDrmFd();
228     unsigned int caps = 0;
229     int ret = drmCommandRead(fd, DRM_PSB_QUERY_HDCP, &caps, sizeof(caps));
230     if (ret != 0) {
231         ETRACE("failed to query HDCP capability");
232         return false;
233     }
234     if (caps == 0) {
235         WTRACE("HDCP is not supported");
236         return false;
237     } else {
238         ITRACE("HDCP is supported");
239         return true;
240     }
241 }
242 
checkAuthenticated()243 bool HdcpControl::checkAuthenticated()
244 {
245     int fd = Hwcomposer::getInstance().getDrm()->getDrmFd();
246     unsigned int match = 0;
247     int ret = drmCommandRead(fd, DRM_PSB_GET_HDCP_LINK_STATUS, &match, sizeof(match));
248     if (ret != 0) {
249         ETRACE("failed to get hdcp link status");
250         return false;
251     }
252     if (match) {
253         VTRACE("HDCP is authenticated");
254         mAuthenticated = true;
255     } else {
256         ETRACE("HDCP is not authenticated");
257         mAuthenticated = false;
258     }
259     return mAuthenticated;
260 }
261 
runHdcp()262 bool HdcpControl::runHdcp()
263 {
264     // Default return value is true so HDCP can be re-authenticated in the working thread
265     bool ret = true;
266 
267     preRunHdcp();
268 
269     for (int i = 0; i < HDCP_INLOOP_RETRY_NUMBER; i++) {
270         VTRACE("enable and verify HDCP, iteration# %d", i);
271         if (mStopped) {
272             WTRACE("HDCP authentication has been stopped");
273             ret = false;
274             break;
275         }
276 
277         if (!enableAuthentication()) {
278             ETRACE("HDCP authentication failed. Retry");
279             mAuthenticated = false;
280             ret = true;
281         } else {
282             ITRACE("HDCP is authenticated");
283             mAuthenticated = true;
284             ret = true;
285             break;
286         }
287 
288         if (mStopped) {
289             WTRACE("HDCP authentication has been stopped");
290             ret = false;
291             break;
292         }
293 
294         if (i < HDCP_INLOOP_RETRY_NUMBER - 1) {
295             // Adding delay to make sure panel receives video signal so it can start HDCP authentication.
296             // (HDCP spec 1.3, section 2.3)
297             usleep(HDCP_INLOOP_RETRY_DELAY_US);
298         }
299     }
300 
301     postRunHdcp();
302 
303     return ret;
304 }
305 
preRunHdcp()306 bool HdcpControl::preRunHdcp()
307 {
308     // TODO: for CTP platform, IED needs to be disabled during HDCP authentication.
309     return true;
310 }
311 
postRunHdcp()312 bool HdcpControl::postRunHdcp()
313 {
314     // TODO: for CTP platform, IED needs to be disabled during HDCP authentication.
315     return true;
316 }
317 
318 
signalCompletion()319 void HdcpControl::signalCompletion()
320 {
321     if (mWaitForCompletion) {
322         ITRACE("signal HDCP authentication completed, status = %d", mAuthenticated);
323         mCompletedCondition.signal();
324         mWaitForCompletion = false;
325     }
326 }
327 
threadLoop()328 bool HdcpControl::threadLoop()
329 {
330     Mutex::Autolock lock(mMutex);
331     status_t err = mStoppedCondition.waitRelative(mMutex, milliseconds(mActionDelay));
332     if (err != -ETIMEDOUT) {
333         ITRACE("Hdcp is stopped.");
334         signalCompletion();
335         return false;
336     }
337 
338     // default is to keep thread active
339     bool ret = true;
340     if (!mAuthenticated) {
341         ret = runHdcp();
342         mAuthRetryCount++;
343     } else {
344         mAuthRetryCount = 0;
345         checkAuthenticated();
346     }
347 
348     // set next action delay
349     if (mAuthenticated) {
350         mActionDelay = HDCP_VERIFICATION_DELAY_MS;
351     } else {
352         // If HDCP can not authenticate after "HDCP_RETRY_LIMIT" attempts
353         // reduce HDCP retry frequency to 2 sec
354         if (mAuthRetryCount >= HDCP_RETRY_LIMIT) {
355             mActionDelay = HDCP_AUTHENTICATION_LONG_DELAY_MS;
356         } else {
357             mActionDelay = HDCP_AUTHENTICATION_SHORT_DELAY_MS;
358         }
359     }
360 
361     // TODO: move out of lock?
362     if (!ret || mAuthenticated) {
363         signalCompletion();
364     }
365 
366     if (mCallback) {
367          if ((mAuthenticated && mCallbackState == CALLBACK_AUTHENTICATED) ||
368             (!mAuthenticated && mCallbackState == CALLBACK_NOT_AUTHENTICATED)) {
369             // ignore callback as state is not changed
370         } else {
371             mCallbackState =
372                 mAuthenticated ? CALLBACK_AUTHENTICATED : CALLBACK_NOT_AUTHENTICATED;
373             (*mCallback)(mAuthenticated, mUserData);
374         }
375     }
376     return ret;
377 }
378 
379 } // namespace intel
380 } // namespace android
381