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  */
updateExtDispDevFbIndex()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 
configureHDMIDisplay()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 
configureWFDDisplay()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 
teardownHDMIDisplay()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 
teardownWFDDisplay()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 
processUEventOnline(const char * str)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 
processUEventOffline(const char * str)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 
ExternalDisplay(hwc_context_t * ctx)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  */
setSPDInfo(const char * node,const char * property)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 
setEDIDMode(int resMode)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 
setHPD(uint32_t startEnd)245 void ExternalDisplay::setHPD(uint32_t startEnd) {
246     ALOGD_IF(DEBUG,"HPD enabled=%d", startEnd);
247     writeHPDOption(startEnd);
248 }
249 
setActionSafeDimension(int w,int h)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 
getModeCount() const262 int ExternalDisplay::getModeCount() const {
263     ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount);
264     Mutex::Autolock lock(mExtDispLock);
265     return mModeCount;
266 }
267 
getEDIDModes(int * out) const268 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 
readCEUnderscanInfo()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 
~ExternalDisplay()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  */
setDisplayTiming(struct fb_var_screeninfo & info,const msm_hdmi_mode_timing_info * mode)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 
parseResolution(char * edidStr,int * edidModes)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 
readResolution()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 
openFrameBuffer(int fbNum)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 
closeFrameBuffer()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
resetInfo()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 
getModeOrder(int mode)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
getUserMode()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
getBestMode()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 
isValidMode(int ID)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
isInterlacedMode(int ID)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 
setResolution(int ID)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 
setExternalDisplay(bool connected,int extFbNum)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 
getExtFbNum(int & fbNum)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 
writeHPDOption(int userOption) const674 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 
setDpyWfdAttr()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 
setDpyHdmiAttr()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 
getAttrForMode(int & width,int & height,int & fps)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