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