1 /* 2 // Copyright(c)2014 IntelCorporation 3 // 4 // LicensedundertheApacheLicense,Version2.0(the"License"); 5 // youmaynotusethisfileexceptincompliancewiththeLicense. 6 // YoumayobtainacopyoftheLicenseat 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unlessrequiredbyapplicablelaworagreedtoinwriting,software 11 // distributedundertheLicenseisdistributedonan"ASIS"BASIS, 12 // WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. 13 // SeetheLicenseforthespecificlanguagegoverningpermissionsand 14 // limitationsundertheLicense. 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 25 namespace android { 26 namespace intel { 27 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 mEnableAuthenticationLog(true) 41 { 42 } 43 44 HdcpControl::~HdcpControl() 45 { 46 } 47 48 bool 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 105 bool 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 146 bool 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 172 bool 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 191 bool 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 202 bool HdcpControl::enableOverlay() 203 { 204 return true; 205 } 206 207 bool HdcpControl::disableOverlay() 208 { 209 return true; 210 } 211 212 bool 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 223 bool 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 234 bool 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 252 bool 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 271 bool 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 319 bool HdcpControl::preRunHdcp() 320 { 321 // TODO: for CTP platform, IED needs to be disabled during HDCP authentication. 322 return true; 323 } 324 325 bool HdcpControl::postRunHdcp() 326 { 327 // TODO: for CTP platform, IED needs to be disabled during HDCP authentication. 328 return true; 329 } 330 331 332 void HdcpControl::signalCompletion() 333 { 334 if (mWaitForCompletion) { 335 ILOGTRACE("signal HDCP authentication completed, status = %d", mAuthenticated); 336 mCompletedCondition.signal(); 337 mWaitForCompletion = false; 338 } 339 } 340 341 bool 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