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 <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