Home | History | Annotate | Download | only in base
      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 <fcntl.h>
     17 #include <errno.h>
     18 #include <common/utils/HwcTrace.h>
     19 #include <IDisplayDevice.h>
     20 #include <DrmConfig.h>
     21 #include <common/base/Drm.h>
     22 #include <Hwcomposer.h>
     23 
     24 namespace android {
     25 namespace intel {
     26 
     27 Drm::Drm()
     28     : mDrmFd(0),
     29       mLock(),
     30       mInitialized(false)
     31 {
     32     memset(&mOutputs, 0, sizeof(mOutputs));
     33 }
     34 
     35 Drm::~Drm()
     36 {
     37     WARN_IF_NOT_DEINIT();
     38 }
     39 
     40 bool Drm::initialize()
     41 {
     42     if (mInitialized) {
     43         WLOGTRACE("Drm object has been initialized");
     44         return true;
     45     }
     46 
     47     const char *path = DrmConfig::getDrmPath();
     48     mDrmFd = open(path, O_RDWR, 0);
     49     if (mDrmFd < 0) {
     50         ELOGTRACE("failed to open Drm, error: %s", strerror(errno));
     51         return false;
     52     }
     53     DLOGTRACE("mDrmFd = %d", mDrmFd);
     54 
     55     memset(&mOutputs, 0, sizeof(mOutputs));
     56     mInitialized = true;
     57     return true;
     58 }
     59 
     60 void Drm::deinitialize()
     61 {
     62     for (int i = 0; i < OUTPUT_MAX; i++) {
     63         resetOutput(i);
     64     }
     65 
     66     if (mDrmFd) {
     67         close(mDrmFd);
     68         mDrmFd = 0;
     69     }
     70     mInitialized = false;
     71 }
     72 
     73 bool Drm::detect(int device)
     74 {
     75     RETURN_FALSE_IF_NOT_INIT();
     76 
     77     Mutex::Autolock _l(mLock);
     78     int outputIndex = getOutputIndex(device);
     79     if (outputIndex < 0 ) {
     80         return false;
     81     }
     82 
     83     resetOutput(outputIndex);
     84 
     85     // get drm resources
     86     drmModeResPtr resources = drmModeGetResources(mDrmFd);
     87     if (!resources) {
     88         ELOGTRACE("fail to get drm resources, error: %s", strerror(errno));
     89         return false;
     90     }
     91 
     92     drmModeConnectorPtr connector = NULL;
     93     DrmOutput *output = &mOutputs[outputIndex];
     94     bool ret = false;
     95 
     96     // find connector for the given device
     97     for (int i = 0; i < resources->count_connectors; i++) {
     98         if (!resources->connectors || !resources->connectors[i]) {
     99             ELOGTRACE("fail to get drm resources connectors, error: %s", strerror(errno));
    100             continue;
    101         }
    102 
    103         connector = drmModeGetConnector(mDrmFd, resources->connectors[i]);
    104         if (!connector) {
    105             ELOGTRACE("drmModeGetConnector failed");
    106             continue;
    107         }
    108 
    109         if (connector->connector_type != DrmConfig::getDrmConnector(device)) {
    110             drmModeFreeConnector(connector);
    111             continue;
    112         }
    113 
    114         if (connector->connection != DRM_MODE_CONNECTED) {
    115             ILOGTRACE("device %d is not connected", device);
    116             drmModeFreeConnector(connector);
    117             ret = true;
    118             break;
    119         }
    120 
    121         output->connector = connector;
    122         output->connected = true;
    123 
    124         // get proper encoder for the given connector
    125         if (connector->encoder_id) {
    126             ILOGTRACE("Drm connector has encoder attached on device %d", device);
    127             output->encoder = drmModeGetEncoder(mDrmFd, connector->encoder_id);
    128             if (!output->encoder) {
    129                 ELOGTRACE("failed to get encoder from a known encoder id");
    130                 // fall through to get an encoder
    131             }
    132         }
    133         if (!output->encoder) {
    134             ILOGTRACE("getting encoder for device %d", device);
    135             drmModeEncoderPtr encoder;
    136             for (int j = 0; j < resources->count_encoders; j++) {
    137                 if (!resources->encoders || !resources->encoders[j]) {
    138                     ELOGTRACE("fail to get drm resources encoders, error: %s", strerror(errno));
    139                     continue;
    140                 }
    141 
    142                 encoder = drmModeGetEncoder(mDrmFd, resources->encoders[i]);
    143                 if (!encoder) {
    144                     ELOGTRACE("drmModeGetEncoder failed");
    145                     continue;
    146                 }
    147                 if (encoder->encoder_type == DrmConfig::getDrmEncoder(device)) {
    148                     output->encoder = encoder;
    149                     break;
    150                 }
    151                 drmModeFreeEncoder(encoder);
    152                 encoder = NULL;
    153             }
    154         }
    155         if (!output->encoder) {
    156             ELOGTRACE("failed to get drm encoder");
    157             break;
    158         }
    159 
    160         // get an attached crtc or spare crtc
    161         if (output->encoder->crtc_id) {
    162             ILOGTRACE("Drm encoder has crtc attached on device %d", device);
    163             output->crtc = drmModeGetCrtc(mDrmFd, output->encoder->crtc_id);
    164             if (!output->crtc) {
    165                 ELOGTRACE("failed to get crtc from a known crtc id");
    166                 // fall through to get a spare crtc
    167             }
    168         }
    169         if (!output->crtc) {
    170             ILOGTRACE("getting crtc for device %d", device);
    171             drmModeCrtcPtr crtc;
    172             for (int j = 0; j < resources->count_crtcs; j++) {
    173                 if (!resources->crtcs || !resources->crtcs[j]) {
    174                     ELOGTRACE("fail to get drm resources crtcs, error: %s", strerror(errno));
    175                     continue;
    176                 }
    177 
    178                 crtc = drmModeGetCrtc(mDrmFd, resources->crtcs[j]);
    179                 if (!crtc) {
    180                     ELOGTRACE("drmModeGetCrtc failed");
    181                     continue;
    182                 }
    183                 // check if legal crtc to the encoder
    184                 if (output->encoder->possible_crtcs & (1<<j)) {
    185                     if (crtc->buffer_id == 0) {
    186                         output->crtc = crtc;
    187                         break;
    188                     }
    189                 }
    190                 drmModeFreeCrtc(crtc);
    191             }
    192         }
    193         if (!output->crtc) {
    194             ELOGTRACE("failed to get drm crtc");
    195             break;
    196         }
    197 
    198         // current mode
    199         if (output->crtc->mode_valid) {
    200             ILOGTRACE("mode is valid, kernel mode settings");
    201             memcpy(&output->mode, &output->crtc->mode, sizeof(drmModeModeInfo));
    202             ret = true;
    203         } else {
    204             ELOGTRACE("mode is invalid. Kernel mode setting is not completed");
    205             ret = false;
    206         }
    207 
    208         if (outputIndex == OUTPUT_PRIMARY) {
    209             if (!readIoctl(DRM_PSB_PANEL_ORIENTATION, &output->panelOrientation, sizeof(int))) {
    210                 ELOGTRACE("failed to get device %d orientation", device);
    211                 output->panelOrientation = PANEL_ORIENTATION_0;
    212             }
    213         } else {
    214             output->panelOrientation = PANEL_ORIENTATION_0;
    215         }
    216         break;
    217     }
    218 
    219     if (!ret) {
    220         if (output->connector == NULL && outputIndex != OUTPUT_PRIMARY) {
    221             // a fatal failure on primary device
    222             // non fatal on secondary device
    223             WLOGTRACE("device %d is disabled?", device);
    224             ret = true;
    225         }
    226          resetOutput(outputIndex);
    227     } else if (output->connected) {
    228         ILOGTRACE("mode is: %dx%d@%dHz", output->mode.hdisplay, output->mode.vdisplay, output->mode.vrefresh);
    229     }
    230 
    231     drmModeFreeResources(resources);
    232     return ret;
    233 }
    234 
    235 bool Drm::isSameDrmMode(drmModeModeInfoPtr value,
    236         drmModeModeInfoPtr base) const
    237 {
    238     if (base->hdisplay == value->hdisplay &&
    239         base->vdisplay == value->vdisplay &&
    240         base->vrefresh == value->vrefresh &&
    241         (base->flags & value->flags) == value->flags) {
    242         VLOGTRACE("Drm mode is not changed");
    243         return true;
    244     }
    245 
    246     return false;
    247 }
    248 
    249 bool Drm::setDrmMode(int device, drmModeModeInfo& value)
    250 {
    251     RETURN_FALSE_IF_NOT_INIT();
    252     Mutex::Autolock _l(mLock);
    253 
    254     if (device != IDisplayDevice::DEVICE_EXTERNAL) {
    255         WLOGTRACE("Setting mode on invalid device %d", device);
    256         return false;
    257     }
    258 
    259     int outputIndex = getOutputIndex(device);
    260     if (outputIndex < 0 ) {
    261         ELOGTRACE("invalid device");
    262         return false;
    263     }
    264 
    265     DrmOutput *output= &mOutputs[outputIndex];
    266     if (!output->connected) {
    267         ELOGTRACE("device is not connected");
    268         return false;
    269     }
    270 
    271     if (output->connector->count_modes <= 0) {
    272         ELOGTRACE("invalid count of modes");
    273         return false;
    274     }
    275 
    276     drmModeModeInfoPtr mode;
    277     int index = 0;
    278     for (int i = 0; i < output->connector->count_modes; i++) {
    279         mode = &output->connector->modes[i];
    280         if (mode->type & DRM_MODE_TYPE_PREFERRED) {
    281             index = i;
    282         }
    283         if (isSameDrmMode(&value, mode)) {
    284             index = i;
    285             break;
    286         }
    287     }
    288 
    289     mode = &output->connector->modes[index];
    290     return setDrmMode(outputIndex, mode);
    291 }
    292 
    293 bool Drm::setRefreshRate(int device, int hz)
    294 {
    295     RETURN_FALSE_IF_NOT_INIT();
    296     Mutex::Autolock _l(mLock);
    297 
    298     if (device != IDisplayDevice::DEVICE_EXTERNAL) {
    299         WLOGTRACE("Setting mode on invalid device %d", device);
    300         return false;
    301     }
    302 
    303     int outputIndex = getOutputIndex(device);
    304     if (outputIndex < 0 ) {
    305         ELOGTRACE("invalid device");
    306         return false;
    307     }
    308 
    309     DrmOutput *output= &mOutputs[outputIndex];
    310     if (!output->connected) {
    311         ELOGTRACE("device is not connected");
    312         return false;
    313     }
    314 
    315     if (output->connector->count_modes <= 0) {
    316         ELOGTRACE("invalid count of modes");
    317         return false;
    318     }
    319 
    320     drmModeModeInfoPtr mode;
    321     int index = 0;
    322     for (int i = 0; i < output->connector->count_modes; i++) {
    323         mode = &output->connector->modes[i];
    324         if (mode->type & DRM_MODE_TYPE_PREFERRED) {
    325             index = i;
    326         }
    327         if (mode->hdisplay == output->mode.hdisplay &&
    328             mode->vdisplay == output->mode.vdisplay &&
    329             mode->vrefresh == (uint32_t)hz) {
    330             index = i;
    331             break;
    332         }
    333     }
    334 
    335     mode = &output->connector->modes[index];
    336     return setDrmMode(outputIndex, mode);
    337 }
    338 
    339 bool Drm::writeReadIoctl(unsigned long cmd, void *data,
    340                            unsigned long size)
    341 {
    342     int err;
    343 
    344     if (mDrmFd <= 0) {
    345         ELOGTRACE("drm is not initialized");
    346         return false;
    347     }
    348 
    349     if (!data || !size) {
    350         ELOGTRACE("invalid parameters");
    351         return false;
    352     }
    353 
    354     err = drmCommandWriteRead(mDrmFd, cmd, data, size);
    355     if (err) {
    356         WLOGTRACE("failed to call %ld ioctl with failure %d", cmd, err);
    357         return false;
    358     }
    359 
    360     return true;
    361 }
    362 
    363 bool Drm::writeIoctl(unsigned long cmd, void *data,
    364                        unsigned long size)
    365 {
    366     int err;
    367 
    368     if (mDrmFd <= 0) {
    369         ELOGTRACE("drm is not initialized");
    370         return false;
    371     }
    372 
    373     if (!data || !size) {
    374         ELOGTRACE("invalid parameters");
    375         return false;
    376     }
    377 
    378     err = drmCommandWrite(mDrmFd, cmd, data, size);
    379     if (err) {
    380         WLOGTRACE("failed to call %ld ioctl with failure %d", cmd, err);
    381         return false;
    382     }
    383 
    384     return true;
    385 }
    386 
    387 
    388 bool Drm::readIoctl(unsigned long cmd, void *data,
    389                        unsigned long size)
    390 {
    391     int err;
    392 
    393     if (mDrmFd <= 0) {
    394         ELOGTRACE("drm is not initialized");
    395         return false;
    396     }
    397 
    398     if (!data || !size) {
    399         ELOGTRACE("invalid parameters");
    400         return false;
    401     }
    402 
    403     err = drmCommandRead(mDrmFd, cmd, data, size);
    404     if (err) {
    405         WLOGTRACE("failed to call %ld ioctl with failure %d", cmd, err);
    406         return false;
    407     }
    408 
    409     return true;
    410 }
    411 
    412 
    413 int Drm::getDrmFd() const
    414 {
    415     return mDrmFd;
    416 }
    417 
    418 bool Drm::getModeInfo(int device, drmModeModeInfo& mode)
    419 {
    420     Mutex::Autolock _l(mLock);
    421 
    422     int outputIndex = getOutputIndex(device);
    423     if (outputIndex < 0 ) {
    424         return false;
    425     }
    426 
    427     DrmOutput *output= &mOutputs[outputIndex];
    428     if (output->connected == false) {
    429         ELOGTRACE("device is not connected");
    430         return false;
    431     }
    432 
    433     if (output->mode.hdisplay == 0 || output->mode.vdisplay == 0) {
    434         ELOGTRACE("invalid width or height");
    435         return false;
    436     }
    437 
    438     memcpy(&mode, &output->mode, sizeof(drmModeModeInfo));
    439 
    440 #ifdef INTEL_SUPPORT_HDMI_PRIMARY
    441     // FIXME: use default fb size instead of hdmi mode, because to
    442     // support hdmi primary, we cannot report dynamic mode to SF.
    443     mode.hdisplay = DEFAULT_DRM_FB_WIDTH;
    444     mode.vdisplay = DEFAULT_DRM_FB_HEIGHT;
    445 #endif
    446 
    447     return true;
    448 }
    449 
    450 bool Drm::getPhysicalSize(int device, uint32_t& width, uint32_t& height)
    451 {
    452     Mutex::Autolock _l(mLock);
    453 
    454     int outputIndex = getOutputIndex(device);
    455     if (outputIndex < 0 ) {
    456         return false;
    457     }
    458 
    459     DrmOutput *output= &mOutputs[outputIndex];
    460     if (output->connected == false) {
    461         ELOGTRACE("device is not connected");
    462         return false;
    463     }
    464 
    465     width = output->connector->mmWidth;
    466     height = output->connector->mmHeight;
    467     return true;
    468 }
    469 
    470 bool Drm::getDisplayResolution(int device, uint32_t& width, uint32_t& height)
    471 {
    472     Mutex::Autolock _l(mLock);
    473 
    474     int outputIndex = getOutputIndex(device);
    475     if (outputIndex < 0) {
    476         return false;
    477     }
    478 
    479     DrmOutput *output= &mOutputs[outputIndex];
    480     if (output->connected == false) {
    481         ELOGTRACE("device is not connected");
    482         return false;
    483     }
    484 
    485     width = output->mode.hdisplay;
    486     height = output->mode.vdisplay;
    487 
    488     if (!width || !height) {
    489         ELOGTRACE("invalid width or height");
    490         return false;
    491     }
    492     return true;
    493 }
    494 
    495 bool Drm::isConnected(int device)
    496 {
    497     Mutex::Autolock _l(mLock);
    498 
    499     int output = getOutputIndex(device);
    500     if (output < 0 ) {
    501         return false;
    502     }
    503 
    504     return mOutputs[output].connected;
    505 }
    506 
    507 bool Drm::setDpmsMode(int device, int mode)
    508 {
    509     Mutex::Autolock _l(mLock);
    510 
    511     int output = getOutputIndex(device);
    512     if (output < 0 ) {
    513         return false;
    514     }
    515 
    516     if (mode != IDisplayDevice::DEVICE_DISPLAY_OFF &&
    517             mode != IDisplayDevice::DEVICE_DISPLAY_STANDBY &&
    518             mode != IDisplayDevice::DEVICE_DISPLAY_ON) {
    519         ELOGTRACE("invalid mode %d", mode);
    520         return false;
    521     }
    522 
    523     DrmOutput *out = &mOutputs[output];
    524     if (!out->connected) {
    525         ELOGTRACE("device is not connected");
    526         return false;
    527     }
    528 
    529     drmModePropertyPtr props;
    530     for (int i = 0; i < out->connector->count_props; i++) {
    531         props = drmModeGetProperty(mDrmFd, out->connector->props[i]);
    532         if (!props) {
    533             continue;
    534         }
    535 
    536         if (strcmp(props->name, "DPMS") == 0) {
    537             int ret = drmModeConnectorSetProperty(
    538                 mDrmFd,
    539                 out->connector->connector_id,
    540                 props->prop_id,
    541                 (mode == IDisplayDevice::DEVICE_DISPLAY_ON) ? DRM_MODE_DPMS_ON :
    542                         IDisplayDevice::DEVICE_DISPLAY_STANDBY == mode ?
    543                         DRM_MODE_DPMS_STANDBY : DRM_MODE_DPMS_OFF);
    544             drmModeFreeProperty(props);
    545             if (ret != 0) {
    546                 ELOGTRACE("unable to set DPMS %d", mode);
    547                 return false;
    548             } else {
    549                 return true;
    550             }
    551         }
    552         drmModeFreeProperty(props);
    553     }
    554     return false;
    555 }
    556 
    557 void Drm::resetOutput(int index)
    558 {
    559     DrmOutput *output = &mOutputs[index];
    560 
    561     output->connected = false;
    562     memset(&output->mode, 0, sizeof(drmModeModeInfo));
    563 
    564     if (output->connector) {
    565         drmModeFreeConnector(output->connector);
    566         output->connector = 0;
    567     }
    568     if (output->encoder) {
    569         drmModeFreeEncoder(output->encoder);
    570         output->encoder = 0;
    571     }
    572     if (output->crtc) {
    573         drmModeFreeCrtc(output->crtc);
    574         output->crtc = 0;
    575     }
    576     if (output->fbId) {
    577         drmModeRmFB(mDrmFd, output->fbId);
    578         output->fbId = 0;
    579     }
    580     if (output->fbHandle) {
    581         Hwcomposer::getInstance().getBufferManager()->freeFrameBuffer(output->fbHandle);
    582         output->fbHandle = 0;
    583     }
    584 }
    585 
    586 bool Drm::initDrmMode(int outputIndex)
    587 {
    588     DrmOutput *output= &mOutputs[outputIndex];
    589     if (output->connector->count_modes <= 0) {
    590         ELOGTRACE("invalid count of modes");
    591         return false;
    592     }
    593 
    594     drmModeModeInfoPtr mode;
    595     int index = 0;
    596     for (int i = 0; i < output->connector->count_modes; i++) {
    597         mode = &output->connector->modes[i];
    598         if (mode->type & DRM_MODE_TYPE_PREFERRED) {
    599             index = i;
    600             break;
    601         }
    602     }
    603 
    604     return setDrmMode(outputIndex, &output->connector->modes[index]);
    605 }
    606 
    607 bool Drm::setDrmMode(int index, drmModeModeInfoPtr mode)
    608 {
    609     DrmOutput *output = &mOutputs[index];
    610 
    611     int oldFbId =0;
    612     int oldFbHandle = 0;
    613 
    614     drmModeModeInfo currentMode;
    615     memcpy(&currentMode, &output->mode, sizeof(drmModeModeInfo));
    616 
    617     if (isSameDrmMode(mode, &currentMode))
    618         return true;
    619 
    620 
    621     if (output->fbId) {
    622         oldFbId = output->fbId ;
    623         output->fbId = 0;
    624     }
    625 
    626     if (output->fbHandle) {
    627         oldFbHandle = output->fbHandle;
    628         output->fbHandle = 0;
    629     }
    630 
    631     // allocate frame buffer
    632     int stride = 0;
    633 #ifdef INTEL_SUPPORT_HDMI_PRIMARY
    634     output->fbHandle = Hwcomposer::getInstance().getBufferManager()->allocFrameBuffer(
    635         DEFAULT_DRM_FB_WIDTH, DEFAULT_DRM_FB_HEIGHT, &stride);
    636 #else
    637     output->fbHandle = Hwcomposer::getInstance().getBufferManager()->allocFrameBuffer(
    638         mode->hdisplay, mode->vdisplay, &stride);
    639 #endif
    640     if (output->fbHandle == 0) {
    641         ELOGTRACE("failed to allocate frame buffer");
    642         return false;
    643     }
    644 
    645     int ret = 0;
    646     ret = drmModeAddFB(
    647         mDrmFd,
    648 #ifdef INTEL_SUPPORT_HDMI_PRIMARY
    649         DEFAULT_DRM_FB_WIDTH,
    650         DEFAULT_DRM_FB_HEIGHT,
    651 #else
    652         mode->hdisplay,
    653         mode->vdisplay,
    654 #endif
    655         DrmConfig::getFrameBufferDepth(),
    656         DrmConfig::getFrameBufferBpp(),
    657         stride,
    658         output->fbHandle,
    659         &output->fbId);
    660     if (ret != 0) {
    661         ELOGTRACE("drmModeAddFB failed, error: %d", ret);
    662         return false;
    663     }
    664 
    665     ILOGTRACE("mode set: %dx%d@%dHz", mode->hdisplay, mode->vdisplay, mode->vrefresh);
    666 
    667     ret = drmModeSetCrtc(mDrmFd, output->crtc->crtc_id, output->fbId, 0, 0,
    668                    &output->connector->connector_id, 1, mode);
    669     if (ret == 0) {
    670         //save mode
    671         memcpy(&output->mode, mode, sizeof(drmModeModeInfo));
    672     } else {
    673         ELOGTRACE("drmModeSetCrtc failed. error: %d", ret);
    674     }
    675 
    676     if (oldFbId) {
    677         drmModeRmFB(mDrmFd, oldFbId);
    678     }
    679 
    680     if (oldFbHandle) {
    681         Hwcomposer::getInstance().getBufferManager()->freeFrameBuffer(oldFbHandle);
    682     }
    683 
    684     return ret == 0;
    685 }
    686 
    687 int Drm::getOutputIndex(int device)
    688 {
    689     switch (device) {
    690     case IDisplayDevice::DEVICE_PRIMARY:
    691         return OUTPUT_PRIMARY;
    692     case IDisplayDevice::DEVICE_EXTERNAL:
    693         return OUTPUT_EXTERNAL;
    694     default:
    695         ELOGTRACE("invalid display device");
    696         break;
    697     }
    698 
    699     return -1;
    700 }
    701 
    702 int Drm::getPanelOrientation(int device)
    703 {
    704     int outputIndex = getOutputIndex(device);
    705     if (outputIndex < 0) {
    706         ELOGTRACE("invalid device");
    707         return PANEL_ORIENTATION_0;
    708     }
    709 
    710     DrmOutput *output= &mOutputs[outputIndex];
    711     if (output->connected == false) {
    712         ELOGTRACE("device is not connected");
    713         return PANEL_ORIENTATION_0;
    714     }
    715 
    716     return output->panelOrientation;
    717 }
    718 
    719 // HWC 1.4 requires that we return all of the compatible configs in getDisplayConfigs
    720 // this is needed so getActiveConfig/setActiveConfig work correctly.  It is up to the
    721 // user space to decide what speed to send.
    722 drmModeModeInfoPtr Drm::detectAllConfigs(int device, int *modeCount)
    723 {
    724     RETURN_NULL_IF_NOT_INIT();
    725     Mutex::Autolock _l(mLock);
    726 
    727     if (modeCount != NULL)
    728         *modeCount = 0;
    729     else
    730         return NULL;
    731 
    732     int outputIndex = getOutputIndex(device);
    733     if (outputIndex < 0) {
    734         ELOGTRACE("invalid device");
    735         return NULL;
    736     }
    737 
    738     DrmOutput *output= &mOutputs[outputIndex];
    739     if (!output->connected) {
    740         ELOGTRACE("device is not connected");
    741         return NULL;
    742     }
    743 
    744     if (output->connector->count_modes <= 0) {
    745         ELOGTRACE("invalid count of modes");
    746         return NULL;
    747     }
    748 
    749     *modeCount = output->connector->count_modes;
    750     return output->connector->modes;
    751 }
    752 
    753 } // namespace intel
    754 } // namespace android
    755 
    756