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