Home | History | Annotate | Download | only in common
      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