Home | History | Annotate | Download | only in devices
      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 
     17 #include <common/utils/HwcTrace.h>
     18 #include <common/base/Drm.h>
     19 #include <DrmConfig.h>
     20 #include <Hwcomposer.h>
     21 #include <ExternalDevice.h>
     22 
     23 namespace android {
     24 namespace intel {
     25 
     26 ExternalDevice::ExternalDevice(uint32_t disp, Hwcomposer& hwc, DisplayPlaneManager& dpm)
     27     : PhysicalDevice(disp, DEVICE_EXTERNAL, hwc, dpm),
     28       mHdcpControl(NULL),
     29       mAbortModeSettingCond(),
     30       mPendingDrmMode(),
     31       mHotplugEventPending(false)
     32 {
     33     CTRACE();
     34 }
     35 
     36 ExternalDevice::~ExternalDevice()
     37 {
     38     CTRACE();
     39 }
     40 
     41 bool ExternalDevice::initialize()
     42 {
     43     if (!PhysicalDevice::initialize()) {
     44         DEINIT_AND_RETURN_FALSE("failed to initialize physical device");
     45     }
     46 
     47     mHdcpControl = createHdcpControl();
     48     if (!mHdcpControl) {
     49         DEINIT_AND_RETURN_FALSE("failed to create HDCP control");
     50     }
     51 
     52     mHotplugEventPending = false;
     53     if (mConnected) {
     54         mHdcpControl->startHdcpAsync(HdcpLinkStatusListener, this);
     55     }
     56 
     57     UeventObserver *observer = Hwcomposer::getInstance().getUeventObserver();
     58     if (observer) {
     59         observer->registerListener(
     60             DrmConfig::getHotplugString(),
     61             hotplugEventListener,
     62             this);
     63     } else {
     64         ELOGTRACE("Uevent observer is NULL");
     65     }
     66     return true;
     67 }
     68 
     69 void ExternalDevice::deinitialize()
     70 {
     71     // abort mode settings if it is in the middle
     72     mAbortModeSettingCond.signal();
     73     if (mThread.get()) {
     74         mThread->join();
     75         mThread = NULL;
     76     }
     77 
     78     if (mHdcpControl) {
     79         mHdcpControl->stopHdcp();
     80         delete mHdcpControl;
     81         mHdcpControl = 0;
     82     }
     83 
     84     mHotplugEventPending = false;
     85     PhysicalDevice::deinitialize();
     86 }
     87 
     88 bool ExternalDevice::blank(bool blank)
     89 {
     90     if (!PhysicalDevice::blank(blank)) {
     91         return false;
     92     }
     93 
     94     if (blank) {
     95         mHdcpControl->stopHdcp();
     96     } else if (mConnected) {
     97         mHdcpControl->startHdcpAsync(HdcpLinkStatusListener, this);
     98     }
     99     return true;
    100 }
    101 
    102 bool ExternalDevice::setDrmMode(drmModeModeInfo& value)
    103 {
    104     if (!mConnected) {
    105         WLOGTRACE("external device is not connected");
    106         return false;
    107     }
    108 
    109     if (mThread.get()) {
    110         mThread->join();
    111         mThread = NULL;
    112     }
    113 
    114     Drm *drm = Hwcomposer::getInstance().getDrm();
    115     drmModeModeInfo mode;
    116     drm->getModeInfo(mType, mode);
    117     if (drm->isSameDrmMode(&value, &mode))
    118         return true;
    119 
    120     // any issue here by faking connection status?
    121     mConnected = false;
    122     mPendingDrmMode = value;
    123 
    124     // setting mode in a working thread
    125     mThread = new ModeSettingThread(this);
    126     if (!mThread.get()) {
    127         ELOGTRACE("failed to create mode settings thread");
    128         return false;
    129     }
    130 
    131     mThread->run("ModeSettingsThread", PRIORITY_URGENT_DISPLAY);
    132     return true;
    133 }
    134 
    135 bool ExternalDevice::threadLoop()
    136 {
    137     // one-time execution
    138     setDrmMode();
    139     return false;
    140 }
    141 
    142 void ExternalDevice::setDrmMode()
    143 {
    144     ILOGTRACE("start mode setting...");
    145 
    146     Drm *drm = Hwcomposer::getInstance().getDrm();
    147 
    148     mConnected = false;
    149     mHwc.hotplug(mDisp, false);
    150 
    151     {
    152         Mutex::Autolock lock(mLock);
    153         // TODO: make timeout value flexible, or wait until surface flinger
    154         // acknowledges hot unplug event.
    155         status_t err = mAbortModeSettingCond.waitRelative(mLock, milliseconds(20));
    156         if (err != -ETIMEDOUT) {
    157             ILOGTRACE("Mode settings is interrupted");
    158             mHwc.hotplug(mDisp, true);
    159             return;
    160         }
    161     }
    162 
    163     // TODO: potential threading issue with onHotplug callback
    164     mHdcpControl->stopHdcp();
    165     if (!drm->setDrmMode(mType, mPendingDrmMode)) {
    166         ELOGTRACE("failed to set Drm mode");
    167         mHwc.hotplug(mDisp, true);
    168         return;
    169     }
    170 
    171     if (!PhysicalDevice::updateDisplayConfigs()) {
    172         ELOGTRACE("failed to update display configs");
    173         mHwc.hotplug(mDisp, true);
    174         return;
    175     }
    176     mConnected = true;
    177     mHotplugEventPending = true;
    178     // delay sending hotplug event until HDCP is authenticated
    179     if (mHdcpControl->startHdcpAsync(HdcpLinkStatusListener, this) == false) {
    180         ELOGTRACE("startHdcpAsync() failed; HDCP is not enabled");
    181         mHotplugEventPending = false;
    182         mHwc.hotplug(mDisp, true);
    183     }
    184 }
    185 
    186 
    187 void ExternalDevice::HdcpLinkStatusListener(bool success, void *userData)
    188 {
    189     if (userData == NULL) {
    190         return;
    191     }
    192 
    193     ExternalDevice *p = (ExternalDevice*)userData;
    194     p->HdcpLinkStatusListener(success);
    195 }
    196 
    197 void ExternalDevice::HdcpLinkStatusListener(bool success)
    198 {
    199     if (mHotplugEventPending) {
    200         DLOGTRACE("HDCP authentication status %d, sending hotplug event...", success);
    201         mHwc.hotplug(mDisp, mConnected);
    202         mHotplugEventPending = false;
    203     }
    204 }
    205 
    206 void ExternalDevice::hotplugEventListener(void *data)
    207 {
    208     ExternalDevice *pThis = (ExternalDevice*)data;
    209     if (pThis) {
    210         pThis->hotplugListener();
    211     }
    212 }
    213 
    214 void ExternalDevice::hotplugListener()
    215 {
    216     bool ret;
    217 
    218     CTRACE();
    219 
    220     // abort mode settings if it is in the middle
    221     mAbortModeSettingCond.signal();
    222 
    223     // remember the current connection status before detection
    224     bool connected = mConnected;
    225 
    226     // detect display configs
    227     ret = detectDisplayConfigs();
    228     if (ret == false) {
    229         ELOGTRACE("failed to detect display config");
    230         return;
    231     }
    232 
    233     ILOGTRACE("hotpug event: %d", mConnected);
    234 
    235     if (connected == mConnected) {
    236         WLOGTRACE("same connection status detected, hotplug event ignored");
    237         return;
    238     }
    239 
    240     if (mConnected == false) {
    241         mHotplugEventPending = false;
    242         mHdcpControl->stopHdcp();
    243         mHwc.hotplug(mDisp, mConnected);
    244     } else {
    245         DLOGTRACE("start HDCP asynchronously...");
    246         // delay sending hotplug event till HDCP is authenticated.
    247         mHotplugEventPending = true;
    248         ret = mHdcpControl->startHdcpAsync(HdcpLinkStatusListener, this);
    249         if (ret == false) {
    250             ELOGTRACE("failed to start HDCP");
    251             mHotplugEventPending = false;
    252             mHwc.hotplug(mDisp, mConnected);
    253         }
    254     }
    255     mActiveDisplayConfig = 0;
    256 }
    257 
    258 void ExternalDevice::setRefreshRate(int hz)
    259 {
    260     RETURN_VOID_IF_NOT_INIT();
    261 
    262     ILOGTRACE("setting refresh rate to %d", hz);
    263 
    264     if (mBlank) {
    265         WLOGTRACE("external device is blank");
    266         return;
    267     }
    268 
    269     Drm *drm = Hwcomposer::getInstance().getDrm();
    270     drmModeModeInfo mode;
    271     if (!drm->getModeInfo(IDisplayDevice::DEVICE_EXTERNAL, mode))
    272         return;
    273 
    274     if (hz == 0 && (mode.type & DRM_MODE_TYPE_PREFERRED))
    275         return;
    276 
    277     if (hz == (int)mode.vrefresh)
    278         return;
    279 
    280     ILOGTRACE("changing refresh rate from %d to %d", mode.vrefresh, hz);
    281 
    282     mHdcpControl->stopHdcp();
    283 
    284     drm->setRefreshRate(IDisplayDevice::DEVICE_EXTERNAL, hz);
    285 
    286     mHotplugEventPending = false;
    287     mHdcpControl->startHdcpAsync(HdcpLinkStatusListener, this);
    288 }
    289 
    290 
    291 bool ExternalDevice::getDisplaySize(int *width, int *height)
    292 {
    293 #ifndef INTEL_SUPPORT_HDMI_PRIMARY
    294     return PhysicalDevice::getDisplaySize(width, height);
    295 #else
    296     if (mConnected)
    297         return PhysicalDevice::getDisplaySize(width, height);
    298 
    299     if (!width || !height)
    300         return false;
    301 
    302     *width = 1920;
    303     *height = 1080;
    304     return true;
    305 #endif
    306 }
    307 
    308 bool ExternalDevice::getDisplayConfigs(uint32_t *configs, size_t *numConfigs)
    309 {
    310 #ifndef INTEL_SUPPORT_HDMI_PRIMARY
    311     return PhysicalDevice::getDisplayConfigs(configs, numConfigs);
    312 #else
    313     if (mConnected)
    314         return PhysicalDevice::getDisplayConfigs(configs, numConfigs);
    315 
    316     if (!configs || !numConfigs)
    317         return false;
    318 
    319     *configs = 0;
    320     *numConfigs = 1;
    321     return true;
    322 #endif
    323 }
    324 
    325 bool ExternalDevice::getDisplayAttributes(uint32_t config,
    326                                       const uint32_t *attributes,
    327                                       int32_t *values)
    328 {
    329 #ifndef INTEL_SUPPORT_HDMI_PRIMARY
    330     return PhysicalDevice::getDisplayAttributes(config, attributes, values);
    331 #else
    332     if (mConnected)
    333         return PhysicalDevice::getDisplayAttributes(config, attributes, values);
    334     if (!attributes || !values)
    335         return false;
    336     int i = 0;
    337     while (attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE) {
    338         switch (attributes[i]) {
    339         case HWC_DISPLAY_VSYNC_PERIOD:
    340             values[i] = 1e9 / 60;
    341             break;
    342         case HWC_DISPLAY_WIDTH:
    343             values[i] = 1920;
    344             break;
    345         case HWC_DISPLAY_HEIGHT:
    346             values[i] = 1080;
    347             break;
    348         case HWC_DISPLAY_DPI_X:
    349             values[i] = 1;
    350             break;
    351         case HWC_DISPLAY_DPI_Y:
    352             values[i] = 1;
    353             break;
    354         default:
    355             ELOGTRACE("unknown attribute %d", attributes[i]);
    356             break;
    357         }
    358         i++;
    359     }
    360     return true;
    361 #endif
    362 }
    363 
    364 int ExternalDevice::getActiveConfig()
    365 {
    366     if (!mConnected) {
    367         return 0;
    368     }
    369     return mActiveDisplayConfig;
    370 }
    371 
    372 bool ExternalDevice::setActiveConfig(int index)
    373 {
    374     if (!mConnected) {
    375         if (index == 0)
    376             return true;
    377         else
    378             return false;
    379     }
    380 
    381     // for now we will only permit the frequency change.  In the future
    382     // we may need to set mode as well.
    383     if (index >= 0 && index < static_cast<int>(mDisplayConfigs.size())) {
    384         DisplayConfig *config = mDisplayConfigs.itemAt(index);
    385         setRefreshRate(config->getRefreshRate());
    386         mActiveDisplayConfig = index;
    387         return true;
    388     } else {
    389         return false;
    390     }
    391     return true;
    392 }
    393 
    394 
    395 
    396 } // namespace intel
    397 } // namespace android
    398