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