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 <media/IAudioPolicyService.h>
     25 #include <media/AudioSystem.h>
     26 #include <utils/threads.h>
     27 #include <utils/Errors.h>
     28 #include <utils/Log.h>
     29 
     30 #include <linux/msm_mdp.h>
     31 #include <video/msm_hdmi_modes.h>
     32 #include <linux/fb.h>
     33 #include <sys/ioctl.h>
     34 #include <sys/poll.h>
     35 #include <sys/resource.h>
     36 #include <cutils/properties.h>
     37 #include "hwc_utils.h"
     38 #include "external.h"
     39 
     40 using namespace android;
     41 
     42 namespace qhwc {
     43 
     44 #define MAX_FRAME_BUFFER_NAME_SIZE      (80)
     45 #define MAX_DISPLAY_DEVICES             (3)
     46 #define MAX_SYSFS_FILE_PATH             255
     47 #define UNKNOWN_STRING                  "unknown"
     48 #define SPD_NAME_LENGTH                 16
     49 
     50 const char* msmFbDevicePath[] = {  "/dev/graphics/fb1",
     51                                    "/dev/graphics/fb2"};
     52 
     53 /*
     54  * Updates extDeviceFbIndex Array with the correct frame buffer indices
     55  * of avaiable external devices
     56  *
     57  */
     58 void ExternalDisplay::updateExtDispDevFbIndex()
     59 {
     60     FILE *displayDeviceFP = NULL;
     61     char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
     62     char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
     63 
     64     for(int j = 1; j < MAX_DISPLAY_DEVICES; j++) {
     65         snprintf (msmFbTypePath, sizeof(msmFbTypePath),
     66                   "/sys/class/graphics/fb%d/msm_fb_type", j);
     67         displayDeviceFP = fopen(msmFbTypePath, "r");
     68         if(displayDeviceFP){
     69             fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
     70                     displayDeviceFP);
     71             if(strncmp(fbType, "dtv panel", strlen("dtv panel")) == 0){
     72                 ALOGD_IF(DEBUG,"hdmi framebuffer index is %d",j);
     73                 mHdmiFbNum = j;
     74             } else if(strncmp(fbType, "writeback panel",
     75                                     strlen("writeback panel")) == 0){
     76                 ALOGD_IF(DEBUG,"wfd framebuffer index is %d",j);
     77                 mWfdFbNum = j;
     78             }
     79             fclose(displayDeviceFP);
     80         }
     81     }
     82     ALOGD_IF(DEBUG,"%s: mHdmiFbNum: %d mWfdFbNum: %d ",__FUNCTION__,
     83                                                        mHdmiFbNum, mWfdFbNum);
     84 }
     85 
     86 int ExternalDisplay::configureHDMIDisplay() {
     87     openFrameBuffer(mHdmiFbNum);
     88     if(mFd == -1)
     89         return -1;
     90     readCEUnderscanInfo();
     91     readResolution();
     92     // TODO: Move this to activate
     93     /* Used for changing the resolution
     94      * getUserMode will get the preferred
     95      * mode set thru adb shell */
     96     int mode = getUserMode();
     97     if (mode == -1) {
     98         //Get the best mode and set
     99         mode = getBestMode();
    100     }
    101     setResolution(mode);
    102     setDpyHdmiAttr();
    103     setExternalDisplay(true, mHdmiFbNum);
    104     return 0;
    105 }
    106 
    107 int ExternalDisplay::configureWFDDisplay() {
    108     int ret = 0;
    109     if(mConnectedFbNum == mHdmiFbNum) {
    110         ALOGE("%s: Cannot process WFD connection while HDMI is active",
    111                      __FUNCTION__);
    112         return -1;
    113     }
    114     openFrameBuffer(mWfdFbNum);
    115     if(mFd == -1)
    116         return -1;
    117     ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
    118     if(ret < 0) {
    119         ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__,
    120                 strerror(errno));
    121     }
    122     setDpyWfdAttr();
    123     setExternalDisplay(true, mWfdFbNum);
    124     return 0;
    125 }
    126 
    127 int ExternalDisplay::teardownHDMIDisplay() {
    128     if(mConnectedFbNum == mHdmiFbNum) {
    129         // hdmi offline event..!
    130         closeFrameBuffer();
    131         resetInfo();
    132         setExternalDisplay(false);
    133     }
    134     return 0;
    135 }
    136 
    137 int ExternalDisplay::teardownWFDDisplay() {
    138     if(mConnectedFbNum == mWfdFbNum) {
    139         // wfd offline event..!
    140         closeFrameBuffer();
    141         memset(&mVInfo, 0, sizeof(mVInfo));
    142         setExternalDisplay(false);
    143     }
    144     return 0;
    145 }
    146 
    147 void ExternalDisplay::processUEventOnline(const char *str) {
    148     const char *s1 = str + strlen("change@/devices/virtual/switch/");
    149     if(!strncmp(s1,"hdmi",strlen(s1))) {
    150         // hdmi online event..!
    151         configureHDMIDisplay();
    152         // set system property
    153         property_set("hw.hdmiON", "1");
    154     }else if(!strncmp(s1,"wfd",strlen(s1))) {
    155         // wfd online event..!
    156         configureWFDDisplay();
    157     }
    158 }
    159 
    160 void ExternalDisplay::processUEventOffline(const char *str) {
    161     const char *s1 = str + strlen("change@/devices/virtual/switch/");
    162     if(!strncmp(s1,"hdmi",strlen(s1))) {
    163         teardownHDMIDisplay();
    164         // unset system property
    165         property_set("hw.hdmiON", "0");
    166     }else if(!strncmp(s1,"wfd",strlen(s1))) {
    167         teardownWFDDisplay();
    168     }
    169 }
    170 
    171 ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1),
    172     mCurrentMode(-1), mConnected(0), mConnectedFbNum(0), mModeCount(0),
    173     mUnderscanSupported(false), mHwcContext(ctx), mHdmiFbNum(-1),
    174     mWfdFbNum(-1), mExtDpyNum(HWC_DISPLAY_EXTERNAL)
    175 {
    176     memset(&mVInfo, 0, sizeof(mVInfo));
    177     //Determine the fb index for external display devices.
    178     updateExtDispDevFbIndex();
    179     // disable HPD at start, it will be enabled later
    180     // when the display powers on
    181     // This helps for framework reboot or adb shell stop/start
    182     writeHPDOption(0);
    183 
    184     // for HDMI - retreive all the modes supported by the driver
    185     if(mHdmiFbNum != -1) {
    186         supported_video_mode_lut =
    187                         new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX];
    188         // Populate the mode table for supported modes
    189         MSM_HDMI_MODES_INIT_TIMINGS(supported_video_mode_lut);
    190         MSM_HDMI_MODES_SET_SUPP_TIMINGS(supported_video_mode_lut,
    191                                         MSM_HDMI_MODES_ALL);
    192         // Update the Source Product Information
    193         // Vendor Name
    194         setSPDInfo("vendor_name", "ro.product.manufacturer");
    195         // Product Description
    196         setSPDInfo("product_description", "ro.product.name");
    197     }
    198 }
    199 /* gets the product manufacturer and product name and writes it
    200  * to the sysfs node, so that the driver can get that information
    201  * Used to show QCOM 8974 instead of Input 1 for example
    202  */
    203 void ExternalDisplay::setSPDInfo(const char* node, const char* property) {
    204     int err = -1;
    205     char info[PROPERTY_VALUE_MAX];
    206     char sysFsSPDFilePath[MAX_SYSFS_FILE_PATH];
    207     memset(sysFsSPDFilePath, 0, sizeof(sysFsSPDFilePath));
    208     snprintf(sysFsSPDFilePath , sizeof(sysFsSPDFilePath),
    209                  "/sys/devices/virtual/graphics/fb%d/%s",
    210                  mHdmiFbNum, node);
    211     int spdFile = open(sysFsSPDFilePath, O_RDWR, 0);
    212     if (spdFile < 0) {
    213         ALOGE("%s: file '%s' not found : ret = %d"
    214               "err str: %s",  __FUNCTION__, sysFsSPDFilePath,
    215               spdFile, strerror(errno));
    216     } else {
    217         memset(info, 0, sizeof(info));
    218         property_get(property, info, UNKNOWN_STRING);
    219         ALOGD_IF(DEBUG, "In %s: %s = %s", __FUNCTION__, property, info);
    220         if (strncmp(info, UNKNOWN_STRING, SPD_NAME_LENGTH)) {
    221             err = write(spdFile, info, strlen(info));
    222             if (err <= 0) {
    223                 ALOGE("%s: file write failed for '%s'"
    224                       "err no = %d", __FUNCTION__, sysFsSPDFilePath, errno);
    225             }
    226         } else {
    227             ALOGD_IF(DEBUG, "%s: property_get failed for SPD %s",
    228                          __FUNCTION__, node);
    229         }
    230         close(spdFile);
    231     }
    232 }
    233 
    234 void ExternalDisplay::setEDIDMode(int resMode) {
    235     ALOGD_IF(DEBUG,"resMode=%d ", resMode);
    236     {
    237         Mutex::Autolock lock(mExtDispLock);
    238         setExternalDisplay(false);
    239         openFrameBuffer(mHdmiFbNum);
    240         setResolution(resMode);
    241     }
    242     setExternalDisplay(true, mHdmiFbNum);
    243 }
    244 
    245 void ExternalDisplay::setHPD(uint32_t startEnd) {
    246     ALOGD_IF(DEBUG,"HPD enabled=%d", startEnd);
    247     writeHPDOption(startEnd);
    248 }
    249 
    250 void ExternalDisplay::setActionSafeDimension(int w, int h) {
    251     ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h);
    252     Mutex::Autolock lock(mExtDispLock);
    253     char actionsafeWidth[PROPERTY_VALUE_MAX];
    254     char actionsafeHeight[PROPERTY_VALUE_MAX];
    255     snprintf(actionsafeWidth, sizeof(actionsafeWidth), "%d", w);
    256     property_set("persist.sys.actionsafe.width", actionsafeWidth);
    257     snprintf(actionsafeHeight, sizeof(actionsafeHeight), "%d", h);
    258     property_set("persist.sys.actionsafe.height", actionsafeHeight);
    259     setExternalDisplay(true, mHdmiFbNum);
    260 }
    261 
    262 int ExternalDisplay::getModeCount() const {
    263     ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount);
    264     Mutex::Autolock lock(mExtDispLock);
    265     return mModeCount;
    266 }
    267 
    268 void ExternalDisplay::getEDIDModes(int *out) const {
    269     Mutex::Autolock lock(mExtDispLock);
    270     for(int i = 0;i < mModeCount;i++) {
    271         out[i] = mEDIDModes[i];
    272     }
    273 }
    274 
    275 void ExternalDisplay::readCEUnderscanInfo()
    276 {
    277     int hdmiScanInfoFile = -1;
    278     int len = -1;
    279     char scanInfo[17];
    280     char *ce_info_str = NULL;
    281     const char token[] = ", \n";
    282     int ce_info = -1;
    283     char sysFsScanInfoFilePath[MAX_SYSFS_FILE_PATH];
    284     snprintf(sysFsScanInfoFilePath, sizeof(sysFsScanInfoFilePath),
    285             "/sys/devices/virtual/graphics/fb%d/"
    286                                    "scan_info", mHdmiFbNum);
    287 
    288     memset(scanInfo, 0, sizeof(scanInfo));
    289     hdmiScanInfoFile = open(sysFsScanInfoFilePath, O_RDONLY, 0);
    290     if (hdmiScanInfoFile < 0) {
    291         ALOGD_IF(DEBUG, "%s: scan_info file '%s' not found",
    292                                 __FUNCTION__, sysFsScanInfoFilePath);
    293         return;
    294     } else {
    295         len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1);
    296         ALOGD("%s: Scan Info string: %s length = %d",
    297                  __FUNCTION__, scanInfo, len);
    298         if (len <= 0) {
    299             close(hdmiScanInfoFile);
    300             ALOGE("%s: Scan Info file empty '%s'",
    301                                 __FUNCTION__, sysFsScanInfoFilePath);
    302             return;
    303         }
    304         scanInfo[len] = '\0';  /* null terminate the string */
    305     }
    306     close(hdmiScanInfoFile);
    307 
    308     /*
    309      * The scan_info contains the three fields
    310      * PT - preferred video format
    311      * IT - video format
    312      * CE video format - containing the underscan support information
    313      */
    314 
    315     /* PT */
    316     ce_info_str = strtok(scanInfo, token);
    317     if (ce_info_str) {
    318         /* IT */
    319         ce_info_str = strtok(NULL, token);
    320         if (ce_info_str) {
    321             /* CE */
    322             ce_info_str = strtok(NULL, token);
    323             if (ce_info_str)
    324                 ce_info = atoi(ce_info_str);
    325         }
    326     }
    327 
    328     if (ce_info_str) {
    329         // ce_info contains the underscan information
    330         if (ce_info == EXT_SCAN_ALWAYS_UNDERSCANED ||
    331             ce_info == EXT_SCAN_BOTH_SUPPORTED)
    332             // if TV supported underscan, then driver will always underscan
    333             // hence no need to apply action safe rectangle
    334             mUnderscanSupported = true;
    335     } else {
    336         ALOGE("%s: scan_info string error", __FUNCTION__);
    337     }
    338 
    339     // Store underscan support info in a system property
    340     const char* prop = (mUnderscanSupported) ? "1" : "0";
    341     property_set("hw.underscan_supported", prop);
    342     return;
    343 }
    344 
    345 ExternalDisplay::~ExternalDisplay()
    346 {
    347     delete [] supported_video_mode_lut;
    348     closeFrameBuffer();
    349 }
    350 
    351 /*
    352  * sets the fb_var_screeninfo from the hdmi_mode_timing_info
    353  */
    354 void setDisplayTiming(struct fb_var_screeninfo &info,
    355                                 const msm_hdmi_mode_timing_info* mode)
    356 {
    357     info.reserved[0] = 0;
    358     info.reserved[1] = 0;
    359     info.reserved[2] = 0;
    360 #ifndef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
    361     info.reserved[3] = (info.reserved[3] & 0xFFFF) |
    362               (mode->video_format << 16);
    363 #endif
    364     info.xoffset = 0;
    365     info.yoffset = 0;
    366     info.xres = mode->active_h;
    367     info.yres = mode->active_v;
    368 
    369     info.pixclock = (mode->pixel_freq)*1000;
    370     info.vmode = mode->interlaced ?
    371                     FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
    372 
    373     info.right_margin = mode->front_porch_h;
    374     info.hsync_len = mode->pulse_width_h;
    375     info.left_margin = mode->back_porch_h;
    376     info.lower_margin = mode->front_porch_v;
    377     info.vsync_len = mode->pulse_width_v;
    378     info.upper_margin = mode->back_porch_v;
    379 }
    380 
    381 int ExternalDisplay::parseResolution(char* edidStr, int* edidModes)
    382 {
    383     char delim = ',';
    384     int count = 0;
    385     char *start, *end;
    386     // EDIDs are string delimited by ','
    387     // Ex: 16,4,5,3,32,34,1
    388     // Parse this string to get mode(int)
    389     start = (char*) edidStr;
    390     end = &delim;
    391     while(*end == delim) {
    392         edidModes[count] = (int) strtol(start, &end, 10);
    393         start = end+1;
    394         count++;
    395     }
    396     ALOGD_IF(DEBUG, "In %s: count = %d", __FUNCTION__, count);
    397     for (int i = 0; i < count; i++)
    398         ALOGD_IF(DEBUG, "Mode[%d] = %d", i, edidModes[i]);
    399     return count;
    400 }
    401 
    402 bool ExternalDisplay::readResolution()
    403 {
    404     char sysFsEDIDFilePath[MAX_SYSFS_FILE_PATH];
    405     snprintf(sysFsEDIDFilePath , sizeof(sysFsEDIDFilePath),
    406             "/sys/devices/virtual/graphics/fb%d/edid_modes", mHdmiFbNum);
    407 
    408     int hdmiEDIDFile = open(sysFsEDIDFilePath, O_RDONLY, 0);
    409     int len = -1;
    410 
    411     if (hdmiEDIDFile < 0) {
    412         ALOGE("%s: edid_modes file '%s' not found",
    413                  __FUNCTION__, sysFsEDIDFilePath);
    414         return false;
    415     } else {
    416         len = read(hdmiEDIDFile, mEDIDs, sizeof(mEDIDs)-1);
    417         ALOGD_IF(DEBUG, "%s: EDID string: %s length = %d",
    418                  __FUNCTION__, mEDIDs, len);
    419         if ( len <= 0) {
    420             ALOGE("%s: edid_modes file empty '%s'",
    421                      __FUNCTION__, sysFsEDIDFilePath);
    422         }
    423         else {
    424             while (len > 1 && isspace(mEDIDs[len-1]))
    425                 --len;
    426             mEDIDs[len] = 0;
    427         }
    428     }
    429     close(hdmiEDIDFile);
    430     if(len > 0) {
    431         // Get EDID modes from the EDID strings
    432         mModeCount = parseResolution(mEDIDs, mEDIDModes);
    433         ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__,
    434                  mModeCount);
    435     }
    436 
    437     return (strlen(mEDIDs) > 0);
    438 }
    439 
    440 bool ExternalDisplay::openFrameBuffer(int fbNum)
    441 {
    442     if (mFd == -1) {
    443         mFd = open(msmFbDevicePath[fbNum-1], O_RDWR);
    444         if (mFd < 0)
    445             ALOGE("%s: %s is not available", __FUNCTION__,
    446                                             msmFbDevicePath[fbNum-1]);
    447         if(mHwcContext) {
    448             mHwcContext->dpyAttr[mExtDpyNum].fd = mFd;
    449         }
    450     }
    451     return (mFd > 0);
    452 }
    453 
    454 bool ExternalDisplay::closeFrameBuffer()
    455 {
    456     int ret = 0;
    457     if(mFd >= 0) {
    458         ret = close(mFd);
    459         mFd = -1;
    460     }
    461     if(mHwcContext) {
    462         mHwcContext->dpyAttr[mExtDpyNum].fd = mFd;
    463     }
    464     return (ret == 0);
    465 }
    466 
    467 // clears the vinfo, edid, best modes
    468 void ExternalDisplay::resetInfo()
    469 {
    470     memset(&mVInfo, 0, sizeof(mVInfo));
    471     memset(mEDIDs, 0, sizeof(mEDIDs));
    472     memset(mEDIDModes, 0, sizeof(mEDIDModes));
    473     mModeCount = 0;
    474     mCurrentMode = -1;
    475     mUnderscanSupported = false;
    476     // Reset the underscan supported system property
    477     const char* prop = "0";
    478     property_set("hw.underscan_supported", prop);
    479 }
    480 
    481 int ExternalDisplay::getModeOrder(int mode)
    482 {
    483     // XXX: We dont support interlaced modes but having
    484     // it here for future
    485     switch (mode) {
    486         default:
    487         case HDMI_VFRMT_1440x480i60_4_3:
    488             return 1; // 480i 4:3
    489         case HDMI_VFRMT_1440x480i60_16_9:
    490             return 2; // 480i 16:9
    491         case HDMI_VFRMT_1440x576i50_4_3:
    492             return 3; // i576i 4:3
    493         case HDMI_VFRMT_1440x576i50_16_9:
    494             return 4; // 576i 16:9
    495         case HDMI_VFRMT_1920x1080i60_16_9:
    496             return 5; // 1080i 16:9
    497         case HDMI_VFRMT_640x480p60_4_3:
    498             return 6; // 640x480 4:3
    499         case HDMI_VFRMT_720x480p60_4_3:
    500             return 7; // 480p 4:3
    501         case HDMI_VFRMT_720x480p60_16_9:
    502             return 8; // 480p 16:9
    503         case HDMI_VFRMT_720x576p50_4_3:
    504             return 9; // 576p 4:3
    505         case HDMI_VFRMT_720x576p50_16_9:
    506             return 10; // 576p 16:9
    507         case HDMI_VFRMT_1024x768p60_4_3:
    508             return 11; // 768p 4:3 Vesa format
    509         case HDMI_VFRMT_1280x1024p60_5_4:
    510             return 12; // 1024p Vesa format
    511         case HDMI_VFRMT_1280x720p50_16_9:
    512             return 13; // 720p@50Hz
    513         case HDMI_VFRMT_1280x720p60_16_9:
    514             return 14; // 720p@60Hz
    515         case HDMI_VFRMT_1920x1080p24_16_9:
    516             return 15; //1080p@24Hz
    517         case HDMI_VFRMT_1920x1080p25_16_9:
    518             return 16; //108-p@25Hz
    519         case HDMI_VFRMT_1920x1080p30_16_9:
    520             return 17; //1080p@30Hz
    521         case HDMI_VFRMT_1920x1080p50_16_9:
    522             return 18; //1080p@50Hz
    523         case HDMI_VFRMT_1920x1080p60_16_9:
    524             return 19; //1080p@60Hz
    525         case HDMI_VFRMT_2560x1600p60_16_9:
    526             return 20; //WQXGA@60Hz541
    527         case HDMI_VFRMT_3840x2160p24_16_9:
    528             return 21;//2160@24Hz
    529         case HDMI_VFRMT_3840x2160p25_16_9:
    530             return 22;//2160@25Hz
    531         case HDMI_VFRMT_3840x2160p30_16_9:
    532             return 23; //2160@30Hz
    533         case HDMI_VFRMT_4096x2160p24_16_9:
    534             return 24; //4kx2k@24Hz
    535     }
    536 }
    537 
    538 /// Returns the user mode set(if any) using adb shell
    539 int ExternalDisplay::getUserMode() {
    540     /* Based on the property set the resolution */
    541     char property_value[PROPERTY_VALUE_MAX];
    542     property_get("hw.hdmi.resolution", property_value, "-1");
    543     int mode = atoi(property_value);
    544     // We dont support interlaced modes
    545     if(isValidMode(mode) && !isInterlacedMode(mode)) {
    546         ALOGD_IF(DEBUG, "%s: setting the HDMI mode = %d", __FUNCTION__, mode);
    547         return mode;
    548     }
    549     return -1;
    550 }
    551 
    552 // Get the best mode for the current HD TV
    553 int ExternalDisplay::getBestMode() {
    554     int bestOrder = 0;
    555     int bestMode = HDMI_VFRMT_640x480p60_4_3;
    556     Mutex::Autolock lock(mExtDispLock);
    557     // for all the edid read, get the best mode
    558     for(int i = 0; i < mModeCount; i++) {
    559         int mode = mEDIDModes[i];
    560         int order = getModeOrder(mode);
    561         if (order > bestOrder) {
    562             bestOrder = order;
    563             bestMode = mode;
    564         }
    565     }
    566     return bestMode;
    567 }
    568 
    569 inline bool ExternalDisplay::isValidMode(int ID)
    570 {
    571     bool valid = false;
    572     for (int i = 0; i < mModeCount; i++) {
    573         if(ID == mEDIDModes[i]) {
    574             valid = true;
    575             break;
    576         }
    577     }
    578     return valid;
    579 }
    580 
    581 // returns true if the mode(ID) is interlaced mode format
    582 bool ExternalDisplay::isInterlacedMode(int ID) {
    583     bool interlaced = false;
    584     switch(ID) {
    585         case HDMI_VFRMT_1440x480i60_4_3:
    586         case HDMI_VFRMT_1440x480i60_16_9:
    587         case HDMI_VFRMT_1440x576i50_4_3:
    588         case HDMI_VFRMT_1440x576i50_16_9:
    589         case HDMI_VFRMT_1920x1080i60_16_9:
    590             interlaced = true;
    591             break;
    592         default:
    593             interlaced = false;
    594             break;
    595     }
    596     return interlaced;
    597 }
    598 
    599 void ExternalDisplay::setResolution(int ID)
    600 {
    601     struct fb_var_screeninfo info;
    602     int ret = 0;
    603     ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
    604     if(ret < 0) {
    605         ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__,
    606                                                             strerror(errno));
    607     }
    608     ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d),"
    609             "(%d,%d,%d) %dMHz>", __FUNCTION__,
    610             mVInfo.reserved[3], mVInfo.xres, mVInfo.yres,
    611             mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
    612             mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
    613             mVInfo.pixclock/1000/1000);
    614     //If its a new ID - update var_screeninfo
    615     if ((isValidMode(ID)) && mCurrentMode != ID) {
    616         const struct msm_hdmi_mode_timing_info *mode =
    617             &supported_video_mode_lut[0];
    618         for (unsigned int i = 0; i < HDMI_VFRMT_MAX; ++i) {
    619             const struct msm_hdmi_mode_timing_info *cur =
    620                                         &supported_video_mode_lut[i];
    621             if (cur->video_format == (uint32_t)ID) {
    622                 mode = cur;
    623                 break;
    624             }
    625         }
    626         setDisplayTiming(mVInfo, mode);
    627         ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d"
    628                  "(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, ID,
    629                  mode->video_format, mVInfo.xres, mVInfo.yres,
    630                  mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
    631                  mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
    632                  mVInfo.pixclock/1000/1000);
    633 #ifdef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
    634         struct msmfb_metadata metadata;
    635         memset(&metadata, 0 , sizeof(metadata));
    636         metadata.op = metadata_op_vic;
    637         metadata.data.video_info_code = mode->video_format;
    638         if (ioctl(mFd, MSMFB_METADATA_SET, &metadata) == -1) {
    639             ALOGD("In %s: MSMFB_METADATA_SET failed Err Str = %s",
    640                                                  __FUNCTION__, strerror(errno));
    641         }
    642 #endif
    643         mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
    644         ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo);
    645         if(ret < 0) {
    646             ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s",
    647                                                  __FUNCTION__, strerror(errno));
    648         }
    649         mCurrentMode = ID;
    650     }
    651 }
    652 
    653 void ExternalDisplay::setExternalDisplay(bool connected, int extFbNum)
    654 {
    655     hwc_context_t* ctx = mHwcContext;
    656     if(ctx) {
    657         ALOGD_IF(DEBUG, "%s: connected = %d", __FUNCTION__, connected);
    658         // Store the external display
    659         mConnected = connected;
    660         mConnectedFbNum = extFbNum;
    661         mHwcContext->dpyAttr[mExtDpyNum].connected = connected;
    662     }
    663 }
    664 
    665 int ExternalDisplay::getExtFbNum(int &fbNum) {
    666     int ret = -1;
    667     if(mConnected) {
    668         fbNum = mConnectedFbNum;
    669         ret = 0;
    670     }
    671     return ret;
    672 }
    673 
    674 bool ExternalDisplay::writeHPDOption(int userOption) const
    675 {
    676     bool ret = true;
    677     if(mHdmiFbNum != -1) {
    678         char sysFsHPDFilePath[255];
    679         snprintf(sysFsHPDFilePath ,sizeof(sysFsHPDFilePath),
    680                  "/sys/devices/virtual/graphics/fb%d/hpd", mHdmiFbNum);
    681         int hdmiHPDFile = open(sysFsHPDFilePath,O_RDWR, 0);
    682         if (hdmiHPDFile < 0) {
    683             ALOGE("%s: state file '%s' not found : ret%d err str: %s", __FUNCTION__,
    684                   sysFsHPDFilePath, hdmiHPDFile, strerror(errno));
    685             ret = false;
    686         } else {
    687             int err = -1;
    688             ALOGD_IF(DEBUG, "%s: option = %d", __FUNCTION__, userOption);
    689             if(userOption)
    690                 err = write(hdmiHPDFile, "1", 2);
    691             else
    692                 err = write(hdmiHPDFile, "0" , 2);
    693             if (err <= 0) {
    694                 ALOGE("%s: file write failed '%s'", __FUNCTION__, sysFsHPDFilePath);
    695                 ret = false;
    696             }
    697             close(hdmiHPDFile);
    698         }
    699     }
    700     return ret;
    701 }
    702 
    703 void ExternalDisplay::setDpyWfdAttr() {
    704     if(mHwcContext) {
    705         mHwcContext->dpyAttr[mExtDpyNum].xres = mVInfo.xres;
    706         mHwcContext->dpyAttr[mExtDpyNum].yres = mVInfo.yres;
    707         mHwcContext->dpyAttr[mExtDpyNum].vsync_period =
    708                 1000000000l /60;
    709         ALOGD_IF(DEBUG,"%s: wfd...connected..!",__FUNCTION__);
    710     }
    711 }
    712 
    713 void ExternalDisplay::setDpyHdmiAttr() {
    714     int width = 0, height = 0, fps = 0;
    715     getAttrForMode(width, height, fps);
    716     if(mHwcContext) {
    717         ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height);
    718         mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
    719         mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
    720         mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
    721             1000000000l / fps;
    722     }
    723 }
    724 
    725 void ExternalDisplay::getAttrForMode(int& width, int& height, int& fps) {
    726     switch (mCurrentMode) {
    727         case HDMI_VFRMT_640x480p60_4_3:
    728             width = 640;
    729             height = 480;
    730             fps = 60;
    731             break;
    732         case HDMI_VFRMT_720x480p60_4_3:
    733         case HDMI_VFRMT_720x480p60_16_9:
    734             width = 720;
    735             height = 480;
    736             fps = 60;
    737             break;
    738         case HDMI_VFRMT_720x576p50_4_3:
    739         case HDMI_VFRMT_720x576p50_16_9:
    740             width = 720;
    741             height = 576;
    742             fps = 50;
    743             break;
    744         case HDMI_VFRMT_1280x720p50_16_9:
    745             width = 1280;
    746             height = 720;
    747             fps = 50;
    748             break;
    749         case HDMI_VFRMT_1280x720p60_16_9:
    750             width = 1280;
    751             height = 720;
    752             fps = 60;
    753             break;
    754         case HDMI_VFRMT_1280x1024p60_5_4:
    755             width = 1280;
    756             height = 1024;
    757             fps = 60;
    758             break;
    759         case HDMI_VFRMT_1024x768p60_4_3:
    760             width = 1024;
    761             height = 768;
    762             fps = 60;
    763             break;
    764         case HDMI_VFRMT_1920x1080p24_16_9:
    765             width = 1920;
    766             height = 1080;
    767             fps = 24;
    768             break;
    769         case HDMI_VFRMT_1920x1080p25_16_9:
    770             width = 1920;
    771             height = 1080;
    772             fps = 25;
    773             break;
    774         case HDMI_VFRMT_1920x1080p30_16_9:
    775             width = 1920;
    776             height = 1080;
    777             fps = 30;
    778             break;
    779         case HDMI_VFRMT_1920x1080p50_16_9:
    780             width = 1920;
    781             height = 1080;
    782             fps = 50;
    783             break;
    784         case HDMI_VFRMT_1920x1080p60_16_9:
    785             width = 1920;
    786             height = 1080;
    787             fps = 60;
    788             break;
    789         case HDMI_VFRMT_2560x1600p60_16_9:
    790             width = 2560;
    791             height = 1600;
    792             fps = 60;
    793             break;
    794         case HDMI_VFRMT_3840x2160p24_16_9:
    795             width = 3840;
    796             height = 2160;
    797             fps = 24;
    798             break;
    799         case HDMI_VFRMT_3840x2160p25_16_9:
    800             width = 3840;
    801             height = 2160;
    802             fps = 25;
    803             break;
    804         case HDMI_VFRMT_3840x2160p30_16_9:
    805             width = 3840;
    806             height = 2160;
    807             fps = 30;
    808             break;
    809         case HDMI_VFRMT_4096x2160p24_16_9:
    810             width = 4096;
    811             height = 2160;
    812             fps = 24;
    813             break;
    814 
    815     }
    816 }
    817 
    818 };
    819