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