Home | History | Annotate | Download | only in libexternal
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved.
      4  *
      5  * Not a Contribution, Apache license notifications and license are
      6  * retained for attribution purposes only.
      7  *
      8  * Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *      http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  */
     20 
     21 #define DEBUG 0
     22 #include <ctype.h>
     23 #include <fcntl.h>
     24 #include <utils/threads.h>
     25 #include <utils/Errors.h>
     26 #include <utils/Log.h>
     27 
     28 #include <linux/msm_mdp.h>
     29 #include <video/msm_hdmi_modes.h>
     30 #include <linux/fb.h>
     31 #include <sys/ioctl.h>
     32 #include <cutils/properties.h>
     33 #include "hwc_utils.h"
     34 #include "external.h"
     35 #include "overlayUtils.h"
     36 #include "overlay.h"
     37 #include "qd_utils.h"
     38 
     39 using namespace android;
     40 
     41 namespace qhwc {
     42 #define MAX_SYSFS_FILE_PATH             255
     43 #define UNKNOWN_STRING                  "unknown"
     44 #define SPD_NAME_LENGTH                 16
     45 /* Max. resolution assignable to when downscale */
     46 #define SUPPORTED_DOWNSCALE_EXT_AREA    (1920*1080)
     47 
     48 
     49 int ExternalDisplay::configure() {
     50     if(!openFrameBuffer()) {
     51         ALOGE("%s: Failed to open FB: %d", __FUNCTION__, mFbNum);
     52         return -1;
     53     }
     54     readCEUnderscanInfo();
     55     readResolution();
     56     // TODO: Move this to activate
     57     /* Used for changing the resolution
     58      * getUserMode will get the preferred
     59      * mode set thru adb shell */
     60     int mode = getUserMode();
     61     if (mode == -1) {
     62         //Get the best mode and set
     63         mode = getBestMode();
     64     }
     65     setResolution(mode);
     66     setAttributes();
     67     // set system property
     68     property_set("hw.hdmiON", "1");
     69     return 0;
     70 }
     71 
     72 void ExternalDisplay::getAttributes(int& width, int& height) {
     73     int fps = 0;
     74     getAttrForMode(width, height, fps);
     75 }
     76 
     77 int ExternalDisplay::teardown() {
     78     closeFrameBuffer();
     79     resetInfo();
     80     // unset system property
     81     property_set("hw.hdmiON", "0");
     82     return 0;
     83 }
     84 
     85 ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1),
     86     mCurrentMode(-1), mModeCount(0),
     87     mUnderscanSupported(false), mHwcContext(ctx)
     88 {
     89     memset(&mVInfo, 0, sizeof(mVInfo));
     90     mFbNum = overlay::Overlay::getInstance()->getFbForDpy(HWC_DISPLAY_EXTERNAL);
     91     // disable HPD at start, it will be enabled later
     92     // when the display powers on
     93     // This helps for framework reboot or adb shell stop/start
     94     writeHPDOption(0);
     95 
     96     // for HDMI - retreive all the modes supported by the driver
     97     if(mFbNum != -1) {
     98         supported_video_mode_lut =
     99                         new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX];
    100         // Populate the mode table for supported modes
    101         MSM_HDMI_MODES_INIT_TIMINGS(supported_video_mode_lut);
    102         MSM_HDMI_MODES_SET_SUPP_TIMINGS(supported_video_mode_lut,
    103                                         MSM_HDMI_MODES_ALL);
    104         // Update the Source Product Information
    105         // Vendor Name
    106         setSPDInfo("vendor_name", "ro.product.manufacturer");
    107         // Product Description
    108         setSPDInfo("product_description", "ro.product.name");
    109     }
    110 }
    111 /* gets the product manufacturer and product name and writes it
    112  * to the sysfs node, so that the driver can get that information
    113  * Used to show QCOM 8974 instead of Input 1 for example
    114  */
    115 void ExternalDisplay::setSPDInfo(const char* node, const char* property) {
    116     ssize_t err = -1;
    117     char info[PROPERTY_VALUE_MAX];
    118     char sysFsSPDFilePath[MAX_SYSFS_FILE_PATH];
    119     memset(sysFsSPDFilePath, 0, sizeof(sysFsSPDFilePath));
    120     snprintf(sysFsSPDFilePath , sizeof(sysFsSPDFilePath),
    121                  "/sys/devices/virtual/graphics/fb%d/%s",
    122                  mFbNum, node);
    123     int spdFile = open(sysFsSPDFilePath, O_RDWR, 0);
    124     if (spdFile < 0) {
    125         ALOGE("%s: file '%s' not found : ret = %d"
    126               "err str: %s",  __FUNCTION__, sysFsSPDFilePath,
    127               spdFile, strerror(errno));
    128     } else {
    129         memset(info, 0, sizeof(info));
    130         property_get(property, info, UNKNOWN_STRING);
    131         ALOGD_IF(DEBUG, "In %s: %s = %s", __FUNCTION__, property, info);
    132         if (strncmp(info, UNKNOWN_STRING, SPD_NAME_LENGTH)) {
    133             err = write(spdFile, info, strlen(info));
    134             if (err <= 0) {
    135                 ALOGE("%s: file write failed for '%s'"
    136                       "err no = %d", __FUNCTION__, sysFsSPDFilePath, errno);
    137             }
    138         } else {
    139             ALOGD_IF(DEBUG, "%s: property_get failed for SPD %s",
    140                          __FUNCTION__, node);
    141         }
    142         close(spdFile);
    143     }
    144 }
    145 
    146 void ExternalDisplay::setHPD(uint32_t startEnd) {
    147     ALOGD_IF(DEBUG,"HPD enabled=%d", startEnd);
    148     writeHPDOption(startEnd);
    149 }
    150 
    151 void ExternalDisplay::setActionSafeDimension(int w, int h) {
    152     ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h);
    153     char actionsafeWidth[PROPERTY_VALUE_MAX];
    154     char actionsafeHeight[PROPERTY_VALUE_MAX];
    155     snprintf(actionsafeWidth, sizeof(actionsafeWidth), "%d", w);
    156     property_set("persist.sys.actionsafe.width", actionsafeWidth);
    157     snprintf(actionsafeHeight, sizeof(actionsafeHeight), "%d", h);
    158     property_set("persist.sys.actionsafe.height", actionsafeHeight);
    159 }
    160 
    161 int ExternalDisplay::getModeCount() const {
    162     ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount);
    163     return mModeCount;
    164 }
    165 
    166 void ExternalDisplay::getEDIDModes(int *out) const {
    167     for(int i = 0;i < mModeCount;i++) {
    168         out[i] = mEDIDModes[i];
    169     }
    170 }
    171 
    172 void ExternalDisplay::readCEUnderscanInfo()
    173 {
    174     int hdmiScanInfoFile = -1;
    175     ssize_t len = -1;
    176     char scanInfo[17];
    177     char *ce_info_str = NULL;
    178     char *save_ptr;
    179     const char token[] = ", \n";
    180     int ce_info = -1;
    181     char sysFsScanInfoFilePath[MAX_SYSFS_FILE_PATH];
    182     snprintf(sysFsScanInfoFilePath, sizeof(sysFsScanInfoFilePath),
    183             "/sys/devices/virtual/graphics/fb%d/"
    184                                    "scan_info", mFbNum);
    185 
    186     memset(scanInfo, 0, sizeof(scanInfo));
    187     hdmiScanInfoFile = open(sysFsScanInfoFilePath, O_RDONLY, 0);
    188     if (hdmiScanInfoFile < 0) {
    189         ALOGD_IF(DEBUG, "%s: scan_info file '%s' not found",
    190                                 __FUNCTION__, sysFsScanInfoFilePath);
    191         return;
    192     } else {
    193         len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1);
    194         ALOGD("%s: Scan Info string: %s length = %zd",
    195                  __FUNCTION__, scanInfo, len);
    196         if (len <= 0) {
    197             close(hdmiScanInfoFile);
    198             ALOGE("%s: Scan Info file empty '%s'",
    199                                 __FUNCTION__, sysFsScanInfoFilePath);
    200             return;
    201         }
    202         scanInfo[len] = '\0';  /* null terminate the string */
    203         close(hdmiScanInfoFile);
    204     }
    205 
    206     /*
    207      * The scan_info contains the three fields
    208      * PT - preferred video format
    209      * IT - video format
    210      * CE video format - containing the underscan support information
    211      */
    212 
    213     /* PT */
    214     ce_info_str = strtok_r(scanInfo, token, &save_ptr);
    215     if (ce_info_str) {
    216         /* IT */
    217         ce_info_str = strtok_r(NULL, token, &save_ptr);
    218         if (ce_info_str) {
    219             /* CE */
    220             ce_info_str = strtok_r(NULL, token, &save_ptr);
    221             if (ce_info_str)
    222                 ce_info = atoi(ce_info_str);
    223         }
    224     }
    225 
    226     if (ce_info_str) {
    227         // ce_info contains the underscan information
    228         if (ce_info == EXT_SCAN_ALWAYS_UNDERSCANED ||
    229             ce_info == EXT_SCAN_BOTH_SUPPORTED)
    230             // if TV supported underscan, then driver will always underscan
    231             // hence no need to apply action safe rectangle
    232             mUnderscanSupported = true;
    233     } else {
    234         ALOGE("%s: scan_info string error", __FUNCTION__);
    235     }
    236 
    237     // Store underscan support info in a system property
    238     const char* prop = (mUnderscanSupported) ? "1" : "0";
    239     property_set("hw.underscan_supported", prop);
    240     return;
    241 }
    242 
    243 ExternalDisplay::~ExternalDisplay()
    244 {
    245     delete [] supported_video_mode_lut;
    246     closeFrameBuffer();
    247 }
    248 
    249 /*
    250  * sets the fb_var_screeninfo from the hdmi_mode_timing_info
    251  */
    252 void setDisplayTiming(struct fb_var_screeninfo &info,
    253                                 const msm_hdmi_mode_timing_info* mode)
    254 {
    255     info.reserved[0] = 0;
    256     info.reserved[1] = 0;
    257     info.reserved[2] = 0;
    258 #ifndef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
    259     info.reserved[3] = (info.reserved[3] & 0xFFFF) |
    260               (mode->video_format << 16);
    261 #endif
    262     info.xoffset = 0;
    263     info.yoffset = 0;
    264     info.xres = mode->active_h;
    265     info.yres = mode->active_v;
    266 
    267     info.pixclock = (mode->pixel_freq)*1000;
    268     info.vmode = mode->interlaced ?
    269                     FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
    270 
    271     info.right_margin = mode->front_porch_h;
    272     info.hsync_len = mode->pulse_width_h;
    273     info.left_margin = mode->back_porch_h;
    274     info.lower_margin = mode->front_porch_v;
    275     info.vsync_len = mode->pulse_width_v;
    276     info.upper_margin = mode->back_porch_v;
    277 }
    278 
    279 int ExternalDisplay::parseResolution(char* edidStr, int* edidModes)
    280 {
    281     char delim = ',';
    282     int count = 0;
    283     char *start, *end;
    284     // EDIDs are string delimited by ','
    285     // Ex: 16,4,5,3,32,34,1
    286     // Parse this string to get mode(int)
    287     start = (char*) edidStr;
    288     end = &delim;
    289     while(*end == delim) {
    290         edidModes[count] = (int) strtol(start, &end, 10);
    291         start = end+1;
    292         count++;
    293     }
    294     ALOGD_IF(DEBUG, "In %s: count = %d", __FUNCTION__, count);
    295     for (int i = 0; i < count; i++)
    296         ALOGD_IF(DEBUG, "Mode[%d] = %d", i, edidModes[i]);
    297     return count;
    298 }
    299 
    300 bool ExternalDisplay::readResolution()
    301 {
    302     char sysFsEDIDFilePath[MAX_SYSFS_FILE_PATH];
    303     snprintf(sysFsEDIDFilePath , sizeof(sysFsEDIDFilePath),
    304             "/sys/devices/virtual/graphics/fb%d/edid_modes", mFbNum);
    305 
    306     int hdmiEDIDFile = open(sysFsEDIDFilePath, O_RDONLY, 0);
    307     ssize_t len = -1;
    308     char edidStr[128] = {'\0'};
    309 
    310     if (hdmiEDIDFile < 0) {
    311         ALOGE("%s: edid_modes file '%s' not found",
    312                  __FUNCTION__, sysFsEDIDFilePath);
    313         return false;
    314     } else {
    315         len = read(hdmiEDIDFile, edidStr, sizeof(edidStr)-1);
    316         ALOGD_IF(DEBUG, "%s: EDID string: %s length = %zd",
    317                  __FUNCTION__, edidStr, len);
    318         if ( len <= 0) {
    319             ALOGE("%s: edid_modes file empty '%s'",
    320                      __FUNCTION__, sysFsEDIDFilePath);
    321             edidStr[0] = '\0';
    322         }
    323         else {
    324             while (len > 1 && isspace(edidStr[len-1])) {
    325                 --len;
    326             }
    327             edidStr[len] = '\0';
    328         }
    329         close(hdmiEDIDFile);
    330     }
    331     if(len > 0) {
    332         // Get EDID modes from the EDID strings
    333         mModeCount = parseResolution(edidStr, mEDIDModes);
    334         ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__,
    335                  mModeCount);
    336     }
    337 
    338     return (len > 0);
    339 }
    340 
    341 bool ExternalDisplay::openFrameBuffer()
    342 {
    343     if (mFd == -1) {
    344         char strDevPath[MAX_SYSFS_FILE_PATH];
    345         snprintf(strDevPath, MAX_SYSFS_FILE_PATH, "/dev/graphics/fb%d", mFbNum);
    346         mFd = open(strDevPath, O_RDWR);
    347         if (mFd < 0)
    348             ALOGE("%s: %s is not available", __FUNCTION__, strDevPath);
    349         mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
    350     }
    351     return (mFd > 0);
    352 }
    353 
    354 bool ExternalDisplay::closeFrameBuffer()
    355 {
    356     int ret = 0;
    357     if(mFd >= 0) {
    358         ret = close(mFd);
    359         mFd = -1;
    360     }
    361     mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
    362     return (ret == 0);
    363 }
    364 
    365 // clears the vinfo, edid, best modes
    366 void ExternalDisplay::resetInfo()
    367 {
    368     memset(&mVInfo, 0, sizeof(mVInfo));
    369     memset(mEDIDModes, 0, sizeof(mEDIDModes));
    370     mModeCount = 0;
    371     mCurrentMode = -1;
    372     mUnderscanSupported = false;
    373     // Reset the underscan supported system property
    374     const char* prop = "0";
    375     property_set("hw.underscan_supported", prop);
    376 }
    377 
    378 int ExternalDisplay::getModeOrder(int mode)
    379 {
    380     // XXX: We dont support interlaced modes but having
    381     // it here for future
    382     switch (mode) {
    383         default:
    384         case HDMI_VFRMT_1440x480i60_4_3:
    385             return 1; // 480i 4:3
    386         case HDMI_VFRMT_1440x480i60_16_9:
    387             return 2; // 480i 16:9
    388         case HDMI_VFRMT_1440x576i50_4_3:
    389             return 3; // i576i 4:3
    390         case HDMI_VFRMT_1440x576i50_16_9:
    391             return 4; // 576i 16:9
    392         case HDMI_VFRMT_1920x1080i60_16_9:
    393             return 5; // 1080i 16:9
    394         case HDMI_VFRMT_640x480p60_4_3:
    395             return 6; // 640x480 4:3
    396         case HDMI_VFRMT_720x480p60_4_3:
    397             return 7; // 480p 4:3
    398         case HDMI_VFRMT_720x480p60_16_9:
    399             return 8; // 480p 16:9
    400         case HDMI_VFRMT_720x576p50_4_3:
    401             return 9; // 576p 4:3
    402         case HDMI_VFRMT_720x576p50_16_9:
    403             return 10; // 576p 16:9
    404         case HDMI_VFRMT_1024x768p60_4_3:
    405             return 11; // 768p 4:3 Vesa format
    406         case HDMI_VFRMT_1280x1024p60_5_4:
    407             return 12; // 1024p Vesa format
    408         case HDMI_VFRMT_1280x720p50_16_9:
    409             return 13; // 720p@50Hz
    410         case HDMI_VFRMT_1280x720p60_16_9:
    411             return 14; // 720p@60Hz
    412         case HDMI_VFRMT_1920x1080p24_16_9:
    413             return 15; //1080p@24Hz
    414         case HDMI_VFRMT_1920x1080p25_16_9:
    415             return 16; //108-p@25Hz
    416         case HDMI_VFRMT_1920x1080p30_16_9:
    417             return 17; //1080p@30Hz
    418         case HDMI_VFRMT_1920x1080p50_16_9:
    419             return 18; //1080p@50Hz
    420         case HDMI_VFRMT_1920x1080p60_16_9:
    421             return 19; //1080p@60Hz
    422         case HDMI_VFRMT_2560x1600p60_16_9:
    423             return 20; //WQXGA@60Hz541
    424         case HDMI_VFRMT_3840x2160p24_16_9:
    425             return 21;//2160@24Hz
    426         case HDMI_VFRMT_3840x2160p25_16_9:
    427             return 22;//2160@25Hz
    428         case HDMI_VFRMT_3840x2160p30_16_9:
    429             return 23; //2160@30Hz
    430         case HDMI_VFRMT_4096x2160p24_16_9:
    431             return 24; //4kx2k@24Hz
    432     }
    433 }
    434 
    435 /// Returns the user mode set(if any) using adb shell
    436 int ExternalDisplay::getUserMode() {
    437     /* Based on the property set the resolution */
    438     char property_value[PROPERTY_VALUE_MAX];
    439     property_get("hw.hdmi.resolution", property_value, "-1");
    440     int mode = atoi(property_value);
    441     // We dont support interlaced modes
    442     if(isValidMode(mode) && !isInterlacedMode(mode)) {
    443         ALOGD_IF(DEBUG, "%s: setting the HDMI mode = %d", __FUNCTION__, mode);
    444         return mode;
    445     }
    446     return -1;
    447 }
    448 
    449 // Get the best mode for the current HD TV
    450 int ExternalDisplay::getBestMode() {
    451     int bestOrder = 0;
    452     int bestMode = HDMI_VFRMT_640x480p60_4_3;
    453     // for all the edid read, get the best mode
    454     for(int i = 0; i < mModeCount; i++) {
    455         int mode = mEDIDModes[i];
    456         int order = getModeOrder(mode);
    457         if (order > bestOrder) {
    458             bestOrder = order;
    459             bestMode = mode;
    460         }
    461     }
    462     return bestMode;
    463 }
    464 
    465 inline bool ExternalDisplay::isValidMode(int ID)
    466 {
    467     bool valid = false;
    468     for (int i = 0; i < mModeCount; i++) {
    469         if(ID == mEDIDModes[i]) {
    470             valid = true;
    471             break;
    472         }
    473     }
    474     return valid;
    475 }
    476 
    477 // returns true if the mode(ID) is interlaced mode format
    478 bool ExternalDisplay::isInterlacedMode(int ID) {
    479     bool interlaced = false;
    480     switch(ID) {
    481         case HDMI_VFRMT_1440x480i60_4_3:
    482         case HDMI_VFRMT_1440x480i60_16_9:
    483         case HDMI_VFRMT_1440x576i50_4_3:
    484         case HDMI_VFRMT_1440x576i50_16_9:
    485         case HDMI_VFRMT_1920x1080i60_16_9:
    486             interlaced = true;
    487             break;
    488         default:
    489             interlaced = false;
    490             break;
    491     }
    492     return interlaced;
    493 }
    494 
    495 void ExternalDisplay::setResolution(int ID)
    496 {
    497     int ret = 0;
    498     ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
    499     if(ret < 0) {
    500         ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__,
    501                                                             strerror(errno));
    502     }
    503     ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d),"
    504             "(%d,%d,%d) %dMHz>", __FUNCTION__,
    505             mVInfo.reserved[3], mVInfo.xres, mVInfo.yres,
    506             mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
    507             mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
    508             mVInfo.pixclock/1000/1000);
    509     //If its a new ID - update var_screeninfo
    510     if ((isValidMode(ID)) && mCurrentMode != ID) {
    511         const struct msm_hdmi_mode_timing_info *mode =
    512             &supported_video_mode_lut[0];
    513         for (unsigned int i = 0; i < HDMI_VFRMT_MAX; ++i) {
    514             const struct msm_hdmi_mode_timing_info *cur =
    515                                         &supported_video_mode_lut[i];
    516             if (cur->video_format == (uint32_t)ID) {
    517                 mode = cur;
    518                 break;
    519             }
    520         }
    521         setDisplayTiming(mVInfo, mode);
    522         ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d"
    523                  "(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, ID,
    524                  mode->video_format, mVInfo.xres, mVInfo.yres,
    525                  mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
    526                  mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
    527                  mVInfo.pixclock/1000/1000);
    528 #ifdef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
    529         struct msmfb_metadata metadata;
    530         memset(&metadata, 0 , sizeof(metadata));
    531         metadata.op = metadata_op_vic;
    532         metadata.data.video_info_code = mode->video_format;
    533         if (ioctl(mFd, MSMFB_METADATA_SET, &metadata) == -1) {
    534             ALOGD("In %s: MSMFB_METADATA_SET failed Err Str = %s",
    535                                                  __FUNCTION__, strerror(errno));
    536         }
    537 #endif
    538         mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
    539         ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo);
    540         if(ret < 0) {
    541             ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s",
    542                                                  __FUNCTION__, strerror(errno));
    543         }
    544         mCurrentMode = ID;
    545     }
    546 }
    547 
    548 bool ExternalDisplay::writeHPDOption(int userOption) const
    549 {
    550     bool ret = true;
    551     if(mFbNum != -1) {
    552         char sysFsHPDFilePath[MAX_SYSFS_FILE_PATH];
    553         snprintf(sysFsHPDFilePath ,sizeof(sysFsHPDFilePath),
    554                  "/sys/devices/virtual/graphics/fb%d/hpd", mFbNum);
    555         int hdmiHPDFile = open(sysFsHPDFilePath,O_RDWR, 0);
    556         if (hdmiHPDFile < 0) {
    557             ALOGE("%s: state file '%s' not found : ret%d err str: %s",
    558                   __FUNCTION__, sysFsHPDFilePath, hdmiHPDFile, strerror(errno));
    559             ret = false;
    560         } else {
    561             ssize_t err = -1;
    562             ALOGD_IF(DEBUG, "%s: option = %d", __FUNCTION__, userOption);
    563             if(userOption)
    564                 err = write(hdmiHPDFile, "1", 2);
    565             else
    566                 err = write(hdmiHPDFile, "0" , 2);
    567             if (err <= 0) {
    568                 ALOGE("%s: file write failed '%s'", __FUNCTION__,
    569                       sysFsHPDFilePath);
    570                 ret = false;
    571             }
    572             close(hdmiHPDFile);
    573         }
    574     }
    575     return ret;
    576 }
    577 
    578 
    579 void ExternalDisplay::setAttributes() {
    580     int width = 0, height = 0, fps = 0;
    581     getAttrForMode(width, height, fps);
    582     ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height);
    583     if(mHwcContext) {
    584         // Always set dpyAttr res to mVInfo res
    585         mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
    586         mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
    587         mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode = false;
    588         if(mHwcContext->mOverlay->isUIScalingOnExternalSupported()
    589                 && mHwcContext->mMDPDownscaleEnabled) {
    590             int priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
    591             int priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
    592             // if primary resolution is more than the hdmi resolution
    593             // configure dpy attr to primary resolution and set
    594             // downscale mode
    595             // Restrict this upto 1080p resolution max
    596             if(((priW * priH) > (width * height)) &&
    597                ((priW * priH) <= SUPPORTED_DOWNSCALE_EXT_AREA)) {
    598                 // tmpW and tmpH will hold the primary dimensions before we
    599                 // update the aspect ratio if necessary.
    600                 int tmpW = priW;
    601                 int tmpH = priH;
    602                 // HDMI is always in landscape, so always assign the higher
    603                 // dimension to hdmi's xres
    604                 if(priH > priW) {
    605                     tmpW = priH;
    606                     tmpH = priW;
    607                 }
    608                 // The aspect ratios of the external and primary displays
    609                 // can be different. As a result, directly assigning primary
    610                 // resolution could lead to an incorrect final image.
    611                 // We get around this by calculating a new resolution by
    612                 // keeping aspect ratio intact.
    613                 hwc_rect r = {0, 0, 0, 0};
    614                 getAspectRatioPosition(tmpW, tmpH, width, height, r);
    615                 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres =
    616                                                               r.right - r.left;
    617                 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres =
    618                                                               r.bottom - r.top;
    619                 // Set External Display MDP Downscale mode indicator
    620                 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode =true;
    621             }
    622         }
    623         //Initialize the display viewFrame info
    624         mHwcContext->mViewFrame[HWC_DISPLAY_EXTERNAL].left = 0;
    625         mHwcContext->mViewFrame[HWC_DISPLAY_EXTERNAL].top = 0;
    626         mHwcContext->mViewFrame[HWC_DISPLAY_EXTERNAL].right =
    627             (int)mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres;
    628         mHwcContext->mViewFrame[HWC_DISPLAY_EXTERNAL].bottom =
    629             (int)mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres;
    630         mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
    631                 (int) 1000000000l / fps;
    632     }
    633 }
    634 
    635 void ExternalDisplay::getAttrForMode(int& width, int& height, int& fps) {
    636     switch (mCurrentMode) {
    637         case HDMI_VFRMT_640x480p60_4_3:
    638             width = 640;
    639             height = 480;
    640             fps = 60;
    641             break;
    642         case HDMI_VFRMT_720x480p60_4_3:
    643         case HDMI_VFRMT_720x480p60_16_9:
    644             width = 720;
    645             height = 480;
    646             fps = 60;
    647             break;
    648         case HDMI_VFRMT_720x576p50_4_3:
    649         case HDMI_VFRMT_720x576p50_16_9:
    650             width = 720;
    651             height = 576;
    652             fps = 50;
    653             break;
    654         case HDMI_VFRMT_1280x720p50_16_9:
    655             width = 1280;
    656             height = 720;
    657             fps = 50;
    658             break;
    659         case HDMI_VFRMT_1280x720p60_16_9:
    660             width = 1280;
    661             height = 720;
    662             fps = 60;
    663             break;
    664         case HDMI_VFRMT_1280x1024p60_5_4:
    665             width = 1280;
    666             height = 1024;
    667             fps = 60;
    668             break;
    669         case HDMI_VFRMT_1024x768p60_4_3:
    670             width = 1024;
    671             height = 768;
    672             fps = 60;
    673             break;
    674         case HDMI_VFRMT_1920x1080p24_16_9:
    675             width = 1920;
    676             height = 1080;
    677             fps = 24;
    678             break;
    679         case HDMI_VFRMT_1920x1080p25_16_9:
    680             width = 1920;
    681             height = 1080;
    682             fps = 25;
    683             break;
    684         case HDMI_VFRMT_1920x1080p30_16_9:
    685             width = 1920;
    686             height = 1080;
    687             fps = 30;
    688             break;
    689         case HDMI_VFRMT_1920x1080p50_16_9:
    690             width = 1920;
    691             height = 1080;
    692             fps = 50;
    693             break;
    694         case HDMI_VFRMT_1920x1080p60_16_9:
    695             width = 1920;
    696             height = 1080;
    697             fps = 60;
    698             break;
    699         case HDMI_VFRMT_2560x1600p60_16_9:
    700             width = 2560;
    701             height = 1600;
    702             fps = 60;
    703             break;
    704         case HDMI_VFRMT_3840x2160p24_16_9:
    705             width = 3840;
    706             height = 2160;
    707             fps = 24;
    708             break;
    709         case HDMI_VFRMT_3840x2160p25_16_9:
    710             width = 3840;
    711             height = 2160;
    712             fps = 25;
    713             break;
    714         case HDMI_VFRMT_3840x2160p30_16_9:
    715             width = 3840;
    716             height = 2160;
    717             fps = 30;
    718             break;
    719         case HDMI_VFRMT_4096x2160p24_16_9:
    720             width = 4096;
    721             height = 2160;
    722             fps = 24;
    723             break;
    724 
    725     }
    726 }
    727 
    728 };
    729