external.cpp revision a249ee3c3e3a7ac7d687d188fcce157ad1706c25
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 return 0; 107} 108 109int ExternalDisplay::configureWFDDisplay() { 110 int ret = 0; 111 if(mConnectedFbNum == mHdmiFbNum) { 112 ALOGE("%s: Cannot process WFD connection while HDMI is active", 113 __FUNCTION__); 114 return -1; 115 } 116 openFrameBuffer(mWfdFbNum); 117 if(mFd == -1) 118 return -1; 119 ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo); 120 if(ret < 0) { 121 ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__, 122 strerror(errno)); 123 } 124 setDpyWfdAttr(); 125 setExternalDisplay(true, mWfdFbNum); 126 return 0; 127} 128 129int ExternalDisplay::teardownHDMIDisplay() { 130 if(mConnectedFbNum == mHdmiFbNum) { 131 // hdmi offline event..! 132 closeFrameBuffer(); 133 resetInfo(); 134 setExternalDisplay(false); 135 } 136 return 0; 137} 138 139int ExternalDisplay::teardownWFDDisplay() { 140 if(mConnectedFbNum == mWfdFbNum) { 141 // wfd offline event..! 142 closeFrameBuffer(); 143 memset(&mVInfo, 0, sizeof(mVInfo)); 144 setExternalDisplay(false); 145 } 146 return 0; 147} 148 149void ExternalDisplay::processUEventOnline(const char *str) { 150 const char *s1 = str + strlen("change@/devices/virtual/switch/"); 151 if(!strncmp(s1,"hdmi",strlen(s1))) { 152 // hdmi online event..! 153 configureHDMIDisplay(); 154 // set system property 155 property_set("hw.hdmiON", "1"); 156 }else if(!strncmp(s1,"wfd",strlen(s1))) { 157 // wfd online event..! 158 configureWFDDisplay(); 159 } 160} 161 162void ExternalDisplay::processUEventOffline(const char *str) { 163 const char *s1 = str + strlen("change@/devices/virtual/switch/"); 164 if(!strncmp(s1,"hdmi",strlen(s1))) { 165 teardownHDMIDisplay(); 166 // unset system property 167 property_set("hw.hdmiON", "0"); 168 }else if(!strncmp(s1,"wfd",strlen(s1))) { 169 teardownWFDDisplay(); 170 } 171} 172 173ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1), 174 mCurrentMode(-1), mConnected(0), mConnectedFbNum(0), mModeCount(0), 175 mUnderscanSupported(false), mHwcContext(ctx), mHdmiFbNum(-1), 176 mWfdFbNum(-1), mExtDpyNum(HWC_DISPLAY_EXTERNAL) 177{ 178 memset(&mVInfo, 0, sizeof(mVInfo)); 179 //Determine the fb index for external display devices. 180 updateExtDispDevFbIndex(); 181 // disable HPD at start, it will be enabled later 182 // when the display powers on 183 // This helps for framework reboot or adb shell stop/start 184 writeHPDOption(0); 185 186 // for HDMI - retreive all the modes supported by the driver 187 if(mHdmiFbNum != -1) { 188 supported_video_mode_lut = 189 new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX]; 190 // Populate the mode table for supported modes 191 MSM_HDMI_MODES_INIT_TIMINGS(supported_video_mode_lut); 192 MSM_HDMI_MODES_SET_SUPP_TIMINGS(supported_video_mode_lut, 193 MSM_HDMI_MODES_ALL); 194 // Update the Source Product Information 195 // Vendor Name 196 setSPDInfo("vendor_name", "ro.product.manufacturer"); 197 // Product Description 198 setSPDInfo("product_description", "ro.product.name"); 199 } 200} 201/* gets the product manufacturer and product name and writes it 202 * to the sysfs node, so that the driver can get that information 203 * Used to show QCOM 8974 instead of Input 1 for example 204 */ 205void ExternalDisplay::setSPDInfo(const char* node, const char* property) { 206 int err = -1; 207 char info[PROPERTY_VALUE_MAX]; 208 char sysFsSPDFilePath[MAX_SYSFS_FILE_PATH]; 209 memset(sysFsSPDFilePath, 0, sizeof(sysFsSPDFilePath)); 210 snprintf(sysFsSPDFilePath , sizeof(sysFsSPDFilePath), 211 "/sys/devices/virtual/graphics/fb%d/%s", 212 mHdmiFbNum, node); 213 int spdFile = open(sysFsSPDFilePath, O_RDWR, 0); 214 if (spdFile < 0) { 215 ALOGE("%s: file '%s' not found : ret = %d" 216 "err str: %s", __FUNCTION__, sysFsSPDFilePath, 217 spdFile, strerror(errno)); 218 } else { 219 memset(info, 0, sizeof(info)); 220 property_get(property, info, UNKNOWN_STRING); 221 ALOGD_IF(DEBUG, "In %s: %s = %s", __FUNCTION__, property, info); 222 if (strncmp(info, UNKNOWN_STRING, SPD_NAME_LENGTH)) { 223 err = write(spdFile, info, strlen(info)); 224 if (err <= 0) { 225 ALOGE("%s: file write failed for '%s'" 226 "err no = %d", __FUNCTION__, sysFsSPDFilePath, errno); 227 } 228 } else { 229 ALOGD_IF(DEBUG, "%s: property_get failed for SPD %s", 230 __FUNCTION__, node); 231 } 232 close(spdFile); 233 } 234} 235 236void ExternalDisplay::setEDIDMode(int resMode) { 237 ALOGD_IF(DEBUG,"resMode=%d ", resMode); 238 { 239 Mutex::Autolock lock(mExtDispLock); 240 setExternalDisplay(false); 241 openFrameBuffer(mHdmiFbNum); 242 setResolution(resMode); 243 } 244 setExternalDisplay(true, mHdmiFbNum); 245} 246 247void ExternalDisplay::setHPD(uint32_t startEnd) { 248 ALOGD_IF(DEBUG,"HPD enabled=%d", startEnd); 249 writeHPDOption(startEnd); 250} 251 252void ExternalDisplay::setActionSafeDimension(int w, int h) { 253 ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h); 254 Mutex::Autolock lock(mExtDispLock); 255 char actionsafeWidth[PROPERTY_VALUE_MAX]; 256 char actionsafeHeight[PROPERTY_VALUE_MAX]; 257 snprintf(actionsafeWidth, sizeof(actionsafeWidth), "%d", w); 258 property_set("persist.sys.actionsafe.width", actionsafeWidth); 259 snprintf(actionsafeHeight, sizeof(actionsafeHeight), "%d", h); 260 property_set("persist.sys.actionsafe.height", actionsafeHeight); 261 setExternalDisplay(true, mHdmiFbNum); 262} 263 264int ExternalDisplay::getModeCount() const { 265 ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount); 266 Mutex::Autolock lock(mExtDispLock); 267 return mModeCount; 268} 269 270void ExternalDisplay::getEDIDModes(int *out) const { 271 Mutex::Autolock lock(mExtDispLock); 272 for(int i = 0;i < mModeCount;i++) { 273 out[i] = mEDIDModes[i]; 274 } 275} 276 277void ExternalDisplay::readCEUnderscanInfo() 278{ 279 int hdmiScanInfoFile = -1; 280 int len = -1; 281 char scanInfo[17]; 282 char *ce_info_str = NULL; 283 const char token[] = ", \n"; 284 int ce_info = -1; 285 char sysFsScanInfoFilePath[MAX_SYSFS_FILE_PATH]; 286 snprintf(sysFsScanInfoFilePath, sizeof(sysFsScanInfoFilePath), 287 "/sys/devices/virtual/graphics/fb%d/" 288 "scan_info", mHdmiFbNum); 289 290 memset(scanInfo, 0, sizeof(scanInfo)); 291 hdmiScanInfoFile = open(sysFsScanInfoFilePath, O_RDONLY, 0); 292 if (hdmiScanInfoFile < 0) { 293 ALOGD_IF(DEBUG, "%s: scan_info file '%s' not found", 294 __FUNCTION__, sysFsScanInfoFilePath); 295 return; 296 } else { 297 len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1); 298 ALOGD("%s: Scan Info string: %s length = %d", 299 __FUNCTION__, scanInfo, len); 300 if (len <= 0) { 301 close(hdmiScanInfoFile); 302 ALOGE("%s: Scan Info file empty '%s'", 303 __FUNCTION__, sysFsScanInfoFilePath); 304 return; 305 } 306 scanInfo[len] = '\0'; /* null terminate the string */ 307 } 308 close(hdmiScanInfoFile); 309 310 /* 311 * The scan_info contains the three fields 312 * PT - preferred video format 313 * IT - video format 314 * CE video format - containing the underscan support information 315 */ 316 317 /* PT */ 318 ce_info_str = strtok(scanInfo, token); 319 if (ce_info_str) { 320 /* IT */ 321 ce_info_str = strtok(NULL, token); 322 if (ce_info_str) { 323 /* CE */ 324 ce_info_str = strtok(NULL, token); 325 if (ce_info_str) 326 ce_info = atoi(ce_info_str); 327 } 328 } 329 330 if (ce_info_str) { 331 // ce_info contains the underscan information 332 if (ce_info == EXT_SCAN_ALWAYS_UNDERSCANED || 333 ce_info == EXT_SCAN_BOTH_SUPPORTED) 334 // if TV supported underscan, then driver will always underscan 335 // hence no need to apply action safe rectangle 336 mUnderscanSupported = true; 337 } else { 338 ALOGE("%s: scan_info string error", __FUNCTION__); 339 } 340 341 // Store underscan support info in a system property 342 const char* prop = (mUnderscanSupported) ? "1" : "0"; 343 property_set("hw.underscan_supported", prop); 344 return; 345} 346 347ExternalDisplay::~ExternalDisplay() 348{ 349 delete [] supported_video_mode_lut; 350 closeFrameBuffer(); 351} 352 353/* 354 * sets the fb_var_screeninfo from the hdmi_mode_timing_info 355 */ 356void setDisplayTiming(struct fb_var_screeninfo &info, 357 const msm_hdmi_mode_timing_info* mode) 358{ 359 info.reserved[0] = 0; 360 info.reserved[1] = 0; 361 info.reserved[2] = 0; 362#ifndef FB_METADATA_VIDEO_INFO_CODE_SUPPORT 363 info.reserved[3] = (info.reserved[3] & 0xFFFF) | 364 (mode->video_format << 16); 365#endif 366 info.xoffset = 0; 367 info.yoffset = 0; 368 info.xres = mode->active_h; 369 info.yres = mode->active_v; 370 371 info.pixclock = (mode->pixel_freq)*1000; 372 info.vmode = mode->interlaced ? 373 FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED; 374 375 info.right_margin = mode->front_porch_h; 376 info.hsync_len = mode->pulse_width_h; 377 info.left_margin = mode->back_porch_h; 378 info.lower_margin = mode->front_porch_v; 379 info.vsync_len = mode->pulse_width_v; 380 info.upper_margin = mode->back_porch_v; 381} 382 383int 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 404bool ExternalDisplay::readResolution() 405{ 406 char sysFsEDIDFilePath[MAX_SYSFS_FILE_PATH]; 407 snprintf(sysFsEDIDFilePath , sizeof(sysFsEDIDFilePath), 408 "/sys/devices/virtual/graphics/fb%d/edid_modes", 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 442bool 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 456bool 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 470void 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 483int ExternalDisplay::getModeOrder(int mode) 484{ 485 // XXX: We dont support interlaced modes but having 486 // it here for future 487 switch (mode) { 488 default: 489 case HDMI_VFRMT_1440x480i60_4_3: 490 return 1; // 480i 4:3 491 case HDMI_VFRMT_1440x480i60_16_9: 492 return 2; // 480i 16:9 493 case HDMI_VFRMT_1440x576i50_4_3: 494 return 3; // i576i 4:3 495 case HDMI_VFRMT_1440x576i50_16_9: 496 return 4; // 576i 16:9 497 case HDMI_VFRMT_1920x1080i60_16_9: 498 return 5; // 1080i 16:9 499 case HDMI_VFRMT_640x480p60_4_3: 500 return 6; // 640x480 4:3 501 case HDMI_VFRMT_720x480p60_4_3: 502 return 7; // 480p 4:3 503 case HDMI_VFRMT_720x480p60_16_9: 504 return 8; // 480p 16:9 505 case HDMI_VFRMT_720x576p50_4_3: 506 return 9; // 576p 4:3 507 case HDMI_VFRMT_720x576p50_16_9: 508 return 10; // 576p 16:9 509 case HDMI_VFRMT_1280x1024p60_5_4: 510 return 11; // 1024p; Vesa format 511 case HDMI_VFRMT_1280x720p50_16_9: 512 return 12; // 720p@50Hz 513 case HDMI_VFRMT_1280x720p60_16_9: 514 return 13; // 720p@60Hz 515 case HDMI_VFRMT_1920x1080p24_16_9: 516 return 14; //1080p@24Hz 517 case HDMI_VFRMT_1920x1080p25_16_9: 518 return 15; //108-p@25Hz 519 case HDMI_VFRMT_1920x1080p30_16_9: 520 return 16; //1080p@30Hz 521 case HDMI_VFRMT_1920x1080p50_16_9: 522 return 17; //1080p@50Hz 523 case HDMI_VFRMT_1920x1080p60_16_9: 524 return 18; //1080p@60Hz 525 case HDMI_VFRMT_2560x1600p60_16_9: 526 return 19; //WQXGA@60Hz541 527 case HDMI_VFRMT_3840x2160p24_16_9: 528 return 20;//2160@24Hz 529 case HDMI_VFRMT_3840x2160p25_16_9: 530 return 21;//2160@25Hz 531 case HDMI_VFRMT_3840x2160p30_16_9: 532 return 22; //2160@30Hz 533 case HDMI_VFRMT_4096x2160p24_16_9: 534 return 23; //4kx2k@24Hz 535 } 536} 537 538/// Returns the user mode set(if any) using adb shell 539int 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 553int 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 569inline 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 582bool 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 default: 592 interlaced = false; 593 } 594 return interlaced; 595} 596 597void ExternalDisplay::setResolution(int ID) 598{ 599 struct fb_var_screeninfo info; 600 int ret = 0; 601 ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo); 602 if(ret < 0) { 603 ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__, 604 strerror(errno)); 605 } 606 ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d)," 607 "(%d,%d,%d) %dMHz>", __FUNCTION__, 608 mVInfo.reserved[3], mVInfo.xres, mVInfo.yres, 609 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin, 610 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin, 611 mVInfo.pixclock/1000/1000); 612 //If its a new ID - update var_screeninfo 613 if ((isValidMode(ID)) && mCurrentMode != ID) { 614 const struct msm_hdmi_mode_timing_info *mode = 615 &supported_video_mode_lut[0]; 616 for (unsigned int i = 0; i < HDMI_VFRMT_MAX; ++i) { 617 const struct msm_hdmi_mode_timing_info *cur = 618 &supported_video_mode_lut[i]; 619 if (cur->video_format == (uint32_t)ID) { 620 mode = cur; 621 break; 622 } 623 } 624 setDisplayTiming(mVInfo, mode); 625 ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d" 626 "(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, ID, 627 mode->video_format, mVInfo.xres, mVInfo.yres, 628 mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin, 629 mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin, 630 mVInfo.pixclock/1000/1000); 631#ifdef FB_METADATA_VIDEO_INFO_CODE_SUPPORT 632 struct msmfb_metadata metadata; 633 memset(&metadata, 0 , sizeof(metadata)); 634 metadata.op = metadata_op_vic; 635 metadata.data.video_info_code = mode->video_format; 636 if (ioctl(mFd, MSMFB_METADATA_SET, &metadata) == -1) { 637 ALOGD("In %s: MSMFB_METADATA_SET failed Err Str = %s", 638 __FUNCTION__, strerror(errno)); 639 } 640#endif 641 mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE; 642 ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo); 643 if(ret < 0) { 644 ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s", 645 __FUNCTION__, strerror(errno)); 646 } 647 mCurrentMode = ID; 648 } 649} 650 651void ExternalDisplay::setExternalDisplay(bool connected, int extFbNum) 652{ 653 hwc_context_t* ctx = mHwcContext; 654 if(ctx) { 655 ALOGD_IF(DEBUG, "%s: connected = %d", __FUNCTION__, connected); 656 // Store the external display 657 mConnected = connected; 658 mConnectedFbNum = extFbNum; 659 mHwcContext->dpyAttr[mExtDpyNum].connected = connected; 660 // Update external fb number in Overlay context 661 overlay::Overlay::getInstance()->setExtFbNum(extFbNum); 662 } 663} 664 665int ExternalDisplay::getExtFbNum(int &fbNum) { 666 int ret = -1; 667 if(mConnected) { 668 fbNum = mConnectedFbNum; 669 ret = 0; 670 } 671 return ret; 672} 673 674bool 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 703void 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 713void 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 725void 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_1920x1080p24_16_9: 760 width = 1920; 761 height = 1080; 762 fps = 24; 763 break; 764 case HDMI_VFRMT_1920x1080p25_16_9: 765 width = 1920; 766 height = 1080; 767 fps = 25; 768 break; 769 case HDMI_VFRMT_1920x1080p30_16_9: 770 width = 1920; 771 height = 1080; 772 fps = 30; 773 break; 774 case HDMI_VFRMT_1920x1080p50_16_9: 775 width = 1920; 776 height = 1080; 777 fps = 50; 778 break; 779 case HDMI_VFRMT_1920x1080p60_16_9: 780 width = 1920; 781 height = 1080; 782 fps = 60; 783 break; 784 case HDMI_VFRMT_2560x1600p60_16_9: 785 width = 2560; 786 height = 1600; 787 fps = 60; 788 break; 789 case HDMI_VFRMT_3840x2160p24_16_9: 790 width = 3840; 791 height = 2160; 792 fps = 24; 793 break; 794 case HDMI_VFRMT_3840x2160p25_16_9: 795 width = 3840; 796 height = 2160; 797 fps = 25; 798 break; 799 case HDMI_VFRMT_3840x2160p30_16_9: 800 width = 3840; 801 height = 2160; 802 fps = 30; 803 break; 804 case HDMI_VFRMT_4096x2160p24_16_9: 805 width = 4096; 806 height = 2160; 807 fps = 24; 808 break; 809 810 } 811} 812 813}; 814