1/* 2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <sys/cdefs.h> 25 26#include <mach/mach.h> 27#include <mach/thread_switch.h> 28#include <sys/file.h> 29#include <sys/stat.h> 30#include <sys/mman.h> 31#include <unistd.h> 32#include <string.h> 33#include <stdlib.h> 34#include <libc.h> 35 36#include <CoreFoundation/CoreFoundation.h> 37#include <CoreFoundation/CFBundlePriv.h> 38 39#include <IOKit/IOKitLib.h> 40#include <libkern/OSByteOrder.h> 41#include <IOKit/graphics/IOGraphicsLib.h> 42#include <IOKit/graphics/IOGraphicsLibPrivate.h> 43#include <IOKit/graphics/IOGraphicsTypesPrivate.h> 44#include <IOKit/graphics/IOGraphicsEngine.h> 45 46#include "IOGraphicsLibInternal.h" 47 48#define DEBUGPARAMS 0 49 50 51/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 52 53__private_extern__ IOReturn 54readFile(const char *path, vm_address_t * objAddr, vm_size_t * objSize); 55__private_extern__ CFMutableDictionaryRef 56readPlist( const char * path, UInt32 key ); 57__private_extern__ Boolean 58writePlist( const char * path, CFMutableDictionaryRef dict, UInt32 key __unused ); 59 60static char gIODisplayBoardID[256] = { 0 }; 61 62/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 63 64static void 65setDictionaryDisplayIconValue(CFMutableDictionaryRef dst, CFDictionaryRef src) 66{ 67 CFTypeRef value = NULL; 68 if (CFDictionaryGetValueIfPresent(src, CFSTR("display-icon"), (const void**)&value)) 69 CFDictionarySetValue(dst, CFSTR("display-icon"), value); 70} 71 72static void 73setDictionaryDisplayResolutionPreviewValues(CFMutableDictionaryRef dst, CFDictionaryRef src) 74{ 75 CFTypeRef value = NULL; 76 if (CFDictionaryGetValueIfPresent(src, CFSTR("display-resolution-preview-icon"), (const void**)&value)) 77 CFDictionarySetValue(dst, CFSTR("display-resolution-preview-icon"), value); 78 if (CFDictionaryGetValueIfPresent(src, CFSTR("resolution-preview-x"), (const void**)&value)) 79 CFDictionarySetValue(dst, CFSTR("resolution-preview-x"), value); 80 if (CFDictionaryGetValueIfPresent(src, CFSTR("resolution-preview-y"), (const void**)&value)) 81 CFDictionarySetValue(dst, CFSTR("resolution-preview-y"), value); 82 if (CFDictionaryGetValueIfPresent(src, CFSTR("resolution-preview-width"), (const void**)&value)) 83 CFDictionarySetValue(dst, CFSTR("resolution-preview-width"), value); 84 if (CFDictionaryGetValueIfPresent(src, CFSTR("resolution-preview-height"), (const void**)&value)) 85 CFDictionarySetValue(dst, CFSTR("resolution-preview-height"), value); 86} 87 88 89static CFMutableDictionaryRef 90IODisplayCreateOverrides( io_service_t framebuffer, IOOptionBits options, 91 IODisplayVendorID vendor, IODisplayProductID product, 92 UInt32 serialNumber __unused, 93 uint32_t manufactureYear, 94 uint32_t manufactureWeek, 95 Boolean isDigital ) 96{ 97 98 char path[256]; 99 CFTypeRef obj = 0; 100 CFMutableDictionaryRef dict = 0; 101 102 if( 0 == (options & kIODisplayMatchingInfo)) { 103 104 snprintf( path, sizeof(path), "/System/Library/Displays/Overrides" 105 "/" kDisplayVendorID "-%x" 106 "/" kDisplayProductID "-%x", 107 (unsigned) vendor, (unsigned) product ); 108 109 obj = readPlist( path, ((vendor & 0xffff) << 16) | (product & 0xffff) ); 110 111 if ((!obj) && manufactureYear && manufactureWeek) 112 { 113 snprintf( path, sizeof(path), "/System/Library/Displays/Overrides" 114 "/" kDisplayVendorID "-%x" 115 "/" kDisplayYearOfManufacture "-%d" 116 "-" kDisplayWeekOfManufacture "-%d", 117 (unsigned) vendor, 118 manufactureYear, manufactureWeek ); 119 obj = readPlist( path, ((vendor & 0xffff) << 16) | (product & 0xffff) ); 120 } 121 if (obj) 122 { 123 if( CFDictionaryGetTypeID() == CFGetTypeID( obj )) 124 { 125 dict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, obj); 126 } 127 else if( CFArrayGetTypeID() == CFGetTypeID( obj )) 128 { 129 CFArrayRef array; 130 CFIndex count, idx; 131 CFTypeRef obj2; 132 CFDictionaryRef matching, candidate; 133 134 // look for a matching override 135 array = obj; 136 candidate = 0; 137 count = CFArrayGetCount(array); 138 for (idx = 0; idx < count; idx++, candidate = 0) 139 { 140 obj2 = CFArrayGetValueAtIndex(array, idx); 141 if (CFDictionaryGetTypeID() != CFGetTypeID(obj2)) 142 continue; 143 candidate = obj2; 144 matching = CFDictionaryGetValue(candidate, CFSTR(kIODisplayOverrideMatchingKey)); 145 if (!matching) 146 break; 147 if (CFDictionaryGetTypeID() != CFGetTypeID(matching)) 148 continue; 149 150 obj2 = CFDictionaryGetValue(matching, CFSTR(kIODisplayIsDigitalKey)); 151 if ((obj2 == kCFBooleanTrue) && !isDigital) 152 continue; 153 if ((obj2 == kCFBooleanFalse) && isDigital) 154 continue; 155 156 break; 157 } 158 if (candidate) 159 dict = CFDictionaryCreateMutableCopy( kCFAllocatorDefault, 0, candidate); 160 } 161 CFRelease( obj ); 162 } 163 } 164 if( !dict) 165 dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, 166 &kCFTypeDictionaryKeyCallBacks, 167 &kCFTypeDictionaryValueCallBacks); 168 169 if( dict) do { 170 CFStringRef string; 171 CFURLRef url; 172 CFBundleRef bdl; 173 174 if((kIODisplayMatchingInfo | kIODisplayNoProductName) & options) 175 continue; 176 177 snprintf( path, sizeof(path), "/System/Library/Displays/Overrides"); 178// "/" kDisplayVendorID "-%lx", vendor ); 179 180 string = CFStringCreateWithCString( kCFAllocatorDefault, path, 181 kCFStringEncodingMacRoman ); 182 if( !string) 183 continue; 184 url = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, string, 185 kCFURLPOSIXPathStyle, true ); 186 CFRelease(string); 187 if( !url) 188 continue; 189 bdl = CFBundleCreate( kCFAllocatorDefault, url); 190 if( bdl) { 191 CFDictionarySetValue( dict, CFSTR(kDisplayBundleKey), bdl); 192 CFRelease(bdl); 193 } 194 CFRelease(url); 195 196 } while( false ); 197 198 if (dict) { 199 if (gIODisplayBoardID[0] == 0) { 200 io_registry_entry_t ioRegRoot = IORegistryGetRootEntry(kIOMasterPortDefault); 201 if (ioRegRoot) { 202 CFDataRef boardId = (CFDataRef) IORegistryEntrySearchCFProperty(ioRegRoot, 203 kIOServicePlane, 204 CFSTR("board-id"), 205 kCFAllocatorDefault, 206 kIORegistryIterateRecursively); 207 IOObjectRelease(ioRegRoot); 208 if (boardId) { 209 size_t len = CFDataGetLength(boardId); 210 if (len > sizeof(gIODisplayBoardID)) len = sizeof(gIODisplayBoardID); 211 strlcpy(gIODisplayBoardID, (const char *) CFDataGetBytePtr(boardId), len); 212 CFRelease(boardId); 213 } 214 } 215 } 216 217 CFDataRef builtin = (CFDataRef) IORegistryEntryCreateCFProperty(framebuffer, 218 CFSTR(kIOFBBuiltInKey), 219 kCFAllocatorDefault, kNilOptions); 220 221 CFMutableDictionaryRef iconDict = NULL; 222 if (access("/System/Library/Displays/Overrides/Icons.plist", F_OK) == 0) 223 iconDict = readPlist("/System/Library/Displays/Overrides/Icons.plist", 0); 224 225 CFStringRef vendorIdString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%x"), vendor); 226 CFStringRef deviceIdString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%x"), product); 227 CFStringRef modelString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s"), gIODisplayBoardID); 228 229 snprintf(path, sizeof(path), "/System/Library/Displays/Overrides" 230 "/" kDisplayVendorID "-%x" 231 "/" kDisplayProductID "-%x-%s.icns", 232 (unsigned)vendor, (unsigned)product, gIODisplayBoardID); 233 234 Boolean foundIcon = false; 235 if (access(path, F_OK) == 0) 236 foundIcon = true; 237 238 if (!foundIcon) { 239 snprintf(path, sizeof(path), "/System/Library/Displays/Overrides" 240 "/" kDisplayVendorID "-%x" 241 "/" kDisplayYearOfManufacture "-%d" 242 "-" kDisplayWeekOfManufacture "-%d-%s.icns", 243 (unsigned)vendor, 244 manufactureYear, manufactureWeek, gIODisplayBoardID); 245 246 if (access(path, F_OK) == 0) 247 foundIcon = true; 248 } 249 250 CFStringRef productModelDisplayIconFilePath = NULL; 251 if (foundIcon) 252 productModelDisplayIconFilePath = CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path); 253 254 CFStringRef modelDisplayIconFilePath = NULL; 255 if (builtin) { 256 snprintf(path, sizeof(path), "/System/Library/Displays/Overrides/Models/%s.icns", gIODisplayBoardID); 257 258 if (access(path, F_OK) == 0) 259 modelDisplayIconFilePath = CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path); 260 } 261 262 snprintf(path, sizeof(path), "/System/Library/Displays/Overrides" 263 "/" kDisplayVendorID "-%x" 264 "/" kDisplayProductID "-%x.icns", 265 (unsigned)vendor, (unsigned)product); 266 267 foundIcon = false; 268 if (access(path, F_OK) == 0) 269 foundIcon = true; 270 271 if (!foundIcon) { 272 snprintf(path, sizeof(path), "/System/Library/Displays/Overrides" 273 "/" kDisplayVendorID "-%x" 274 "/" kDisplayYearOfManufacture "-%d" 275 "-" kDisplayWeekOfManufacture "-%d.icns", 276 (unsigned)vendor, 277 manufactureYear, manufactureWeek); 278 279 if (access(path, F_OK) == 0) 280 foundIcon = true; 281 } 282 283 CFStringRef productDisplayIconFilePath = NULL; 284 if (foundIcon) 285 productDisplayIconFilePath = CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path); 286 287 288 snprintf(path, sizeof(path), "/System/Library/Displays/Overrides" 289 "/" kDisplayVendorID "-%x.icns", 290 (unsigned)vendor); 291 292 CFStringRef vendorDisplayIconFilePath = NULL; 293 if (access(path, F_OK) == 0) 294 vendorDisplayIconFilePath = CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path); 295 296 CFMutableDictionaryRef displayDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 297 298 CFMutableDictionaryRef modelIdsDict = NULL; 299 if (iconDict && builtin && CFDictionaryGetValueIfPresent(iconDict, CFSTR("board-ids"), (const void**)&modelIdsDict)) { 300 CFMutableDictionaryRef modelDict = NULL; 301 if (CFDictionaryGetValueIfPresent(modelIdsDict, modelString, (const void**)&modelDict)) { 302 setDictionaryDisplayIconValue(displayDict, modelDict); 303 setDictionaryDisplayResolutionPreviewValues(displayDict, modelDict); 304 } 305 } 306 307 if (builtin && !CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && modelDisplayIconFilePath) 308 CFDictionarySetValue(dict, CFSTR("display-icon"), vendorDisplayIconFilePath); 309 310 CFMutableDictionaryRef vendorIdsDict = NULL; 311 if (iconDict && CFDictionaryGetValueIfPresent(iconDict, CFSTR("vendors"), (const void**)&vendorIdsDict)) { 312 CFMutableDictionaryRef vendorDict = NULL; 313 if (CFDictionaryGetValueIfPresent(vendorIdsDict, vendorIdString, (const void**)&vendorDict)) { 314 CFMutableDictionaryRef displayIdsDict = NULL; 315 if (CFDictionaryGetValueIfPresent(vendorDict, CFSTR("products"), (const void**)&displayIdsDict)) { 316 CFMutableDictionaryRef deviceDict = NULL; 317 if (CFDictionaryGetValueIfPresent(displayIdsDict, deviceIdString, (const void**)&deviceDict)) { 318 if (builtin && CFDictionaryGetValueIfPresent(deviceDict, CFSTR("board-ids"), (const void**)&modelIdsDict)) { 319 CFMutableDictionaryRef modelDict = NULL; 320 if (CFDictionaryGetValueIfPresent(modelIdsDict, modelString, (const void**)&modelDict)) { 321 setDictionaryDisplayIconValue(displayDict, modelDict); 322 setDictionaryDisplayResolutionPreviewValues(displayDict, modelDict); 323 324 if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && productModelDisplayIconFilePath) 325 CFDictionarySetValue(displayDict, CFSTR("display-icon"), productModelDisplayIconFilePath); 326 } 327 } 328 329 if (!builtin) { 330 if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon"))) 331 setDictionaryDisplayIconValue(displayDict, deviceDict); 332 333 if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && productDisplayIconFilePath) 334 CFDictionarySetValue(displayDict, CFSTR("display-icon"), productDisplayIconFilePath); 335 336 if (!CFDictionaryContainsKey(displayDict, CFSTR("display-resolution-preview-icon"))) 337 setDictionaryDisplayResolutionPreviewValues(displayDict, deviceDict); 338 } 339 } 340 } 341 342 if (!builtin) { 343 if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && productDisplayIconFilePath) 344 CFDictionarySetValue(displayDict, CFSTR("display-icon"), productDisplayIconFilePath); 345 346 if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon"))) 347 setDictionaryDisplayIconValue(displayDict, vendorDict); 348 349 if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && vendorDisplayIconFilePath) 350 CFDictionarySetValue(displayDict, CFSTR("display-icon"), vendorDisplayIconFilePath); 351 352 if (!CFDictionaryContainsKey(displayDict, CFSTR("display-resolution-preview-icon"))) 353 setDictionaryDisplayResolutionPreviewValues(displayDict, vendorDict); 354 } 355 } 356 357 if (!builtin) { 358 if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && productDisplayIconFilePath) 359 CFDictionarySetValue(displayDict, CFSTR("display-icon"), productDisplayIconFilePath); 360 361 if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && vendorDisplayIconFilePath) 362 CFDictionarySetValue(displayDict, CFSTR("display-icon"), vendorDisplayIconFilePath); 363 364 if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon"))) 365 setDictionaryDisplayIconValue(displayDict, vendorIdsDict); 366 } 367 } 368 369 setDictionaryDisplayIconValue(dict, displayDict); 370 setDictionaryDisplayResolutionPreviewValues(dict, displayDict); 371 372 CFRelease(displayDict); 373 374 if (iconDict) 375 CFRelease(iconDict); 376 377 if (builtin) 378 CFRelease(builtin); 379 380 if (vendorDisplayIconFilePath) 381 CFRelease(vendorDisplayIconFilePath); 382 383 if (productDisplayIconFilePath) 384 CFRelease(productDisplayIconFilePath); 385 386 if (modelDisplayIconFilePath) 387 CFRelease(modelDisplayIconFilePath); 388 389 if (productModelDisplayIconFilePath) 390 CFRelease(productModelDisplayIconFilePath); 391 392 CFRelease(modelString); 393 CFRelease(deviceIdString); 394 CFRelease(vendorIdString); 395 } 396 397 return( dict ); 398} 399 400static void 401EDIDInfo( struct EDID * edid, 402 IODisplayVendorID * vendor, IODisplayProductID * product, 403 UInt32 * serialNumber, 404 uint32_t * manufactureYear, uint32_t * manufactureWeek, 405 Boolean * isDigital ) 406{ 407 SInt32 sint; 408 409 if (vendor) 410 *vendor = (edid->vendorProduct[0] << 8) | edid->vendorProduct[1]; 411 if (product) 412 *product = (edid->vendorProduct[3] << 8) | edid->vendorProduct[2]; 413 if (isDigital) 414 *isDigital = (0 != (0x80 & edid->displayParams[0])); 415 416 if( serialNumber) { 417 sint = (edid->serialNumber[3] << 24) 418 | (edid->serialNumber[2] << 16) 419 | (edid->serialNumber[1] << 8) 420 | (edid->serialNumber[0]); 421 if( sint == 0x01010101) 422 sint = 0; 423 *serialNumber = sint; 424 } 425 426 if (manufactureYear) *manufactureYear = edid->yearOfManufacture + 1990; 427 if (manufactureWeek) *manufactureWeek = edid->weekOfManufacture; 428} 429 430__private_extern__ Boolean 431IODisplayEDIDName( EDID * edid, char * name ) 432{ 433 char * oname = name; 434 EDIDDesc * desc; 435 int i,j; 436 Boolean ok; 437 char c; 438 439 if( !edid || (edid->version < 1) || (edid->revision < 1)) 440 return( false ); 441 442 desc = edid->descriptors; 443 for( i = 0; i < 4; i++, desc++) { 444 if( desc->general.flag1 || desc->general.flag2 || desc->general.flag3) 445 continue; 446 if( 0xfc != desc->general.type) 447 continue; 448 449 for( j = 0; j < (int) sizeof(desc->general.data); j++) { 450 c = desc->general.data[j]; 451 if( c != 0x0a) 452 *oname++ = c; 453 else 454 break; 455 } 456 } 457 ok = (oname != name); 458 if( ok) 459 *oname++ = 0; 460 461 return( ok ); 462} 463 464struct MakeOneLocalContext { 465 CFBundleRef bdl; 466 CFMutableDictionaryRef dict; 467 CFStringRef key; 468}; 469 470static void MakeOneLocalization( const void * item, void * context ) 471{ 472 struct MakeOneLocalContext * ctx = (struct MakeOneLocalContext *) context; 473 CFStringRef value = NULL; 474 CFDictionaryRef stringTable = NULL; 475 CFURLRef url; 476 CFDataRef tableData = NULL; 477 CFStringRef errStr; 478 SInt32 errCode; 479 480 url = CFBundleCopyResourceURLForLocalization( ctx->bdl, 481 CFSTR("Localizable"), CFSTR("strings"), NULL, item ); 482 if (url && CFURLCreateDataAndPropertiesFromResource( kCFAllocatorDefault, 483 url, &tableData, NULL, NULL, &errCode)) { 484 stringTable = CFPropertyListCreateFromXMLData( kCFAllocatorDefault, 485 tableData, kCFPropertyListImmutable, &errStr); 486 if (errStr) 487 CFRelease( errStr); 488 CFRelease( tableData); 489 } 490 if( url) 491 CFRelease(url); 492 if( stringTable) 493 value = CFDictionaryGetValue(stringTable, ctx->key); 494 if (!value) 495 value = ctx->key; 496 497 { 498 SInt32 languageCode, regionCode, scriptCode; 499 CFStringEncoding stringEncoding; 500 if( CFBundleGetLocalizationInfoForLocalization( item, &languageCode, ®ionCode, 501 &scriptCode, &stringEncoding )) { 502 item = CFBundleCopyLocalizationForLocalizationInfo( languageCode, regionCode, 503 scriptCode, stringEncoding ); 504 } else 505 item = CFRetain(item); 506 } 507 508 CFDictionarySetValue( ctx->dict, item, value ); 509 CFRelease( item ); 510 511 if( stringTable) 512 CFRelease( stringTable ); 513} 514 515static void GenerateProductName( CFMutableDictionaryRef dict, 516 EDID * edid, SInt32 displayType, IOOptionBits options ) 517{ 518 CFStringRef key; 519 CFBundleRef bdl; 520 CFArrayRef localizations; 521 struct MakeOneLocalContext ctx; 522 static const char * type2Name[] = { 523 NULL, // 000 kUnknownConnect 524 NULL, // 001 kUnknownConnect 525 "Color LCD", // 002 kPanelTFTConnect 526 NULL, // 003 kFixedModeCRTConnect 527 "Multiple Scan Display", // 004 kMultiModeCRT1Connect 528 "Multiple Scan Display", // 005 kMultiModeCRT2Connect 529 "Multiple Scan Display", // 006 kMultiModeCRT3Connect 530 "Multiple Scan Display", // 007 kMultiModeCRT4Connect 531 NULL, // 008 kModelessConnect 532 "Full-Page Display", // 009 kFullPageConnect 533 "VGA Display", // 010 kVGAConnect 534 "Television", // 011 kNTSCConnect 535 "Television", // 012 kPALConnect 536 NULL, // 013 kHRConnect 537 "Color LCD", // 014 kPanelFSTNConnect 538 "Two-Page Display", // 015 kMonoTwoPageConnect 539 "Two-Page Display", // 016 kColorTwoPageConnect 540 NULL, // 017 kColor16Connect 541 NULL, // 018 kColor19Connect 542 NULL, // 019 kGenericCRT 543 "Color LCD", // 020 kGenericLCD 544 NULL, // 021 kDDCConnect 545 NULL // 022 kNoConnect 546 }; 547 548 key = CFDictionaryGetValue( dict, CFSTR(kDisplayProductName)); 549 if( key) { 550 if( CFStringGetTypeID() != CFGetTypeID( key )) 551 return; 552 CFRetain(key); 553 } 554 bdl = (CFBundleRef) CFDictionaryGetValue( dict, CFSTR(kDisplayBundleKey)); 555 556 if( !key) { 557 char sbuf[ 128 ]; 558 const char * name = NULL; 559 560 if( IODisplayEDIDName(edid, sbuf)) 561 name = sbuf; 562 else if (edid) 563 name = "Unknown Display"; 564 else { 565 566 if( displayType < (int) (sizeof( type2Name) / sizeof(type2Name[0]))) 567 name = type2Name[displayType]; 568 if( !name) 569 name = "Unknown Display"; 570 } 571 572 key = CFStringCreateWithCString( kCFAllocatorDefault, name, 573 kCFStringEncodingMacRoman ); 574 if( !key) 575 return; 576 } 577 578 if( bdl) { 579 localizations = CFBundleCopyBundleLocalizations( bdl); 580 if (localizations) 581 { 582 ctx.bdl = bdl; 583 ctx.dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, 584 &kCFTypeDictionaryKeyCallBacks, 585 &kCFTypeDictionaryValueCallBacks); 586 ctx.key = key; 587 588 if( kIODisplayOnlyPreferredName & options) { 589 CFArrayRef temp = localizations; 590 localizations = CFBundleCopyPreferredLocalizationsFromArray( temp ); 591 CFRelease( temp ); 592 } 593 594 CFArrayApplyFunction( localizations, 595 CFRangeMake(0, CFArrayGetCount(localizations)), 596 &MakeOneLocalization, 597 &ctx); 598 CFDictionarySetValue( dict, CFSTR(kDisplayProductName), ctx.dict); 599 600 CFRelease( localizations ); 601 CFRelease( ctx.dict ); 602 } 603 } 604 CFRelease( key ); 605} 606 607static void 608MaxTimingRangeRec( IODisplayTimingRange * range ) 609{ 610 bzero( range, sizeof( IODisplayTimingRange) ); 611 612 range->supportedSyncFlags = 0xffffffff; 613 range->supportedSignalLevels = 0xffffffff; 614 range->supportedSignalConfigs = 0xffffffff; 615 616 range->maxFrameRate = 0xffffffff; 617 range->maxLineRate = 0xffffffff; 618 range->maxPixelClock = 0xffffffff; 619 range->maxPixelError = 0xffffffff; 620 621 range->maxHorizontalTotal = 0xffffffff; 622 range->maxVerticalTotal = 0xffffffff; 623 range->maxHorizontalActiveClocks = 0xffffffff; 624 range->maxHorizontalBlankingClocks = 0xffffffff; 625 range->maxHorizontalSyncOffsetClocks = 0xffffffff; 626 range->maxHorizontalPulseWidthClocks = 0xffffffff; 627 range->maxVerticalActiveClocks = 0xffffffff; 628 range->maxVerticalBlankingClocks = 0xffffffff; 629 range->maxVerticalSyncOffsetClocks = 0xffffffff; 630 range->maxVerticalPulseWidthClocks = 0xffffffff; 631 range->maxHorizontalBorderLeft = 0xffffffff; 632 range->maxHorizontalBorderRight = 0xffffffff; 633 range->maxVerticalBorderTop = 0xffffffff; 634 range->maxVerticalBorderBottom = 0xffffffff; 635 636 range->charSizeHorizontalActive = 1; 637 range->charSizeHorizontalBlanking = 1; 638 range->charSizeHorizontalSyncOffset = 1; 639 range->charSizeHorizontalSyncPulse = 1; 640 range->charSizeVerticalActive = 1; 641 range->charSizeVerticalBlanking = 1; 642 range->charSizeVerticalSyncOffset = 1; 643 range->charSizeVerticalSyncPulse = 1; 644 range->charSizeHorizontalBorderLeft = 1; 645 range->charSizeHorizontalBorderRight = 1; 646 range->charSizeVerticalBorderTop = 1; 647 range->charSizeVerticalBorderBottom = 1; 648 range->charSizeHorizontalTotal = 1; 649 range->charSizeVerticalTotal = 1; 650} 651 652static Boolean 653EDIDDescToDisplayTimingRangeRec( EDID * edid, EDIDGeneralDesc * desc, 654 IODisplayTimingRange * range ) 655{ 656 UInt8 byte; 657 658 if( !edid || (edid->version < 1) || (edid->revision < 1)) 659 return( false ); 660 661 if( desc->flag1 || desc->flag2 || desc->flag3) 662 return( false ); 663 if( 0xfd != desc->type) 664 return( false ); 665 666 MaxTimingRangeRec( range ); 667 668 byte = edid->displayParams[0]; 669 if (!(0x80 & byte)) 670 { 671 range->supportedSignalLevels = 1 << ((byte >> 5) & 3); 672 range->supportedSyncFlags = ((byte & 1) ? kIORangeSupportsVSyncSerration : 0) 673 | ((byte & 2) ? kIORangeSupportsSyncOnGreen : 0) 674 | ((byte & 4) ? kIORangeSupportsCompositeSync : 0) 675 | ((byte & 8) ? kIORangeSupportsSeparateSyncs : 0); 676 } 677 678 range->supportedSignalConfigs = kIORangeSupportsInterlacedCEATiming; 679 680 range->minVerticalPulseWidthClocks = 1; 681 range->minHorizontalPulseWidthClocks = 1; 682 683 range->minFrameRate = desc->data[0]; 684 range->maxFrameRate = desc->data[1]; 685 range->minLineRate = desc->data[2] * 1000; 686 range->maxLineRate = desc->data[3] * 1000; 687 range->maxPixelClock = desc->data[4] * 10000000ULL; 688 689 range->minHorizontalActiveClocks = 640; 690 range->minVerticalActiveClocks = 480; 691 692 if( range->minLineRate) 693 range->maxHorizontalActiveClocks = range->maxPixelClock / range->minLineRate; 694 if( range->minFrameRate) 695 range->maxVerticalActiveClocks = range->maxPixelClock 696 / (range->minHorizontalActiveClocks * range->minFrameRate); 697 698 return( true ); 699} 700 701static void 702ParseMonitorDescriptor(IOFBConnectRef connectRef, EDID * edid __unused, EDIDGeneralDesc * desc) 703{ 704 UInt8 byte; 705 CFIndex idx; 706 SInt32 vendor; 707 708 if (desc->flag1 || desc->flag2) 709 return; 710 711 if (desc->type >= 0x11) 712 { 713 if (desc->flag3) 714 return; 715 // vesa 716 return; 717 } 718 719 if (kDisplayAppleVendorID != ((desc->data[0] << 8) | desc->data[1])) 720 return; 721 722 // version = desc->flag3 723 switch (desc->type) 724 { 725 case 1: 726 // lvds 727 // link type = desc->data[2]; 728 // link bits = desc->data[3] & 15; 729 byte = desc->data[3] >> 4; 730 if (!byte) 731 connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayRGBColorComponentBits6; 732 else if (1 == byte) 733 connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayRGBColorComponentBits8; 734 735 if ((1 << 3) & desc->data[4]) 736 connectRef->ditherControl[kAllVendors] = (kIODisplayDitherDisable << kIODisplayDitherRGBShift); 737 break; 738 739 case 2: 740 // dp 741 for (idx = 2; idx < 11; idx += 3) 742 { 743 vendor = desc->data[idx]; 744 if (vendor >= kNumVendors) 745 continue; 746 connectRef->vendorsFound |= (1 << vendor); 747#if DISABLED_7668853 748 byte = desc->data[idx + 1]; // bpp 749 if ((byte >= 6) && (byte <= 16)) 750 { 751 connectRef->supportedComponentDepths[vendor] 752 = (kIODisplayRGBColorComponentBits6 << ((byte - 6) >> 1)); 753 } 754#endif 755 byte = desc->data[idx + 2]; // dither 756 connectRef->ditherControl[vendor] = (byte << kIODisplayDitherRGBShift); 757 758 DEBG(connectRef, "dp vendor 0x%x bpc 0x%x dith 0x%x\n", (int) vendor, 759 connectRef->supportedComponentDepths[vendor], 760 connectRef->ditherControl[vendor]); 761 } 762 break; 763 } 764} 765 766 767static kern_return_t 768DecodeStandardTiming( EDID * edid, UInt16 standardTiming, 769 UInt32 * oWidth, UInt32 * height, float * refreshRate) 770{ 771 UInt32 width; 772 773 if( 0x0101 == standardTiming) 774 return (kIOReturnBadArgument); 775 776 width = ((standardTiming >> 8) + 31) << 3; 777 *oWidth = width; 778 switch( (standardTiming >> 6) & 3) { 779 case 0: 780 if ((edid->version > 1) || (edid->revision >= 3)) 781 *height = (10 * width) / 16; 782 else 783 *height = width; 784 break; 785 case 2: 786 *height = (4 * width) / 5; 787 break; 788 case 3: 789 *height = (9 * width) / 16; 790 break; 791 default: 792 case 1: 793 *height = (3 * width) / 4; 794 break; 795 } 796 797 if (refreshRate) 798 *refreshRate = (float) ((standardTiming & 63) + 60); 799 800 return (kIOReturnSuccess); 801} 802 803static void 804AdjustTimingForInterlace( IODetailedTimingInformation * timing ) 805{ 806 timing->signalConfig |= kIOInterlacedCEATiming; 807 timing->verticalActive = (timing->verticalActive << 1); 808 timing->verticalBlanking = (timing->verticalBlanking << 1) | 1; 809 timing->verticalSyncPulseWidth = (timing->verticalSyncPulseWidth << 1); 810 timing->verticalSyncOffset = (timing->verticalSyncOffset << 1) | 1; 811 timing->verticalBorderTop = (timing->verticalBorderTop << 1); 812 timing->verticalBorderBottom = (timing->verticalBorderBottom << 1); 813} 814 815static IOReturn 816EDIDDescToDetailedTiming( EDID * edid, EDIDDetailedTimingDesc * desc, 817 IODetailedTimingInformation * timing ) 818{ 819 bool interlaced; 820 821 bzero( timing, sizeof( IODetailedTimingInformation) ); 822 823 if( !desc->clock) 824 return( kIOReturnBadArgument ); 825 826 timing->signalConfig = (edid->displayParams[0] & 16) 827 ? kIOAnalogSetupExpected : 0; 828 interlaced = (0 != (desc->flags & 0x80)); 829 830 timing->signalLevels = (edid->displayParams[0] >> 5) & 3; 831 832 timing->pixelClock = ((UInt64) OSReadLittleInt16(&desc->clock, 0)) 833 * 10000ULL; 834 timing->maxPixelClock = timing->pixelClock; 835 timing->minPixelClock = timing->pixelClock; 836 837 timing->horizontalActive = desc->horizActive 838 | ((desc->horizHigh & 0xf0) << 4); 839 timing->horizontalBlanking = desc->horizBlanking 840 | ((desc->horizHigh & 0x0f) << 8); 841 842 timing->verticalActive = desc->verticalActive 843 | ((desc->verticalHigh & 0xf0) << 4); 844 timing->verticalBlanking = desc->verticalBlanking 845 | ((desc->verticalHigh & 0x0f) << 8); 846 847 timing->horizontalSyncOffset = desc->horizSyncOffset 848 | ((desc->syncHigh & 0xc0) << 2); 849 timing->horizontalSyncPulseWidth = desc->horizSyncWidth 850 | ((desc->syncHigh & 0x30) << 4); 851 852 timing->verticalSyncOffset = ((desc->verticalSyncOffsetWidth & 0xf0) >> 4) 853 | ((desc->syncHigh & 0x0c) << 2); 854 timing->verticalSyncPulseWidth = ((desc->verticalSyncOffsetWidth & 0x0f) >> 0) 855 | ((desc->syncHigh & 0x03) << 4); 856 857 timing->horizontalBorderLeft = desc->horizBorder; 858 timing->horizontalBorderRight = desc->horizBorder; 859 timing->verticalBorderTop = desc->verticalBorder; 860 timing->verticalBorderBottom = desc->verticalBorder; 861 862 timing->horizontalSyncConfig = (desc->flags & 2) 863 ? kIOSyncPositivePolarity : 0; 864 timing->horizontalSyncLevel = 0; 865 timing->verticalSyncConfig = (desc->flags & 4) 866 ? kIOSyncPositivePolarity : 0; 867 timing->verticalSyncLevel = 0; 868 869 if (interlaced) 870 AdjustTimingForInterlace(timing); 871 872 return( kIOReturnSuccess ); 873} 874 875static void 876TimingToHost( const IODetailedTimingInformationV2 * _t1, IODetailedTimingInformationV2 * t2 ) 877{ 878 IODetailedTimingInformationV2 * t1 = (IODetailedTimingInformationV2 *) _t1; 879 880 bcopy(t1, t2, sizeof(IODetailedTimingInformationV2)); 881 882 t2->scalerFlags = OSReadBigInt32(&t1->scalerFlags, 0); 883 t2->horizontalScaled = OSReadBigInt32(&t1->horizontalScaled, 0); 884 t2->verticalScaled = OSReadBigInt32(&t1->verticalScaled, 0); 885 t2->signalConfig = OSReadBigInt32(&t1->signalConfig, 0); 886 t2->signalLevels = OSReadBigInt32(&t1->signalLevels, 0); 887 888 t2->pixelClock = OSReadBigInt64(&t1->pixelClock, 0); 889 t2->minPixelClock = OSReadBigInt64(&t1->minPixelClock, 0); 890 t2->maxPixelClock = OSReadBigInt64(&t1->maxPixelClock, 0); 891 892 t2->horizontalActive = OSReadBigInt32(&t1->horizontalActive, 0); 893 t2->horizontalBlanking = OSReadBigInt32(&t1->horizontalBlanking, 0); 894 t2->horizontalSyncOffset = OSReadBigInt32(&t1->horizontalSyncOffset, 0); 895 t2->horizontalSyncPulseWidth = OSReadBigInt32(&t1->horizontalSyncPulseWidth, 0); 896 897 t2->verticalActive = OSReadBigInt32(&t1->verticalActive, 0); 898 t2->verticalBlanking = OSReadBigInt32(&t1->verticalBlanking, 0); 899 t2->verticalSyncOffset = OSReadBigInt32(&t1->verticalSyncOffset, 0); 900 t2->verticalSyncPulseWidth = OSReadBigInt32(&t1->verticalSyncPulseWidth, 0); 901 902 t2->horizontalBorderLeft = OSReadBigInt32(&t1->horizontalBorderLeft, 0); 903 t2->horizontalBorderRight = OSReadBigInt32(&t1->horizontalBorderRight, 0); 904 t2->verticalBorderTop = OSReadBigInt32(&t1->verticalBorderTop, 0); 905 t2->verticalBorderBottom = OSReadBigInt32(&t1->verticalBorderBottom, 0); 906 t2->horizontalSyncConfig = OSReadBigInt32(&t1->horizontalSyncConfig, 0); 907 t2->horizontalSyncLevel = OSReadBigInt32(&t1->horizontalSyncLevel, 0); 908 t2->verticalSyncConfig = OSReadBigInt32(&t1->verticalSyncConfig, 0); 909 t2->verticalSyncLevel = OSReadBigInt32(&t1->verticalSyncLevel, 0); 910} 911 912static IOReturn 913StandardResolutionToDetailedTiming( IOFBConnectRef connectRef, EDID * edid __unused, 914 IOFBResolutionSpec * spec, 915 IOTimingInformation * timing ) 916{ 917 CFDictionaryRef stdModes, timingIDs, dict; 918 const void * key; 919 CFDataRef data; 920 921 if (kResSpecNeedInterlace & spec->flags) 922 return (kIOReturnUnsupportedMode); 923 924 stdModes = CFDictionaryGetValue(connectRef->iographicsProperties, CFSTR("std-modes")); 925 if (!stdModes) 926 return (kIOReturnUnsupportedMode); 927 928 key = (const void *) (uintptr_t) spec->timingID; 929 if (!key) 930 { 931 CFStringRef timingKey; 932 if (kResSpecInternalReducedBlank & spec->flags) 933 timingKey = CFSTR("irb-timing-ids"); 934 else 935 timingKey = CFSTR("timing-ids"); 936 timingIDs = CFDictionaryGetValue(connectRef->iographicsProperties, timingKey); 937 if (!timingIDs) 938 return (kIOReturnUnsupportedMode); 939 key = (const void *)(uintptr_t)((spec->width << 20) | (spec->height << 8) | ((UInt32)(spec->refreshRate + 0.5))); 940 key = CFDictionaryGetValue(timingIDs, key); 941 } 942 dict = CFDictionaryGetValue(stdModes, key); 943 944 if (!dict) 945 return (kIOReturnUnsupportedMode); 946 data = CFDictionaryGetValue(dict, CFSTR(kIOFBModeTMKey)); 947 if (!data) 948 return (kIOReturnUnsupportedMode); 949 950 TimingToHost( (const IODetailedTimingInformationV2 *) CFDataGetBytePtr(data), &timing->detailedInfo.v2 ); 951 952 timing->appleTimingID = (UInt32) (uintptr_t) key; 953 954 return (kIOReturnSuccess); 955} 956 957static UInt32 958IODisplayGetCVTSyncWidth( UInt32 horizontalActive, UInt32 verticalActive ) 959{ 960 // CVT Table 2 961 enum { 962 kCVTAspect4By3 = 4, 963 kCVTAspect16By9 = 5, 964 kCVTAspect16By10 = 6, 965 kCVTAspect5By4 = 7, 966 kCVTAspect15By9 = 7, 967 kCVTAspectUnknown = 10 968 }; 969 970 float ratio = ((float) horizontalActive) / ((float) verticalActive); 971 972 if (ratioOver(ratio, 4.0 / 3.0) <= 1.03125) 973 return (kCVTAspect4By3); 974 975 if (ratioOver(ratio, 16.0 / 9.0) <= 1.03125) 976 return (kCVTAspect16By9); 977 978 if (ratioOver(ratio, 16.0 / 10.0) <= 1.03125) 979 return (kCVTAspect16By10); 980 981 if (ratioOver(ratio, 5.0 / 4.0) <= 1.03125) 982 return (kCVTAspect5By4); 983 984 if (ratioOver(ratio, 15.0 / 9.0) <= 1.03125) 985 return (kCVTAspect15By9); 986 987 return (kCVTAspectUnknown); 988} 989 990static IOReturn 991GTFToDetailedTiming( IOFBConnectRef connectRef, EDID * edid, 992 IOFBResolutionSpec * spec, UInt32 characterSize, 993 IODetailedTimingInformation * timing ) 994{ 995 float interlace = (kResSpecNeedInterlace & spec->flags) ? 0.5 : 0.0; 996 float interlaceFactor = (kResSpecNeedInterlace & spec->flags) ? 2.0 : 1.0; 997 float fieldRate; // V_FIELD_RATE_RQD 998 float pixelFrequency; // ACT_PIXEL_FREQ 999 int horizontalTotal; // TOTAL_PIXELS 1000 int horizontalActive; // TOTAL_ACTIVE_PIXELS 1001 int horizontalBlanking; // H_BLANK 1002 int horizontalSyncWidth; // H_SYNC_PIXELS 1003 int verticalActive; // V_LINES_RND 1004 int verticalBlanking; // VBI_LINES 1005 int verticalSyncWidth = 3; // V_SYNC_RND 1006 int verticalSyncAndBackPorch; // V_SYNC_BP 1007 int verticalSyncFrontPorch; 1008 // 4,5,15,16. 1009 int topMargin = 0; 1010 int bottomMargin = 0; 1011 int leftMargin = 0; 1012 int rightMargin = 0; 1013 1014 UInt32 horizontalSyncConfig; 1015 UInt32 verticalSyncConfig; 1016 1017 enum { kGTF, kCVT, kCVTRB } genType; 1018 1019 // 1. 1020 fieldRate = spec->refreshRate; // * interlaceFactor; 1021 // 4. 1022 horizontalActive = roundf(spec->width / characterSize) * characterSize 1023 + leftMargin + rightMargin; 1024 // 5. 1025 verticalActive = roundf(spec->height / interlaceFactor); 1026 1027 if (kResSpecReducedBlank & spec->flags) 1028 genType = kCVTRB; 1029 else if (connectRef->gtfDisplay && !connectRef->cvtDisplay) 1030 genType = kGTF; 1031 else 1032 genType = kCVT; 1033 1034 if (kGTF != genType) 1035 verticalSyncWidth = IODisplayGetCVTSyncWidth(horizontalActive, verticalActive * interlaceFactor); 1036 1037 if (kGTF == genType) 1038 { 1039 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * GTF */ 1040 1041 float horizontalSyncPercent = 8.0/100.0; // H_SYNC_PER 1042 float verticalSyncAndBackPorchTime = 550e-6; // MIN_VSYNC_BP 1043 int minVerticalFrontPorch = 1; // MIN_V_PORCH_RND 1044 float estimatedHorizontalPeriod; // H_PERIOD_EST 1045 float verticalFieldTotal; // TOTAL_V_LINES 1046 float estimatedFieldRate; // V_FIELD_RATE_EST 1047 SInt32 curve; 1048 1049 // 7. 1050 estimatedHorizontalPeriod = 1051 ((1 / fieldRate) - verticalSyncAndBackPorchTime) 1052 / (verticalActive + (2 * topMargin) + minVerticalFrontPorch + interlace); 1053 1054 // 8. 1055 verticalSyncAndBackPorch = roundf(verticalSyncAndBackPorchTime / estimatedHorizontalPeriod); 1056 verticalSyncFrontPorch = minVerticalFrontPorch; 1057 verticalBlanking = verticalSyncFrontPorch + verticalSyncAndBackPorch; 1058 1059 // 10. 1060 verticalFieldTotal = verticalActive + topMargin + bottomMargin 1061 + verticalBlanking + interlace; 1062 // 11. 1063 estimatedFieldRate = 1.0 / estimatedHorizontalPeriod / verticalFieldTotal; 1064 1065 // 12. 1066 float hPeriod = estimatedHorizontalPeriod / (fieldRate / estimatedFieldRate); 1067 1068 for (curve = (connectRef->numGTFCurves - 1); curve >= 0; curve--) 1069 { 1070 if ((1 / hPeriod) > connectRef->gtfCurves[curve].startHFrequency) 1071 break; 1072 } 1073 1074 float cPrime = ((((float) connectRef->gtfCurves[curve].c) - ((float) connectRef->gtfCurves[curve].j)) 1075 * ((float) connectRef->gtfCurves[curve].k) / 256.0) 1076 + ((float) connectRef->gtfCurves[curve].j); 1077 float mPrime = ((float) connectRef->gtfCurves[curve].k) / 256.0 * ((float) connectRef->gtfCurves[curve].m); 1078 1079 // 18. 1080 float idealDutyCycle = cPrime - (mPrime * hPeriod * 1e6 / 1000.0); 1081 // 19. 1082 horizontalBlanking = 2 * characterSize * roundf( 1083 (horizontalActive * idealDutyCycle / (100.0 - idealDutyCycle) 1084 / (2 * characterSize))); 1085 1086 // 20. 1087 horizontalTotal = horizontalActive + horizontalBlanking; 1088 // 21. 1089 pixelFrequency = horizontalTotal / hPeriod; 1090 1091 // gtf 2.17. 1092 horizontalSyncWidth = characterSize * 1093 roundf(horizontalSyncPercent * horizontalTotal / characterSize); 1094 1095 horizontalSyncConfig = (curve == 0) ? 0 : kIOSyncPositivePolarity; 1096 verticalSyncConfig = (curve == 0) ? kIOSyncPositivePolarity : 0; 1097 } 1098 else if (kCVT == genType) 1099 { 1100 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * CVT */ 1101 1102 float horizontalSyncPercent = 8.0/100.0; // H_SYNC_PER 1103 float verticalSyncAndBackPorchTime = 550e-6; // MIN_VSYNC_BP 1104 int minVerticalBackPorch = 6; // MIN_VBPORCH 1105 int minVerticalFrontPorch = 3; // MIN_V_PORCH_RND 1106 float estimatedHorizontalPeriod; // H_PERIOD_EST 1107 float verticalFieldTotal; // TOTAL_V_LINES 1108 SInt32 curve = 0; 1109 1110 float cPrime = ((((float) connectRef->gtfCurves[curve].c) - ((float) connectRef->gtfCurves[curve].j)) 1111 * ((float) connectRef->gtfCurves[curve].k) / 256.0) 1112 + ((float) connectRef->gtfCurves[curve].j); 1113 float mPrime = ((float) connectRef->gtfCurves[curve].k) / 256.0 * ((float) connectRef->gtfCurves[curve].m); 1114 1115 // 8. 1116 estimatedHorizontalPeriod = 1117 ((1 / fieldRate) - verticalSyncAndBackPorchTime) 1118 / (verticalActive + (topMargin + bottomMargin) + minVerticalFrontPorch + interlace); 1119 // 9. 1120 1121 verticalSyncAndBackPorch = 1 + truncf(verticalSyncAndBackPorchTime / estimatedHorizontalPeriod); 1122 1123 if (verticalSyncAndBackPorch < (verticalSyncWidth + minVerticalBackPorch)) 1124 verticalSyncAndBackPorch = verticalSyncWidth + minVerticalBackPorch; 1125 1126 // 10. 1127 1128 verticalSyncFrontPorch = minVerticalFrontPorch; 1129 verticalBlanking = verticalSyncFrontPorch + verticalSyncAndBackPorch; 1130 1131 // 11. 1132 verticalFieldTotal = verticalActive + topMargin + bottomMargin 1133 + verticalBlanking + interlace; 1134 // 12. 1135 float idealDutyCycle = cPrime - (mPrime * estimatedHorizontalPeriod * 1e6 / 1000.0); 1136 1137 // 13. 1138 if (idealDutyCycle < 20.0) 1139 idealDutyCycle = 20.0; 1140 1141 horizontalBlanking = 2 * characterSize * truncf( 1142 (horizontalActive * idealDutyCycle / (100.0 - idealDutyCycle) 1143 / (2 * characterSize))); 1144 // 14. 1145 horizontalTotal = horizontalActive + horizontalBlanking; 1146 1147 // 15. 1148 float frequencyStep = 0.25e6; // CLOCK_STEP 1149 pixelFrequency = frequencyStep * truncf( 1150 (horizontalTotal / estimatedHorizontalPeriod) / frequencyStep); 1151 1152 // gtf 2.17. 1153 horizontalSyncWidth = characterSize * truncf( 1154 horizontalSyncPercent * horizontalTotal / characterSize); 1155 1156 horizontalSyncConfig = 0 * kIOSyncPositivePolarity; 1157 verticalSyncConfig = 1 * kIOSyncPositivePolarity; 1158 } 1159 else 1160 { 1161 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * CVT reduced blank */ 1162 1163 float minVerticalBlankTime = 460e-6; // RB_MIN_V_BLANK 1164 int minVerticalBackPorch = 6; // MIN_VBPORCH 1165 float estimatedHorizontalPeriod; // H_PERIOD_EST 1166 verticalSyncFrontPorch = 3; // RB_V_FPORCH 1167 horizontalBlanking = 160; // RB_H_BLANK 1168 horizontalSyncWidth = 32; // RB_H_SYNC 1169 1170 1171 // 8. 1172 estimatedHorizontalPeriod = ((1 / fieldRate) - minVerticalBlankTime) 1173 / (verticalActive + topMargin + bottomMargin); 1174 // 9. 1175 verticalBlanking = truncf(minVerticalBlankTime / estimatedHorizontalPeriod) + 1; // VBI_LINES 1176 1177 // 10. 1178 if (verticalBlanking < (verticalSyncFrontPorch + verticalSyncWidth + minVerticalBackPorch)) 1179 verticalBlanking = (verticalSyncFrontPorch + verticalSyncWidth + minVerticalBackPorch); 1180 1181 verticalSyncAndBackPorch = verticalBlanking - verticalSyncFrontPorch; 1182 1183 // 11. 1184 int verticalFieldTotal = verticalBlanking + verticalActive 1185 + topMargin + bottomMargin + interlace; 1186 1187 // 12. 1188 horizontalTotal = horizontalActive + horizontalBlanking; 1189 1190 // 13. 1191 float frequencyStep = 0.25e6; // CLOCK_STEP 1192 pixelFrequency = frequencyStep * truncf( 1193 (horizontalTotal * verticalFieldTotal * fieldRate) / frequencyStep); 1194 1195 horizontalSyncConfig = 1 * kIOSyncPositivePolarity; 1196 verticalSyncConfig = 0 * kIOSyncPositivePolarity; 1197 } 1198 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 1199 1200 int horizontalSyncOffset = (horizontalBlanking / 2) - horizontalSyncWidth; 1201 1202 // -- 1203 bzero( timing, sizeof(IODetailedTimingInformation) ); 1204 1205 if (edid) 1206 { 1207 timing->signalConfig = (edid->displayParams[0] & 16) 1208 ? kIOAnalogSetupExpected : 0; 1209 timing->signalLevels = (edid->displayParams[0] >> 5) & 3; 1210 } 1211 else 1212 { 1213 timing->signalConfig = kIOAnalogSetupExpected; 1214 timing->signalLevels = kIOAnalogSignalLevel_0700_0300; 1215 } 1216 1217 timing->pixelClock = pixelFrequency; 1218 1219 timing->horizontalActive = horizontalActive; 1220 timing->horizontalBlanking = horizontalBlanking; 1221 1222 timing->verticalActive = verticalActive; 1223 timing->verticalBlanking = verticalBlanking; 1224 1225 timing->horizontalSyncOffset = horizontalSyncOffset; 1226 timing->horizontalSyncPulseWidth = horizontalSyncWidth; 1227 1228 timing->verticalSyncOffset = verticalSyncFrontPorch; 1229 timing->verticalSyncPulseWidth = verticalSyncWidth; 1230 1231 timing->horizontalBorderLeft = leftMargin; 1232 timing->horizontalBorderRight = rightMargin; 1233 timing->verticalBorderTop = topMargin; 1234 timing->verticalBorderBottom = bottomMargin; 1235 1236 timing->horizontalSyncConfig = horizontalSyncConfig; 1237 timing->horizontalSyncLevel = 0; 1238 timing->verticalSyncConfig = verticalSyncConfig; 1239 timing->verticalSyncLevel = 0; 1240 1241 if (kResSpecNeedInterlace & spec->flags) 1242 AdjustTimingForInterlace(timing); 1243 1244 return( kIOReturnSuccess ); 1245} 1246 1247#if RLOG 1248__private_extern__ void 1249IOFBLogRange(IOFBConnectRef connectRef, const IODisplayTimingRange * range) 1250{ 1251 if (!connectRef->logfile || !range) 1252 return; 1253 1254 fprintf(connectRef->logfile, " minPixelClock %qd\n", range->minPixelClock); 1255 fprintf(connectRef->logfile, " maxPixelClock %qd\n", range->maxPixelClock); 1256 1257 fprintf(connectRef->logfile, " maxPixelError %d\n", (int) range->maxPixelError); 1258 fprintf(connectRef->logfile, " supportedSyncFlags %x\n", (int) range->supportedSyncFlags); 1259 fprintf(connectRef->logfile, " supportedSignalLevels %x\n", (int) range->supportedSignalLevels); 1260 fprintf(connectRef->logfile, " supportedSignalConfigs %x\n", (int) range->supportedSignalConfigs); 1261 fprintf(connectRef->logfile, " minFrameRate %d\n", (int) range->minFrameRate); 1262 fprintf(connectRef->logfile, " maxFrameRate %d\n", (int) range->maxFrameRate); 1263 fprintf(connectRef->logfile, " minLineRate %d\n", (int) range->minLineRate); 1264 fprintf(connectRef->logfile, " maxLineRate %d\n", (int) range->maxLineRate); 1265 1266 fprintf(connectRef->logfile, " maxHorizontalTotal %d\n", (int) range->maxHorizontalTotal); 1267 fprintf(connectRef->logfile, " maxVerticalTotal %d\n", (int) range->maxVerticalTotal); 1268 fprintf(connectRef->logfile, " charSizeHorizontalActive %d\n", range->charSizeHorizontalActive); 1269 fprintf(connectRef->logfile, " charSizeHorizontalBlanking %d\n", range->charSizeHorizontalBlanking); 1270 fprintf(connectRef->logfile, " charSizeHorizontalSyncOffset %d\n", range->charSizeHorizontalSyncOffset); 1271 fprintf(connectRef->logfile, " charSizeHorizontalSyncPulse %d\n", range->charSizeHorizontalSyncPulse); 1272 fprintf(connectRef->logfile, " charSizeVerticalActive %d\n", range->charSizeVerticalActive); 1273 fprintf(connectRef->logfile, " charSizeVerticalBlanking %d\n", range->charSizeVerticalBlanking); 1274 fprintf(connectRef->logfile, " charSizeVerticalSyncOffset %d\n", range->charSizeVerticalSyncOffset); 1275 fprintf(connectRef->logfile, " charSizeVerticalSyncPulse %d\n", range->charSizeVerticalSyncPulse); 1276 fprintf(connectRef->logfile, " charSizeHorizontalBorderLeft %d\n", range->charSizeHorizontalBorderLeft); 1277 fprintf(connectRef->logfile, " charSizeHorizontalBorderRight %d\n", range->charSizeHorizontalBorderRight); 1278 fprintf(connectRef->logfile, " charSizeVerticalBorderTop %d\n", range->charSizeVerticalBorderTop); 1279 fprintf(connectRef->logfile, " charSizeVerticalBorderBottom %d\n", range->charSizeVerticalBorderBottom); 1280 fprintf(connectRef->logfile, " charSizeHorizontalTotal %d\n", range->charSizeHorizontalTotal); 1281 fprintf(connectRef->logfile, " charSizeVerticalTotal %d\n", range->charSizeVerticalTotal); 1282 1283 fprintf(connectRef->logfile, " minHorizontalActiveClocks %d\n", (int) range->minHorizontalActiveClocks); 1284 fprintf(connectRef->logfile, " maxHorizontalActiveClocks %d\n", (int) range->maxHorizontalActiveClocks); 1285 fprintf(connectRef->logfile, " minHorizontalBlankingClocks %d\n", (int) range->minHorizontalBlankingClocks); 1286 fprintf(connectRef->logfile, " maxHorizontalBlankingClocks %d\n", (int) range->maxHorizontalBlankingClocks); 1287 fprintf(connectRef->logfile, " minHorizontalSyncOffsetClocks %d\n", (int) range->minHorizontalSyncOffsetClocks); 1288 fprintf(connectRef->logfile, " maxHorizontalSyncOffsetClocks %d\n", (int) range->maxHorizontalSyncOffsetClocks); 1289 fprintf(connectRef->logfile, " minHorizontalPulseWidthClocks %d\n", (int) range->minHorizontalPulseWidthClocks); 1290 fprintf(connectRef->logfile, " maxHorizontalPulseWidthClocks %d\n", (int) range->maxHorizontalPulseWidthClocks); 1291 1292 fprintf(connectRef->logfile, " minVerticalActiveClocks %d\n", (int) range->minVerticalActiveClocks); 1293 fprintf(connectRef->logfile, " maxVerticalActiveClocks %d\n", (int) range->maxVerticalActiveClocks); 1294 fprintf(connectRef->logfile, " minVerticalBlankingClocks %d\n", (int) range->minVerticalBlankingClocks); 1295 fprintf(connectRef->logfile, " maxVerticalBlankingClocks %d\n", (int) range->maxVerticalBlankingClocks); 1296 1297 fprintf(connectRef->logfile, " minVerticalSyncOffsetClocks %d\n", (int) range->minVerticalSyncOffsetClocks); 1298 fprintf(connectRef->logfile, " maxVerticalSyncOffsetClocks %d\n", (int) range->maxVerticalSyncOffsetClocks); 1299 fprintf(connectRef->logfile, " minVerticalPulseWidthClocks %d\n", (int) range->minVerticalPulseWidthClocks); 1300 fprintf(connectRef->logfile, " maxVerticalPulseWidthClocks %d\n", (int) range->maxVerticalPulseWidthClocks); 1301 1302 fprintf(connectRef->logfile, " minHorizontalBorderLeft %d\n", (int) range->minHorizontalBorderLeft); 1303 fprintf(connectRef->logfile, " maxHorizontalBorderLeft %d\n", (int) range->maxHorizontalBorderLeft); 1304 fprintf(connectRef->logfile, " minHorizontalBorderRight %d\n", (int) range->minHorizontalBorderRight); 1305 fprintf(connectRef->logfile, " maxHorizontalBorderRight %d\n", (int) range->maxHorizontalBorderRight); 1306 1307 fprintf(connectRef->logfile, " minVerticalBorderTop %d\n", (int) range->minVerticalBorderTop); 1308 fprintf(connectRef->logfile, " maxVerticalBorderTop %d\n", (int) range->maxVerticalBorderTop); 1309 fprintf(connectRef->logfile, " minVerticalBorderBottom %d\n", (int) range->minVerticalBorderBottom); 1310 fprintf(connectRef->logfile, " maxVerticalBorderBottom %d\n", (int) range->maxVerticalBorderBottom); 1311 1312 fprintf(connectRef->logfile, " maxNumLinks %d\n", (int) range->maxNumLinks); 1313 fprintf(connectRef->logfile, " minLink0PixelClock %d\n", (int) range->minLink0PixelClock); 1314 fprintf(connectRef->logfile, " maxLink0PixelClock %d\n", (int) range->maxLink0PixelClock); 1315 fprintf(connectRef->logfile, " minLink1PixelClock %d\n", (int) range->minLink1PixelClock); 1316 fprintf(connectRef->logfile, " maxLink1PixelClock %d\n", (int) range->maxLink1PixelClock); 1317 1318 fflush(connectRef->logfile); 1319} 1320 1321__private_extern__ void 1322IOFBLogTiming(IOFBConnectRef connectRef, const IOTimingInformation * timing) 1323{ 1324 if (!connectRef->logfile || !timing) 1325 return; 1326 1327 fprintf(connectRef->logfile, " pixelClock %qd\n", timing->detailedInfo.v2.pixelClock); 1328 fprintf(connectRef->logfile, " minPixelClock %qd\n", timing->detailedInfo.v2.minPixelClock); 1329 fprintf(connectRef->logfile, " maxPixelClock %qd\n", timing->detailedInfo.v2.maxPixelClock); 1330 fprintf(connectRef->logfile, " signalConfig %x\n", (int) timing->detailedInfo.v2.signalConfig); 1331 fprintf(connectRef->logfile, " signalLevels %x\n", (int) timing->detailedInfo.v2.signalLevels); 1332 fprintf(connectRef->logfile, " horizontalActive %d\n", (int) timing->detailedInfo.v2.horizontalActive); 1333 fprintf(connectRef->logfile, " horizontalBlanking %d\n", (int) timing->detailedInfo.v2.horizontalBlanking); 1334 fprintf(connectRef->logfile, " horizontalSyncOffset %d\n", (int) timing->detailedInfo.v2.horizontalSyncOffset); 1335 fprintf(connectRef->logfile, " horizontalSyncPulseWidth %d\n", (int) timing->detailedInfo.v2.horizontalSyncPulseWidth); 1336 fprintf(connectRef->logfile, " verticalActive %d\n", (int) timing->detailedInfo.v2.verticalActive); 1337 fprintf(connectRef->logfile, " verticalBlanking %d\n", (int) timing->detailedInfo.v2.verticalBlanking); 1338 fprintf(connectRef->logfile, " verticalSyncOffset %d\n", (int) timing->detailedInfo.v2.verticalSyncOffset); 1339 fprintf(connectRef->logfile, " verticalSyncPulseWidth %d\n", (int) timing->detailedInfo.v2.verticalSyncPulseWidth); 1340 fprintf(connectRef->logfile, " horizontalSyncConfig %d\n", (int) timing->detailedInfo.v2.horizontalSyncConfig); 1341 fprintf(connectRef->logfile, " horizontalSyncLevel %d\n", (int) timing->detailedInfo.v2.horizontalSyncLevel); 1342 fprintf(connectRef->logfile, " verticalSyncConfig %d\n", (int) timing->detailedInfo.v2.verticalSyncConfig); 1343 fprintf(connectRef->logfile, " verticalSyncLevel %d\n", (int) timing->detailedInfo.v2.verticalSyncLevel); 1344 fprintf(connectRef->logfile, " numLinks %d\n", (int) timing->detailedInfo.v2.numLinks); 1345 1346 fprintf(connectRef->logfile, " scalerFlags %x\n", (int) timing->detailedInfo.v2.scalerFlags); 1347 fprintf(connectRef->logfile, " horizontalScaled %d\n", (int) timing->detailedInfo.v2.horizontalScaled); 1348 fprintf(connectRef->logfile, " verticalScaled %d\n", (int) timing->detailedInfo.v2.verticalScaled); 1349 fprintf(connectRef->logfile, " horizontalScaledInset %d\n", (int) timing->detailedInfo.v2.horizontalScaledInset); 1350 fprintf(connectRef->logfile, " verticalScaledInset %d\n", (int) timing->detailedInfo.v2.verticalScaledInset); 1351 1352 fflush(connectRef->logfile); 1353} 1354#endif 1355 1356static void 1357AdjustTimingForRange( IODisplayTimingRange * range, 1358 IODetailedTimingInformation * timing ) 1359{ 1360 if( timing->horizontalSyncPulseWidth % range->charSizeHorizontalSyncPulse) 1361 // digital only? 1362#if 0 1363 // round 1364 timing->horizontalSyncPulseWidth += range->charSizeHorizontalSyncPulse 1365 - (timing->horizontalSyncPulseWidth % range->charSizeHorizontalSyncPulse); 1366#else 1367 // trunc 1368 timing->horizontalSyncPulseWidth -= 1369 (timing->horizontalSyncPulseWidth % range->charSizeHorizontalSyncPulse); 1370#endif 1371} 1372 1373static UInt32 1374GetAssumedPixelRepetition( IODetailedTimingInformation * timing ) 1375{ 1376 if (!(kIOInterlacedCEATiming & timing->signalConfig)) 1377 return (0); 1378 1379 if ((1440 == timing->horizontalActive) 1380 && ((480 == timing->verticalActive) || (576 == timing->verticalActive))) 1381 return (2); 1382 1383 if ((2880 == timing->horizontalActive) 1384 && ((480 == timing->verticalActive) || (576 == timing->verticalActive))) 1385 return (4); // 1 - 10 1386 1387 return (0); 1388} 1389 1390static int 1391CheckTimingWithRange( IOFBConnectRef connectRef __unused, 1392 IODisplayTimingRange * range, IODetailedTimingInformation * timing ) 1393{ 1394 UInt64 pixelClock; 1395 UInt64 rate; 1396 UInt64 hTotal, vTotal; 1397 1398 if( kIODigitalSignal & timing->signalConfig) 1399 return(1); 1400 1401 if ((kIOInterlacedCEATiming & timing->signalConfig) 1402 && !((kIORangeSupportsInterlacedCEATiming | kIORangeSupportsInterlacedCEATimingWithConfirm) 1403 & range->supportedSignalConfigs)) 1404 return(34); 1405 1406 if ((timing->numLinks > 1) 1407 && range->maxNumLinks 1408 && (timing->numLinks > range->maxNumLinks)) 1409 return(35); 1410 1411// if( 0 == (range->supportedSyncFlags & (1 << (timing->signalLevels)))) 1412// return(2); 1413// if( 0 == (range->supportedSignalLevels & (1 << (timing->signalLevels)))) 1414// return(3); 1415 1416 pixelClock = timing->pixelClock; 1417 hTotal = timing->horizontalActive; 1418 hTotal += timing->horizontalBlanking; 1419 vTotal = timing->verticalActive; 1420 vTotal += timing->verticalBlanking; 1421 1422 if (!hTotal || !vTotal) 1423 return(36); 1424 1425 if( (pixelClock > range->maxPixelClock) 1426 || (pixelClock < range->minPixelClock)) 1427 return(4); 1428 1429 // line rate 1430 rate = pixelClock / hTotal; 1431 if( (rate > range->maxLineRate) 1432 || (rate < range->minLineRate)) 1433 return(5); 1434 1435 // frame rate 1436 rate = pixelClock; 1437 if (kIOInterlacedCEATiming & timing->signalConfig) 1438 rate *= 2; 1439 rate /= (hTotal * vTotal); 1440 if( (rate > range->maxFrameRate) 1441 || (rate < range->minFrameRate)) 1442 return(6); 1443 1444 if( hTotal > range->maxHorizontalTotal) 1445 return(7); 1446 if( vTotal > range->maxVerticalTotal) 1447 return(8); 1448 1449 if( (timing->horizontalActive > range->maxHorizontalActiveClocks) 1450 || (timing->horizontalActive < range->minHorizontalActiveClocks)) 1451 return(9); 1452 if( (timing->verticalActive > range->maxVerticalActiveClocks) 1453 || (timing->verticalActive < range->minVerticalActiveClocks)) 1454 return(10); 1455 1456/* 1457 if( (timing->horizontalBlanking > range->maxHorizontalBlankingClocks) 1458 || (timing->horizontalBlanking < range->minHorizontalBlankingClocks)) 1459 return(11); 1460 if( (timing->verticalBlanking > range->maxVerticalBlankingClocks) 1461 || (timing->verticalBlanking < range->minVerticalBlankingClocks)) 1462 return(12); 1463*/ 1464 if( (timing->horizontalSyncOffset > range->maxHorizontalSyncOffsetClocks) 1465 || (timing->horizontalSyncOffset < range->minHorizontalSyncOffsetClocks)) 1466 return(13); 1467 if( (timing->horizontalSyncPulseWidth > range->maxHorizontalPulseWidthClocks) 1468 || (timing->horizontalSyncPulseWidth < range->minHorizontalPulseWidthClocks)) 1469 return(14); 1470 1471 if( (timing->verticalSyncOffset > range->maxVerticalSyncOffsetClocks) 1472 || (timing->verticalSyncOffset < range->minVerticalSyncOffsetClocks)) 1473 return(15); 1474 if( (timing->verticalSyncPulseWidth > range->maxVerticalPulseWidthClocks) 1475 || (timing->verticalSyncPulseWidth < range->minVerticalPulseWidthClocks)) 1476 return(16); 1477 1478 if( (timing->horizontalBorderLeft > range->maxHorizontalBorderLeft) 1479 || (timing->horizontalBorderLeft < range->minHorizontalBorderLeft)) 1480 return(17); 1481 if( (timing->horizontalBorderRight > range->maxHorizontalBorderRight) 1482 || (timing->horizontalBorderRight < range->minHorizontalBorderRight)) 1483 return(18); 1484 if( (timing->verticalBorderTop > range->maxVerticalBorderTop) 1485 || (timing->verticalBorderTop < range->minVerticalBorderTop)) 1486 return(19); 1487 if( (timing->verticalBorderBottom > range->maxVerticalBorderBottom) 1488 || (timing->verticalBorderBottom < range->minVerticalBorderBottom)) 1489 return(20); 1490 1491 if( timing->horizontalActive % range->charSizeHorizontalActive) 1492 return(21); 1493 if( timing->horizontalBlanking % range->charSizeHorizontalBlanking) 1494 return(22); 1495 if( timing->horizontalSyncOffset % range->charSizeHorizontalSyncOffset) 1496 return(23); 1497 if( timing->horizontalSyncPulseWidth % range->charSizeHorizontalSyncPulse) 1498 return(24); 1499 if( timing->verticalActive % range->charSizeVerticalActive) 1500 return(34); 1501 if( timing->verticalBlanking % range->charSizeVerticalBlanking) 1502 return(25); 1503 if( timing->verticalSyncOffset % range->charSizeVerticalSyncOffset) 1504 return(26); 1505 if( timing->verticalSyncPulseWidth % range->charSizeVerticalSyncPulse) 1506 return(27); 1507 if( timing->horizontalBorderLeft % range->charSizeHorizontalBorderLeft) 1508 return(28); 1509 if( timing->horizontalBorderRight % range->charSizeHorizontalBorderRight) 1510 return(29); 1511 if( timing->verticalBorderTop % range->charSizeVerticalBorderTop) 1512 return(30); 1513 if( timing->verticalBorderBottom % range->charSizeVerticalBorderBottom) 1514 return(31); 1515 if( hTotal % range->charSizeHorizontalTotal) 1516 return(32); 1517 if( vTotal % range->charSizeVerticalTotal) 1518 return(33); 1519 1520 return (0); 1521} 1522 1523static Boolean 1524HasEstablishedTiming( IOFBConnectRef connectRef, UInt32 appleTimingID ) 1525{ 1526 CFDataRef data; 1527 UInt32 * establishedIDs; 1528 UInt32 i; 1529 1530 if (kIOTimingIDInvalid == appleTimingID) 1531 return (false); 1532 1533 data = CFDictionaryGetValue(connectRef->iographicsProperties, CFSTR("established-ids")); 1534 if (data) 1535 establishedIDs = (UInt32 *) CFDataGetBytePtr(data); 1536 else 1537 establishedIDs = 0; 1538 1539 for( i = 0; 1540 establishedIDs && (i < 24) && (appleTimingID != OSReadBigInt32(&establishedIDs[i], 0)); 1541 i++ ) {} 1542 1543 return( i < 24 ); 1544} 1545 1546__private_extern__ IOReturn 1547IOCheckTimingWithDisplay( IOFBConnectRef connectRef, 1548 IOFBDisplayModeDescription * desc, 1549 IOOptionBits modeGenFlags ) 1550{ 1551 IOTimingInformation * timing = &desc->timingInfo; 1552 IOReturn result; 1553 CFDataRef edidData; 1554 CFDataRef data; 1555 int diag; 1556 1557 do 1558 { 1559 if (connectRef->fbRange && !(kIOFBDriverMode & modeGenFlags)) 1560 { 1561 AdjustTimingForRange(connectRef->fbRange, &timing->detailedInfo.v2); 1562 1563 if ((diag = CheckTimingWithRange(connectRef, connectRef->fbRange, &timing->detailedInfo.v2))) 1564 { 1565#if RLOG 1566 DEBG(connectRef, "out of cards range(%d) %d x %d\n", diag, 1567 (int) timing->detailedInfo.v2.horizontalActive, 1568 (int) timing->detailedInfo.v2.verticalActive ); 1569 IOFBLogTiming(connectRef, timing); 1570#endif 1571 result = kIOReturnUnsupportedMode; 1572 continue; 1573 } 1574 1575 result = IOFBDriverPreflight(connectRef, desc); 1576 if (kIOReturnSuccess != result) 1577 continue; 1578 } 1579 1580 result = kIOReturnNotFound; 1581 if(!connectRef->overrides) 1582 continue; 1583 1584 if (!(kIOFBEDIDStdEstMode & modeGenFlags)) 1585 { 1586 edidData = CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayEDIDKey)); 1587 if (edidData && HasEstablishedTiming(connectRef, timing->appleTimingID)) 1588 { 1589 result = kIOReturnUnsupportedMode; 1590 continue; 1591 } 1592 } 1593 1594 if (connectRef->hasCEAExt 1595 && !((kIOFBScaledMode | kIOFBEDIDDetailedMode | kIOFBEDIDStdEstMode) & modeGenFlags)) 1596 { 1597 result = kIOReturnUnsupportedMode; 1598 continue; 1599 } 1600 1601 if (kIODetailedTimingValid & timing->flags) 1602 { 1603 CFNumberRef num; 1604 1605 num = CFDictionaryGetValue( connectRef->overrides, CFSTR("sync") ); 1606 if( num) 1607 { 1608 UInt32 hSyncMask, hSyncValue, vSyncMask, vSyncValue; 1609 1610 CFNumberGetValue( num, kCFNumberSInt32Type, &vSyncValue ); 1611 hSyncMask = 0xff & (vSyncValue >> 24); 1612 hSyncValue = 0xff & (vSyncValue >> 16); 1613 vSyncMask = 0xff & (vSyncValue >> 8); 1614 vSyncValue = 0xff & (vSyncValue >> 0); 1615 if ((hSyncValue != (timing->detailedInfo.v2.horizontalSyncConfig & hSyncMask)) 1616 || (vSyncValue != (timing->detailedInfo.v2.verticalSyncConfig & vSyncMask))) 1617 { 1618 result = kIOReturnUnsupportedMode; 1619 continue; 1620 } 1621 } 1622 1623 if ((timing->detailedInfo.v2.numLinks > 1) 1624 && connectRef->maxDisplayLinks 1625 && (timing->detailedInfo.v2.numLinks > connectRef->maxDisplayLinks)) 1626 { 1627#if RLOG 1628 DEBG(connectRef, "out display maxDisplayLinks\n"); 1629 IOFBLogTiming(connectRef, timing); 1630#endif 1631 result = kIOReturnUnsupportedMode; 1632 continue; 1633 } 1634 1635 uint64_t maxClock = 0; 1636 if (connectRef->dpcdData 1637 && ((size_t) CFDataGetLength(connectRef->dpcdData)) >= sizeof(DPCD)) 1638 do 1639 { 1640 const DPCD * dpcd = (typeof(dpcd)) CFDataGetBytePtr(connectRef->dpcdData); 1641 1642 if ((kDownStreamPortDetailed|kDownStreamPortPresent) 1643 != ((kDownStreamPortDetailed|kDownStreamPortPresent) & dpcd->downStreamPortPresent)) 1644 continue; 1645 1646 switch (kDownStreamPortType & dpcd->downstreamPorts.detailed[0].type) 1647 { 1648 case kDownStreamPortTypeHDMI: 1649 case kDownStreamPortTypeDPP: 1650 maxClock = dpcd->downstreamPorts.detailed[0].maxClock; 1651 maxClock *= 2500000ULL; 1652 break; 1653 default: 1654 break; 1655 } 1656 } 1657 while (false); 1658 1659 if (maxClock && (timing->detailedInfo.v2.pixelClock > maxClock)) 1660 { 1661#if RLOG 1662 DEBG(connectRef, "out transport clock(%qd)\n", timing->detailedInfo.v2.pixelClock); 1663 IOFBLogTiming(connectRef, timing); 1664#endif 1665 result = kIOReturnUnsupportedMode; 1666 continue; 1667 } 1668 1669 data = CFDictionaryGetValue(connectRef->overrides, CFSTR("trng")); 1670 if (data && ((kIOFBGTFMode | kIOFBStdMode | kIOFBDriverMode) & modeGenFlags)) 1671 { 1672 if ((diag = CheckTimingWithRange(connectRef, (IODisplayTimingRange *) CFDataGetBytePtr(data), 1673 (IODetailedTimingInformation *) &timing->detailedInfo.v2))) 1674 { 1675#if RLOG 1676 DEBG(connectRef, "out display range(%d)\n", diag); 1677 IOFBLogTiming(connectRef, timing); 1678#endif 1679 result = kIOReturnUnsupportedMode; 1680 continue; 1681 } 1682 if (kIOFBDriverMode & modeGenFlags) 1683 { 1684 if (ratioOver( 1685 ((float) timing->detailedInfo.v2.horizontalActive) 1686 / ((float) timing->detailedInfo.v2.verticalActive), 1687 connectRef->nativeAspect) > 1.2) 1688 { 1689#if RLOG 1690 DEBG(connectRef, "aspect too different\n"); 1691 IOFBLogTiming(connectRef, timing); 1692#endif 1693 continue; 1694 } 1695 } 1696 result = kIOReturnSuccess; 1697 } 1698 } 1699 } 1700 while (false); 1701 1702 return (result); 1703} 1704 1705static kern_return_t 1706InstallTiming( IOFBConnectRef connectRef, 1707 IOFBDisplayModeDescription * desc, 1708 IOOptionBits modeGenFlags ) 1709{ 1710 IOReturn err; 1711 IOOptionBits dmFlags; 1712 IOTimingInformation * timing = &desc->timingInfo; 1713 1714 if (connectRef->dualLinkCrossover) 1715 { 1716 if (timing->detailedInfo.v2.pixelClock > connectRef->dualLinkCrossover) 1717 timing->detailedInfo.v2.numLinks = 2; 1718 else 1719 timing->detailedInfo.v2.numLinks = 1; 1720 } 1721 else 1722 timing->detailedInfo.v2.numLinks = 0; 1723 1724 UpdateTimingInfoForTransform(connectRef, desc, 0); 1725 1726 if (InvalidTiming(connectRef, timing)) 1727 return (kIOReturnUnsupportedMode); 1728 1729 if ((kIOFBEDIDStdEstMode | kIOFBEDIDDetailedMode) & modeGenFlags) 1730 { 1731 if ((0xffffffff == connectRef->dimensions.width) 1732 || (timing->detailedInfo.v2.horizontalActive > connectRef->dimensions.width)) 1733 connectRef->dimensions.width = timing->detailedInfo.v2.horizontalActive; 1734 if ((0xffffffff == connectRef->dimensions.height) 1735 || (timing->detailedInfo.v2.verticalActive > connectRef->dimensions.height)) 1736 connectRef->dimensions.height = timing->detailedInfo.v2.verticalActive; 1737 } 1738 1739 err = IOCheckTimingWithDisplay( connectRef, desc, modeGenFlags ); 1740 if (kIOReturnUnsupportedMode == err) 1741 return( err ); 1742 1743 dmFlags = desc->info.flags; 1744 1745 if (0 == ((kIOFBEDIDStdEstMode | kIOFBEDIDDetailedMode) & modeGenFlags)) 1746 { 1747 if( (timing->detailedInfo.v2.horizontalActive > connectRef->dimensions.width) 1748 || (timing->detailedInfo.v2.verticalActive > connectRef->dimensions.height)) { 1749 dmFlags |= connectRef->dimensions.setFlags; 1750 dmFlags &= ~connectRef->dimensions.clearFlags; 1751 } 1752 if (kIOReturnSuccess != err) 1753 dmFlags &= ~kDisplayModeSafeFlag; 1754 } 1755 1756 if (timing->detailedInfo.v2.signalConfig & kIOInterlacedCEATiming) 1757 { 1758 dmFlags |= (kDisplayModeInterlacedFlag /*| kDisplayModeTelevisionFlag*/); 1759 if (connectRef->fbRange && (kIORangeSupportsInterlacedCEATimingWithConfirm & connectRef->fbRange->supportedSignalConfigs)) 1760 dmFlags &= ~kDisplayModeSafeFlag; 1761 } 1762 1763 desc->info.flags = dmFlags; 1764 1765 err = IOFBInstallMode( connectRef, 0xffffffff, desc, 0, modeGenFlags ); 1766 1767#if RLOG 1768 if (timing->detailedInfo.v2.signalConfig & kIOInterlacedCEATiming) 1769 { 1770 DEBG(connectRef, "interlaced: %x\n", (int) modeGenFlags); 1771 IOFBLogTiming(connectRef, timing); 1772 } 1773#endif 1774 1775 return( err ); 1776} 1777 1778static kern_return_t 1779InstallFromCEAShortVideoDesc( IOFBConnectRef connectRef, UInt8 * bytes ) 1780{ 1781 IOReturn err = kIOReturnSuccess; 1782 int length; 1783 int offset; 1784 IOOptionBits flags; 1785 uint8_t code; 1786 CFArrayRef array; 1787 CFDataRef data; 1788 1789 IOFBDisplayModeDescription modeDesc; 1790 IOTimingInformation * timing = &modeDesc.timingInfo; 1791 1792 array = CFDictionaryGetValue( gIOGraphicsProperties, CFSTR("cea-modes") ); 1793 if (!array) return (kIOReturnUnsupported); 1794 1795 bzero( &modeDesc, sizeof( modeDesc )); 1796 timing->flags = kIODetailedTimingValid; 1797 1798 length = (bytes[0] & 0x1f); 1799 for (offset = 1; offset < (length + 1); offset++) 1800 { 1801 code = bytes[offset] & 0x7F; 1802 if (code >= CFArrayGetCount(array)) continue; 1803 data = CFArrayGetValueAtIndex(array, code); 1804 if (CFDataGetTypeID() != CFGetTypeID(data)) continue; 1805 if (CFDataGetLength(data) != sizeof(timing->detailedInfo.v2)) continue; 1806 CFDataGetBytes(data, CFRangeMake(0, sizeof(timing->detailedInfo.v2)), 1807 (UInt8 *) &timing->detailedInfo.v2); 1808 1809 flags = kDisplayModeValidFlag | kDisplayModeSafeFlag; 1810 if (false && connectRef->hasHDMI && (bytes[offset] & 0x80)) 1811 flags |= kDisplayModeDefaultFlag; 1812 1813 // If VIC code is between 1 and 64 and the most significant bit is 1, 1814 // then this is a native mode 1815 if ((bytes[offset] >= 129) && (bytes[offset] <= 192)) 1816 flags |= kDisplayModeNativeFlag; 1817 1818 modeDesc.info.flags = flags; 1819 err = InstallTiming( connectRef, &modeDesc, kIOFBEDIDDetailedMode ); 1820 } 1821 1822 return err; 1823} 1824 1825static kern_return_t 1826InstallFromHDMIVIC( IOFBConnectRef connectRef, uint32_t count, uint8_t * vics ) 1827{ 1828 IOReturn err = kIOReturnSuccess; 1829 uint32_t idx; 1830 uint8_t code; 1831 IOOptionBits flags; 1832 CFArrayRef array; 1833 CFDataRef data; 1834 1835 IOFBDisplayModeDescription modeDesc; 1836 IOTimingInformation * timing = &modeDesc.timingInfo; 1837 1838 array = CFDictionaryGetValue( gIOGraphicsProperties, CFSTR("hdmi-vic-modes") ); 1839 if (!array) return (kIOReturnUnsupported); 1840 1841 bzero( &modeDesc, sizeof( modeDesc )); 1842 timing->flags = kIODetailedTimingValid; 1843 1844 for (idx = 0; idx < count; idx++) 1845 { 1846 code = vics[idx]; 1847 if (code > CFArrayGetCount(array)) continue; 1848 data = CFArrayGetValueAtIndex(array, code); 1849 if (CFDataGetTypeID() != CFGetTypeID(data)) continue; 1850 if (CFDataGetLength(data) != sizeof(timing->detailedInfo.v2)) continue; 1851 CFDataGetBytes(data, CFRangeMake(0, sizeof(timing->detailedInfo.v2)), 1852 (UInt8 *) &timing->detailedInfo.v2); 1853 flags = kDisplayModeValidFlag | kDisplayModeSafeFlag; 1854 modeDesc.info.flags = flags; 1855 err = InstallTiming( connectRef, &modeDesc, kIOFBEDIDDetailedMode ); 1856 } 1857 1858 return err; 1859} 1860 1861static kern_return_t 1862InstallFromEDIDDesc( IOFBConnectRef connectRef, 1863 EDID * edid, EDIDDetailedTimingDesc * desc, 1864 IOOptionBits dmFlags) 1865{ 1866 IOReturn err; 1867 UInt32 pixelRep; 1868 IOFBDisplayModeDescription modeDesc; 1869 IOTimingInformation * timing = &modeDesc.timingInfo; 1870 1871 bzero( &modeDesc, sizeof( modeDesc )); 1872 timing->flags = kIODetailedTimingValid; 1873 1874 err = EDIDDescToDetailedTiming( edid, desc, (IODetailedTimingInformation *) &timing->detailedInfo.v2 ); 1875 if( kIOReturnSuccess != err) 1876 return (err); 1877 1878 if ((connectRef->defaultIndex != -1) 1879 && !bcmp(desc, &edid->descriptors[connectRef->defaultIndex].timing, 1880 sizeof(EDIDDetailedTimingDesc))) 1881 { 1882 DEBG(connectRef, "edid default\n"); 1883 dmFlags |= kDisplayModeDefaultFlag; 1884 } 1885 if (kIOInterlacedCEATiming & timing->detailedInfo.v2.signalConfig) 1886 { 1887 connectRef->hasInterlaced = true; 1888 DEBG(connectRef, "hasInterlaced\n"); 1889 } 1890#if 1 1891 // internal reduced blank timing switch 1892 else if ( 1893 (kDisplayModeDefaultFlag & dmFlags) 1894 && connectRef->fbRange 1895 && CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayIsDigitalKey)) 1896 && ((timing->detailedInfo.v2.pixelClock > connectRef->fbRange->maxPixelClock) 1897 || (connectRef->fbRange->maxLink0PixelClock 1898 && (timing->detailedInfo.v2.pixelClock > (connectRef->fbRange->maxLink0PixelClock * 1000ULL))))) 1899 { 1900 IOTimingInformation _newTiming; 1901 IOTimingInformation * newTiming = &_newTiming; 1902 IOFBResolutionSpec spec; 1903 1904 spec.timingID = kIOTimingIDInvalid; 1905 spec.width = timing->detailedInfo.v2.horizontalActive; 1906 spec.height = timing->detailedInfo.v2.verticalActive; 1907 spec.refreshRate = RefreshRateFromDetailedTiming( &timing->detailedInfo.v2 ); 1908 spec.flags = kResSpecInternalReducedBlank; 1909 1910 err = StandardResolutionToDetailedTiming( connectRef, edid, &spec, newTiming ); 1911 if (kIOReturnSuccess == err) 1912 { 1913#if RLOG 1914 DEBG(connectRef, "switching:\n"); 1915 IOFBLogTiming(connectRef, timing); 1916#endif 1917 timing->detailedInfo.v2.pixelClock = newTiming->detailedInfo.v2.pixelClock; 1918 timing->detailedInfo.v2.maxPixelClock = newTiming->detailedInfo.v2.pixelClock; 1919 timing->detailedInfo.v2.minPixelClock = newTiming->detailedInfo.v2.pixelClock; 1920 timing->detailedInfo.v2.horizontalActive = newTiming->detailedInfo.v2.horizontalActive; 1921 timing->detailedInfo.v2.horizontalBlanking = newTiming->detailedInfo.v2.horizontalBlanking; 1922 timing->detailedInfo.v2.verticalActive = newTiming->detailedInfo.v2.verticalActive; 1923 timing->detailedInfo.v2.verticalBlanking = newTiming->detailedInfo.v2.verticalBlanking; 1924 timing->detailedInfo.v2.horizontalSyncOffset = newTiming->detailedInfo.v2.horizontalSyncOffset; 1925 timing->detailedInfo.v2.horizontalSyncPulseWidth = newTiming->detailedInfo.v2.horizontalSyncPulseWidth; 1926 timing->detailedInfo.v2.verticalSyncOffset = newTiming->detailedInfo.v2.verticalSyncOffset; 1927 timing->detailedInfo.v2.verticalSyncPulseWidth = newTiming->detailedInfo.v2.verticalSyncPulseWidth; 1928 timing->detailedInfo.v2.horizontalBorderLeft = newTiming->detailedInfo.v2.horizontalBorderLeft; 1929 timing->detailedInfo.v2.horizontalBorderRight = newTiming->detailedInfo.v2.horizontalBorderRight; 1930 timing->detailedInfo.v2.verticalBorderTop = newTiming->detailedInfo.v2.verticalBorderTop; 1931 timing->detailedInfo.v2.verticalBorderBottom = newTiming->detailedInfo.v2.verticalBorderBottom; 1932#if RLOG 1933 DEBG(connectRef, "switching to:\n"); 1934 IOFBLogTiming(connectRef, timing); 1935#endif 1936 } 1937 } 1938#endif 1939 1940 if ((pixelRep = GetAssumedPixelRepetition((IODetailedTimingInformation *) &timing->detailedInfo.v2))) 1941 { 1942 enum { kNeedFeatures = (kIOScaleCanUpSamplePixels | kIOScaleCanScaleInterlaced) }; 1943 1944 if (2 != pixelRep || !connectRef->scalerInfo) 1945 return (kIOReturnUnsupported); 1946 1947 if (kNeedFeatures != (kNeedFeatures & connectRef->scalerInfo->scalerFeatures)) 1948 return (kIOReturnUnsupported); 1949 1950 if (timing->detailedInfo.v2.verticalActive > connectRef->scalerInfo->maxVerticalPixels) 1951 return (kIOReturnUnsupported); 1952 if ((timing->detailedInfo.v2.horizontalActive >> 1) > connectRef->scalerInfo->maxHorizontalPixels) 1953 return (kIOReturnUnsupported); 1954 1955 timing->detailedInfo.v2.scalerFlags = kIOScaleStretchToFit; 1956 timing->detailedInfo.v2.horizontalScaled = timing->detailedInfo.v2.horizontalActive >> 1; 1957 timing->detailedInfo.v2.verticalScaled = timing->detailedInfo.v2.verticalActive; 1958#if RLOG 1959 DEBG(connectRef, "pixel rep: %d\n", (int) pixelRep); 1960 IOFBLogTiming(connectRef, timing); 1961#endif 1962 } 1963 1964 uint16_t imageWidth = desc->horizImageSize | ((desc->imageSizeHigh & 0xf0) << 4); 1965 uint16_t imageHeight = desc->verticalImageSize | ((desc->imageSizeHigh & 0x0f) << 8); 1966 1967 // sanity checks against display size 1968 if (imageWidth && connectRef->displayImageWidth) 1969 { 1970 if (((8 * imageWidth) < (5 * connectRef->displayImageWidth)) 1971 || (imageWidth > (connectRef->displayImageWidth + 9))) 1972 { 1973 imageWidth = 0; 1974 } 1975 } 1976 if (imageHeight && connectRef->displayImageHeight) 1977 { 1978 if (((8 * imageHeight) < (5 * connectRef->displayImageHeight)) 1979 || (imageHeight > (connectRef->displayImageHeight + 9))) 1980 { 1981 imageHeight = 0; 1982 } 1983 } 1984 1985 if ((!imageWidth) || (!imageHeight)) imageWidth = imageHeight = 0; 1986 1987 if (!connectRef->defaultWidth) 1988 { 1989 // this mode is default 1990 connectRef->defaultWidth = timing->detailedInfo.v2.horizontalActive; 1991 connectRef->defaultHeight = timing->detailedInfo.v2.verticalActive; 1992 connectRef->defaultImageWidth = imageWidth; 1993 connectRef->defaultImageHeight = imageHeight; 1994 if (!imageWidth) 1995 { 1996 imageWidth = connectRef->displayImageWidth; 1997 imageHeight = connectRef->displayImageHeight; 1998 } 1999 } 2000 modeDesc.info.imageWidth = imageWidth; 2001 modeDesc.info.imageHeight = imageHeight; 2002 modeDesc.info.flags = dmFlags; 2003 err = InstallTiming( connectRef, &modeDesc, kIOFBEDIDDetailedMode ); 2004 2005 return( err ); 2006} 2007 2008static kern_return_t 2009InstallFromTimingOverride( IOFBConnectRef connectRef, 2010 IODetailedTimingInformation * desc, 2011 IOOptionBits dmFlags) 2012{ 2013 IOReturn err; 2014 IOFBDisplayModeDescription modeDesc; 2015 IOTimingInformation * timing = &modeDesc.timingInfo; 2016 2017 bzero( &modeDesc, sizeof( modeDesc )); 2018 timing->flags = kIODetailedTimingValid; 2019 2020 TimingToHost( desc, &timing->detailedInfo.v2 ); 2021 2022 if (!connectRef->defaultWidth) 2023 { 2024 connectRef->defaultWidth = timing->detailedInfo.v2.horizontalActive; 2025 connectRef->defaultHeight = timing->detailedInfo.v2.verticalActive; 2026 // doh!: 2027 connectRef->defaultImageWidth = timing->detailedInfo.v2.horizontalActive; 2028 connectRef->defaultImageHeight = timing->detailedInfo.v2.verticalActive; 2029 } 2030 modeDesc.info.flags = dmFlags; 2031 err = InstallTiming( connectRef, &modeDesc, kIOFBEDIDDetailedMode ); 2032 2033 return( err ); 2034} 2035 2036static IOReturn 2037InstallTimingForResolution( IOFBConnectRef connectRef, EDID * edid, 2038 IOFBResolutionSpec * spec, 2039 IOOptionBits dmFlags, IOOptionBits modeGenFlags ) 2040{ 2041 IOReturn err; 2042 CFNumberRef num; 2043 IOFBDisplayModeDescription modeDesc; 2044 IOTimingInformation * timing = &modeDesc.timingInfo; 2045 bool isDigital; 2046 2047 bzero( &modeDesc, sizeof( modeDesc )); 2048 timing->flags = kIODetailedTimingValid; 2049 2050 do 2051 { 2052 err = StandardResolutionToDetailedTiming( connectRef, edid, spec, timing ); 2053 2054 DEBG(connectRef, "%s std-mode for %dx%d@%d, id %d, genFlags 0x%x\n", 2055 (kIOReturnSuccess == err) ? "Have" : "No", 2056 (int) spec->width, (int) spec->height, (int)(spec->refreshRate + 0.5), 2057 (int) timing->appleTimingID, (int) modeGenFlags); 2058 2059 isDigital = (connectRef->overrides 2060 && CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayIsDigitalKey))); 2061 2062 if (kIOReturnSuccess == err) 2063 { 2064 if (kIOFBGTFMode & modeGenFlags) 2065 { 2066 modeGenFlags = kIOFBStdMode; 2067 dmFlags = kDisplayModeValidFlag; 2068 } 2069 } 2070 else 2071 { 2072 if (!(kIOFBCVTEstMode & modeGenFlags) 2073#if GTF_ON_TV 2074 && !(connectRef->hasInterlaced) 2075#endif 2076 && isDigital) 2077 { 2078 err = kIOReturnUnsupportedMode; 2079 continue; 2080 } 2081 err = GTFToDetailedTiming( connectRef, edid, spec, 8, 2082 (IODetailedTimingInformation *) &timing->detailedInfo.v2 ); 2083 2084 if( kIOReturnSuccess != err) 2085 continue; 2086 } 2087 2088 if( connectRef->overrides 2089 && (num = CFDictionaryGetValue( connectRef->overrides, CFSTR("sync") ))) 2090 { 2091 UInt32 hSyncMask, hSyncValue, vSyncMask, vSyncValue; 2092 2093 CFNumberGetValue( num, kCFNumberSInt32Type, &vSyncValue ); 2094 hSyncMask = 0xff & (vSyncValue >> 24); 2095 hSyncValue = 0xff & (vSyncValue >> 16); 2096 vSyncMask = 0xff & (vSyncValue >> 8); 2097 vSyncValue = 0xff & (vSyncValue >> 0); 2098 if ((hSyncValue != (timing->detailedInfo.v2.horizontalSyncConfig & hSyncMask)) 2099 || (vSyncValue != (timing->detailedInfo.v2.verticalSyncConfig & vSyncMask))) 2100 { 2101 err = kIOReturnUnsupportedMode; 2102 continue; 2103 } 2104 } 2105 modeDesc.info.flags = dmFlags; 2106 err = InstallTiming( connectRef, &modeDesc, modeGenFlags ); 2107 } 2108 while (false); 2109 2110 DEBG(connectRef, "%x\n", err); 2111 2112 return (err); 2113} 2114 2115static IOReturn 2116InstallGTFResolution( IOFBConnectRef connectRef, EDID * edid, 2117 float h, float v ) 2118{ 2119 IOReturn err = kIOReturnSuccess; 2120 CFArrayRef array; 2121 CFTypeRef obj; 2122 CFIndex count, i; 2123 IOOptionBits dmFlags; 2124 IOFBResolutionSpec spec; 2125 UInt32 width = (UInt32) h; 2126 UInt32 height = (UInt32) v; // rounding? 2127 2128 memset(&spec, 0, sizeof(spec)); 2129 if (width > connectRef->dimensions.width) 2130 return (kIOReturnNoSpace); 2131 if (height > connectRef->dimensions.height) 2132 return (kIOReturnNoSpace); 2133 2134 array = CFDictionaryGetValue( connectRef->iographicsProperties, CFSTR("gtf-refresh-rates") ); 2135 count = array ? CFArrayGetCount(array) : 0; 2136 2137 dmFlags = kDisplayModeValidFlag; 2138 if (connectRef->gtfDisplay) 2139 dmFlags |= kDisplayModeSafeFlag; 2140 if( !connectRef->gtfDisplay || (ratioOver(connectRef->nativeAspect, h / v) > 1.03125)) 2141 dmFlags |= kDisplayModeNotPresetFlag; 2142 2143 spec.width = width; 2144 spec.height = height; 2145 spec.flags = 0; 2146 if (connectRef->supportsReducedBlank) 2147 spec.flags |= kResSpecReducedBlank; 2148 2149 for (i = 0; i < count; i++) 2150 { 2151 obj = CFArrayGetValueAtIndex(array, i); 2152 if( CFNumberGetTypeID() != CFGetTypeID(obj)) 2153 continue; 2154 CFNumberGetValue( (CFNumberRef) obj, kCFNumberFloatType, &spec.refreshRate ); 2155 2156 err = InstallTimingForResolution( connectRef, edid, 2157 &spec, dmFlags, kIOFBGTFMode ); 2158 2159 if ((kIOReturnSuccess != err) 2160 && connectRef->hasInterlaced) 2161 { 2162 spec.flags |= kResSpecNeedInterlace; 2163 err = InstallTimingForResolution( connectRef, edid, 2164 &spec, dmFlags, kIOFBGTFMode ); 2165 spec.flags &= ~kResSpecNeedInterlace; 2166 } 2167 } 2168 2169 return (err); 2170} 2171 2172static void 2173InstallStandardEstablishedTiming( 2174 IOFBConnectRef connectRef, EDID * edid, 2175 IOFBResolutionSpec * spec ) 2176 2177{ 2178 InstallTimingForResolution( connectRef, edid, spec, 2179 kDisplayModeValidFlag | kDisplayModeSafeFlag, kIOFBEDIDStdEstMode ); 2180} 2181 2182static void 2183InstallStandardEstablishedTimings( IOFBConnectRef connectRef, EDID * edid ) 2184{ 2185 CFDataRef data; 2186 IOFBResolutionSpec spec; 2187 UInt32 * establishedIDs; 2188 UInt32 i; 2189 2190 memset(&spec, 0, sizeof(spec)); 2191 2192 data = CFDictionaryGetValue(connectRef->iographicsProperties, CFSTR("established-ids")); 2193 if (data) 2194 establishedIDs = (UInt32 *) CFDataGetBytePtr(data); 2195 else 2196 establishedIDs = 0; 2197 2198 spec.flags = 0; 2199 2200 for( i = 7; establishedIDs && (i < 24); i++ ) 2201 { 2202 if (0 != (edid->establishedTimings[ 2 - (i / 8) ] & (1 << (i % 8)))) 2203 { 2204 spec.timingID = OSReadBigInt32(&establishedIDs[i], 0); 2205 if (spec.timingID != kIOTimingIDInvalid) 2206 InstallStandardEstablishedTiming(connectRef, edid, &spec); 2207 } 2208 } 2209 2210 for( i = 0; i < 8; i++ ) 2211 { 2212 spec.timingID = kIOTimingIDInvalid; 2213 if (kIOReturnSuccess != DecodeStandardTiming(edid, OSReadBigInt16(&edid->standardTimings[i], 0), 2214 &spec.width, &spec.height, &spec.refreshRate)) 2215 continue; 2216 InstallStandardEstablishedTiming(connectRef, edid, &spec); 2217 } 2218} 2219 2220static void 2221InstallCVTStandardTimings( IOFBConnectRef connectRef, EDID * edid ) 2222{ 2223 EDIDGeneralDesc * desc; 2224 CFDataRef data; 2225 CFArrayRef array; 2226 CFIndex i, count; 2227 IOFBResolutionSpec spec; 2228 UInt8 * bits; 2229 2230 memset(&spec, 0, sizeof(spec)); 2231 2232 connectRef->gtfDisplay = (0 != (edid->featureSupport & 1)); 2233 2234 data = CFDictionaryGetValue(connectRef->overrides, CFSTR("drng")); 2235 if (!data) 2236 return; 2237 desc = (EDIDGeneralDesc *) CFDataGetBytePtr(data); 2238 2239 if (0x04 == desc->data[5]) 2240 { 2241 connectRef->cvtDisplay = true; 2242 connectRef->gtfDisplay = true; 2243 } 2244 2245 if (!connectRef->cvtDisplay) 2246 return; 2247 2248 array = CFDictionaryGetValue(connectRef->iographicsProperties, CFSTR("cvt-established-ids")); 2249 if (!array) 2250 return; 2251 2252 count = CFArrayGetCount(array); 2253 if (count > (7 * 8)) 2254 count = 7 * 8; 2255 bits = &desc->data[6]; 2256 for (i = 0; i < count; i++) 2257 { 2258 if (0 != (bits[i / 8] & (0x80 >> (i % 8)))) 2259 { 2260 UInt32 * rec; 2261 CFIndex num; 2262 2263 data = CFArrayGetValueAtIndex(array, i); 2264 rec = (UInt32 *) CFDataGetBytePtr(data); 2265 num = CFDataGetLength(data) / sizeof(UInt32); 2266 if (num < 4) 2267 continue; 2268 2269 spec.width = OSReadBigInt32(rec, 0); 2270 spec.height = OSReadBigInt32(rec, 4); 2271 spec.refreshRate = OSReadBigInt32(rec, 8); 2272 spec.flags = OSReadBigInt32(rec, 12); 2273 if (num >= 5) 2274 spec.timingID = OSReadBigInt32(rec, 16); 2275 else 2276 spec.timingID = kIOTimingIDInvalid; 2277 2278 connectRef->supportsReducedBlank |= (0 != (kResSpecReducedBlank & spec.flags)); 2279 2280 InstallTimingForResolution(connectRef, edid, &spec, 2281 kDisplayModeValidFlag | kDisplayModeSafeFlag, kIOFBCVTEstMode); 2282 } 2283 } 2284} 2285 2286static Boolean 2287IODisplayConsiderAspect( float w, float h, float * aspectWidth, float * aspectHeight ) 2288{ 2289 float ratio; 2290 2291 if (!w || !h) 2292 return (false); 2293 2294 ratio = w / h; 2295 2296 if ((ratio > 1.85) || (ratio < 1.2)) 2297 { 2298 *aspectWidth = w; 2299 *aspectHeight = h; 2300 return (true); 2301 } 2302 2303 if (ratio > 1.65) 2304 { 2305 *aspectWidth = 16.0; 2306 *aspectHeight = 9.0; 2307 return (true); 2308 } 2309 2310 if (ratio > 1.55) 2311 { 2312 *aspectWidth = 16.0; 2313 *aspectHeight = 10.0; 2314 return (true); 2315 } 2316 2317 if (ratio > 1.45) 2318 { 2319 *aspectWidth = 3.0; 2320 *aspectHeight = 2.0; 2321 return (true); 2322 } 2323 2324 return (false); 2325} 2326 2327static void 2328IODisplayGetAspect( IOFBConnectRef connectRef ) 2329{ 2330 CFDictionaryRef ovr; 2331 CFNumberRef imageH, imageV; 2332 float aspectWidth, aspectHeight; 2333 float w, h; 2334 2335 aspectWidth = 4.0; 2336 aspectHeight = 3.0; 2337 2338 ovr = connectRef->overrides; 2339 do 2340 { 2341 if (IODisplayConsiderAspect(connectRef->defaultWidth, connectRef->defaultHeight, 2342 &aspectWidth, &aspectHeight)) 2343 break; 2344 2345 if (IODisplayConsiderAspect(connectRef->defaultImageWidth, connectRef->defaultImageHeight, 2346 &aspectWidth, &aspectHeight)) 2347 break; 2348 2349 if( ovr) 2350 { 2351 imageH = CFDictionaryGetValue( ovr, CFSTR(kDisplayHorizontalImageSize) ); 2352 imageV = CFDictionaryGetValue( ovr, CFSTR(kDisplayVerticalImageSize) ); 2353 if (imageH && imageV) 2354 { 2355 CFNumberGetValue( imageH, kCFNumberFloatType, &w ); 2356 CFNumberGetValue( imageV, kCFNumberFloatType, &h ); 2357 if (IODisplayConsiderAspect(w, h, &aspectWidth, &aspectHeight)) 2358 break; 2359 } 2360 } 2361 } 2362 while (false); 2363 2364 connectRef->nativeAspect = aspectWidth / aspectHeight; 2365} 2366 2367 2368static kern_return_t 2369InstallGTFTimings( IOFBConnectRef connectRef, EDID * edid ) 2370{ 2371 IOReturn err = kIOReturnSuccess; 2372 CFArrayRef array; 2373 CFIndex i, count; 2374 CFStringRef key; 2375 float h, v, nativeAspect; 2376 Boolean wide, displayNot4By3; 2377 2378 // arb timings 2379 2380 nativeAspect = connectRef->nativeAspect; 2381 wide = (nativeAspect > 1.45); 2382 displayNot4By3 = (ratioOver(nativeAspect, 4.0 / 3.0) > 1.03125); 2383 2384 key = wide ? CFSTR("gtf-resolutions-wide") : CFSTR("gtf-resolutions"); 2385 array = CFDictionaryGetValue( connectRef->iographicsProperties, key ); 2386 count = array ? CFArrayGetCount(array) : 0; 2387 2388 for( i = 0; i < count; i++) 2389 { 2390 CFTypeRef obj; 2391 2392 obj = CFArrayGetValueAtIndex(array, i); 2393 if( CFNumberGetTypeID() == CFGetTypeID(obj)) { 2394 SInt32 value; 2395 CFNumberGetValue( (CFNumberRef) obj, kCFNumberSInt32Type, &value ); 2396 h = (float) (value & 0xffff); 2397 v = (float) (value >> 16); 2398 2399 } else 2400 continue; 2401 2402 if (v) 2403 { 2404 err = InstallGTFResolution( connectRef, edid, h, v ); 2405 } 2406 else 2407 { 2408 if (displayNot4By3) 2409 { 2410 err = InstallGTFResolution( connectRef, edid, h, (h * 3.0) / 4.0 ); 2411 } 2412 err = InstallGTFResolution( connectRef, edid, h, h / nativeAspect ); 2413 } 2414 } 2415 2416 return( err ); 2417} 2418 2419static void 2420InstallDIEXT( IOFBConnectRef connectRef, EDID *edid __unused, DIEXT * ext, Boolean installModes ) 2421{ 2422 UInt16 minPixelClockPerLink, maxPixelClockPerLink, crossover; 2423 2424 if (installModes) 2425 return; 2426 2427 minPixelClockPerLink = ext->minPixelClockPerLink; 2428 maxPixelClockPerLink = (ext->maxPixelClockPerLink[1] << 16) | ext->maxPixelClockPerLink[0]; 2429 crossover = (ext->crossoverFreq[1] << 16) | ext->crossoverFreq[0]; 2430 2431 if ((3 == ext->standardSupported) || (4 == ext->standardSupported)) 2432 { 2433 connectRef->dualLinkCrossover = ((UInt64) crossover) * 1000000ULL; 2434 connectRef->maxDisplayLinks = 2; 2435 } 2436 else 2437 connectRef->maxDisplayLinks = 1; 2438 2439 switch (ext->dataFormats) 2440 { 2441 case 0x24: 2442 case 0x48: 2443 connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayRGBColorComponentBits8; 2444 break; 2445 case 0x49: 2446 connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayRGBColorComponentBits16; 2447 break; 2448 } 2449 2450 DEBG(connectRef, "(%d) minPixelClockPerLink %d, maxPixelClockPerLink %d, cross %qd\n", 2451 ext->standardSupported, 2452 minPixelClockPerLink, maxPixelClockPerLink, connectRef->dualLinkCrossover); 2453} 2454 2455static void 2456InstallVTBEXT( IOFBConnectRef connectRef, EDID * edid, VTBEXT * ext, Boolean installModes ) 2457{ 2458 IOByteCount offset = 0; 2459 IOItemCount idx, count; 2460 IOFBResolutionSpec spec; 2461 Boolean malformed = false; 2462 2463 if (!installModes) 2464 return; 2465 2466 do 2467 { 2468 count = ext->numDetailedTimings; 2469 for (idx = 0; idx < count; idx++) 2470 { 2471 malformed = (offset > (sizeof(ext->data) - sizeof(EDIDDetailedTimingDesc))); 2472 if (malformed) 2473 break; 2474 InstallFromEDIDDesc( connectRef, 2475 edid, (EDIDDetailedTimingDesc *) &ext->data[offset], 2476 kDisplayModeValidFlag | kDisplayModeSafeFlag ); 2477 offset += sizeof(EDIDDetailedTimingDesc); 2478 } 2479 if (malformed) 2480 break; 2481 2482 // -- 2483 count = ext->numCVTTimings; 2484 for (idx = 0; idx < count; idx++) 2485 { 2486 SInt32 refreshBit; 2487 UInt32 vsize; 2488 VTBCVTTimingDesc * desc; 2489 static const UInt32 cvtRefreshRates[] = { 60, 85, 75, 60, 50 }; 2490 2491 malformed = (offset > (sizeof(ext->data) - sizeof(VTBCVTTimingDesc))); 2492 if (malformed) 2493 break; 2494 2495 desc = (VTBCVTTimingDesc *) &ext->data[offset]; 2496 vsize = ((desc->verticalSizeHigh & 0xf0) << 4) | desc->verticalSize; 2497 vsize = 2 * (vsize + 1); 2498 spec.height = vsize; 2499 switch (kVTBCVTAspectRatioMask & desc->verticalSizeHigh) 2500 { 2501 case kVTBCVTAspectRatio16By10: 2502 spec.width = (vsize * 16) / 10; 2503 break; 2504 case kVTBCVTAspectRatio16By9: 2505 spec.width = (vsize * 16) / 9; 2506 break; 2507 case kVTBCVTAspectRatio4By3: 2508 default: 2509 spec.width = (vsize * 4) / 3; 2510 break; 2511 } 2512 spec.timingID = kIOTimingIDInvalid; 2513 spec.width &= ~7; 2514 for (refreshBit = 4; refreshBit >= 0; refreshBit--) 2515 { 2516 if ((1 << refreshBit) & desc->refreshRates) 2517 { 2518 spec.refreshRate = cvtRefreshRates[refreshBit]; 2519 spec.flags = (kVTBCVTRefresh60RBlank == (1 << refreshBit)) ? kResSpecReducedBlank : kNilOptions; 2520 InstallTimingForResolution(connectRef, edid, &spec, 2521 kDisplayModeValidFlag | kDisplayModeSafeFlag, kIOFBCVTEstMode); 2522 DEBG(connectRef, "VTB cvt: %dx%d @ %f (%x)\n", 2523 (int) spec.width, (int) spec.height, spec.refreshRate, (int) spec.flags); 2524 } 2525 } 2526 offset += sizeof(VTBCVTTimingDesc); 2527 } 2528 2529 // -- 2530 count = ext->numStandardTimings; 2531 for (idx = 0; idx < count; idx++) 2532 { 2533 UInt16 stdTiming; 2534 2535 malformed = (offset > (sizeof(ext->data) - sizeof(UInt16))); 2536 if (malformed) 2537 break; 2538 2539 spec.flags = 0; 2540 spec.timingID = kIOTimingIDInvalid; 2541 stdTiming = (ext->data[offset] << 8) | ext->data[offset + 1]; 2542 2543 DEBG(connectRef, "VTB st: %04x\n", stdTiming); 2544 if (kIOReturnSuccess != DecodeStandardTiming(edid, stdTiming, 2545 &spec.width, &spec.height, &spec.refreshRate)) 2546 continue; 2547 DEBG(connectRef, "VTB st: %dx%d @ %f (%x)\n", 2548 (int) spec.width, (int) spec.height, spec.refreshRate, (int) spec.flags); 2549 InstallStandardEstablishedTiming(connectRef, edid, &spec); 2550 offset += sizeof(UInt16); 2551 } 2552 } 2553 while (false); 2554} 2555 2556enum { 2557 // flags 2558 kCEASupportUnderscan = 0x80, 2559 kCEASupportBasicAudio = 0x40, 2560 kCEASupportYCbCr444 = 0x20, 2561 kCEASupportYCbCr422 = 0x10, 2562 kCEASupportNativeCount = 0x0F, 2563}; 2564enum { 2565 kHDMISupportFlagAI = 0x80, 2566 kHDMISupportFlagDC48 = 0x40, 2567 kHDMISupportFlagDC36 = 0x20, 2568 kHDMISupportFlagDC30 = 0x10, 2569 kHDMISupportFlagDCY444 = 0x08, 2570 kHDMISupportFlagDVIDual = 0x01, 2571}; 2572 2573static void 2574InstallCEA861EXTColor( IOFBConnectRef connectRef, EDID * edid __unused, CEA861EXT * ext ) 2575{ 2576 IOByteCount offset = ext->detailedTimingsOffset; 2577 2578 if( offset < 4 ) 2579 return; 2580 offset -= 4; 2581 2582 if (0x03 <= ext->version) 2583 { 2584 // Start by looking for the HDMI Identifier. We need to know this before processing 2585 // the short video descriptor block. 2586 IOByteCount index; 2587 IOByteCount length; 2588 2589 connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayRGBColorComponentBits8; 2590 if (kCEASupportYCbCr444 & ext->flags) 2591 { 2592 connectRef->supportedColorModes[kAllVendors] |= kIODisplayColorModeYCbCr444; 2593 connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayYCbCr444ColorComponentBits8; 2594 } 2595 if (kCEASupportYCbCr422 & ext->flags) 2596 { 2597 connectRef->supportedColorModes[kAllVendors] |= kIODisplayColorModeYCbCr422; 2598 connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayYCbCr422ColorComponentBits8; 2599 } 2600 2601 index = 0; 2602 while( index < offset ) 2603 { 2604 length = (ext->data[index] & 0x1f) + 1; 2605 switch( (ext->data[index] & 0xE0) ) 2606 { 2607 // HDMI Vendor Specific Data Block (HDMI 1.3a, p.119) 2608 case 0x60: 2609 { 2610 if (length < 4) break; 2611 2612 if (connectRef->displayAttributes) 2613 { 2614 CFMutableDataRef data; 2615 CFStringRef key; 2616 char name[strlen("IODisplayVSDB") + 10]; 2617 sprintf(name, "IODisplayVSDB%02X%02X%02X", 2618 ext->data[index+1], ext->data[index+2], ext->data[index+3]); 2619 key = CFStringCreateWithCString(kCFAllocatorDefault, name, 2620 kCFStringEncodingMacRoman); 2621 if (key) 2622 { 2623 data = (CFMutableDataRef) CFDictionaryGetValue(connectRef->displayAttributes, key); 2624 if (!data) 2625 { 2626 data = CFDataCreateMutable(kCFAllocatorDefault, 0); 2627 if (data) 2628 { 2629 CFDictionarySetValue(connectRef->displayAttributes, key, data); 2630 CFRelease(data); 2631 } 2632 } 2633 if (data) CFDataAppendBytes(data, &ext->data[index + 4], length - 4); 2634 CFRelease(key); 2635 } 2636 } 2637 DEBG( connectRef, "Found 24-bit IEEE Registration Identifier (0x%02x%02x%02x)\n", 2638 ext->data[index+3], ext->data[index+2], ext->data[index+1] ); 2639 2640 if ((ext->data[index+1] != 0x03) 2641 || (ext->data[index+2] != 0x0C) 2642 || (ext->data[index+3] != 0x00)) 2643 break; 2644 2645 DEBG( connectRef, "Found HDMI VSDB: offset=%d\n", (int) (index + 4) ); 2646 connectRef->hasHDMI = true; 2647 2648 if (length < 7) break; 2649 2650 uint32_t depths; 2651 uint8_t byte; 2652 byte = ext->data[index+6]; 2653 depths = kIODisplayRGBColorComponentBits8; 2654#if 0 2655 if (kHDMISupportFlagDC30 & byte) 2656 depths |= kIODisplayRGBColorComponentBits10; 2657 if (kHDMISupportFlagDC36 & byte) 2658 depths |= kIODisplayRGBColorComponentBits12; 2659 if (kHDMISupportFlagDC48 & byte) 2660 depths |= kIODisplayRGBColorComponentBits16; 2661#endif 2662 if (kHDMISupportFlagDCY444 & byte) 2663 depths |= (depths * kIODisplayYCbCr444ColorComponentBits6); 2664 connectRef->supportedComponentDepths[kAllVendors] |= depths; 2665 break; 2666 } 2667 } 2668 index += length; 2669 } 2670 } 2671} 2672 2673static void 2674InstallCEA861EXT( IOFBConnectRef connectRef, EDID * edid, CEA861EXT * ext, Boolean installModes ) 2675{ 2676 IOReturn err; 2677 IOByteCount offset = ext->detailedTimingsOffset; 2678 2679 connectRef->useScalerUnderscan = (connectRef->scalerInfo 2680 && (kIOScaleCanSupportInset & connectRef->scalerInfo->scalerFeatures)); 2681 connectRef->addTVFlag = true; 2682 2683 if( offset < 4 ) 2684 return; 2685 offset -= 4; 2686 2687 if (0x03 <= ext->version) 2688 { 2689 IOByteCount index; 2690 IOByteCount length; 2691 2692 // Now we look for the short video descriptor block. 2693 index = 0; 2694 while( index < offset ) 2695 { 2696 length = (ext->data[index] & 0x1f) + 1; 2697 switch( (ext->data[index] & 0xE0) ) 2698 { 2699 // Short Video Descriptors (CEA-861-E p.59). 2700 case 0x40: 2701 DEBG( connectRef, "Found Video Data Block: offset=%d\n", (int) (index + 4) ); 2702 if (installModes) 2703 InstallFromCEAShortVideoDesc( connectRef, &ext->data[index] ); 2704 connectRef->hasShortVideoDescriptors = true; 2705 break; 2706 2707 // HDMI Vendor Specific Data Block (HDMI 1.3a, p.119) 2708 case 0x60: 2709 { 2710 uint32_t vicOffset, vicCount; 2711 2712 if (length < 8) break; 2713 if ((ext->data[index+1] != 0x03) 2714 || (ext->data[index+2] != 0x0C) 2715 || (ext->data[index+3] != 0x00)) break; 2716 2717 if (ext->data[index+7]) 2718 { 2719 connectRef->dualLinkCrossover = ext->data[index+7] * 5000000ULL; 2720 } 2721 2722 if (!installModes) break; 2723 if (length < 9) break; 2724 // hdmi video present? 2725 if (!(0x20 & ext->data[index + 8])) break; 2726 vicOffset = 10; 2727 // latency fields present? 2728 if (0x80 & ext->data[index + 8]) vicOffset += 2; 2729 if (0x40 & ext->data[index + 8]) vicOffset += 2; 2730 2731 if (vicOffset >= length) break; 2732 vicCount = ext->data[index + vicOffset]; 2733 vicCount >>= 5; 2734 vicOffset++; 2735 if ((vicOffset + vicCount) > length) vicCount = length - vicOffset; 2736 vicOffset += index; 2737 DEBG( connectRef, "Found HDMI VICs %d@%d\n", vicCount, vicOffset ); 2738 InstallFromHDMIVIC(connectRef, vicCount, &ext->data[vicOffset]); 2739 } 2740 } 2741 index += length; 2742 } 2743 2744 if ((kCEASupportUnderscan & ext->flags) && !connectRef->hasShortVideoDescriptors) 2745 { 2746 // version 3 requires CEA modes to have short video descriptors, 2747 // so no CEA modes on this display 2748 connectRef->useScalerUnderscan = false; 2749 connectRef->addTVFlag = false; 2750 } 2751 } 2752 2753 if ((1 == (kCEASupportNativeCount & ext->flags)) 2754 && (kDisplayAppleVendorID == connectRef->displayVendor)) 2755 { 2756 connectRef->defaultOnly = true; 2757 } 2758 2759 if (!installModes) 2760 { 2761 InstallCEA861EXTColor(connectRef, edid, ext); 2762 return; 2763 } 2764 2765 // Process the CEA Detailed Timing Descriptor. 2766 while (offset <= (sizeof(ext->data) - sizeof(EDIDDetailedTimingDesc))) 2767 { 2768 DEBG(connectRef, "FromCEA:\n"); 2769 err = InstallFromEDIDDesc( connectRef, 2770 edid, (EDIDDetailedTimingDesc *) &ext->data[offset], 2771 kDisplayModeValidFlag | kDisplayModeSafeFlag ); 2772 if (connectRef->defaultOnly 2773 && ((kIOReturnSuccess == err) || (kIOReturnPortExists == err))) 2774 break; 2775 offset += sizeof(EDIDDetailedTimingDesc); 2776 } 2777} 2778 2779static kern_return_t 2780InstallFromDisplayIDDetailedType1(IOFBConnectRef connectRef, EDID * edid, 2781 const DisplayIDDetailedType1 * desc, 2782 IOOptionBits dmFlags) 2783{ 2784 kern_return_t err; 2785 IOFBDisplayModeDescription modeDesc; 2786 IODetailedTimingInformation * timing = (IODetailedTimingInformation *) &modeDesc.timingInfo.detailedInfo.v2; 2787 2788 DEBG(connectRef, "FromDIDType1\n"); 2789 2790 bzero(&modeDesc, sizeof( modeDesc)); 2791 modeDesc.timingInfo.flags = kIODetailedTimingValid; 2792 2793 timing->signalConfig = (edid->displayParams[0] & 16) 2794 ? kIOAnalogSetupExpected : 0; 2795 timing->signalLevels = (edid->displayParams[0] >> 5) & 3; 2796 2797 timing->pixelClock = (1+ ((((UInt64)desc->pixelClock[2]) << 16) 2798 | (((UInt64)desc->pixelClock[1]) << 8) 2799 | desc->pixelClock[0])) 2800 * 10000ULL; 2801 timing->maxPixelClock = timing->pixelClock; 2802 timing->minPixelClock = timing->pixelClock; 2803 2804 if (!timing->pixelClock) return( kIOReturnBadArgument ); 2805 2806 timing->horizontalActive = (1+ ((((UInt32)desc->horizActive[1]) << 8) 2807 | desc->horizActive[0])); 2808 timing->horizontalBlanking = (1+ ((((UInt32)desc->horizBlanking[1]) << 8) 2809 | desc->horizBlanking[0])); 2810 timing->horizontalSyncOffset = (1+ ((((UInt32)(0x7F & desc->horizSyncOffset[1])) << 8) 2811 | desc->horizSyncOffset[0])); 2812 timing->horizontalSyncPulseWidth = (1+ ((((UInt32)desc->horizSyncWidth[1]) << 8) 2813 | desc->horizSyncWidth[0])); 2814 timing->horizontalSyncConfig = (0x80 & desc->horizSyncOffset[1]) 2815 ? kIOSyncPositivePolarity : 0; 2816 timing->horizontalSyncLevel = 0; 2817 2818 timing->verticalActive = (1+ ((((UInt32)desc->verticalActive[1]) << 8) 2819 | desc->verticalActive[0])); 2820 timing->verticalBlanking = (1+ ((((UInt32)desc->verticalBlanking[1]) << 8) 2821 | desc->verticalBlanking[0])); 2822 timing->verticalSyncOffset = (1+ ((((UInt32)(0x7F & desc->verticalSyncOffset[1])) << 8) 2823 | desc->verticalSyncOffset[0])); 2824 timing->verticalSyncPulseWidth = (1+ ((((UInt32)desc->verticalSyncWidth[1]) << 8) 2825 | desc->verticalSyncWidth[0])); 2826 timing->verticalSyncConfig = (0x80 & desc->verticalSyncOffset[1]) 2827 ? kIOSyncPositivePolarity : 0; 2828 timing->verticalSyncLevel = 0; 2829 2830 timing->horizontalBorderLeft = 0; 2831 timing->horizontalBorderRight = 0; 2832 timing->verticalBorderTop = 0; 2833 timing->verticalBorderBottom = 0; 2834 2835 bool interlaced = (0 != (desc->flags & 0x10)); 2836 if (interlaced) 2837 AdjustTimingForInterlace(timing); 2838 2839 if (0 != (desc->flags & 0x80)) 2840 { 2841 DEBG(connectRef, "default\n"); 2842 dmFlags |= kDisplayModeDefaultFlag; 2843 } 2844 2845 modeDesc.info.imageWidth = connectRef->displayImageWidth; 2846 modeDesc.info.imageHeight = connectRef->displayImageHeight; 2847 modeDesc.info.flags = dmFlags; 2848 2849 err = InstallTiming(connectRef, &modeDesc, kIOFBEDIDDetailedMode); 2850 2851 return (err); 2852} 2853 2854static void 2855InstallDisplayIDEXT(IOFBConnectRef connectRef, EDID * edid, DisplayIDEXT * ext, Boolean installModes) 2856{ 2857 if (!installModes) return; 2858 2859 const DisplayIDBlock * block; 2860 uint32_t bytes, offset; 2861 2862 bytes = ext->sectionSize; 2863 2864 const uint8_t * byte = &ext->version; 2865 const uint8_t * end = byte + bytes + 5; 2866 uint8_t sum = 0; 2867 2868 while (byte < end) sum += *byte++; 2869 if (sum) return; 2870 2871 offset = 0; 2872 while (bytes >= sizeof(DisplayIDBlock)) 2873 { 2874 block = (typeof(block)) &ext->section[offset]; 2875 bytes -= sizeof(DisplayIDBlock); 2876 if (bytes < block->size) break; 2877 switch (block->type) 2878 { 2879 case kDIDBlockTypeDetailedType1: 2880 { 2881 const DisplayIDBlockDetailedType1 * detailedBlock = (typeof(detailedBlock)) block; 2882 uint32_t count, idx; 2883 2884 count = block->size / sizeof(DisplayIDDetailedType1); 2885 for (idx = 0; idx < count; idx++) 2886 { 2887 InstallFromDisplayIDDetailedType1(connectRef, edid, &detailedBlock->detailed[idx], 2888 kDisplayModeValidFlag | kDisplayModeSafeFlag); 2889 } 2890 break; 2891 } 2892 default: 2893 break; 2894 } 2895 bytes -= block->size; 2896 offset += block->size; 2897 } 2898} 2899 2900static void 2901LookExtensions( IOFBConnectRef connectRef, 2902 EDID * edid, UInt8 * blocks, IOByteCount length, Boolean installModes) 2903{ 2904 UInt8 tag; 2905 2906 while (length >= 128) 2907 { 2908 tag = blocks[0]; 2909 switch (tag) 2910 { 2911 case kExtTagDI: 2912 InstallDIEXT( connectRef, edid, (DIEXT *) blocks, installModes); 2913 connectRef->hasDIEXT = true; 2914 break; 2915 case kExtTagVTB: 2916 InstallVTBEXT( connectRef, edid, (VTBEXT *) blocks, installModes); 2917 break; 2918 case kExtTagCEA: 2919 connectRef->hasCEAExt = true; 2920 InstallCEA861EXT( connectRef, edid, (CEA861EXT *) blocks, installModes); 2921 break; 2922 case kExtTagDID: 2923 InstallDisplayIDEXT(connectRef, edid, (DisplayIDEXT *) blocks, installModes); 2924 break; 2925 } 2926 length -= 128; 2927 blocks += 128; 2928 } 2929} 2930 2931__private_extern__ void 2932IODisplayInstallTimings( IOFBConnectRef connectRef ) 2933{ 2934 int i; 2935 io_service_t service = connectRef->framebuffer; 2936 EDID * edid = 0; 2937 CFDataRef fbRange; 2938 CFDataRef edidData; 2939 CFDataRef data; 2940 CFArrayRef array; 2941 CFIndex count; 2942 bool checkDI = false; 2943 2944 static const GTFTimingCurve defaultGTFCurves[] = { 2945 { 0, 40, 600, 128, 20 }, 2946 { 0xffffffff, 0, 0, 0, 0 } 2947 }; 2948 2949 // controller timing range 2950 fbRange = (CFDataRef) IORegistryEntryCreateCFProperty( service, 2951 CFSTR(kIOFBTimingRangeKey), 2952 kCFAllocatorDefault, kNilOptions); 2953 if (fbRange && (size_t) CFDataGetLength(fbRange) >= sizeof(IODisplayTimingRange)) 2954 connectRef->fbRange = (IODisplayTimingRange *) CFDataGetBytePtr(fbRange); 2955 2956 2957 // dpcd 2958 connectRef->dpcdData = (CFDataRef) IORegistryEntrySearchCFProperty(service, kIOServicePlane, 2959 CFSTR(kIOFBDisplayPortConfigurationDataKey), 2960 kCFAllocatorDefault, 2961 kIORegistryIterateParents|kIORegistryIterateRecursively); 2962 // hdmi dongle 2963 connectRef->hdmiData = (CFDataRef) IORegistryEntrySearchCFProperty(service, kIOServicePlane, 2964 CFSTR(kIOFBHDMIDongleROMKey), 2965 kCFAllocatorDefault, 2966 kIORegistryIterateParents|kIORegistryIterateRecursively); 2967 2968 connectRef->vendorsFound = (1 << kAllVendors); 2969 for (i = 0; i < kNumVendors; i++) 2970 { 2971 connectRef->supportedComponentDepths[i] = kIODisplayRGBColorComponentBitsUnknown; 2972 if (i == kAllVendors) 2973 connectRef->supportedColorModes[i] = kIODisplayColorModeRGB; 2974 else 2975 connectRef->supportedColorModes[i] = kIODisplayColorModeReserved; 2976 connectRef->ditherControl[i] = kIODisplayDitherControlDefault; 2977 } 2978 2979 connectRef->defaultIndex = 0; 2980 connectRef->defaultOnly = false; 2981 connectRef->gtfDisplay = false; 2982 connectRef->cvtDisplay = false; 2983 connectRef->supportsReducedBlank = false; 2984 connectRef->hasInterlaced = false; 2985 connectRef->hasDIEXT = false; 2986 connectRef->hasCEAExt = false; 2987 connectRef->hasHDMI = false; 2988 connectRef->hasShortVideoDescriptors = false; 2989 connectRef->numGTFCurves = 1; 2990 bcopy(&defaultGTFCurves, &connectRef->gtfCurves, sizeof(connectRef->gtfCurves)); 2991 2992 if (connectRef->displayAttributes) CFRelease(connectRef->displayAttributes); 2993 connectRef->displayAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 2994 &kCFTypeDictionaryKeyCallBacks, 2995 &kCFTypeDictionaryValueCallBacks); 2996 2997 // defaults for no DIEXT 2998 if (CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayIsDigitalKey))) 2999 { 3000 connectRef->dualLinkCrossover = 165000000ULL; 3001 connectRef->maxDisplayLinks = 2; 3002 } 3003 else 3004 { 3005 connectRef->dualLinkCrossover = 0; 3006 connectRef->maxDisplayLinks = 0; 3007 } 3008 3009#if RLOG 3010 DEBG(connectRef, "FB range:\n"); 3011 IOFBLogRange(connectRef, connectRef->fbRange); 3012 3013 DEBG(connectRef, "Display range:\n"); 3014 data = CFDictionaryGetValue(connectRef->overrides, CFSTR("trng")); 3015 if (data && (((size_t)CFDataGetLength(data)) >= sizeof(IODisplayTimingRange))) 3016 IOFBLogRange(connectRef, (IODisplayTimingRange *) CFDataGetBytePtr(data)); 3017#endif 3018 3019 do 3020 { 3021 // EDID timings 3022 3023 edidData = CFDictionaryGetValue( connectRef->overrides, CFSTR(kIODisplayEDIDKey) ); 3024 if( !edidData || ((size_t) CFDataGetLength(edidData) < sizeof( EDID)) ) 3025 continue; 3026#if RLOG 3027 if (connectRef->logfile) 3028 { 3029 DEBG(connectRef, "EDID\n"); 3030 fprintf(connectRef->logfile, "/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */"); 3031 for (i = 0; i < CFDataGetLength(edidData); i++) 3032 { 3033 if( 0 == (i & 15)) 3034 fprintf(connectRef->logfile, "\n/* %02X */ ", i); 3035 fprintf(connectRef->logfile, "0x%02x,", CFDataGetBytePtr( edidData )[i]); 3036 } 3037 fprintf(connectRef->logfile, "\n"); 3038 fflush(connectRef->logfile); 3039 } 3040#endif 3041 edid = (EDID *) CFDataGetBytePtr( edidData ); 3042 3043 static const uint8_t checkHeader[] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00 }; 3044 if (bcmp(&checkHeader[0], &edid->header[0], sizeof(checkHeader))) 3045 { 3046 edid = 0; 3047 continue; 3048 } 3049 3050 if (2 & edid->featureSupport) 3051 {} 3052 else if ((kDisplayAppleVendorID == connectRef->displayVendor) 3053 && ((edid->version > 1) || (edid->revision >= 3))) 3054 { 3055 checkDI = true; 3056 } 3057 else 3058 connectRef->defaultIndex = -1; 3059 3060 DEBG(connectRef, "EDID default idx %d, only %d\n", 3061 connectRef->defaultIndex, connectRef->defaultOnly); 3062 3063 connectRef->displayImageWidth = edid->displayParams[1] * 10; 3064 connectRef->displayImageHeight = edid->displayParams[2] * 10; 3065 3066 uint8_t videoInput = edid->displayParams[0]; 3067 if ((0x80 & videoInput) && ((edid->version > 1) || (edid->revision >= 4))) 3068 { 3069 static const uint32_t depths[8] = { 3070 kIODisplayRGBColorComponentBitsUnknown, kIODisplayRGBColorComponentBits6, 3071 kIODisplayRGBColorComponentBits8, kIODisplayRGBColorComponentBits10, 3072 kIODisplayRGBColorComponentBits12, kIODisplayRGBColorComponentBits14, 3073 kIODisplayRGBColorComponentBits16, kIODisplayRGBColorComponentBitsUnknown 3074 }; 3075 static const uint32_t modes[4] = { 3076 kIODisplayColorModeRGB, 3077 kIODisplayColorModeRGB | kIODisplayColorModeYCbCr444, 3078 kIODisplayColorModeRGB | kIODisplayColorModeYCbCr422, 3079 kIODisplayColorModeRGB | kIODisplayColorModeYCbCr444 | kIODisplayColorModeYCbCr422, 3080 }; 3081 uint32_t supportedModes, supportedDepths; 3082 3083 /* feature support */ 3084 supportedModes = modes[(edid->displayParams[4] >> 3) & 3]; 3085 supportedDepths = depths[(videoInput >> 4) & 7]; 3086 if ((0x9236 == connectRef->displayProduct) 3087 && (kDisplayAppleVendorID == connectRef->displayVendor)) 3088 { 3089 supportedModes = kIODisplayColorModeRGB; 3090 } 3091 connectRef->supportedColorModes[kAllVendors] |= supportedModes; 3092 connectRef->supportedComponentDepths[kAllVendors] |= supportedDepths; 3093 if (kIODisplayColorModeYCbCr444 & supportedModes) 3094 { 3095 connectRef->supportedComponentDepths[kAllVendors] |= supportedDepths * 3096 (kIODisplayYCbCr444ColorComponentBits6 / kIODisplayRGBColorComponentBits6); 3097 } 3098 if (kIODisplayColorModeYCbCr422 & supportedModes) 3099 { 3100 connectRef->supportedComponentDepths[kAllVendors] |= supportedDepths * 3101 (kIODisplayYCbCr422ColorComponentBits6 / kIODisplayRGBColorComponentBits6); 3102 } 3103 } 3104 3105 count = CFDataGetLength(edidData); 3106 if ((size_t) count > sizeof(EDID)) 3107 { 3108 LookExtensions(connectRef, edid, (UInt8 *)(edid + 1), count - sizeof(EDID), false); 3109 } 3110 3111 if (!connectRef->hasHDMI) 3112 { 3113 connectRef->supportedColorModes[kAllVendors] = kIODisplayColorModeRGB; 3114 connectRef->supportedComponentDepths[kAllVendors] &= 3115 (kIODisplayRGBColorComponentBits6 3116 | kIODisplayRGBColorComponentBits8 3117 | kIODisplayRGBColorComponentBits10 3118 | kIODisplayRGBColorComponentBits12 3119 | kIODisplayRGBColorComponentBits14 3120 | kIODisplayRGBColorComponentBits16); 3121 } 3122 3123 if ((edid->version > 1) || edid->revision) for (i = 1; i < 4; i++) 3124 { 3125 ParseMonitorDescriptor(connectRef, edid, &edid->descriptors[i].general); 3126 } 3127 3128 array = (CFArrayRef) CFDictionaryGetValue(connectRef->overrides, CFSTR("mdes")); 3129 if (array && (CFArrayGetTypeID() == CFGetTypeID(array))) 3130 count = CFArrayGetCount(array); 3131 else 3132 count = 0; 3133 for (i = 0; i < count; i++) 3134 { 3135 data = CFArrayGetValueAtIndex(array, i); 3136 if (!data 3137 || (CFDataGetTypeID() != CFGetTypeID(data)) 3138 || (sizeof(EDIDGeneralDesc) > (size_t) CFDataGetLength(data))) 3139 continue; 3140 3141 ParseMonitorDescriptor(connectRef, edid, (EDIDGeneralDesc *) CFDataGetBytePtr(data)); 3142 } 3143 3144 // send display attributes 3145 IOFBSetKernelDisplayConfig(connectRef); 3146 3147 if (checkDI && connectRef->hasDIEXT) 3148 { 3149 connectRef->defaultIndex = 1; 3150 connectRef->defaultOnly = true; 3151 } 3152 3153 DEBG(connectRef, "Display maxLinks %d, crossover %qd\n", 3154 (int) connectRef->maxDisplayLinks, connectRef->dualLinkCrossover); 3155 3156 // max dimensions 3157 connectRef->dimensions.setFlags = kDisplayModeNotPresetFlag; 3158 if( CFDictionaryGetValue( connectRef->overrides, CFSTR(kIODisplayIsDigitalKey))) 3159 connectRef->dimensions.clearFlags = 3160 kDisplayModeValidFlag | kDisplayModeSafeFlag | kDisplayModeDefaultFlag; 3161 else 3162 connectRef->dimensions.clearFlags = 3163 kDisplayModeSafeFlag | kDisplayModeDefaultFlag; 3164 3165 // override timing recs (18-byte) 3166 array = (CFArrayRef) CFDictionaryGetValue( connectRef->overrides, CFSTR("dspc")); 3167 if( array) 3168 count = CFArrayGetCount(array); 3169 else 3170 count = 0; 3171 for( i = 0; i < count; i++ ) { 3172 data = CFArrayGetValueAtIndex(array, i); 3173 if( !data || (sizeof(EDIDDetailedTimingDesc) != CFDataGetLength(data))) 3174 continue; 3175 3176 InstallFromEDIDDesc( connectRef, 3177 edid, (EDIDDetailedTimingDesc *) CFDataGetBytePtr(data), 3178 kDisplayModeValidFlag | kDisplayModeSafeFlag ); 3179 } 3180 3181 if (connectRef->defaultOnly 3182 && (-1 != connectRef->defaultIndex) 3183 && !CFDictionaryGetValue(connectRef->overrides, CFSTR("trng"))) 3184 { 3185 // just install the default for scaling, if it works 3186 IOReturn 3187 err = InstallFromEDIDDesc(connectRef, 3188 edid, 3189 &edid->descriptors[connectRef->defaultIndex].timing, 3190 kDisplayModeValidFlag | kDisplayModeSafeFlag | kDisplayModeDefaultFlag 3191 | ((0 == connectRef->defaultIndex) ? kDisplayModeNativeFlag : 0)); 3192 if ((kIOReturnSuccess == err) || (kIOReturnPortExists == err)) 3193 continue; 3194 } 3195 3196 // EDID timing recs 3197 for( i = 0; i < 4; i++ ) 3198 { 3199 if( i && (0 == bcmp(&edid->descriptors[0].timing, 3200 &edid->descriptors[i].timing, 3201 sizeof( EDIDDetailedTimingDesc)))) 3202 continue; 3203 3204 InstallFromEDIDDesc(connectRef, 3205 edid, 3206 &edid->descriptors[i].timing, 3207 kDisplayModeValidFlag | kDisplayModeSafeFlag 3208 | ((i == connectRef->defaultIndex) ? kDisplayModeDefaultFlag : 0) 3209 | (((i == 0) && (i == connectRef->defaultIndex)) ? kDisplayModeNativeFlag : 0)); 3210 } 3211 3212 if( !connectRef->hasHDMI ) 3213 { 3214 InstallCVTStandardTimings( connectRef, edid ); 3215 InstallStandardEstablishedTimings( connectRef, edid ); 3216 } 3217 } 3218 while( false ); 3219 3220 // override timing recs 3221 array = (CFArrayRef) CFDictionaryGetValue( connectRef->overrides, CFSTR("tspc")); 3222 if (array) 3223 count = CFArrayGetCount(array); 3224 else 3225 count = 0; 3226 for (i = 0; i < count; i++ ) { 3227 data = CFArrayGetValueAtIndex(array, i); 3228 if( !data || (sizeof(IODetailedTimingInformation) != CFDataGetLength(data))) 3229 continue; 3230 3231 InstallFromTimingOverride(connectRef, 3232 (IODetailedTimingInformation *) CFDataGetBytePtr(data), 3233 kDisplayModeValidFlag | kDisplayModeSafeFlag); 3234 } 3235 3236 IODisplayGetAspect( connectRef ); 3237 3238 if (edidData && edid) 3239 { 3240 count = CFDataGetLength(edidData); 3241 if ((size_t) count > sizeof(EDID)) 3242 { 3243 LookExtensions(connectRef, edid, (UInt8 *)(edid + 1), count - sizeof(EDID), true); 3244 } 3245 } 3246 3247 if (!connectRef->hasHDMI) 3248 { 3249 if (CFDictionaryGetValue(connectRef->overrides, CFSTR("trng")) 3250 || ((!CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayIsDigitalKey))) 3251 && ((connectRef->displayVendor != kDisplayVendorIDUnknown) 3252 || (connectRef->displayProduct == kDisplayProductIDGeneric)) 3253 && (!edid || ((0xffffffff != connectRef->dimensions.width) 3254 && (0xffffffff != connectRef->dimensions.height))))) 3255 { 3256 // have range limits, or analog-VGA/nonsensed 3257 InstallGTFTimings( connectRef, edid ); 3258 } 3259 } 3260 3261 connectRef->fbRange = 0; 3262 if (fbRange) 3263 CFRelease(fbRange); 3264 3265 if (connectRef->dpcdData) 3266 { 3267 CFRelease(connectRef->dpcdData); 3268 connectRef->dpcdData = NULL; 3269 } 3270 if (connectRef->hdmiData) 3271 { 3272 CFRelease(connectRef->hdmiData); 3273 connectRef->hdmiData = NULL; 3274 } 3275} 3276 3277SInt32 3278IODisplayMatchDictionaries( 3279 CFDictionaryRef matching1, 3280 CFDictionaryRef matching2, 3281 IOOptionBits options __unused ) 3282{ 3283 CFNumberRef num1, num2; 3284 CFStringRef str1, str2; 3285 SInt32 matches = 0; 3286 3287 if( !matching1 || !matching2) 3288 return( -1 ); 3289 3290 do { 3291 num1 = CFDictionaryGetValue( matching1, CFSTR(kDisplayVendorID) ); 3292 num2 = CFDictionaryGetValue( matching2, CFSTR(kDisplayVendorID) ); 3293 if( !num1 || !num2) 3294 continue; 3295 if( !CFEqual( num1, num2)) 3296 continue; 3297 3298 num1 = CFDictionaryGetValue( matching1, CFSTR(kDisplayProductID) ); 3299 num2 = CFDictionaryGetValue( matching2, CFSTR(kDisplayProductID) ); 3300 if( !num1 || !num2) 3301 continue; 3302 if( !CFEqual( num1, num2)) 3303 continue; 3304 3305 num1 = CFDictionaryGetValue( matching1, CFSTR(kDisplaySerialNumber) ); 3306 num2 = CFDictionaryGetValue( matching2, CFSTR(kDisplaySerialNumber) ); 3307 if( num1 && num2 && (!CFEqual( num1, num2))) 3308 continue; 3309 3310 str1 = CFDictionaryGetValue( matching1, CFSTR(kIODisplayLocationKey) ); 3311 str2 = CFDictionaryGetValue( matching2, CFSTR(kIODisplayLocationKey) ); 3312 if( str1 && str2 && (!CFEqual( str1, str2))) 3313 continue; 3314 3315 matches = 1000; 3316 3317 } while( false ); 3318 3319 return( matches ); 3320} 3321 3322io_service_t 3323IODisplayForFramebuffer( 3324 io_service_t framebuffer, 3325 IOOptionBits options __unused ) 3326{ 3327 IOReturn kr; 3328 io_iterator_t iter; 3329 io_service_t service = 0; 3330 3331 if( IOObjectConformsTo( framebuffer, "IODisplay")) 3332 { 3333 IOObjectRetain(framebuffer); 3334 return( framebuffer ); 3335 } 3336 3337 kr = IORegistryEntryCreateIterator( framebuffer, kIOServicePlane, 3338 kIORegistryIterateRecursively, &iter); 3339 if( kr != kIOReturnSuccess ) 3340 return( 0 ); 3341 3342 do 3343 { 3344 for( ; 3345 (service = IOIteratorNext( iter)); 3346 IOObjectRelease(service)) { 3347 3348 if( IOObjectConformsTo( service, "IODisplay")) 3349 break; 3350 } 3351 } 3352 while (!service && !IOIteratorIsValid(iter) && (IOIteratorReset(iter), true)); 3353 IOObjectRelease( iter ); 3354 3355 return( service ); 3356} 3357 3358enum { 3359 /* Used by default calibrator (should we show brightness panel) */ 3360 kDisplayGestaltBrightnessAffectsGammaMask = (1 << 0), 3361 kDisplayGestaltViewAngleAffectsGammaMask = (1 << 1) 3362}; 3363 3364static void 3365IODisplayDictAddValues(const void *key, const void *value, void *context) 3366{ 3367 CFMutableDictionaryRef dict = context; 3368 // add if not exists 3369 CFDictionaryAddValue(dict, key, value); 3370} 3371 3372CFDictionaryRef 3373_IODisplayCreateInfoDictionary( 3374 IOFBConnectRef connectRef __unused, 3375 io_service_t framebuffer, 3376 IOOptionBits options ) 3377{ 3378 IOReturn kr; 3379 io_service_t service = 0; 3380 Boolean isDigital = false; 3381 CFDataRef data = 0; 3382 CFNumberRef num; 3383 CFMutableDictionaryRef dict = 0; 3384 CFMutableDictionaryRef regDict; 3385 CFMutableDictionaryRef fbRegDict; 3386 CFTypeRef obj; 3387 SInt32 sint; 3388 UInt8 low; 3389 float fnum; 3390 EDID * edid = 0; 3391 IODisplayVendorID vendor = 0; 3392 IODisplayProductID product = 0; 3393 SInt32 displayType = 0; 3394 UInt32 serialNumber = 0; 3395 uint32_t manufactureYear = 0; 3396 uint32_t manufactureWeek = 0; 3397 io_string_t path; 3398 int i; 3399 IODisplayTimingRange displayRange; 3400 3401 if( !(service = IODisplayForFramebuffer( framebuffer, options))) { 3402 dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, 3403 &kCFTypeDictionaryKeyCallBacks, 3404 &kCFTypeDictionaryValueCallBacks ); 3405 if( dict) 3406 CFDictionarySetValue( dict, CFSTR(kIODisplayLocationKey), CFSTR("unknown")); 3407 return( dict ); 3408 } 3409 3410 do { 3411 3412 regDict = 0; 3413 kr = IORegistryEntryCreateCFProperties( service, ®Dict, 3414 kCFAllocatorDefault, kNilOptions ); 3415 if( kr != kIOReturnSuccess) 3416 continue; 3417 3418 num = CFDictionaryGetValue( regDict, CFSTR(kDisplayVendorID) ); 3419 if( num) 3420 CFNumberGetValue( num, kCFNumberSInt32Type, &vendor ); 3421 num = CFDictionaryGetValue( regDict, CFSTR(kDisplayProductID) ); 3422 if( num) 3423 CFNumberGetValue( num, kCFNumberSInt32Type, &product ); 3424 3425 num = CFDictionaryGetValue( regDict, CFSTR(kAppleDisplayTypeKey) ); 3426 if( num) { 3427 CFNumberGetValue( num, kCFNumberSInt32Type, &displayType ); 3428 if( (vendor == kDisplayVendorIDUnknown) && (displayType == 10)) 3429 product = kDisplayProductIDGeneric; 3430 } 3431 3432 data = CFDictionaryGetValue( regDict, CFSTR(kIODisplayEDIDKey) ); 3433 3434#if SPOOF_EDID 3435#warning **************** 3436#warning ** SPOOF_EDID ** 3437#warning **************** 3438 if (data) 3439 { 3440 EDIDInfo( (EDID *) CFDataGetBytePtr(data), &vendor, &product, NULL, NULL, NULL, NULL); 3441 if (0x10ac == vendor) 3442 { 3443 data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, 3444 spoofEDID, sizeof(spoofEDID), kCFAllocatorNull); 3445 } 3446 vendor = product = 0; 3447 } 3448#endif 3449 if( !data) 3450 continue; 3451 edid = (EDID *) CFDataGetBytePtr( data ); 3452 if( vendor && product) 3453 EDIDInfo( edid, 0, 0, &serialNumber, &manufactureYear, &manufactureWeek, &isDigital ); 3454 else 3455 EDIDInfo( edid, &vendor, &product, &serialNumber, &manufactureYear, &manufactureWeek, &isDigital ); 3456 3457 } while( false ); 3458 3459 // <hack> 3460 if( !vendor && !product) { 3461 vendor = kDisplayVendorIDUnknown; 3462 product = kDisplayProductIDGeneric; 3463 } // </hack> 3464 3465 dict = IODisplayCreateOverrides( framebuffer, options, vendor, product, 3466 serialNumber, manufactureYear, manufactureWeek, 3467 isDigital ); 3468 3469#define makeInt( key, value ) \ 3470 num = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &value ); \ 3471 CFDictionaryAddValue( dict, key, num ); \ 3472 CFRelease( num ); 3473 3474#define addFloat( key ) \ 3475 num = CFNumberCreate( kCFAllocatorDefault, kCFNumberFloatType, &fnum ); \ 3476 CFDictionaryAddValue( dict, key, num ); \ 3477 CFRelease( num ); 3478 3479 do { 3480 if( !dict) 3481 continue; 3482 3483 makeInt( CFSTR( kDisplayVendorID ), vendor ); 3484 makeInt( CFSTR( kDisplayProductID ), product ); 3485 3486 if( serialNumber) { 3487 makeInt( CFSTR( kDisplaySerialNumber ), serialNumber ); 3488 } 3489 3490 kr = IORegistryEntryGetPath( service, kIOServicePlane, path ); 3491 if( KERN_SUCCESS == kr) { 3492 CFStringRef string; 3493 string = CFStringCreateWithCString( kCFAllocatorDefault, path, 3494 kCFStringEncodingMacRoman ); 3495 if( string) { 3496 CFDictionaryAddValue( dict, CFSTR(kIODisplayLocationKey), string); 3497 CFRelease(string); 3498 } 3499 } 3500 3501 if ((kIODisplayNoProductName | kIODisplayMatchingInfo) & options) 3502 // the raw override form is not what clients expect 3503 CFDictionaryRemoveValue( dict, CFSTR(kDisplayProductName) ); 3504 3505 // -- that's all for matching -- 3506 if( options & kIODisplayMatchingInfo) 3507 continue; 3508 3509 if (data) 3510 { 3511 // if !exist add display edid 3512 CFDictionaryAddValue(dict, CFSTR(kIODisplayEDIDKey), data); 3513 CFDictionaryAddValue(dict, CFSTR(kIODisplayEDIDOriginalKey), data); 3514 } 3515 // get final edid 3516 data = CFDictionaryGetValue(dict, CFSTR(kIODisplayEDIDKey)); 3517 if (data) 3518 edid = (EDID *) CFDataGetBytePtr(data); 3519 // no point in serial# / manufacture date from override 3520 else 3521 edid = 0; 3522 3523 if (regDict) 3524 { 3525 obj = CFDictionaryGetValue( regDict, CFSTR(kIODisplayConnectFlagsKey) ); 3526 if( obj) 3527 CFDictionarySetValue( dict, CFSTR(kIODisplayConnectFlagsKey), obj ); 3528 3529 obj = CFDictionaryGetValue( regDict, CFSTR(kIODisplayPrefKeyKey) ); 3530 if( obj) 3531 CFDictionarySetValue( dict, CFSTR(kIODisplayPrefKeyKey), obj ); 3532 3533 CFDictionaryRef attrDict; 3534 attrDict = CFDictionaryGetValue(regDict, CFSTR(kIODisplayAttributesKey)); 3535 if (attrDict && (CFDictionaryGetTypeID() == CFGetTypeID(attrDict))) 3536 CFDictionaryApplyFunction(attrDict, &IODisplayDictAddValues, dict); 3537 } 3538 3539 if( IOObjectConformsTo( service, "IOBacklightDisplay")) 3540 CFDictionarySetValue( dict, CFSTR(kIODisplayHasBacklightKey), kCFBooleanTrue ); 3541 3542 kr = IORegistryEntryCreateCFProperties(framebuffer, &fbRegDict, 3543 kCFAllocatorDefault, kNilOptions ); 3544 if (kIOReturnSuccess == kr) 3545 { 3546 if( (obj = CFDictionaryGetValue(fbRegDict, CFSTR(kIOFBTransformKey)))) 3547 { 3548 CFNumberGetValue(obj, kCFNumberSInt32Type, &sint); 3549 sint = (sint & kIOFBRotateFlags) | ((sint >> 4) & kIOFBRotateFlags); 3550 makeInt( CFSTR(kIOFBTransformKey), sint ); 3551 } 3552 if( (obj = CFDictionaryGetValue(fbRegDict, CFSTR("graphic-options")))) 3553 CFDictionaryAddValue(dict, CFSTR("graphic-options"), obj); 3554 CFRelease(fbRegDict); 3555 } 3556 3557 data = CFDictionaryGetValue( dict, CFSTR("dmdg") ); 3558 if( data) 3559 sint = OSReadBigInt32((void *) CFDataGetBytePtr(data), 0); 3560 else 3561 sint = kDisplayGestaltBrightnessAffectsGammaMask; 3562 3563 if( kDisplayGestaltBrightnessAffectsGammaMask & sint) 3564 CFDictionaryAddValue( dict, CFSTR(kDisplayBrightnessAffectsGamma), kCFBooleanTrue ); 3565 if( kDisplayGestaltViewAngleAffectsGammaMask & sint) 3566 CFDictionaryAddValue( dict, CFSTR(kDisplayViewAngleAffectsGamma), kCFBooleanTrue ); 3567 3568 if (!(kIODisplayNoProductName & options)) 3569 GenerateProductName( dict, edid, displayType, options ); 3570 3571 if( !edid) 3572 continue; 3573 3574 if( 0x80 & edid->displayParams[0]) { 3575 CFDictionarySetValue( dict, CFSTR(kIODisplayIsDigitalKey), kCFBooleanTrue ); 3576 3577 if( kDisplayAppleVendorID == vendor) { 3578 CFDictionaryAddValue( dict, CFSTR(kDisplayFixedPixelFormat), kCFBooleanTrue ); 3579 sint = kDisplaySubPixelLayoutRGB; 3580 makeInt( CFSTR( kDisplaySubPixelLayout ), sint ); 3581 3582 CFDictionaryRemoveValue( dict, CFSTR(kDisplayBrightnessAffectsGamma) ); 3583 CFDictionarySetValue( dict, CFSTR(kDisplayViewAngleAffectsGamma), kCFBooleanTrue ); 3584 } 3585 } 3586 3587 // EDID timing range 3588 for( i = 0; i < 4; i++ ) { 3589 if( EDIDDescToDisplayTimingRangeRec( edid, 3590 &edid->descriptors[i].general, 3591 &displayRange )) { 3592 3593 if( !CFDictionaryGetValue( dict, CFSTR("drng"))) { 3594 data = CFDataCreate( kCFAllocatorDefault, 3595 (UInt8 *) &edid->descriptors[i].general, sizeof(EDIDGeneralDesc)); 3596 if( data) { 3597 CFDictionarySetValue(dict, CFSTR("drng"), data); 3598 CFRelease(data); 3599 } 3600 } 3601 3602 if( !CFDictionaryGetValue( dict, CFSTR("trng"))) { 3603 data = CFDataCreate( kCFAllocatorDefault, 3604 (UInt8 *) &displayRange, sizeof(displayRange)); 3605 if( data) { 3606 CFDictionarySetValue(dict, CFSTR("trng"), data); 3607 CFRelease(data); 3608 } 3609 } 3610 break; 3611 } 3612 } 3613 3614 sint = edid->weekOfManufacture; 3615 makeInt( CFSTR( kDisplayWeekOfManufacture ), sint ); 3616 sint = edid->yearOfManufacture + 1990; 3617 makeInt( CFSTR( kDisplayYearOfManufacture ), sint ); 3618 3619 sint = edid->displayParams[1] * 10; 3620 makeInt( CFSTR( kDisplayHorizontalImageSize ), sint ); 3621 sint = edid->displayParams[2] * 10; 3622 makeInt( CFSTR( kDisplayVerticalImageSize ), sint ); 3623 3624 // color info 3625 low = edid->colorCharacteristics[0]; 3626 3627 fnum = (edid->colorCharacteristics[2] << 2) | ((low >> 6) & 3); 3628 fnum /= (1 << 10); 3629 addFloat( CFSTR( kDisplayRedPointX ) ); 3630 fnum = (edid->colorCharacteristics[3] << 2) | ((low >> 4) & 3); 3631 fnum /= (1 << 10); 3632 addFloat( CFSTR( kDisplayRedPointY ) ); 3633 3634 fnum = (edid->colorCharacteristics[4] << 2) | ((low >> 2) & 3); 3635 fnum /= (1 << 10); 3636 addFloat( CFSTR( kDisplayGreenPointX ) ); 3637 fnum = (edid->colorCharacteristics[5] << 2) | ((low >> 0) & 3); 3638 fnum /= (1 << 10); 3639 addFloat( CFSTR( kDisplayGreenPointY ) ); 3640 3641 low = edid->colorCharacteristics[1]; 3642 3643 fnum = (edid->colorCharacteristics[6] << 2) | ((low >> 6) & 3); 3644 fnum /= (1 << 10); 3645 addFloat( CFSTR( kDisplayBluePointX ) ); 3646 fnum = (edid->colorCharacteristics[7] << 2) | ((low >> 4) & 3); 3647 fnum /= (1 << 10); 3648 addFloat( CFSTR( kDisplayBluePointY ) ); 3649 3650 fnum = (edid->colorCharacteristics[8] << 2) | ((low >> 2) & 3); 3651 fnum /= (1 << 10); 3652 addFloat( CFSTR( kDisplayWhitePointX ) ); 3653 fnum = (edid->colorCharacteristics[9] << 2) | ((low >> 0) & 3); 3654 fnum /= (1 << 10); 3655 addFloat( CFSTR( kDisplayWhitePointY ) ); 3656 3657 fnum = edid->displayParams[3]; 3658 fnum = (fnum + 100.0) / 100.0; 3659 addFloat( CFSTR( kDisplayWhiteGamma ) ); 3660 3661 } while( false ); 3662 3663 if (service) 3664 IOObjectRelease(service); 3665 3666 if( regDict) 3667 CFRelease( regDict ); 3668 3669 return( dict ); 3670} 3671 3672IOReturn 3673IODisplayCopyParameters( 3674 io_service_t service, 3675 IOOptionBits options, 3676 CFDictionaryRef * params ) 3677{ 3678 if( (service = IODisplayForFramebuffer( service, options))) 3679 { 3680 *params = IORegistryEntryCreateCFProperty( service, CFSTR(kIODisplayParametersKey), 3681 kCFAllocatorDefault, kNilOptions ); 3682 IOObjectRelease(service); 3683 } 3684 else 3685 *params = 0; 3686 3687 return( *params ? kIOReturnSuccess : kIOReturnUnsupported ); 3688} 3689 3690IOReturn 3691IODisplayCopyFloatParameters( 3692 io_service_t service __unused, 3693 IOOptionBits options __unused, 3694 CFDictionaryRef * params __unused ) 3695{ 3696 return( kIOReturnUnsupported ); 3697} 3698 3699IOReturn 3700IODisplayGetIntegerRangeParameter( 3701 io_service_t service, 3702 IOOptionBits options, 3703 CFStringRef parameterName, 3704 SInt32 * value, 3705 SInt32 * min, 3706 SInt32 * max ) 3707{ 3708 IOReturn err; 3709 CFDictionaryRef params; 3710 CFDictionaryRef param; 3711 CFNumberRef num; 3712 3713#if DEBUGPARAMS 3714 const char * cStr = 0; 3715 3716 if( (cStr = CFStringGetCStringPtr( parameterName, kCFStringEncodingMacRoman)) 3717 && (cStr = getenv(cStr))) 3718 parameterName = CFStringCreateWithCString( kCFAllocatorDefault, cStr, 3719 kCFStringEncodingMacRoman ); 3720#endif 3721 3722 do { 3723 err = IODisplayCopyParameters( service, options, ¶ms ); 3724 if( err != kIOReturnSuccess) 3725 continue; 3726 3727 param = CFDictionaryGetValue( params, parameterName ); 3728 3729 if( !param) { 3730 err = kIOReturnUnsupported; 3731 continue; 3732 } 3733 if( value && (num = CFDictionaryGetValue( param, CFSTR(kIODisplayValueKey)))) 3734 CFNumberGetValue( num, kCFNumberSInt32Type, value ); 3735 if( min && (num = CFDictionaryGetValue( param, CFSTR(kIODisplayMinValueKey)))) 3736 CFNumberGetValue( num, kCFNumberSInt32Type, min ); 3737 if( max && (num = CFDictionaryGetValue( param, CFSTR(kIODisplayMaxValueKey)))) 3738 CFNumberGetValue( num, kCFNumberSInt32Type, max ); 3739 3740 } while( false ); 3741 3742 if( params) 3743 CFRelease(params); 3744 3745#if DEBUGPARAMS 3746 if( cStr) 3747 CFRelease(parameterName); 3748#endif 3749 3750 return( err ); 3751} 3752 3753IOReturn 3754IODisplayGetFloatParameter( 3755 io_service_t service, 3756 IOOptionBits options, 3757 CFStringRef parameterName, 3758 float * value ) 3759{ 3760 IOReturn err; 3761 SInt32 ivalue, min, max; 3762 3763 err = IODisplayGetIntegerRangeParameter( service, options, parameterName, 3764 &ivalue, &min, &max ); 3765 if( err) 3766 return( err); 3767 3768 if( min == max) 3769 *value = 0; 3770 else 3771 *value = (((float) ivalue) - ((float) min)) / (((float) max) - ((float) min)); 3772 3773 return( err ); 3774} 3775 3776 3777IOReturn 3778IODisplaySetParameters( 3779 io_service_t service, 3780 IOOptionBits options, 3781 CFDictionaryRef params ) 3782{ 3783 IOReturn err; 3784 3785 if( !(service = IODisplayForFramebuffer( service, options))) 3786 return( kIOReturnUnsupported ); 3787 3788 err = IORegistryEntrySetCFProperties( service, params ); 3789 3790 IOObjectRelease(service); 3791 3792 return( err ); 3793} 3794 3795IOReturn 3796IODisplaySetIntegerParameter( 3797 io_service_t service, 3798 IOOptionBits options __unused, 3799 CFStringRef parameterName, 3800 SInt32 value ) 3801{ 3802 IOReturn err; 3803 CFDictionaryRef dict; 3804 CFNumberRef num; 3805 3806#if DEBUGPARAMS 3807 const char * cStr; 3808 3809 if( (cStr = CFStringGetCStringPtr( parameterName, kCFStringEncodingMacRoman)) 3810 && (cStr = getenv(cStr))) 3811 parameterName = CFStringCreateWithCString( kCFAllocatorDefault, cStr, 3812 kCFStringEncodingMacRoman ); 3813#endif 3814 3815 num = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &value ); 3816 if( !num) 3817 return( kIOReturnNoMemory ); 3818 3819 dict = CFDictionaryCreate( kCFAllocatorDefault, 3820 (const void **) ¶meterName, (const void **) &num, 1, 3821 &kCFTypeDictionaryKeyCallBacks, 3822 &kCFTypeDictionaryValueCallBacks ); 3823 CFRelease(num); 3824 if( !dict) 3825 return( kIOReturnNoMemory ); 3826 3827 err = IODisplaySetParameters( service, kNilOptions, dict ); 3828 3829 CFRelease(dict); 3830 3831#if DEBUGPARAMS 3832 if( cStr) 3833 CFRelease(parameterName); 3834#endif 3835 3836 return( err ); 3837} 3838 3839IOReturn 3840IODisplaySetFloatParameter( 3841 io_service_t service, 3842 IOOptionBits options, 3843 CFStringRef parameterName, 3844 float value ) 3845{ 3846 IOReturn err; 3847 SInt32 ivalue, min, max; 3848 3849 err = IODisplayGetIntegerRangeParameter( service, options, parameterName, 3850 NULL, &min, &max ); 3851 if( err) 3852 return( err); 3853 3854 ivalue = roundf((value * (((float) max) - ((float) min)) + ((float) min))); 3855 3856 err = IODisplaySetIntegerParameter( service, options, parameterName, ivalue ); 3857 3858 return( err ); 3859} 3860 3861IOReturn 3862IODisplayCommitParameters( 3863 io_service_t service, 3864 IOOptionBits options ) 3865{ 3866 return( IODisplaySetIntegerParameter( service, options, 3867 CFSTR(kIODisplayParametersCommitKey), 1)); 3868} 3869 3870#undef IOCreateDisplayInfoDictionary 3871CFDictionaryRef 3872IOCreateDisplayInfoDictionary( 3873 io_service_t framebuffer, 3874 IOOptionBits options ) 3875{ 3876 return( _IODisplayCreateInfoDictionary( NULL, framebuffer, options)); 3877} 3878 3879CFDictionaryRef 3880IODisplayCreateInfoDictionary( 3881 io_service_t framebuffer, 3882 IOOptionBits options ) 3883{ 3884 return( _IODisplayCreateInfoDictionary( NULL, framebuffer, options)); 3885} 3886