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 <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 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 43 HdcpControl::~HdcpControl() 44 { 45 } 46 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 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 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 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 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 193 bool HdcpControl::enableOverlay() 194 { 195 return true; 196 } 197 198 bool HdcpControl::disableOverlay() 199 { 200 return true; 201 } 202 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 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 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 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 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 306 bool HdcpControl::preRunHdcp() 307 { 308 // TODO: for CTP platform, IED needs to be disabled during HDCP authentication. 309 return true; 310 } 311 312 bool HdcpControl::postRunHdcp() 313 { 314 // TODO: for CTP platform, IED needs to be disabled during HDCP authentication. 315 return true; 316 } 317 318 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 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