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