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