1/* 2 * Copyright (c) 1998-2000, 2012 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/mach_vm.h> 28#include <mach/thread_switch.h> 29#include <sys/file.h> 30#include <sys/stat.h> 31#include <sys/sysctl.h> 32#include <unistd.h> 33#include <string.h> 34#include <stdlib.h> 35#include <mach/mach_time.h> 36#include <syslog.h> 37#include <asl.h> 38#include <msgtracer_keys.h> 39 40#include <CoreFoundation/CoreFoundation.h> 41 42#include <IOKit/IOKitLib.h> 43#include <libkern/OSByteOrder.h> 44#include <IOKit/IOMessage.h> 45#include <IOKit/IOCFURLAccess.h> 46#include <IOKit/graphics/IOGraphicsLib.h> 47#include <IOKit/graphics/IOGraphicsLibPrivate.h> 48#include <IOKit/graphics/IOGraphicsTypesPrivate.h> 49#include <IOKit/graphics/IOAccelSurfaceControl.h> 50#include <IOKit/graphics/IOAccelSurfaceConnect.h> 51#include <IOKit/IOHibernatePrivate.h> 52#include "IOGraphicsLibInternal.h" 53 54#ifndef kIOFBDependentIDKey 55#define kIOFBDependentIDKey "IOFBDependentID" 56#endif 57#ifndef kIOFBDependentIndexKey 58#define kIOFBDependentIndexKey "IOFBDependentIndex" 59#endif 60 61#define FILTER_MAXDEPTH 32 62#ifndef kIOFBModePIKey 63#define kIOFBModePIKey "PI" 64#endif 65 66 67#define arrayCnt(var) (sizeof(var) / sizeof(var[0])) 68 69enum { 70 kAquaMinWidth = 800, 71 kAquaMinHeight = 600, 72 kInstallMinWidth = 1024, 73 kInstallMinHeight = 768 74}; 75 76enum { 77 kMirrorOnlyFlags = (kDisplayModeValidForAirPlayFlag | kDisplayModeValidForMirroringFlag), 78 kAddSafeFlags = (kDisplayModeValidFlag | kDisplayModeValidateAgainstDisplay) 79}; 80 81enum { kIOFBSWOfflineDisplayModeID = (IODisplayModeID) 0xffffff00 }; 82 83#define kAppleSetupDonePath "/var/db/.AppleSetupDone" 84#define kIOFirstBootFlagPath "/var/db/.com.apple.iokit.graphics" 85 86#define kIOGraphicsLogfilePath "/var/log/.com.apple.iokit.graphics.log" 87#define kIOGraphicsDesktopImagePath "/private/var/tmp/desktop.tga" 88#define kIOGraphicsLockImagePath "/private/var/tmp/screenlock.tga" 89 90#define DEBUG_NO_DRIVER_MODES 0 91 92struct DMTimingOverrideRec { 93 UInt32 timingOverrideVersion; 94 UInt32 timingOverrideAttributes; // flags 95 UInt32 timingOverrideSetFlags; // VDTimingInfoRec.csTimingFlags |= timingOverrideSetFlags 96 UInt32 timingOverrideClearFlags; // VDTimingInfoRec.csTimingFlags &= (~timingOverrideClearFlags) 97 UInt32 timingOverrideReserved[16]; // reserved 98}; 99typedef struct DMTimingOverrideRec DMTimingOverrideRec; 100 101struct DMDisplayTimingInfoRec { 102 UInt32 timingInfoVersion; 103 UInt32 timingInfoAttributes; // flags 104 SInt32 timingInfoRelativeQuality; // quality of the timing 105 SInt32 timingInfoRelativeDefault; // relative default of the timing 106 UInt32 timingInfoReserved[16]; // reserved 107}; 108typedef struct DMDisplayTimingInfoRec DMDisplayTimingInfoRec; 109 110#define desireDPI (75.0) 111#define mmPerInch (25.4) 112 113static kern_return_t 114IOFramebufferServerOpen( mach_port_t connect ); 115kern_return_t 116IOFramebufferServerFinishOpen( io_connect_t connect ); 117static kern_return_t 118IOFramebufferFinishOpen( IOFBConnectRef connectRef ); 119 120static kern_return_t 121IOFBLookDefaultDisplayMode( IOFBConnectRef connectRef ); 122 123static void 124IOFBCreateOverrides( IOFBConnectRef connectRef ); 125 126static kern_return_t 127IOFBCreateDisplayModeInformation( 128 IOFBConnectRef connectRef, 129 IODisplayModeID displayMode, 130 IOFBDisplayModeDescription * allInfo ); 131 132static kern_return_t 133IOFBAdjustDisplayModeInformation( 134 IOFBConnectRef connectRef, 135 IODisplayModeID displayMode, 136 IOFBDisplayModeDescription * allInfo ); 137 138static IOIndex 139IOFBIndexForPixelBits( IOFBConnectRef connectRef, IODisplayModeID mode, 140 IOIndex maxIndex, UInt32 bpp ); 141 142static Boolean 143IOFBLookScaleBaseMode( IOFBConnectRef connectRef, 144 IOFBDisplayModeDescription * scaleBase, 145 IOFBDisplayModeDescription * scaleDesc ); 146static kern_return_t 147IOFBInstallScaledModes( IOFBConnectRef connectRef, 148 IOFBDisplayModeDescription * scaleBase, 149 Boolean onlyMirrorModes ); 150static kern_return_t 151IOFBInstallScaledMode( IOFBConnectRef connectRef, 152 IOFBDisplayModeDescription * desc, 153 IOOptionBits installFlags ); 154 155static kern_return_t 156_IOFBGetAttributeForFramebuffer( io_connect_t connect, io_connect_t otherConnect, 157 IOSelect attribute, UInt32 * value ); 158 159static kern_return_t 160__IOFBGetPixelInformation( 161 IOFBConnectRef connectRef, 162 IODisplayModeID displayMode, 163 IOIndex depth, 164 IOPixelAperture aperture, 165 IOPixelInformation * pixelInfo ); 166 167static kern_return_t 168_IOFBGetPixelInformation( 169 IOFBConnectRef connectRef, 170 IODisplayModeID displayMode, 171 IOIndex depth, 172 IOPixelAperture aperture, 173 IOPixelInformation * pixelInfo ); 174 175 176static kern_return_t 177__IOFBGetCurrentDisplayModeAndDepth( IOFBConnectRef connectRef, 178 IODisplayModeID * displayMode, 179 IOIndex * depth ); 180 181static kern_return_t 182_IOFBGetCurrentDisplayModeAndDepth( IOFBConnectRef connectRef, 183 IODisplayModeID * displayMode, 184 IOIndex * depth ); 185 186static kern_return_t 187IOFBResetTransform( IOFBConnectRef connectRef ); 188 189static bool 190IOFBWritePrefs( IOFBConnectRef connectRef ); 191 192__private_extern__ CFMutableDictionaryRef gIOGraphicsProperties = 0; 193 194static struct IOFBConnect * gAllConnects = 0; 195static CFMutableDictionaryRef gConnectRefDict = 0; 196static bool gIOGraphicsSentPrefs = false; 197static io_service_t gIOGraphicsPrefsService; 198static bool gIOGraphicsInstallBoot = false; 199static const char * gIOGraphicsImageFiles[2] = { 200 kIOGraphicsDesktopImagePath, 201 kIOGraphicsLockImagePath }; 202 203/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 204 205struct IOFBMakeNumKeysContext 206{ 207 CFMutableDictionaryRef dict; 208 Boolean andValues; 209}; 210 211static void 212IOFBMakeNumKeys( const void * key, const void * value, void * context ) 213{ 214 CFStringRef str = key; 215 CFMutableDictionaryRef newDict = ((struct IOFBMakeNumKeysContext *)context)->dict; 216 Boolean andValues = ((struct IOFBMakeNumKeysContext *)context)->andValues; 217 const char * cStr; 218 char * buffer = NULL; 219 220 cStr = CFStringGetCStringPtr( str, kCFStringEncodingMacRoman); 221 if( !cStr) { 222 CFIndex bufferSize = CFStringGetMaximumSizeForEncoding( CFStringGetLength(str), 223 kCFStringEncodingMacRoman) + sizeof('\0'); 224 buffer = malloc( bufferSize); 225 if( buffer && CFStringGetCString( str, buffer, bufferSize, kCFStringEncodingMacRoman)) 226 cStr = buffer; 227 } 228 if( cStr) 229 key = (const void *) (unsigned long) strtol( cStr, 0, 0 ); 230 else 231 key = 0; 232 if( buffer) 233 free( buffer); 234 235 if (!key) 236 return; 237 238 if (andValues) 239 { 240 SInt32 scalarValue; 241 CFNumberGetValue(value, kCFNumberSInt32Type, &scalarValue); 242 value = (const void *)(uintptr_t) scalarValue; 243 } 244 245 CFDictionarySetValue(newDict, key, value); 246} 247 248static CFMutableDictionaryRef 249IOFBMakeIntegerKeys( CFDictionaryRef dict, Boolean andValues ) 250{ 251 struct IOFBMakeNumKeysContext context; 252 253 context.dict = 0; 254 context.andValues = andValues; 255 256 if( dict && (context.dict = CFDictionaryCreateMutable( 257 kCFAllocatorDefault, (CFIndex) 0, 258 (CFDictionaryKeyCallBacks *) 0, 259 andValues ? (CFDictionaryValueCallBacks *) 0 260 : &kCFTypeDictionaryValueCallBacks ))) 261 CFDictionaryApplyFunction( dict, &IOFBMakeNumKeys, &context ); 262 263 return (context.dict); 264} 265 266/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 267 268void IOLoadPEFsFromURL( CFURLRef ndrvDirURL, io_service_t service ); 269 270static void ScanNDRVs( io_service_t service ) 271{ 272 io_registry_entry_t root; 273 CFURLRef url; 274 Boolean scan = false; 275 CFDataRef data; 276 UInt32 * gen; 277 278 root = IORegistryGetRootEntry(kIOMasterPortDefault); 279 if (root) 280 { 281 data = (CFDataRef) IORegistryEntryCreateCFProperty(root, 282 CFSTR(kIONDRVFramebufferGenerationKey), 283 kCFAllocatorDefault, kNilOptions); 284 if (data) 285 { 286 gen = (UInt32 *) CFDataGetBytePtr(data); 287 scan = (gen[0] != gen[1]); 288 CFRelease(data); 289 } 290 IOObjectRelease(root); 291 } 292 293 if (scan) 294 { 295 url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 296 CFSTR("/System/Library/Extensions/AppleNDRV"), kCFURLPOSIXPathStyle, true); 297 if (url) 298 { 299 IOLoadPEFsFromURL(url, service); 300 CFRelease(url); 301 } 302 gIOGraphicsSentPrefs = false; 303 } 304} 305 306/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 307 308kern_return_t 309IOFramebufferServerStart( void ) 310{ 311 CFMutableDictionaryRef newDict; 312 CFMutableDictionaryRef prefs = 0; 313 314 ScanNDRVs( MACH_PORT_NULL ); 315 316 if (!gIOGraphicsProperties) 317 { 318 gIOGraphicsProperties = readPlist("/System/Library/Frameworks/IOKit.framework/" 319 "Resources/IOGraphicsProperties.plist", 0); 320 if (gIOGraphicsProperties) 321 { 322 if ((newDict = IOFBMakeIntegerKeys(CFDictionaryGetValue(gIOGraphicsProperties, 323 CFSTR("std-modes")), false))) 324 { 325 CFDictionarySetValue(gIOGraphicsProperties, CFSTR("std-modes"), newDict); 326 CFRelease( newDict ); 327 } 328 if ((newDict = IOFBMakeIntegerKeys(CFDictionaryGetValue(gIOGraphicsProperties, 329 CFSTR("timing-ids")), true))) 330 { 331 CFDictionarySetValue(gIOGraphicsProperties, CFSTR("timing-ids"), newDict); 332 CFRelease( newDict ); 333 } 334 if ((newDict = IOFBMakeIntegerKeys(CFDictionaryGetValue(gIOGraphicsProperties, 335 CFSTR("irb-timing-ids")), true))) 336 { 337 CFDictionarySetValue(gIOGraphicsProperties, CFSTR("irb-timing-ids"), newDict); 338 CFRelease( newDict ); 339 } 340 } 341 else 342 gIOGraphicsProperties = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, 343 &kCFTypeDictionaryKeyCallBacks, 344 &kCFTypeDictionaryValueCallBacks); 345 346 gIOGraphicsPrefsService = IORegistryEntryFromPath(kIOMasterPortDefault, 347 kIOServicePlane ":/IOResources/IODisplayWrangler"); 348 349 int sbmib[] = { CTL_KERN, KERN_SAFEBOOT }; 350 uint32_t value = 0; 351 size_t vsize = sizeof(value); 352 Boolean safeBoot = (-1 != sysctl(sbmib, 2, &value, &vsize, NULL, 0)) && (value != 0); 353 354 if (!safeBoot) 355 prefs = readPlist(kIOFirstBootFlagPath, 0); 356 if (!prefs) 357 prefs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 358 &kCFTypeDictionaryKeyCallBacks, 359 &kCFTypeDictionaryValueCallBacks); 360 if (prefs) 361 { 362 CFDictionarySetValue(gIOGraphicsProperties, CFSTR("prefs"), prefs); 363 CFRelease(prefs); 364 365 if (!gIOGraphicsSentPrefs) 366 { 367 gIOGraphicsSentPrefs = true; 368 if (gIOGraphicsPrefsService) 369 IORegistryEntrySetCFProperty(gIOGraphicsPrefsService, CFSTR(kIOGraphicsPrefsKey), prefs); 370 } 371 } 372 struct stat stat_buf; 373 gIOGraphicsInstallBoot = (0 != stat(kAppleSetupDonePath, &stat_buf)); 374 } 375 376 return( KERN_SUCCESS ); 377} 378 379kern_return_t 380IOFramebufferOpen( 381 io_service_t service, 382 task_port_t owningTask, 383 unsigned int type, 384 io_connect_t * connect ) 385{ 386 kern_return_t kr; 387 388 kr = IOServiceOpen( service, owningTask, type, connect ); 389 390 if ((KERN_SUCCESS == kr) && (type == kIOFBServerConnectType)) 391 kr = IOFramebufferServerOpen( *connect ); 392 393 return( kr ); 394} 395 396 397kern_return_t 398IOFBCreateSharedCursor( io_connect_t connect, 399 unsigned int version, 400 unsigned int maxWidth, unsigned int maxHeight ) 401{ 402 403 IOFramebufferServerOpen( connect ); 404 IOFramebufferServerFinishOpen( connect ); 405 406 uint64_t inData[] = { version, maxWidth, maxHeight }; 407 return IOConnectCallMethod(connect, 0, // Index 408 inData, arrayCnt(inData), NULL, 0, // Input 409 NULL, NULL, NULL, NULL); // Output 410} 411 412extern kern_return_t 413IOFBGetFramebufferInformationForAperture( io_connect_t connect, 414 IOPixelAperture aperture, 415 IOFramebufferInformation * info ) 416{ 417 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 418 IOPixelInformation pixelInfo; 419 IODisplayModeID mode; 420 IOIndex depth; 421 kern_return_t err; 422 423 if (!connectRef) 424 return (kIOReturnBadArgument); 425 426 err = _IOFBGetCurrentDisplayModeAndDepth(connectRef, &mode, &depth); 427 if( err) 428 return( err); 429 err = _IOFBGetPixelInformation(connectRef, mode, depth, aperture, &pixelInfo); 430 if( err) 431 return( err); 432 433 err = IOFBGetFramebufferOffsetForAperture( connect, aperture, 434 &info->baseAddress); 435 info->activeWidth = pixelInfo.activeWidth; 436 info->activeHeight = pixelInfo.activeHeight; 437 info->bytesPerRow = pixelInfo.bytesPerRow; 438 info->bytesPerPlane = pixelInfo.bytesPerPlane; 439 info->bitsPerPixel = pixelInfo.bitsPerPixel; 440 info->pixelType = pixelInfo.pixelType; 441 info->flags = pixelInfo.flags; 442 443 return( err); 444} 445 446extern kern_return_t 447IOFBGetFramebufferOffsetForAperture( mach_port_t connect, 448 IOPixelAperture aperture, 449 IOByteCount * offset ) 450{ 451 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 452 453 if (!connectRef) 454 return (kIOReturnBadArgument); 455 456 if (kIOFBConnectStateUnusable & connectRef->state) 457 { 458 *offset = 0; 459 return (kIOReturnSuccess); 460 } 461 uint64_t inData = aperture; 462 uint64_t outData = 0; 463 uint32_t outSize = 1; 464 kern_return_t kr = IOConnectCallMethod(connect, 8, // Index 465 &inData, 1, NULL, 0, // Input 466 &outData, &outSize, NULL, NULL); // Output 467 *offset = (IOByteCount) outData; 468 return kr; 469} 470 471extern kern_return_t 472IOFBSetBounds( io_connect_t connect, 473 IOGBounds * rect ) 474{ 475 IOGBounds rects[2]; 476 rects[0] = rects[1] = *rect; 477 return IOConnectCallMethod(connect, 9, // Index 478 NULL, 0, rects, sizeof(rects), // Input 479 NULL, NULL, NULL, NULL); // Output 480} 481 482extern kern_return_t 483IOFBSetVirtualBounds(io_connect_t connect, 484 IOGBounds * screenBounds, 485 IOGBounds * desktopBounds ) 486{ 487 IOGBounds rects[2]; 488 rects[0] = *screenBounds; 489 rects[1] = *desktopBounds; 490 return IOConnectCallMethod(connect, 9, // Index 491 NULL, 0, rects, sizeof(rects), // Input 492 NULL, NULL, NULL, NULL); // Output 493} 494 495static kern_return_t 496__IOFBGetCurrentDisplayModeAndDepth( IOFBConnectRef connectRef, 497 IODisplayModeID * displayMode, 498 IOIndex * depth ) 499{ 500 kern_return_t err; 501 uint64_t outData[2]; 502 uint32_t outSize = arrayCnt(outData); 503 504 err = IOConnectCallMethod(connectRef->connect, 2, // Index 505 NULL, 0, NULL, 0, // Input 506 outData, &outSize, NULL, NULL); // Output 507 *displayMode = (IODisplayModeID) outData[0]; 508 *depth = (IOIndex) outData[1]; 509 510 DEBG(connectRef, "IOFBGetCurrentDisplayModeAndDepth(%x), %x, %d\n", err, (int) *displayMode, (int) *depth); 511 512 return( err ); 513} 514 515static kern_return_t 516_IOFBGetCurrentDisplayModeAndDepth( IOFBConnectRef connectRef, 517 IODisplayModeID * displayMode, 518 IOIndex * depth ) 519{ 520 if (kIOFBConnectStateUnusable & connectRef->state) 521 { 522 *displayMode = kIOFBSWOfflineDisplayModeID; 523 *depth = 0; 524 return (kIOReturnSuccess); 525 } 526 else return (__IOFBGetCurrentDisplayModeAndDepth(connectRef, displayMode, depth)); 527} 528 529kern_return_t 530IOFBGetCurrentDisplayModeAndDepth( io_connect_t connect, 531 IODisplayModeID * displayMode, 532 IOIndex * depth ) 533{ 534 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 535 if (!connectRef) 536 return (kIOReturnBadArgument); 537 538 return (_IOFBGetCurrentDisplayModeAndDepth(connectRef, displayMode, depth)); 539} 540 541extern kern_return_t 542IOFBGetPixelFormat( io_connect_t connect, 543 IODisplayModeID mode, 544 IOIndex depth, 545 IOPixelAperture aperture, 546 IOPixelEncoding * pixelFormat ) 547{ 548 IOPixelInformation pixelInfo; 549 kern_return_t err; 550 551 err = IOFBGetPixelInformation( connect, mode, depth, aperture, &pixelInfo ); 552 if( err) 553 return( err); 554 555 strncpy( *pixelFormat, pixelInfo.pixelFormat, kIOMaxPixelBits ); 556 557 return( err); 558} 559 560extern kern_return_t 561IOFBSetCLUT( io_connect_t connect, 562 UInt32 startIndex, 563 UInt32 numEntries, 564 IOOptionBits options, 565 IOColorEntry * colors ) 566{ 567 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 568 if (!connectRef) 569 return (kIOReturnBadArgument); 570 571 if (kIOFBConnectStateUnusable & connectRef->state) 572 { 573 return (kIOReturnSuccess); 574 } 575 576 uint64_t inData[] = { startIndex, options }; 577 size_t inSize = numEntries * sizeof( IOColorEntry); 578 return IOConnectCallMethod(connect, 16, // Index 579 inData, arrayCnt(inData), colors, inSize, // Input 580 NULL, NULL, NULL, NULL); // Output 581} 582 583extern kern_return_t 584IOFBSetGamma( io_connect_t connect, 585 UInt32 channelCount, 586 UInt32 dataCount, 587 UInt32 dataWidth, 588 void * data ) 589{ 590 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 591 if (!connectRef) 592 return (kIOReturnBadArgument); 593 594 if (kIOFBConnectStateUnusable & connectRef->state) 595 { 596 return (kIOReturnSuccess); 597 } 598 599 uint64_t inData[] = { channelCount, dataCount, dataWidth }; 600 size_t inSize = ((dataWidth + 7) / 8) * dataCount * channelCount; 601 602 return IOConnectCallMethod(connect, 11, // Index 603 inData, arrayCnt(inData), data, inSize, // Input 604 NULL, NULL, NULL, NULL); // Output 605} 606 607static IOOptionBits 608IOFBGetState( IOFBConnectRef connectRef ) 609{ 610 IOOptionBits state = 0; 611 io_service_t display; 612 613 if( (display = IODisplayForFramebuffer( connectRef->framebuffer, kNilOptions))) { 614 state |= (kIOFBConnectStateHWOnline | kIOFBConnectStateOnline); 615 IOObjectRelease( display ); 616 } 617 if (connectRef) 618 DEBG(connectRef, "IOFBGetState(%p) = %08x\n", 619 connectRef, (int) state); 620 621 return( state ); 622} 623 624extern kern_return_t 625IOFBSet444To555Table( io_connect_t connect, 626 const unsigned char * table ) 627{ 628 uint64_t inData = 0; 629 size_t inSize = 16 * sizeof(table[0]); 630 return IOConnectCallMethod(connect, 15, // Index 631 &inData, 1, table, inSize, // Input 632 NULL, NULL, NULL, NULL); // Output 633} 634 635extern kern_return_t 636IOFBSet555To444Table( io_connect_t connect, 637 const unsigned char * table ) 638{ 639 uint64_t inData = 1; 640 size_t inSize = 32 * sizeof(table[0]); 641 return IOConnectCallMethod(connect, 15, // Index 642 &inData, 1, table, inSize, // Input 643 NULL, NULL, NULL, NULL); // Output 644} 645 646extern kern_return_t 647IOFBSet256To888Table( io_connect_t connect, 648 const unsigned int * table ) 649{ 650 uint64_t inData = 2; 651 size_t inSize = 256 * sizeof(table[0]); 652 return IOConnectCallMethod(connect, 15, // Index 653 &inData, 1, table, inSize, // Input 654 NULL, NULL, NULL, NULL); // Output 655} 656 657extern kern_return_t 658IOFBSet888To256Table( io_connect_t connect, 659 const unsigned char * table ) 660{ 661 uint64_t inData = 3; 662 size_t inSize = 5 * 256 * sizeof(table[0]); 663 return IOConnectCallMethod(connect, 15, // Index 664 &inData, 1, table, inSize, // Input 665 NULL, NULL, NULL, NULL); // Output 666} 667 668static kern_return_t 669_IOFBGetDisplayModeCount( IOFBConnectRef connectRef, 670 UInt32 * count ) 671{ 672 if (kIOFBConnectStateUnusable & connectRef->state) 673 { 674 *count = 1; 675 return (kIOReturnSuccess); 676 } 677 678 uint64_t outData = 0; 679 uint32_t outCnt = 1; 680 681 kern_return_t kr = IOConnectCallMethod(connectRef->connect, 6, // Index 682 NULL, 0, NULL, 0, // Input 683 &outData, &outCnt, NULL, NULL); // Output 684 *count = (UInt32) outData; 685 return kr; 686} 687 688static kern_return_t 689_IOFBGetDisplayModes( IOFBConnectRef connectRef, 690 UInt32 count, 691 IODisplayModeID * allDisplayModes ) 692{ 693 if (kIOFBConnectStateUnusable & connectRef->state) 694 { 695 if (1 != count) 696 return (kIOReturnBadArgument); 697 *allDisplayModes = kIOFBSWOfflineDisplayModeID; 698 return (kIOReturnSuccess); 699 } 700 701 size_t len = count * sizeof( IODisplayModeID); 702 return IOConnectCallMethod(connectRef->connect, 7, // Index 703 NULL, 0, NULL, 0, // Input 704 NULL, NULL, allDisplayModes, &len); // Output 705} 706 707 708kern_return_t 709IOFBGetDisplayModeCount( io_connect_t connect, 710 UInt32 * count ) 711{ 712 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 713 714 *count = CFArrayGetCount( connectRef->modesArray ); 715 716 return( kIOReturnSuccess ); 717} 718 719 720kern_return_t 721IOFBGetDisplayModes( io_connect_t connect, 722 UInt32 count, 723 IODisplayModeID * allDisplayModes ) 724{ 725 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 726 UInt32 i, modeCount; 727 728 modeCount = CFArrayGetCount( connectRef->modesArray ); 729 if( count < modeCount) 730 modeCount = count; 731 732 for( i = 0; i < modeCount; i++ ) { 733 CFDictionaryRef dict; 734 CFNumberRef num; 735 736 dict = (CFMutableDictionaryRef) CFArrayGetValueAtIndex( connectRef->modesArray, i ); 737 num = CFDictionaryGetValue( dict, CFSTR(kIOFBModeIDKey) ); 738 if( num) 739 CFNumberGetValue( num, kCFNumberSInt32Type, (SInt32 *) &allDisplayModes[i] ); 740 else 741 allDisplayModes[i] = 0; 742 } 743 744 return( kIOReturnSuccess ); 745} 746 747static kern_return_t 748_IOFBGetAttributeForFramebuffer( io_connect_t connect, io_connect_t otherConnect, 749 IOSelect attribute, UInt32 * value ) 750{ 751 IOReturn err; 752 753 if( otherConnect) { 754 err = IOConnectAddClient( connect, otherConnect ); 755 if( err) 756 return( err ); 757 } 758 759 uint64_t inData = attribute; 760 uint64_t outData = 0; 761 uint32_t outCnt = 1; 762 err = IOConnectCallMethod(connect, 18, // Index 763 &inData, 1, NULL, 0, // Input 764 &outData, &outCnt, NULL, NULL); // Output 765 *value = (UInt32) outData; 766 767 return( err ); 768} 769 770kern_return_t 771IOFBGetAttributeForFramebuffer( io_connect_t connect, io_connect_t otherConnect, 772 IOSelect attribute, UInt32 * value ) 773{ 774 IOReturn err; 775 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 776 777 if (!connectRef) 778 return (kIOReturnBadArgument); 779 780 if (kIOFBConnectStateUnusable & connectRef->state) 781 { 782 *value = 0; 783 if (kIOMirrorDefaultAttribute == attribute) 784 err = kIOReturnSuccess; 785 else 786 err = kIOReturnOffline; 787 } 788 else 789 { 790 switch (attribute) 791 { 792 case kIOFBMatchedConnectChangeAttribute: 793 *value = (connectRef->matchMode != kIODisplayModeIDInvalid); 794 err = kIOReturnSuccess; 795 break; 796 797 default: 798 err = _IOFBGetAttributeForFramebuffer( connect, otherConnect, attribute, value ); 799 break; 800 } 801 } 802 803 if ((kIOReturnSuccess == err) 804 && (kIOMirrorDefaultAttribute == attribute) 805 && connectRef 806 && connectRef->displayMirror) 807 { 808 *value |= kIOMirrorDefault; 809 } 810 if (kIOMirrorDefaultAttribute == attribute) 811 DEBG(connectRef, "kIOMirrorDefaultAttribute = %08x (%p, %p)\n", 812 (int) *value, connectRef, connectRef ? connectRef->overrides : 0); 813 814 return( err ); 815} 816 817static void 818IOFBDictRemoveModePI(const void *key __unused, const void *value, void *context __unused) 819{ 820 CFDictionaryRemoveValue((CFMutableDictionaryRef) value, CFSTR(kIOFBModePIKey)); 821} 822 823kern_return_t 824IOFBSetAttributeForFramebuffer( io_connect_t connect, io_connect_t otherConnect, 825 IOSelect attribute, UInt32 value ) 826{ 827 IOReturn err; 828 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 829 830 if (!connectRef) 831 return (kIOReturnBadArgument); 832 833 if (kIOFBConnectStateUnusable & connectRef->state) 834 return (kIOReturnSuccess); 835 836 if( otherConnect) { 837 err = IOConnectAddClient( connect, otherConnect ); 838 if( err) 839 return( err ); 840 } 841 842 if (kIOMirrorAttribute == attribute) 843 { 844 DEBG(connectRef, "set mirror %d\n", (int) value); 845 } 846 847 uint64_t inData[] = { attribute, value }; 848 err = IOConnectCallMethod(connect, 19, // Index 849 inData, arrayCnt(inData), NULL, 0, // Input 850 NULL, NULL, NULL, NULL); // Output 851 852 if (kIOMirrorAttribute == attribute) 853 { 854 DEBG(connectRef, "did set mirror(%x)\n", err); 855 IOFBResetTransform(connectRef); 856 857 CFDictionaryApplyFunction(connectRef->modes, &IOFBDictRemoveModePI, NULL); 858 if (otherConnect) 859 { 860 IOFBConnectRef otherConnectRef = IOFBConnectToRef( otherConnect ); 861 if (otherConnectRef) CFDictionaryApplyFunction(otherConnectRef->modes, &IOFBDictRemoveModePI, NULL); 862 } 863 } 864 865 return( err ); 866} 867 868__private_extern__ float 869ratioOver( float a, float b ) 870{ 871 if( a > b) 872 return( a / b ); 873 else 874 return( b / a ); 875} 876 877__private_extern__ Boolean 878ValidateTimingInformation( IOFBConnectRef connectRef __unused, const IOTimingInformation * timingInfo ) 879{ 880 if (!timingInfo->detailedInfo.v2.horizontalActive 881 || !timingInfo->detailedInfo.v2.verticalActive 882 || ((timingInfo->detailedInfo.v2.horizontalSyncOffset + timingInfo->detailedInfo.v2.horizontalSyncPulseWidth) 883 > timingInfo->detailedInfo.v2.horizontalBlanking) 884 || ((timingInfo->detailedInfo.v2.verticalSyncOffset + timingInfo->detailedInfo.v2.verticalSyncPulseWidth) 885 > timingInfo->detailedInfo.v2.verticalBlanking) 886 || !timingInfo->detailedInfo.v2.verticalActive) 887 { 888#if RLOG 889 DEBG(connectRef, "!ValidateTimingInformation\n"); 890 IOFBLogTiming(connectRef, timingInfo); 891#endif 892 return (false); 893 } 894 895 return (true); 896} 897 898// timing is bad enough it should be ignored regardless of source 899__private_extern__ Boolean 900InvalidTiming( IOFBConnectRef connectRef __unused, const IOTimingInformation * timingInfo ) 901{ 902 903 if ((kIODetailedTimingValid & timingInfo->flags) 904 && (!timingInfo->detailedInfo.v2.horizontalSyncPulseWidth 905 || !timingInfo->detailedInfo.v2.verticalSyncPulseWidth)) 906 { 907#if RLOG 908 DEBG(connectRef, "InvalidTiming\n"); 909 IOFBLogTiming(connectRef, timingInfo); 910#endif 911 return (true); 912 } 913 914 return (false); 915} 916 917__private_extern__ float 918RefreshRateFromDetailedTiming( IODetailedTimingInformationV2 * detailed ) 919{ 920 float rate; 921 922 rate = ((float) detailed->pixelClock) 923 / ((float)(detailed->horizontalActive + detailed->horizontalBlanking)) 924 / ((float)(detailed->verticalActive + detailed->verticalBlanking)); 925 926 if (kIOInterlacedCEATiming & detailed->signalConfig) 927 rate *= 2.0; 928 929 return (rate); 930} 931 932static void 933MakeDetailedRefresh( IOFBConnectRef connectRef, IOFBDisplayModeDescription * modeInfo ) 934{ 935 if (!(kIODetailedTimingValid & modeInfo->timingInfo.flags)) 936 return; 937// if (kDisplayModeTelevisionFlag & modeInfo->info.flags) 938// return; 939 940 if (false 941 || (kIOTimingIDAppleNTSC_ST == modeInfo->timingInfo.appleTimingID) 942 || (kIOTimingIDAppleNTSC_FF == modeInfo->timingInfo.appleTimingID) 943 || (kIOTimingIDAppleNTSC_STconv == modeInfo->timingInfo.appleTimingID) 944 || (kIOTimingIDAppleNTSC_FFconv == modeInfo->timingInfo.appleTimingID) 945 || (kIOTimingIDApplePAL_ST == modeInfo->timingInfo.appleTimingID) 946 || (kIOTimingIDApplePAL_FF == modeInfo->timingInfo.appleTimingID) 947 || (kIOTimingIDApplePAL_STconv == modeInfo->timingInfo.appleTimingID) 948 || (kIOTimingIDApplePAL_FFconv == modeInfo->timingInfo.appleTimingID)) 949 return; 950 951 if (!ValidateTimingInformation(connectRef, &modeInfo->timingInfo)) 952 return; 953 954 modeInfo->info.refreshRate = 65536ULL * modeInfo->timingInfo.detailedInfo.v2.pixelClock 955 / ((UInt64)(modeInfo->timingInfo.detailedInfo.v2.horizontalActive 956 + modeInfo->timingInfo.detailedInfo.v2.horizontalBlanking)) 957 / ((UInt64)(modeInfo->timingInfo.detailedInfo.v2.verticalActive 958 + modeInfo->timingInfo.detailedInfo.v2.verticalBlanking)); 959 960 if (kDisplayModeInterlacedFlag & modeInfo->info.flags) 961 modeInfo->info.refreshRate *= 2; 962} 963 964enum 965{ 966 kDetailedTimingsNotEqual = false, 967 kDetailedTimingsEqual = true, 968 kDetailedTimingsIdentical = 2 969}; 970 971static Boolean 972DetailedTimingsEqual( IODetailedTimingInformationV2 * newTimingInfo, 973 IODetailedTimingInformationV2 * existingTimingInfo, 974 IOOptionBits modeGenFlags ) 975{ 976 Boolean existingScaled, newScaled; 977 UInt32 vMask; 978 UInt32 eH, eV, eF, nH, nV, nF, swap; 979 980 eH = existingTimingInfo->horizontalScaled; 981 eV = existingTimingInfo->verticalScaled; 982 eF = existingTimingInfo->scalerFlags; 983 nH = newTimingInfo->horizontalScaled; 984 nV = newTimingInfo->verticalScaled; 985 nF = newTimingInfo->scalerFlags; 986 987 existingScaled = (eH && eV); 988 newScaled = (nH && nV); 989 990 if (kIOInterlacedCEATiming & (newTimingInfo->signalConfig ^ existingTimingInfo->signalConfig)) 991 return (false); 992 993 if (kIOFBGTFMode & modeGenFlags) 994 { 995 UInt32 new, existing; 996 997 existing = existingScaled ? existingTimingInfo->horizontalScaled 998 : existingTimingInfo->horizontalActive; 999 new = newScaled ? newTimingInfo->horizontalScaled 1000 : newTimingInfo->horizontalActive; 1001 if( new < (existing - 20)) 1002 return (kDetailedTimingsNotEqual); 1003 if( new > (existing + 20)) 1004 return (kDetailedTimingsNotEqual); 1005 1006 existing = existingScaled ? existingTimingInfo->verticalScaled 1007 : existingTimingInfo->verticalActive; 1008 new = newScaled ? newTimingInfo->verticalScaled 1009 : newTimingInfo->verticalActive; 1010 1011 if( new < (existing - 20)) 1012 return (kDetailedTimingsNotEqual); 1013 if( new > (existing + 20)) 1014 return (kDetailedTimingsNotEqual); 1015 1016 if (fabsf(RefreshRateFromDetailedTiming(newTimingInfo) 1017 - RefreshRateFromDetailedTiming(existingTimingInfo)) < 1.0) 1018 return (kDetailedTimingsEqual); 1019 1020 return (kDetailedTimingsNotEqual); 1021 } 1022 1023 if (existingScaled || newScaled) 1024 { 1025 if (kIOFBTimingMatch & modeGenFlags) 1026 { 1027 if (kIOScaleSwapAxes & eF) 1028 { 1029 swap = eH; 1030 eH = eV; 1031 eV = swap; 1032 } 1033 eF &= ~kIOScaleRotateFlags; 1034 if (eH == existingTimingInfo->horizontalActive) 1035 eH = 0; 1036 if (eV == existingTimingInfo->verticalActive) 1037 eV = 0; 1038 if (kIOScaleSwapAxes & nF) 1039 { 1040 swap = nH; 1041 nH = nV; 1042 nV = swap; 1043 } 1044 nF &= ~kIOScaleRotateFlags; 1045 if (nH == newTimingInfo->horizontalActive) 1046 nH = 0; 1047 if (nV == newTimingInfo->verticalActive) 1048 nV = 0; 1049 } 1050 if (eF != nF) 1051 return (kDetailedTimingsNotEqual); 1052 if (eH != nH) 1053 return (kDetailedTimingsNotEqual); 1054 if (eV != nV) 1055 return (kDetailedTimingsNotEqual); 1056 } 1057 1058 if (kIOInterlacedCEATiming 1059 & newTimingInfo->signalConfig & existingTimingInfo->signalConfig) 1060 vMask = ~1; 1061 else 1062 vMask = ~0; 1063 1064 if (newTimingInfo->horizontalActive != existingTimingInfo->horizontalActive) 1065 return (kDetailedTimingsNotEqual); 1066 if (newTimingInfo->horizontalBlanking != existingTimingInfo->horizontalBlanking) 1067 return (kDetailedTimingsNotEqual); 1068 if (newTimingInfo->verticalActive != existingTimingInfo->verticalActive) 1069 return (kDetailedTimingsNotEqual); 1070 if ((newTimingInfo->verticalBlanking & vMask) != (existingTimingInfo->verticalBlanking & vMask)) 1071 return (kDetailedTimingsNotEqual); 1072 1073 if (newTimingInfo->horizontalBorderLeft != existingTimingInfo->horizontalBorderLeft) 1074 return (kDetailedTimingsNotEqual); 1075 if (newTimingInfo->horizontalBorderRight != existingTimingInfo->horizontalBorderRight) 1076 return (kDetailedTimingsNotEqual); 1077 if ((newTimingInfo->verticalBorderTop & vMask) != (existingTimingInfo->verticalBorderTop & vMask)) 1078 return (kDetailedTimingsNotEqual); 1079 if ((newTimingInfo->verticalBorderBottom & vMask) != (existingTimingInfo->verticalBorderBottom & vMask)) 1080 return (kDetailedTimingsNotEqual); 1081 1082 if (newTimingInfo->pixelClock == existingTimingInfo->pixelClock) 1083 { 1084 if (newTimingInfo->horizontalSyncOffset != existingTimingInfo->horizontalSyncOffset) 1085 return (kDetailedTimingsEqual); 1086 1087 if (newTimingInfo->horizontalSyncPulseWidth != existingTimingInfo->horizontalSyncPulseWidth) 1088 return (kDetailedTimingsEqual); 1089 1090 if ((newTimingInfo->verticalSyncOffset & vMask) != (existingTimingInfo->verticalSyncOffset & vMask)) 1091 return (kDetailedTimingsEqual); 1092 1093 if ((newTimingInfo->verticalSyncPulseWidth & vMask) != (existingTimingInfo->verticalSyncPulseWidth & vMask)) 1094 return (kDetailedTimingsEqual); 1095 1096 return (kDetailedTimingsIdentical); 1097 } 1098 1099 return (kDetailedTimingsNotEqual); 1100} 1101 1102static bool 1103GetTovr( IOFBConnectRef connectRef, IOAppleTimingID appleTimingID, UInt32 * flags, UInt32 * _maskFlags ) 1104{ 1105 CFDictionaryRef tovr; 1106 CFDataRef modetovr = NULL; 1107 UInt32 maskFlags = 0xffffffff; 1108 bool result = false; 1109 1110 if (appleTimingID && connectRef->overrides) 1111 { 1112 if ((connectRef->defaultMinWidth == kInstallMinWidth) 1113 && (kDisplayVendorIDUnknown == connectRef->displayVendor) 1114 && (kDisplayProductIDGeneric == connectRef->displayProduct)) 1115 { 1116 if (kIOTimingIDVESA_1024x768_60hz == appleTimingID) 1117 { 1118 appleTimingID = kIOTimingIDVESA_800x600_60hz; 1119 } 1120 else if ((kIOTimingIDVESA_800x600_60hz == appleTimingID) 1121 || (kIOTimingIDVESA_800x600_56hz == appleTimingID)) 1122 { 1123 appleTimingID = kIOTimingIDVESA_1024x768_60hz; 1124 } 1125 } 1126 tovr = CFDictionaryGetValue( connectRef->overrides, CFSTR("tovr") ); 1127 result = (tovr && (modetovr = CFDictionaryGetValue( tovr, (const void *) (uintptr_t) (UInt32) appleTimingID ))); 1128 if (result) 1129 { 1130 DMTimingOverrideRec * tovrRec; 1131 tovrRec = (DMTimingOverrideRec *) CFDataGetBytePtr(modetovr); 1132 DEBG(connectRef, "tovr: clr %08x, set %08x\n", 1133 OSReadBigInt32(&tovrRec->timingOverrideClearFlags, 0), 1134 OSReadBigInt32(&tovrRec->timingOverrideSetFlags, 0)); 1135 maskFlags = ~OSReadBigInt32(&tovrRec->timingOverrideClearFlags, 0); 1136 *flags &= maskFlags; 1137 *flags |= OSReadBigInt32(&tovrRec->timingOverrideSetFlags, 0); 1138 } 1139 1140 } 1141 1142 if (_maskFlags) 1143 *_maskFlags = maskFlags; 1144 1145 return (result); 1146} 1147 1148static void 1149MergeDisplayModeInformation(IOFBConnectRef connectRef __unused, 1150 IODisplayModeInformation * from, 1151 IODisplayModeInformation * to) 1152{ 1153 to->flags |= from->flags; 1154 if (!to->imageWidth) to->imageWidth = from->imageWidth; 1155 if (!to->imageHeight) to->imageHeight = from->imageHeight; 1156} 1157 1158static void 1159IOFBSetImageSize(IOFBConnectRef connectRef __unused, 1160 IOFBDisplayModeDescription * desc) 1161{ 1162 float nativeWidth, nativeHeight; 1163 float width, height, aspectDiff; 1164 uint32_t imageWidth, imageHeight; 1165 1166 DEBG(connectRef, "%d x %d, %d x %d, %d x %d\n", 1167 desc->timingInfo.detailedInfo.v2.horizontalActive, 1168 desc->timingInfo.detailedInfo.v2.verticalActive, 1169 desc->timingInfo.detailedInfo.v2.horizontalScaled, 1170 desc->timingInfo.detailedInfo.v2.verticalScaled, 1171 desc->info.imageWidth, 1172 desc->info.imageHeight 1173 ); 1174 1175 nativeWidth = desc->timingInfo.detailedInfo.v2.horizontalActive; 1176 nativeHeight = desc->timingInfo.detailedInfo.v2.verticalActive; 1177 width = desc->timingInfo.detailedInfo.v2.horizontalScaled; 1178 if (!width) width = nativeWidth; 1179 height = desc->timingInfo.detailedInfo.v2.verticalScaled; 1180 if (!height) height = nativeHeight; 1181 if (kIOScaleSwapAxes & desc->timingInfo.detailedInfo.v2.scalerFlags) 1182 { 1183 aspectDiff = width; 1184 width = height; 1185 height = aspectDiff; 1186 } 1187 imageWidth = desc->info.imageWidth; 1188 imageHeight = desc->info.imageHeight; 1189 if (!(kDisplayModeStretchedFlag & desc->info.flags)) 1190 { 1191 aspectDiff = (nativeWidth / nativeHeight) / (width / height); 1192 if (aspectDiff > 1.03125) 1193 imageWidth = (width / height * imageHeight); 1194 else if (aspectDiff < (1.0 - 0.03125)) 1195 imageHeight = (height / width * imageWidth); 1196 } 1197 if (kIOScaleSwapAxes & desc->timingInfo.detailedInfo.v2.scalerFlags) 1198 { 1199 desc->info.imageHeight = imageWidth; 1200 desc->info.imageWidth = imageHeight; 1201 } 1202 else 1203 { 1204 desc->info.imageWidth = imageWidth; 1205 desc->info.imageHeight = imageHeight; 1206 } 1207 1208 DEBG(connectRef, "%d x %d\n", 1209 desc->info.imageWidth, 1210 desc->info.imageHeight 1211 ); 1212} 1213 1214__private_extern__ kern_return_t 1215IOFBInstallMode( IOFBConnectRef connectRef, IODisplayModeID mode, 1216 IOFBDisplayModeDescription * desc, 1217 UInt32 driverFlags, IOOptionBits modeGenFlags ) 1218{ 1219 IOReturn ret = kIOReturnSuccess; 1220 CFMutableDictionaryRef dict; 1221 CFMutableArrayRef array; 1222 CFNumberRef num; 1223 CFDataRef data; 1224 CFDataRef timingData = 0; 1225 IODisplayModeInformation * otherInfo; 1226 IODisplayModeInformation * info = &desc->info; 1227 IOTimingInformation * timingInfo = &desc->timingInfo; 1228 1229 1230 array = (CFMutableArrayRef) CFDictionaryGetValue( connectRef->kernelInfo, 1231 CFSTR(kIOFBDetailedTimingsKey) ); 1232 1233 if( timingInfo && (kIODetailedTimingValid & timingInfo->flags)) 1234 { 1235 if(mode == -1) 1236 { 1237 timingInfo->detailedInfo.v2.detailedTimingModeID = 1238 kIODisplayModeIDReservedBase 1239 + connectRef->arbModeIDSeed 1240 + (array ? CFArrayGetCount(array) : 0); 1241 1242 DEBG(connectRef, "arb mode %08x\n", (int) timingInfo->detailedInfo.v2.detailedTimingModeID); 1243 } 1244 else 1245 timingInfo->detailedInfo.v2.detailedTimingModeID = mode; 1246 1247 timingData = CFDataCreate( kCFAllocatorDefault, 1248 (UInt8 *) &timingInfo->detailedInfo.v2, 1249 sizeof(IODetailedTimingInformationV2) ); 1250 } 1251 1252 if( connectRef->trimToDependent && info 1253 && info->nominalWidth && info->nominalHeight) do { 1254 1255 IOFBConnectRef other; 1256 CFIndex modeCount, i; 1257 CFDataRef data; 1258 Boolean matches; 1259 1260 if( 0 == (info->flags & kDisplayModeSafetyFlags /*kDisplayModeSafeFlag*/)) 1261 continue; 1262 1263 other = connectRef->nextDependent; 1264 if( !other->modesArray) 1265 continue; 1266 modeCount = CFArrayGetCount( other->modesArray ); 1267 if( !modeCount) 1268 continue; 1269 1270 for( i = 0, matches = false; 1271 !matches && (i < modeCount); 1272 i++) { 1273 1274 dict = (CFMutableDictionaryRef) CFArrayGetValueAtIndex( other->modesArray, i ); 1275 data = CFDictionaryGetValue( dict, CFSTR(kIOFBModeDMKey) ); 1276 otherInfo = (IODisplayModeInformation *) CFDataGetBytePtr( data ); 1277 1278#define kNeedFlags (kDisplayModeValidFlag | kDisplayModeSafeFlag) 1279 if( kNeedFlags != (otherInfo->flags & kNeedFlags)) 1280 continue; 1281 matches = (info->nominalWidth == otherInfo->nominalWidth) 1282 && (info->nominalHeight == otherInfo->nominalHeight); 1283 } 1284 if( !matches) 1285 info->flags &= ~(kDisplayModeSafetyFlags /*kDisplayModeSafeFlag*/); 1286 1287 } while( false ); 1288 1289 do 1290 { 1291 if( mode == -1) 1292 { 1293 // assign a programmable mode ID after checking for dups 1294 1295 if( timingData && !(kIOFBScaledMode & modeGenFlags)) 1296 { 1297 CFIndex modeCount, i; 1298 UInt32 eq = false; 1299 1300 UInt32 maskFlags; 1301 1302 GetTovr(connectRef, timingInfo->appleTimingID, &info->flags, &maskFlags); 1303 1304 if (kIOFBEDIDDetailedMode & modeGenFlags) 1305 { 1306 // add safe mode driver modes for dups 1307 modeCount = (CFIndex) connectRef->driverModeCount; 1308 for( i = 0; i < modeCount; i++) 1309 { 1310 if (kAddSafeFlags != (kAddSafeFlags & connectRef->driverModeInfo[i].info.flags)) 1311 continue; 1312 if (DetailedTimingsEqual( &timingInfo->detailedInfo.v2, 1313 &connectRef->driverModeInfo[i].timingInfo.detailedInfo.v2, 1314 modeGenFlags)) 1315 { 1316 MergeDisplayModeInformation(connectRef, info, &connectRef->driverModeInfo[i].info); 1317 connectRef->driverModeInfo[i].info.flags &= maskFlags; 1318 eq = true; 1319 } 1320 } 1321 } 1322 if (eq) 1323 { 1324 ret = kIOReturnPortExists; 1325 continue; 1326 } 1327 1328 // check driver modes for dups 1329 modeCount = (CFIndex) connectRef->driverModeCount; 1330 for( i = 0; i < modeCount; i++) 1331 { 1332 if ((kDisplayModeBuiltInFlag | kDisplayModeNeverShowFlag /*| kDisplayModeInterlacedFlag*/) 1333 & connectRef->driverModeInfo[i].info.flags) 1334 continue; 1335 1336 if (InvalidTiming(connectRef, &connectRef->driverModeInfo[i].timingInfo)) 1337 continue; 1338 1339 if( (0 != (kIOInterlacedCEATiming & timingInfo->detailedInfo.v2.signalConfig)) 1340 != (0 != (kDisplayModeInterlacedFlag & connectRef->driverModeInfo[i].info.flags))) 1341 continue; 1342 1343 // 2488698, 3052614 1344 if ((kIOTimingIDApple_FixedRateLCD == connectRef->driverModeInfo[i].timingInfo.appleTimingID) 1345 && !CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayIsDigitalKey))) 1346 continue; 1347 1348 if ((kIOTimingIDInvalid != timingInfo->appleTimingID) 1349 && (kIOTimingIDInvalid != connectRef->driverModeInfo[i].timingInfo.appleTimingID) 1350 && (kIOTimingIDApple_FixedRateLCD != connectRef->driverModeInfo[i].timingInfo.appleTimingID)) 1351 { 1352 if ((eq = (timingInfo->appleTimingID == connectRef->driverModeInfo[i].timingInfo.appleTimingID))) 1353 break; 1354 continue; 1355 } 1356 1357 if (0 == (kIODetailedTimingValid & connectRef->driverModeInfo[i].timingInfo.flags)) 1358 continue; 1359 if ((eq = DetailedTimingsEqual( &timingInfo->detailedInfo.v2, 1360 &connectRef->driverModeInfo[i].timingInfo.detailedInfo.v2, 1361 modeGenFlags))) 1362 break; 1363 } 1364 1365 if (eq) 1366 { 1367 DEBG(connectRef, "%d(%x) has a driver mode(%d)\n", (int) timingInfo->appleTimingID, 1368 (int) modeGenFlags, (int) connectRef->driverModeInfo[i].timingInfo.appleTimingID); 1369 1370 if ((kDetailedTimingsIdentical != eq) && (kIOFBEDIDDetailedMode & modeGenFlags)) 1371 { 1372 connectRef->driverModeInfo[i].info.flags = kDisplayModeNeverShowFlag; 1373 DEBG(connectRef, "disabling\n"); 1374 } 1375 else 1376 { 1377 if (0 == (kIOFBGTFMode & modeGenFlags)) 1378 /* && (!connectRef->overrides 1379 || !CFDictionaryGetValue(connectRef->overrides, CFSTR("trng")))*/ 1380 { 1381 MergeDisplayModeInformation(connectRef, info, &connectRef->driverModeInfo[i].info); 1382 connectRef->driverModeInfo[i].info.flags &= maskFlags; 1383 } 1384 1385 ret = kIOReturnPortExists; 1386 continue; 1387 } 1388 } 1389 1390 // check already added modes for dups 1391 modeCount = array ? CFArrayGetCount(array) : 0; 1392 for( i = connectRef->arbModeBase; i < modeCount; i++) { 1393 1394 data = CFArrayGetValueAtIndex(array, i); 1395 if( !data) 1396 continue; 1397 if( DetailedTimingsEqual( &timingInfo->detailedInfo.v2, 1398 (IODetailedTimingInformationV2 *) CFDataGetBytePtr(data), 1399 modeGenFlags)) { 1400 ret = kIOReturnPortExists; 1401 break; 1402 } 1403 } 1404 if( kIOReturnSuccess != ret) 1405 continue; 1406 } 1407 1408 // no dups 1409 if ((0 == (kIOFBScaledMode & modeGenFlags)) && !connectRef->fbRange) 1410 { 1411 ret = kIOReturnUnsupported; 1412 continue; 1413 } 1414 1415 if( !array) { 1416 array = CFArrayCreateMutable( kCFAllocatorDefault, 0, 1417 &kCFTypeArrayCallBacks ); 1418 if( !array) { 1419 ret = kIOReturnNoMemory; 1420 continue; 1421 } 1422 CFDictionarySetValue( connectRef->kernelInfo, 1423 CFSTR(kIOFBDetailedTimingsKey), array ); 1424 CFRelease( array ); 1425 } 1426 mode = timingInfo->detailedInfo.v2.detailedTimingModeID; 1427 if( timingData) 1428 CFArrayAppendValue( array, timingData ); 1429 } 1430 1431 if( NULL == info) 1432 continue; 1433 1434 dict = (CFMutableDictionaryRef) CFDictionaryGetValue( connectRef->modes, 1435 (const void *) (uintptr_t) (UInt32) mode ); 1436 if( !dict) { 1437 dict = CFDictionaryCreateMutable( kCFAllocatorDefault, (CFIndex) 0, 1438 &kCFTypeDictionaryKeyCallBacks, 1439 &kCFTypeDictionaryValueCallBacks ); 1440 if( dict) { 1441 CFArrayAppendValue( connectRef->modesArray, dict ); 1442 CFDictionarySetValue( connectRef->modes, (const void *) (uintptr_t) (UInt32) mode, dict ); 1443 CFRelease( dict ); 1444 } else { 1445 ret = kIOReturnNoMemory; 1446 continue; 1447 } 1448 } 1449 1450 num = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &mode ); 1451 if( num) { 1452 CFDictionarySetValue( dict, CFSTR(kIOFBModeIDKey), num ); 1453 CFRelease( num ); 1454 } 1455 1456 if( driverFlags && (0 == (mode & 0x80000000))) { 1457 num = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &driverFlags ); 1458 if( num) { 1459 CFDictionarySetValue( dict, CFSTR(kIOFBModeDFKey), num ); 1460 CFRelease( num ); 1461 } 1462 } 1463 1464 if( info) { 1465 1466 data = CFDataCreate( kCFAllocatorDefault, 1467 (UInt8 *) info, sizeof(IODisplayModeInformation)); 1468 if( data) { 1469 CFDictionarySetValue( dict, CFSTR(kIOFBModeDMKey), data ); 1470 CFRelease(data); 1471 } 1472 } 1473 1474 if( timingData) 1475 CFDictionaryAddValue( dict, CFSTR(kIOFBModeTMKey), timingData ); // add if not present 1476 1477 if( timingInfo && timingInfo->appleTimingID) { 1478 num = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &timingInfo->appleTimingID ); 1479 if( num) { 1480 CFDictionarySetValue( dict, CFSTR(kIOFBModeAIDKey), num ); 1481 CFRelease( num ); 1482 } 1483 } 1484 1485 } while( false ); 1486 1487 if( timingData) 1488 CFRelease(timingData); 1489 1490 return( ret ); 1491} 1492 1493static kern_return_t 1494IOFBSetKernelConfig( IOFBConnectRef connectRef ) 1495{ 1496 kern_return_t err = kIOReturnSuccess; 1497 1498 DEBG(connectRef, "IOFBSetKernelConfig: %ld\n", CFDictionaryGetCount(connectRef->kernelInfo)); 1499 1500 if( CFDictionaryGetCount(connectRef->kernelInfo)) { 1501 err = IOConnectSetCFProperty( connectRef->connect, CFSTR(kIOFBConfigKey), connectRef->kernelInfo ); 1502 } 1503 1504 return( err ); 1505} 1506 1507static void 1508IOFBDictSetValues(const void *key, const void *value, void *context) 1509{ 1510 CFMutableDictionaryRef dict = context; 1511 CFDictionarySetValue(dict, key, value); 1512} 1513 1514__private_extern__ kern_return_t 1515IOFBSetKernelDisplayConfig( IOFBConnectRef connectRef ) 1516{ 1517 kern_return_t err = kIOReturnSuccess; 1518 CFDataRef data; 1519 enum { kNumAttrPairs = 6 }; 1520 uint32_t attributes[kNumVendors * kNumAttrPairs * 2]; 1521 uint32_t value; 1522 uint32_t attrIdx = 0; 1523 int32_t idx; 1524 1525 DEBG(connectRef, "IOFBSetKernelDisplayConfig\n"); 1526 1527 if (!connectRef->setKernelDisplayConfig) return (kIOReturnSuccess); 1528 connectRef->setKernelDisplayConfig = false; 1529 1530 for (idx = (kNumVendors - 1); idx >= 0; idx--) 1531 { 1532 static const uint32_t vendors[kNumVendors] = { 0, 0x1002, 0x8086, 0x10de }; 1533 1534 if (!((1 << idx) & connectRef->vendorsFound)) 1535 continue; 1536 1537 // 1 1538 attributes[attrIdx++] = kConnectionVendorTag; 1539 attributes[attrIdx++] = vendors[idx]; 1540 1541 // 2 1542 attributes[attrIdx++] = kConnectionFlags; 1543 attributes[attrIdx++] = connectRef->ovrFlags; 1544 1545 // 3 1546 attributes[attrIdx++] = kConnectionColorModesSupported; 1547 value = connectRef->supportedColorModes[idx]; 1548 if ((kAllVendors != idx) && (kIODisplayColorModeReserved == value)) 1549 value = connectRef->supportedColorModes[kAllVendors]; 1550 attributes[attrIdx++] = value; 1551 1552 // 4 1553 attributes[attrIdx++] = kConnectionColorDepthsSupported; 1554 value = connectRef->supportedComponentDepths[idx]; 1555 if ((kAllVendors != idx) && (kIODisplayRGBColorComponentBitsUnknown == value)) 1556 value = connectRef->supportedComponentDepths[kAllVendors]; 1557 attributes[attrIdx++] = value; 1558 1559 // 5 1560 attributes[attrIdx++] = kConnectionControllerDitherControl; 1561 value = connectRef->ditherControl[idx]; 1562 if ((kAllVendors != idx) && (kIODisplayDitherControlDefault == value)) 1563 value = connectRef->ditherControl[kAllVendors]; 1564 attributes[attrIdx++] = value; 1565 1566 // 6 kNumAttrPairs 1567 attributes[attrIdx++] = kConnectionDisplayFlags; 1568 value = 0; 1569 if (connectRef->addTVFlag) 1570 value |= kIODisplayNeedsCEAUnderscan; 1571 attributes[attrIdx++] = value; 1572 } 1573 1574 data = CFDataCreate(kCFAllocatorDefault, 1575 (UInt8 *) &attributes[0], 1576 attrIdx * sizeof(attributes[0])); 1577 1578 if (data && connectRef->displayAttributes) 1579 { 1580 CFDictionarySetValue(connectRef->displayAttributes, CFSTR(kIODisplayAttributesKey), data); 1581 CFRelease(data); 1582 1583 CFDictionaryRef attrDict; 1584 attrDict = CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayAttributesKey)); 1585 if (attrDict && (CFDictionaryGetTypeID() == CFGetTypeID(attrDict))) 1586 CFDictionaryApplyFunction(attrDict, &IOFBDictSetValues, connectRef->displayAttributes); 1587 1588 err = IOConnectSetCFProperty(connectRef->connect, CFSTR(kIODisplayAttributesKey), connectRef->displayAttributes); 1589// CFDictionarySetValue(connectRef->kernelInfo, CFSTR(kIODisplayAttributesKey), connectRef->displayAttributes); 1590 } 1591 1592 return( err ); 1593} 1594 1595static kern_return_t 1596IOFBBuildModeList( IOFBConnectRef connectRef, Boolean forConnectChange ) 1597{ 1598 kern_return_t err; 1599 CFMutableDictionaryRef dict; 1600 CFMutableArrayRef array; 1601 CFDataRef data; 1602 CFDataRef scalerProp; 1603 CFDataRef timingProp = NULL; 1604 CFNumberRef num; 1605 IODisplayModeID * modes; 1606 IOFBDisplayModeDescription *modeInfo; 1607 IOOptionBits * driverFlags; 1608 IOFBDisplayModeDescription *arbModeInfo; 1609 UInt32 i, modeCount = 0, arbModeCount; 1610 IODisplayModeID mode; 1611 IOFBDisplayModeDescription currentTiming; 1612 IODisplayModeID currentMode = kIODisplayModeIDInvalid; 1613 IOIndex currentDepth; 1614 IOTimingInformation _startupTiming; 1615 IOTimingInformation * startupTiming = NULL; 1616 IOFBDisplayModeDescription * info; 1617 IOOptionBits installedFlags; 1618 IOFBDisplayModeDescription scaleDesc; 1619 Boolean scaleCandidate, scaleVGA, pruneKeepCurrent; 1620 1621 if( connectRef->kernelInfo) 1622 CFRelease( connectRef->kernelInfo ); 1623 if( connectRef->modes) 1624 CFRelease( connectRef->modes ); 1625 if( connectRef->modesArray) 1626 CFRelease( connectRef->modesArray ); 1627 1628 connectRef->suppressRefresh = (0 != connectRef->overrides); 1629 connectRef->detailedRefresh = false; 1630 connectRef->useScalerUnderscan = false; 1631 connectRef->addTVFlag = false; 1632 connectRef->matchMode = kIODisplayModeIDInvalid; 1633 connectRef->startMode = kIODisplayModeIDInvalid; 1634 1635 dict = CFDictionaryCreateMutable( kCFAllocatorDefault, (CFIndex) 0, 1636 (CFDictionaryKeyCallBacks *) 0, 1637 &kCFTypeDictionaryValueCallBacks ); 1638 connectRef->modes = dict; 1639 if (forConnectChange) 1640 dict = NULL; 1641 else 1642 dict = (CFMutableDictionaryRef) IORegistryEntryCreateCFProperty( 1643 connectRef->framebuffer, 1644 CFSTR(kIOFBConfigKey), 1645 kCFAllocatorDefault, kNilOptions); 1646 1647 if( true && dict && (array = (CFMutableArrayRef) CFDictionaryGetValue( dict, CFSTR(kIOFBModesKey)))) { 1648 // pick up existing config 1649 connectRef->kernelInfo = dict; 1650 CFRetain(array); 1651 connectRef->modesArray = array; 1652 1653 if( connectRef->suppressRefresh) 1654 connectRef->suppressRefresh = (0 != CFDictionaryGetValue(dict, CFSTR("IOFB0Hz"))); 1655 1656 connectRef->detailedRefresh = (0 != CFDictionaryGetValue(dict, CFSTR("IOFBmHz"))); 1657 connectRef->displayMirror = (0 != CFDictionaryGetValue(dict, CFSTR("IOFBmir"))); 1658 connectRef->useScalerUnderscan = (0 != CFDictionaryGetValue(dict, CFSTR("IOFBScalerUnderscan"))); 1659 connectRef->addTVFlag = (0 != CFDictionaryGetValue(dict, CFSTR("IOFBtv"))); 1660 1661 if( (data = CFDictionaryGetValue(dict, CFSTR("dims")))) 1662 bcopy( CFDataGetBytePtr(data), &connectRef->dimensions, sizeof(connectRef->dimensions) ); 1663 1664 modeCount = CFArrayGetCount( connectRef->modesArray ); 1665 for( i = 0; i < modeCount; i++ ) { 1666 UInt32 key; 1667 1668 dict = (CFMutableDictionaryRef) CFArrayGetValueAtIndex( connectRef->modesArray, i ); 1669 num = CFDictionaryGetValue( dict, CFSTR(kIOFBModeIDKey) ); 1670 CFNumberGetValue( num, kCFNumberSInt32Type, (SInt32 *) &key ); 1671 CFDictionarySetValue( connectRef->modes, (const void *)(uintptr_t) (UInt32)key, dict ); 1672 } 1673 1674 connectRef->relaunch = true; 1675 1676 return( kIOReturnSuccess ); 1677 } 1678 1679 dict = CFDictionaryCreateMutable( kCFAllocatorDefault, (CFIndex) 0, 1680 &kCFTypeDictionaryKeyCallBacks, 1681 &kCFTypeDictionaryValueCallBacks ); 1682 connectRef->kernelInfo = dict; 1683 1684 connectRef->modesArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, 1685 &kCFTypeArrayCallBacks ); 1686 CFDictionarySetValue( dict, CFSTR(kIOFBModesKey), connectRef->modesArray ); 1687 1688 scalerProp = IORegistryEntryCreateCFProperty( connectRef->framebuffer, CFSTR(kIOFBScalerInfoKey), 1689 kCFAllocatorDefault, kNilOptions ); 1690 if (scalerProp && (size_t) CFDataGetLength(scalerProp) >= sizeof(IODisplayScalerInformation)) 1691 connectRef->scalerInfo = (IODisplayScalerInformation *) CFDataGetBytePtr(scalerProp); 1692 1693 if (connectRef->scalerInfo) 1694 { 1695 DEBG(connectRef, "FB scaler info: (%d x %d), features %08x\n", 1696 (int) connectRef->scalerInfo->maxHorizontalPixels, 1697 (int) connectRef->scalerInfo->maxVerticalPixels, 1698 (int) connectRef->scalerInfo->scalerFeatures); 1699 } 1700 1701 // -- keep timing for alias mode 1702 1703 connectRef->arbModeBase = 0; 1704 connectRef->arbModeIDSeed = (0x00007000 & (connectRef->arbModeIDSeed + 0x00001000)); 1705 DEBG(connectRef, "seed : 0x%08x\n", (int) connectRef->arbModeIDSeed); 1706 1707 bzero(¤tTiming, sizeof(currentTiming)); 1708 connectRef->matchMode = kIODisplayModeIDInvalid; 1709 connectRef->startMode = kIODisplayModeIDInvalid; 1710 1711 do 1712 { 1713 CFMutableArrayRef array; 1714 CFDataRef timingData; 1715 1716 err = _IOFBGetCurrentDisplayModeAndDepth(connectRef, ¤tMode, ¤tDepth); 1717 if (((kIODisplayModeIDReservedBase | kIODisplayModeIDAliasBase) != currentMode) && !connectRef->inMuxSwitch) 1718 break; 1719 err = IOFBCreateDisplayModeInformation(connectRef, currentMode, ¤tTiming); 1720 if (kIOReturnSuccess != err) 1721 break; 1722 if (!(kIODetailedTimingValid & currentTiming.timingInfo.flags)) 1723 break; 1724 1725 currentTiming.timingInfo.detailedInfo.v2.detailedTimingModeID = currentMode; 1726 timingData = CFDataCreate(kCFAllocatorDefault, 1727 (UInt8 *) ¤tTiming.timingInfo.detailedInfo.v2, 1728 sizeof(IODetailedTimingInformationV2)); 1729 if (!timingData) 1730 break; 1731 array = CFArrayCreateMutable(kCFAllocatorDefault, 0, 1732 &kCFTypeArrayCallBacks); 1733 if (!array) 1734 break; 1735 CFArrayAppendValue(array, timingData); 1736 CFRelease(timingData); 1737 CFDictionarySetValue(connectRef->kernelInfo, 1738 CFSTR(kIOFBDetailedTimingsKey), array); 1739 CFRelease(array); 1740 connectRef->arbModeBase = 1; 1741 connectRef->inMuxSwitch = true; 1742 } 1743 while (false); 1744 1745 // -- get the info for all driver modes 1746 1747#if DEBUG_NO_DRIVER_MODES 1748 if (!connectRef->dependentIndex) 1749 err = _IOFBGetDisplayModeCount( connectRef, &modeCount ); 1750 else 1751 err = kIOReturnUnsupported; 1752#else 1753 err = _IOFBGetDisplayModeCount( connectRef, &modeCount ); 1754#endif 1755 if( kIOReturnSuccess == err) { 1756 modes = (IODisplayModeID *) calloc(modeCount, sizeof(IODisplayModeID)); 1757 modeInfo = (IOFBDisplayModeDescription *) calloc(modeCount, sizeof(IOFBDisplayModeDescription)); 1758 driverFlags = (IOOptionBits *) calloc(modeCount, sizeof(IOOptionBits)); 1759 err = _IOFBGetDisplayModes( connectRef, modeCount, modes ); 1760 } else { 1761 modes = 0; 1762 modeInfo = 0; 1763 driverFlags = 0; 1764 modeCount = 0; 1765 } 1766 1767 connectRef->driverModeInfo = modeInfo; 1768 connectRef->driverModeCount = modeCount; 1769 1770 for( i = 0; i < modeCount; i++) { 1771 if( (modes[i] & kIODisplayModeIDReservedBase) && (modes[i] != kIOFBSWOfflineDisplayModeID) ) { 1772 err = kIOReturnBadArgument; 1773 DEBG(connectRef, "Driver is attempting to create a mode with the reserved base mode ID bit set!"); 1774 } 1775 else 1776 err = IOFBCreateDisplayModeInformation( connectRef, modes[i], &modeInfo[i] ); 1777 if( kIOReturnSuccess != err) { 1778 modes[i] = 0; 1779 continue; 1780 } 1781 driverFlags[i] = modeInfo[i].info.flags; 1782 1783#if RLOG 1784 DEBG(connectRef, "driver mode[%d] (%x,%x) %d x %d %f Hz flags %x\n", 1785 (int) i, (int) modes[i], (int) modeInfo[i].timingInfo.appleTimingID, 1786 (int) modeInfo[i].info.nominalWidth, (int) modeInfo[i].info.nominalHeight, 1787 modeInfo[i].info.refreshRate / 65536.0, (int) driverFlags[i]); 1788 IOFBLogTiming(connectRef, &modeInfo[i].timingInfo); 1789#endif 1790 } 1791 1792 // -- get modes from display 1793 1794 if (!(kIOFBConnectStateUnusable & connectRef->state)) { 1795 1796 IODisplayInstallTimings( connectRef ); 1797 1798 if( (data = CFDictionaryGetValue( connectRef->overrides, CFSTR("dims")))) { 1799 bcopy( CFDataGetBytePtr(data), &connectRef->dimensions, sizeof(connectRef->dimensions) ); 1800 CFRetain(data); 1801 } else 1802 data = CFDataCreate( kCFAllocatorDefault, 1803 (const UInt8 *) &connectRef->dimensions, 1804 sizeof(connectRef->dimensions) ); 1805 if( data) { 1806 CFDictionarySetValue( dict, CFSTR("dims"), data ); 1807 CFRelease(data); 1808 } 1809 } 1810 1811 // -- gather all mode info 1812 1813 array = (CFMutableArrayRef) CFDictionaryGetValue( connectRef->kernelInfo, 1814 CFSTR(kIOFBDetailedTimingsKey) ); 1815 arbModeCount = array ? (CFArrayGetCount(array) - connectRef->arbModeBase) : 0; 1816 arbModeInfo = (IOFBDisplayModeDescription *) 1817 (arbModeCount 1818 ? (IOFBDisplayModeDescription *) calloc(arbModeCount, sizeof(IOFBDisplayModeDescription)) : 0); 1819 1820 for( i = 0; i < (modeCount + arbModeCount); i++) 1821 { 1822 if( i >= modeCount) 1823 { 1824 CFDictionaryRef modeDict; 1825 1826 info = &arbModeInfo[i - modeCount]; 1827 1828 data = CFArrayGetValueAtIndex(array, i - modeCount + connectRef->arbModeBase); 1829 CFDataGetBytes(data, CFRangeMake(0, sizeof(IODetailedTimingInformationV2)), 1830 (UInt8 *) &info->timingInfo.detailedInfo.v2); 1831 info->timingInfo.flags = kIODetailedTimingValid; 1832 1833 mode = info->timingInfo.detailedInfo.v2.detailedTimingModeID; 1834 1835 modeDict = CFDictionaryGetValue( connectRef->modes, (const void *) (uintptr_t) (UInt32) mode ); 1836 if (!modeDict) 1837 { 1838 DEBG(connectRef, "invalid mode 0x%x\n", (int) mode); 1839 continue; 1840 } 1841 1842 if(!(data = CFDictionaryGetValue( modeDict, CFSTR(kIOFBModeDMKey) ))) 1843 { 1844 DEBG(connectRef, "no kIOFBModeDMKey 0x%x\n", (int) mode); 1845 continue; 1846 } 1847 CFDataGetBytes(data, CFRangeMake(0, sizeof(IODisplayModeInformation)), 1848 (UInt8 *) &info->info); 1849 1850 if((num = CFDictionaryGetValue( modeDict, CFSTR(kIOFBModeAIDKey) ))) 1851 CFNumberGetValue(num, kCFNumberSInt32Type, &info->timingInfo.appleTimingID); 1852 } 1853 else 1854 { 1855 mode = modes[i]; 1856 if( 0 == mode) 1857 continue; 1858 info = &modeInfo[i]; 1859 } 1860 1861 IOFBAdjustDisplayModeInformation( connectRef, mode, info ); 1862 } 1863 1864 // -- refresh rate futzing 1865 1866 for( i = 0; i < (modeCount + arbModeCount); i++) 1867 { 1868 UInt32 j; 1869 if( i >= modeCount) 1870 info = &arbModeInfo[i - modeCount]; 1871 else if (!modes[i]) 1872 continue; 1873 else 1874 info = &modeInfo[i]; 1875 1876 installedFlags = info->info.flags; 1877 if (!(kDisplayModeValidFlag & installedFlags)) 1878 continue; 1879 1880 MakeDetailedRefresh( connectRef, info ); 1881 1882 // make refresh rates unique 1883 for( j = 0; (!connectRef->detailedRefresh) && (j < i); j++ ) 1884 { 1885 IOFBDisplayModeDescription * dupInfo; 1886 1887 if (j >= modeCount) 1888 dupInfo = &arbModeInfo[j - modeCount]; 1889 else if (!modes[j]) 1890 continue; 1891 else 1892 dupInfo = &modeInfo[j]; 1893 1894 if( true 1895 && (((info->info.refreshRate + 0x8000) >> 16) 1896 == ((dupInfo->info.refreshRate + 0x8000) >> 16)) 1897 && (info->info.nominalWidth == dupInfo->info.nominalWidth) 1898 && (info->info.nominalHeight == dupInfo->info.nominalHeight) 1899 && (0 == (~kDisplayModeSafetyFlags 1900 & (info->info.flags ^ dupInfo->info.flags))) ) { 1901 1902 connectRef->detailedRefresh = true; 1903 } 1904 } 1905 1906 if (connectRef->suppressRefresh) 1907 { 1908 if ((kDisplayModeTelevisionFlag | kDisplayModeInterlacedFlag) & installedFlags) 1909 connectRef->suppressRefresh = false; 1910 else if(info->info.refreshRate 1911 && ((info->info.refreshRate < 0x398000) || (info->info.refreshRate > 0x3e8000))) 1912 connectRef->suppressRefresh = false; 1913 } 1914 } 1915 1916 // -- install modes, look for scale candidate 1917 1918 bzero( &scaleDesc, sizeof(scaleDesc) ); 1919 scaleCandidate = scaleVGA = false; 1920 pruneKeepCurrent = false; //(0 != (kIOFBConnectStateOnline & connectRef->state)); 1921 1922 for( i = 0; i < (modeCount + arbModeCount); i++) 1923 { 1924 if( i >= modeCount) 1925 { 1926 info = &arbModeInfo[i - modeCount]; 1927 mode = info->timingInfo.detailedInfo.v2.detailedTimingModeID; 1928 installedFlags = info->info.flags; 1929 } 1930 else 1931 { 1932 mode = modes[i]; 1933 if( 0 == mode) 1934 continue; 1935 info = &modeInfo[i]; 1936 installedFlags = driverFlags[i]; 1937 } 1938 if (kDisplayModeValidFlag & info->info.flags) 1939 pruneKeepCurrent = false; 1940 1941 if (connectRef->scalerInfo && !(kIOFBConnectStateUnusable & connectRef->state)) 1942 { 1943 Boolean ok = IOFBLookScaleBaseMode(connectRef, info, &scaleDesc); 1944 if (CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayIsDigitalKey))) scaleCandidate |= ok; 1945 else scaleVGA |= ok; 1946 } 1947 1948 IOFBSetImageSize(connectRef, info); 1949 1950 IOFBInstallMode( connectRef, mode, info, 1951 installedFlags, kNilOptions ); 1952 1953 } 1954 1955 if ( !(kIOFBConnectStateUnusable & connectRef->state) 1956 && ((kIOScaleRotateFlags & connectRef->transform) 1957 || (connectRef->useScalerUnderscan && (kIOFBScalerUnderscan & connectRef->transform))) ) 1958 { 1959 for( i = 0; i < (modeCount + arbModeCount); i++) 1960 { 1961 // add the transformed version of driver modes 1962 IOFBDisplayModeDescription _desc; 1963 IOFBDisplayModeDescription * desc = &_desc; 1964 1965 if( i >= modeCount) 1966 { 1967 info = &arbModeInfo[i - modeCount]; 1968 mode = info->timingInfo.detailedInfo.v2.detailedTimingModeID; 1969 installedFlags = info->info.flags; 1970 } 1971 else 1972 { 1973 mode = modes[i]; 1974 if( 0 == mode) 1975 continue; 1976 info = &modeInfo[i]; 1977 if (!(kIODetailedTimingValid & info->timingInfo.flags)) 1978 continue; 1979 installedFlags = driverFlags[i]; 1980 if (!scaleCandidate) 1981 { 1982 *desc = *info; 1983 UpdateTimingInfoForTransform(connectRef, desc, kScaleInstallAlways); 1984 1985 err = IOFBInstallScaledMode( connectRef, desc, kScaleInstallAlways ); 1986 if (kIOReturnSuccess != err) 1987 continue; 1988 } 1989 } 1990 1991 if (!scaleCandidate && (kIOScaleSwapAxes & connectRef->transform)) 1992 { 1993 UInt32 h, v; 1994 1995 h = info->timingInfo.detailedInfo.v2.horizontalActive; 1996 v = info->timingInfo.detailedInfo.v2.verticalActive; 1997 1998 if ((h == 1024) && (v == 768)) 1999 { 2000 h = 640; 2001 v = 480; 2002 } 2003 else if ((h == 1280) && (v == 1024)) 2004 { 2005 h = 800; 2006 v = 600; 2007 } 2008 else if ((h == 1600) && (v == 1200)) 2009 { 2010 h = 1280; 2011 v = 1024; 2012 } 2013 else 2014 h = v = 0; 2015 2016 if (h && v) 2017 { 2018 *desc = *info; 2019 UpdateTimingInfoForTransform(connectRef, desc, kScaleInstallAlways); 2020 2021 desc->timingInfo.detailedInfo.v2.horizontalScaled = h; 2022 desc->timingInfo.detailedInfo.v2.verticalScaled = v; 2023 2024 err = IOFBInstallScaledMode(connectRef, desc, kScaleInstallAlways); 2025 2026 if ((h == 800) && (v == 600)) 2027 { 2028 h = 1024; 2029 v = 768; 2030 desc->timingInfo.detailedInfo.v2.horizontalScaled = h; 2031 desc->timingInfo.detailedInfo.v2.verticalScaled = v; 2032 2033 err = IOFBInstallScaledMode(connectRef, desc, kScaleInstallAlways); 2034 } 2035 } 2036 } 2037 2038 if (i < modeCount) 2039 { 2040 // disable the driver mode 2041 info->info.flags &= ~kDisplayModeSafetyFlags; 2042 IOFBInstallMode( connectRef, mode, info, 0, kNilOptions ); 2043 } 2044 } 2045 } 2046 2047 if( modes) 2048 free( modes ); 2049 if( modeInfo) 2050 free( modeInfo ); 2051 if( driverFlags) 2052 free( driverFlags ); 2053 if( arbModeInfo) 2054 free( arbModeInfo ); 2055 modes = 0; 2056 modeInfo = 0; 2057 driverFlags = 0; 2058 arbModeInfo = 0; 2059 connectRef->driverModeInfo = 0; 2060 connectRef->driverModeCount = 0; 2061 2062 // -- scaling 2063 if(scaleCandidate || scaleVGA) 2064 IOFBInstallScaledModes( connectRef, &scaleDesc, scaleVGA ); 2065 2066 if( connectRef->suppressRefresh) 2067 CFDictionarySetValue(connectRef->kernelInfo, CFSTR("IOFB0Hz"), kCFBooleanTrue); 2068 if( connectRef->detailedRefresh) 2069 CFDictionarySetValue(connectRef->kernelInfo, CFSTR("IOFBmHz"), kCFBooleanTrue); 2070 if( connectRef->displayMirror) 2071 CFDictionarySetValue(connectRef->kernelInfo, CFSTR("IOFBmir"), kCFBooleanTrue); 2072 2073 if (connectRef->useScalerUnderscan) 2074 CFDictionarySetValue(connectRef->kernelInfo, CFSTR("IOFBScalerUnderscan"), kCFBooleanTrue); 2075 if (connectRef->addTVFlag) 2076 CFDictionarySetValue(connectRef->kernelInfo, CFSTR("IOFBtv"), kCFBooleanTrue); 2077 2078 // -- prune, search alias 2079 2080 if( !(kIOFBConnectStateUnusable & connectRef->state) 2081 && (kIODisplayModeIDReservedBase | kIODisplayModeIDAliasBase) != currentMode) 2082 { 2083 timingProp = IORegistryEntryCreateCFProperty(connectRef->framebuffer, CFSTR(kIOFBStartupTimingPrefsKey), 2084 kCFAllocatorDefault, kNilOptions ); 2085 if (timingProp && (size_t) CFDataGetLength(timingProp) >= sizeof(typeof(_startupTiming))) 2086 { 2087 2088 CFDataGetBytes(timingProp, CFRangeMake(0, sizeof(_startupTiming)), 2089 (UInt8 *) &_startupTiming); 2090 2091 startupTiming = &_startupTiming; 2092 IOFBTimingSanity(startupTiming); 2093#if RLOG 2094 DEBG(connectRef, " look startup mode \n"); 2095 IOFBLogTiming(connectRef, startupTiming); 2096#endif 2097 } 2098 if (timingProp) 2099 CFRelease(timingProp); 2100 } 2101 2102 modeCount = CFArrayGetCount( connectRef->modesArray ); 2103 for( i = 0; i < modeCount; i++) 2104 { 2105 IODetailedTimingInformationV2 * timing; 2106 IODisplayModeInformation * dmInfo; 2107 CFNumberRef num; 2108 2109 dict = (CFMutableDictionaryRef) CFArrayGetValueAtIndex( connectRef->modesArray, i ); 2110 2111 num = CFDictionaryGetValue( dict, CFSTR(kIOFBModeIDKey) ); 2112 if( !num) 2113 continue; 2114 CFNumberGetValue( num, kCFNumberSInt32Type, &mode ); 2115 if (pruneKeepCurrent && (mode == currentMode)) 2116 continue; 2117 2118 data = CFDictionaryGetValue( dict, CFSTR(kIOFBModeDMKey) ); 2119 if( !data) 2120 continue; 2121 dmInfo = (IODisplayModeInformation *) CFDataGetBytePtr( data ); 2122 2123 if (!(dmInfo->flags & kDisplayModeValidFlag)) 2124 { 2125 // remove it 2126 CFArrayRemoveValueAtIndex( connectRef->modesArray, i ); 2127 CFDictionaryRemoveValue( connectRef->modes, (const void *) (uintptr_t) (UInt32) mode ); 2128 i--; modeCount--; 2129 continue; 2130 } 2131 2132 data = CFDictionaryGetValue(dict, CFSTR(kIOFBModeTMKey)); 2133 if (!data) 2134 continue; 2135 timing = (typeof(timing)) CFDataGetBytePtr(data); 2136 2137 if (connectRef->inMuxSwitch) 2138 { 2139 if (DetailedTimingsEqual(timing, 2140 ¤tTiming.timingInfo.detailedInfo.v2, 2141 kNilOptions)) 2142 { 2143 connectRef->matchMode = (kIODisplayModeIDAliasBase | timing->detailedTimingModeID); 2144 connectRef->matchDepth = currentDepth; 2145 DEBG(connectRef, " swizzle -> %x\n", (int) connectRef->matchMode); 2146 } 2147 } 2148 else if (startupTiming 2149 && (DetailedTimingsEqual(timing, 2150 &startupTiming->detailedInfo.v2, 2151 1*kIOFBTimingMatch))) 2152 { 2153 connectRef->startMode = mode; 2154 connectRef->startDepth = -1; 2155 DEBG(connectRef, " startup mode from timing %x\n", (int) mode); 2156 } 2157 } 2158 2159 // -- install 2160 2161 enum { kNeed = (kIOFBConnectStateUnusable | kIOFBConnectStateHWOnline) }; 2162 if ((kNeed != (kNeed & connectRef->state)) 2163 && CFArrayGetCount(connectRef->modesArray)) 2164 { 2165 err = IOFBSetKernelConfig( connectRef ); 2166 } 2167 2168 if (scalerProp) 2169 { 2170 CFRelease(scalerProp); 2171 connectRef->scalerInfo = 0; 2172 } 2173 2174 return( err ); 2175} 2176 2177static void 2178IOFBUpdateConnectState( IOFBConnectRef connectRef ) 2179{ 2180 connectRef->defaultMode = 0; 2181 connectRef->defaultDepth = 1; 2182 2183 connectRef->displayVendor = kDisplayVendorIDUnknown; 2184 connectRef->displayProduct = kDisplayProductIDGeneric; 2185 2186 connectRef->state = IOFBGetState( connectRef ); 2187 2188 if (!(kIOFBConnectStateOnline & connectRef->state)) connectRef->state |= kIOFBConnectStateUnusable; 2189} 2190 2191IOReturn 2192IOAccelReadFramebuffer(io_service_t framebuffer, uint32_t width, uint32_t height, size_t rowBytes, 2193 mach_vm_address_t * result, mach_vm_size_t * bytecount) 2194{ 2195 IOReturn err; 2196 io_service_t accelerator; 2197 UInt32 framebufferIndex; 2198 mach_vm_size_t size = 0; 2199 uintptr_t surfaceID = 155; 2200 mach_vm_address_t buffer = 0; 2201 IOAccelConnect connect = MACH_PORT_NULL; 2202 IOAccelDeviceRegion * region = NULL; 2203 IOAccelSurfaceInformation surfaceInfo; 2204 IOGraphicsAcceleratorInterface ** interface = 0; 2205 IOBlitterPtr copyRegionProc; 2206 IOBlitCopyRegion op; 2207 IOBlitSurface dest; 2208 SInt32 quality = 0; 2209 2210 TIMESTART(); 2211 2212 *result = 0; 2213 *bytecount = 0; 2214 dest.interfaceRef = NULL; 2215 2216 do 2217 { 2218 err = IOAccelFindAccelerator(framebuffer, &accelerator, &framebufferIndex); 2219 if (kIOReturnSuccess != err) continue; 2220 err = IOAccelCreateSurface(accelerator, surfaceID, 2221 kIOAccelSurfaceModeWindowedBit | kIOAccelSurfaceModeColorDepth8888, 2222 &connect); 2223 IOObjectRelease(accelerator); 2224 if (kIOReturnSuccess != err) continue; 2225 2226 size = rowBytes * height; 2227 2228 region = calloc(1, sizeof (IOAccelDeviceRegion) + sizeof(IOAccelBounds)); 2229 if (!region) continue; 2230 2231 region->num_rects = 1; 2232 region->bounds.x = region->rect[0].x = 0; 2233 region->bounds.y = region->rect[0].y = 0; 2234 region->bounds.h = region->rect[0].h = height; 2235 region->bounds.w = region->rect[0].w = width; 2236 2237 err = mach_vm_allocate(mach_task_self(), &buffer, size, 2238 VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_COREGRAPHICS_FRAMEBUFFERS)); 2239 if (kIOReturnSuccess != err) continue; 2240 2241 err = IOAccelSetSurfaceFramebufferShapeWithBackingAndLength(connect, region, 2242 kIOAccelSurfaceShapeIdentityScaleBit| 2243 kIOAccelSurfaceShapeNonBlockingBit| 2244 //kIOAccelSurfaceShapeStaleBackingBit | 2245 kIOAccelSurfaceShapeNonSimpleBit, 2246 0, 2247 (IOVirtualAddress) buffer, 2248 (UInt32) rowBytes, 2249 (UInt32) size); 2250 if (kIOReturnSuccess != err) continue; 2251 err = IOCreatePlugInInterfaceForService(framebuffer, 2252 kIOGraphicsAcceleratorTypeID, 2253 kIOGraphicsAcceleratorInterfaceID, 2254 (IOCFPlugInInterface ***)&interface, &quality ); 2255 if (kIOReturnSuccess != err) continue; 2256 err = (*interface)->GetBlitter(interface, 2257 kIOBlitAllOptions, 2258 (kIOBlitTypeCopyRegion | kIOBlitTypeOperationType0), 2259 kIOBlitSourceFramebuffer, 2260 ©RegionProc); 2261 if (kIOReturnSuccess != err) continue; 2262 err = (*interface)->AllocateSurface(interface, kIOBlitHasCGSSurface, &dest, (void *) surfaceID); 2263 if (kIOReturnSuccess != err) continue; 2264 err = (*interface)->SetDestination(interface, kIOBlitSurfaceDestination, &dest); 2265 if (kIOReturnSuccess != err) continue; 2266 op.region = region; 2267 op.deltaX = 0; 2268 op.deltaY = 0; 2269 err = (*copyRegionProc)(interface, 2270 kNilOptions, 2271 (kIOBlitTypeCopyRegion | kIOBlitTypeOperationType0), 2272 kIOBlitSourceFramebuffer, 2273 &op.operation, 2274 (void *) 0); 2275 if (kIOReturnSuccess != err) continue; 2276 (*interface)->Flush(interface, kNilOptions); 2277 err = IOAccelWriteLockSurfaceWithOptions(connect, 2278 kIOAccelSurfaceLockInBacking, &surfaceInfo, sizeof(surfaceInfo)); 2279 if (kIOReturnSuccess != err) continue; 2280 2281 (void ) IOAccelWriteUnlockSurfaceWithOptions(connect, kIOAccelSurfaceLockInBacking); 2282 } 2283 while (false); 2284 2285 if (dest.interfaceRef) (*interface)->FreeSurface(interface, kIOBlitHasCGSSurface, &dest); 2286 2287 // destroy the surface 2288 if (connect) (void) IOAccelDestroySurface(connect); 2289 2290 if (region) free(region); 2291 2292 if (interface) IODestroyPlugInInterface((IOCFPlugInInterface **)interface); 2293 2294 if (kIOReturnSuccess == err) 2295 { 2296 *result = buffer; 2297 *bytecount = size; 2298 } 2299 2300 TIMEEND("IOAccelReadFramebuffer"); 2301 2302 return (err); 2303} 2304static kern_return_t 2305IOFBResetTransform( IOFBConnectRef connectRef ) 2306{ 2307 kern_return_t err = kIOReturnSuccess; 2308 CFNumberRef num; 2309 2310 num = IORegistryEntryCreateCFProperty( connectRef->framebuffer, CFSTR(kIOFBTransformKey), 2311 kCFAllocatorDefault, kNilOptions ); 2312 if( num) 2313 { 2314 CFNumberGetValue( num, kCFNumberSInt64Type, &connectRef->transform ); 2315 CFRelease(num); 2316 } 2317 else 2318 connectRef->transform = 0; 2319 2320 if (connectRef->transformSurface) 2321 { 2322 IOAccelDestroySurface(connectRef->transformSurface); 2323 connectRef->transformSurface = 0; 2324 } 2325 2326 DEBG(connectRef, " %qx\n", connectRef->transform); 2327 2328 if (kIOFBRotateFlags & connectRef->transform) do 2329 { 2330 io_service_t accelerator; 2331 UInt32 index; 2332 IOAccelDeviceRegion rgn; 2333 IODisplayModeID mode; 2334 IOIndex depth; 2335 IOPixelInformation pixelInfo; 2336 UInt32 surfaceMode; 2337 IOAccelSurfaceInformation surfaceInfo; 2338 UInt32 vramSave; 2339 2340 err = IOFBGetAttributeForFramebuffer( connectRef->connect, 2341 MACH_PORT_NULL, 2342 kIOVRAMSaveAttribute, &vramSave ); 2343 DEBG(connectRef, "IOFBGetAttributeForFramebuffer(kIOVRAMSaveAttribute, %x), %08x\n", err, (int) vramSave); 2344 if (kIOReturnSuccess != err) 2345 vramSave = true; 2346 if (!vramSave) 2347 continue; 2348 2349 err = _IOFBGetCurrentDisplayModeAndDepth(connectRef, &mode, &depth); 2350 DEBG(connectRef, "IOFBGetCurrentDisplayModeAndDepth(%x), %x, %d\n", err, (int) mode, (int) depth); 2351 if (err) 2352 continue; 2353 err = _IOFBGetPixelInformation( connectRef, mode, depth, 2354 kIOFBSystemAperture, &pixelInfo ); 2355 DEBG(connectRef, "_IOFBGetPixelInformation(%x)\n", err); 2356 if (err) 2357 continue; 2358 2359 rgn.num_rects = 0; 2360 rgn.bounds.x = 0; 2361 rgn.bounds.y = 0; 2362 rgn.bounds.w = pixelInfo.activeWidth; 2363 rgn.bounds.h = pixelInfo.activeHeight; 2364 2365 surfaceMode = 0x00000040 /*| kIOAccelSurfaceModeWindowedBit*/; 2366 if (pixelInfo.bitsPerPixel == 32) 2367 surfaceMode |= kIOAccelSurfaceModeColorDepth8888; 2368 else 2369 surfaceMode |= kIOAccelSurfaceModeColorDepth1555; 2370 2371 err = IOAccelFindAccelerator(connectRef->framebuffer, &accelerator, &index); 2372 DEBG(connectRef, "IOAccelFindAccelerator(%x)\n", err); 2373 if (err) 2374 continue; 2375 2376 err = IOAccelCreateSurface(accelerator, index, surfaceMode, &connectRef->transformSurface); 2377 DEBG(connectRef, "IOAccelCreateSurface(%x)\n", err); 2378 if (err) 2379 continue; 2380 2381 err = IOAccelSetSurfaceFramebufferShape(connectRef->transformSurface, &rgn, kNilOptions, index); 2382 DEBG(connectRef, "IOAccelSetSurfaceFramebufferShape(%x)\n", err); 2383 if (err) 2384 continue; 2385 2386 err = IOAccelWriteLockSurface(connectRef->transformSurface, &surfaceInfo, sizeof(surfaceInfo)); 2387 DEBG(connectRef, "IOAccelWriteLockSurface(%x)\n", err); 2388 if (err) 2389 continue; 2390 2391 } 2392 while (false); 2393 2394 if ((kIOReturnSuccess != err) && connectRef->transformSurface) 2395 { 2396 IOAccelDestroySurface(connectRef->transformSurface); 2397 connectRef->transformSurface = 0; 2398 } 2399 2400 return (err); 2401} 2402 2403static bool 2404IOFBWritePrefs( IOFBConnectRef connectRef ) 2405{ 2406 CFMutableDictionaryRef prefs, newPrefs; 2407 bool madeChanges = false; 2408 2409 prefs = (CFMutableDictionaryRef) CFDictionaryGetValue(connectRef->iographicsProperties, CFSTR("prefs")); 2410 if (!prefs || !gIOGraphicsPrefsService) 2411 return (false); 2412 2413 newPrefs = (CFMutableDictionaryRef) IORegistryEntryCreateCFProperty(gIOGraphicsPrefsService, 2414 CFSTR(kIOGraphicsPrefsKey), 2415 kCFAllocatorDefault, kNilOptions); 2416 madeChanges |= (!newPrefs || !CFEqual(newPrefs, prefs)); 2417 if (newPrefs) 2418 prefs = newPrefs; 2419 2420 DEBG(connectRef, "writePlist %d\n", madeChanges); 2421 if (madeChanges) 2422 { 2423 uid_t euid = geteuid(); 2424 seteuid(0); 2425 writePlist(kIOFirstBootFlagPath, prefs, 0); 2426 seteuid(euid); 2427 CFDictionarySetValue(connectRef->iographicsProperties, CFSTR("prefs"), prefs); 2428 } 2429 if (newPrefs) 2430 CFRelease(newPrefs); 2431 2432 return (true); 2433} 2434 2435static kern_return_t 2436IOFBRebuild( IOFBConnectRef connectRef, Boolean forConnectChange ) 2437{ 2438 TIMESTART(); 2439 2440 if( kIOReturnSuccess != IOFBGetAttributeForFramebuffer( connectRef->connect, MACH_PORT_NULL, 2441 kIOMirrorDefaultAttribute, &connectRef->mirrorDefaultFlags)) 2442 connectRef->mirrorDefaultFlags = 0; 2443 2444 TIMEEND("IOFBGetAttributeForFramebuffer"); 2445 2446 DEBG(connectRef, "IOFBRebuild(%d)\n", forConnectChange); 2447 2448 DEBG(connectRef, "%p: ID(%qx,%d) -> %p, %08x, %08x, %08x\n", 2449 connectRef, connectRef->dependentID, (int) connectRef->dependentIndex, connectRef->nextDependent, 2450 (int) connectRef->state, connectRef->nextDependent ? (int) connectRef->nextDependent->state : 0, 2451 (int) connectRef->mirrorDefaultFlags); 2452 2453 connectRef->trimToDependent = (kIOMirrorForced == ((kIOMirrorForced | kIOMirrorNoTrim) 2454 & connectRef->mirrorDefaultFlags)) 2455 && (0 != connectRef->dependentIndex) 2456 && (connectRef->nextDependent) 2457 && (0 != (kIOMirrorHint & connectRef->mirrorDefaultFlags)); 2458 2459 connectRef->defaultToDependent = true 2460 && (kIOMirrorForced == ((kIOMirrorForced | kIOMirrorNoTrim) 2461 & connectRef->mirrorDefaultFlags)) 2462 && (0 != connectRef->dependentIndex) 2463 && (connectRef->nextDependent) 2464 && (0 != (kIOMirrorHint & connectRef->mirrorDefaultFlags)); 2465 2466 connectRef->dimensions.width = 0xffffffff; 2467 connectRef->dimensions.height = 0xffffffff; 2468 connectRef->dimensions.setFlags = 0; 2469 connectRef->dimensions.clearFlags = 0; 2470 2471 connectRef->defaultWidth = 0; 2472 connectRef->defaultHeight = 0; 2473 connectRef->defaultImageWidth = 0; 2474 connectRef->defaultImageHeight = 0; 2475 connectRef->displayImageWidth = 0; 2476 connectRef->displayImageHeight = 0; 2477 2478 connectRef->displayMirror = false; 2479 2480 TIMESTART(); 2481 2482 IOFBCreateOverrides( connectRef ); 2483 2484 TIMEEND("IOFBCreateOverrides"); 2485 2486 if(forConnectChange && connectRef->overrides && !(kIOFBConnectStateUnusable & connectRef->state)) do 2487 { 2488 CFNumberRef num; 2489 SInt32 h = -1, v = -1; 2490 2491 if( (num = CFDictionaryGetValue( connectRef->overrides, CFSTR(kDisplayHorizontalImageSize) ))) 2492 CFNumberGetValue( num, kCFNumberSInt32Type, &h ); 2493 if( (num = CFDictionaryGetValue( connectRef->overrides, CFSTR(kDisplayVerticalImageSize) ))) 2494 CFNumberGetValue( num, kCFNumberSInt32Type, &v ); 2495 2496 if ((!h && !v) || (kDisplayVendorIDUnknown == connectRef->displayVendor)) 2497 connectRef->displayMirror = true; 2498 2499 } while( false ); 2500 2501 TIMESTART(); 2502 2503 IOFBResetTransform( connectRef ); 2504 2505 TIMEEND("IOFBResetTransform"); 2506 2507 TIMESTART(); 2508 2509 IOFBBuildModeList( connectRef, forConnectChange ); 2510 2511 if (0 == CFArrayGetCount(connectRef->modesArray)) 2512 { 2513 DEBG(connectRef, " made unusable\n"); 2514 connectRef->state |= kIOFBConnectStateUnusable; 2515 IOFBBuildModeList( connectRef, true ); 2516 } 2517 2518 TIMEEND("IOFBBuildModeList"); 2519 2520 TIMESTART(); 2521 2522 IOFBLookDefaultDisplayMode( connectRef ); 2523 2524 TIMEEND("IOFBLookDefaultDisplayMode"); 2525 2526 CFMutableDictionaryRef prefs; 2527 CFMutableDictionaryRef displayPrefs = NULL; 2528 CFTypeRef displayKey; 2529 displayKey = CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayPrefKeyKey)); 2530 prefs = (CFMutableDictionaryRef) CFDictionaryGetValue(connectRef->iographicsProperties, CFSTR("prefs")); 2531 connectRef->firstBoot = (displayKey && (!prefs 2532 || (NULL == (displayPrefs = (CFMutableDictionaryRef) CFDictionaryGetValue(prefs, displayKey))))); 2533 DEBG(connectRef, "firstBoot == %d\n", connectRef->firstBoot); 2534 2535 connectRef->make4By3 = false 2536 && (kIOMirrorDefault & connectRef->mirrorDefaultFlags) 2537 && (connectRef->defaultNot4By3) 2538 && (0 == connectRef->dependentIndex) 2539 && (0 != (kIOMirrorHint & connectRef->mirrorDefaultFlags)); 2540 2541 bool logDisplay = false; 2542 if (kIOFBConnectStateHWOnline & connectRef->state) 2543 { 2544 logDisplay = connectRef->firstBoot; 2545 if (!logDisplay && displayPrefs) 2546 { 2547 int32_t version = 0; 2548 CFNumberRef 2549 num = CFDictionaryGetValue(displayPrefs, CFSTR(kIOGraphicsPrefsVersionKey)); 2550 if (num && (CFGetTypeID(num) == CFNumberGetTypeID())) 2551 { 2552 CFNumberGetValue(num, kCFNumberSInt32Type, &version); 2553 } 2554 logDisplay = (version < 2); 2555 } 2556 } 2557 2558 if (logDisplay) 2559 { 2560 aslmsg (msg) = asl_new(ASL_TYPE_MSG); 2561 if (msg) 2562 { 2563 char sbuf[256]; 2564 CFDataRef edidData; 2565 io_registry_entry_t regEntry; 2566 2567 snprintf(sbuf, sizeof(sbuf), "0x%x,0x%x(%dx%d)", 2568 (int)connectRef->displayVendor, (int)connectRef->displayProduct, 2569 (int)connectRef->defaultWidth, (int)connectRef->defaultHeight); 2570 2571 asl_set(msg, kMsgTracerKeyDomain, "com.apple.iokit.graphics.displaytype" ); 2572 asl_set(msg, kMsgTracerKeySignature, sbuf); 2573 2574 if ((edidData = CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayEDIDKey))) 2575 && IODisplayEDIDName((EDID *) CFDataGetBytePtr(edidData), sbuf)) 2576 { 2577 asl_set(msg, kMsgTracerKeySignature2, sbuf); 2578 } 2579 regEntry = IORegistryEntryFromPath(kIOMasterPortDefault, 2580 kIOServicePlane ":/"); 2581 if (regEntry) 2582 { 2583 if (kIOReturnSuccess == IORegistryEntryGetName(regEntry, sbuf)) 2584 { 2585 asl_set(msg, kMsgTracerKeySignature3, sbuf); 2586 } 2587 IOObjectRelease(regEntry); 2588 } 2589 asl_set(msg, kMsgTracerKeyResult, "noop"); 2590 asl_log(NULL, msg, ASL_LEVEL_NOTICE, "displayonline"); 2591 asl_free(msg); 2592 } 2593 } 2594 2595 2596 return( kIOReturnSuccess ); 2597} 2598 2599 2600static void 2601IOFBProcessConnectChange( IOFBConnectRef connectRef ) 2602{ 2603 IOReturn err; 2604 IODisplayModeID mode = 0; 2605 IOIndex depth = -1; 2606 IODisplayModeInformation info; 2607 2608#if RLOG 2609 if (gAllConnects) 2610 { 2611 gAllConnects->time0 = mach_absolute_time(); 2612 if (gAllConnects->next) 2613 gAllConnects->next->time0 = gAllConnects->time0; 2614 } 2615#endif 2616 2617 DEBG(connectRef, "IOFBProcessConnectChange\n"); 2618 2619 if (connectRef->matchMode != kIODisplayModeIDInvalid) 2620 { 2621 mode = connectRef->matchMode; 2622 depth = connectRef->matchDepth; 2623 } 2624 else if (connectRef->startMode != kIODisplayModeIDInvalid) 2625 { 2626 mode = connectRef->startMode; 2627 depth = connectRef->startDepth; 2628 } 2629 if (!mode) 2630 mode = connectRef->defaultMode; 2631 if (-1 == depth) 2632 depth = connectRef->defaultDepth; 2633 2634 if( connectRef->make4By3 && connectRef->default4By3Mode) { 2635 err = IOFBGetDisplayModeInformation( connectRef->connect, mode, &info ); 2636 if( (kIOReturnSuccess == err) 2637 && ratioOver(((float)info.nominalWidth) / ((float)info.nominalHeight), 4.0 / 3.0) > 1.03125) { 2638 mode = connectRef->default4By3Mode; 2639 } 2640 } 2641 2642 enum { kNeed = (kIOFBConnectStateUnusable | kIOFBConnectStateHWOnline) }; 2643 if (kNeed == (kNeed & connectRef->state)) 2644 { 2645 __IOFBGetCurrentDisplayModeAndDepth(connectRef, &mode, &depth); 2646 } 2647 2648 TIMESTART(); 2649 2650 DEBG(connectRef, " IOFBSetDisplayModeAndDepth 0x%x, 0x%x\n", (int)mode, depth); 2651 2652 err = IOFBSetDisplayModeAndDepth( connectRef->connect, mode, depth ); 2653 2654 TIMEEND("IOFBSetDisplayModeAndDepth"); 2655} 2656 2657static void 2658IOFBInterestCallback( void * refcon, io_service_t service __unused, 2659 natural_t messageType, void * messageArgument __unused ) 2660{ 2661 IOFBConnectRef connectRef = (IOFBConnectRef) refcon; 2662 IOFBConnectRef next; 2663 UInt32 value; 2664 2665 switch( messageType) { 2666 2667 case kIOMessageServiceIsSuspended: 2668 2669 DEBG(connectRef, " start connect change\n"); 2670 2671 next = connectRef; 2672 do { 2673 TIMESTART(); 2674 2675 _IOFBGetAttributeForFramebuffer( next->connect, MACH_PORT_NULL, 2676 kIOFBProcessConnectChangeAttribute, &value ); 2677 2678 TIMEEND("kIOFBProcessConnectChangeAttribute"); 2679 2680 next = next->nextDependent; 2681 2682 } while( next && (next != connectRef) ); 2683 2684 next = connectRef; 2685 do { 2686 2687 TIMESTART(); 2688 IOFBUpdateConnectState( next ); 2689 TIMEEND("IOFBUpdateConnectState"); 2690 2691 next->setKernelDisplayConfig = true; 2692 2693 TIMESTART(); 2694 DEBG(next, " IOFBRebuild1\n"); 2695 IOFBRebuild( next, true ); 2696 TIMEEND("IOFBRebuild"); 2697 2698 IOFBProcessConnectChange(next); 2699 2700 next = next->nextDependent; 2701 2702 } while( next && (next != connectRef) ); 2703 2704 next = connectRef; 2705 do { 2706 if (next->inMuxSwitch) next->inMuxSwitch = false; 2707 else 2708 { 2709 TIMESTART(); 2710 IOFBRebuild( next, true ); 2711 TIMEEND("IOFBRebuild2"); 2712 2713 DEBG(next, " IOFBProcessConnectChange\n"); 2714 IOFBProcessConnectChange(next); 2715 } 2716 next = next->nextDependent; 2717 2718 } while( next && (next != connectRef) ); 2719 2720 next = connectRef; 2721 do { 2722 2723 TIMESTART(); 2724 2725 if (next->clientCallbacks) 2726 next->clientCallbacks->ConnectionChange(next->clientCallbackRef, (void *) NULL); 2727 2728 TIMEEND("ConnectionChange"); 2729 2730 enum { kNeed = (kIOFBConnectStateUnusable | kIOFBConnectStateOnline) }; 2731 if (kNeed == (kNeed & next->state)) 2732 { 2733 next->state &= ~kIOFBConnectStateOnline; 2734 if (next->clientCallbacks) 2735 next->clientCallbacks->ConnectionChange(next->clientCallbackRef, (void *) NULL); 2736 } 2737 2738 next = next->nextDependent; 2739 } while( next && (next != connectRef) ); 2740 2741 TIMESTART(); 2742 2743 _IOFBGetAttributeForFramebuffer(connectRef->connect, MACH_PORT_NULL, 2744 kIOFBEndConnectChangeAttribute, &value); 2745 2746 TIMEEND("kIOFBEndConnectChangeAttribute"); 2747 2748 break; 2749 2750 case kIOMessageServicePropertyChange: 2751 IOFBWritePrefs(connectRef); 2752 break; 2753 2754 default: 2755 break; 2756 } 2757} 2758 2759mach_port_t 2760IOFBGetNotificationMachPort( io_connect_t connect ) 2761{ 2762 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 2763 2764 if( connectRef) 2765 return( IONotificationPortGetMachPort( connectRef->notifyPort )); 2766 else 2767 return( MACH_PORT_NULL ); 2768} 2769 2770kern_return_t 2771IOFBDispatchMessageNotification( io_connect_t connect, mach_msg_header_t * message, 2772 UInt32 version, 2773 const IOFBMessageCallbacks * callbacks, void * callbackRef ) 2774{ 2775 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 2776 UInt32 value; 2777 2778 switch( message->msgh_id) 2779 { 2780 case 0: 2781 connectRef->didPowerOff = true; 2782 if ((version >= kIOFBMessageCallbacksVersionCurrent) 2783 && callbacks->WillPowerOffWithImages) 2784 { 2785 callbacks->WillPowerOffWithImages(callbackRef, (void *) (uintptr_t) connect, 2786 arrayCnt(connectRef->imageBuffers), 2787 &connectRef->imageBuffers[0], &connectRef->imageSizes[0]); 2788 } 2789 else 2790 { 2791 callbacks->WillPowerOff(callbackRef, (void *) (uintptr_t) connect); 2792 } 2793 break; 2794 2795 case 1: 2796 connectRef->didPowerOff = false; 2797 callbacks->DidPowerOn(callbackRef, (void *) (uintptr_t) connect); 2798 break; 2799 2800 case 0x87654321: 2801 _IOFBGetAttributeForFramebuffer(connectRef->connect, MACH_PORT_NULL, 2802 kIOFBWSStartAttribute, &value); 2803 } 2804 2805 connectRef->clientCallbacks = callbacks; 2806 connectRef->clientCallbackRef = callbackRef; 2807 IODispatchCalloutFromMessage( NULL, message, connectRef->notifyPort ); 2808 2809 return( kIOReturnSuccess ); 2810} 2811 2812kern_return_t 2813IOFBAcknowledgeNotification( void * notificationID ) 2814{ 2815 io_connect_t connect = (io_connect_t) (uintptr_t) notificationID; 2816 2817 if( connect) 2818 return( IOFBAcknowledgePM( connect )); 2819 else 2820 return( kIOReturnSuccess ); 2821} 2822 2823extern kern_return_t 2824IOFBAcknowledgePM( io_connect_t connect ) 2825{ 2826 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 2827 IOReturn err; 2828 UInt32 vramSave; 2829 IODisplayModeID mode; 2830 IOIndex depth; 2831 IOPixelInformation pixelInfo; 2832 uint32_t idx; 2833 2834 if (connectRef->didPowerOff) 2835 do 2836 { 2837 connectRef->didPowerOff = false; 2838 2839 if (connectRef->imageBuffers[kIOPreviewImageIndexDesktop]) continue; 2840 2841 if (kIOFBConnectStateUnusable & connectRef->state) 2842 continue; 2843 2844 err = _IOFBGetAttributeForFramebuffer( connect, 2845 MACH_PORT_NULL, 2846 kIOVRAMSaveAttribute, &vramSave ); 2847 if ((kIOReturnSuccess != err) || !vramSave) 2848 continue; 2849 err = _IOFBGetCurrentDisplayModeAndDepth(connectRef, &mode, &depth); 2850 if (err) 2851 continue; 2852 err = _IOFBGetPixelInformation( connectRef, mode, depth, 2853 kIOFBSystemAperture, &pixelInfo ); 2854 if (err) 2855 continue; 2856 err = IOAccelReadFramebuffer(connectRef->framebuffer, 2857 pixelInfo.activeWidth, pixelInfo.activeHeight, 2858 pixelInfo.bytesPerRow, 2859 &connectRef->imageBuffers[kIOPreviewImageIndexDesktop], 2860 &connectRef->imageSizes[kIOPreviewImageIndexDesktop]); 2861 if (err) 2862 continue; 2863#if 0 2864 { 2865 mach_vm_size_t bytes; 2866 2867 bytes = connectRef->imageSizes[kIOPreviewImageIndexDesktop]; 2868 mach_vm_allocate(mach_task_self(), &connectRef->imageBuffers[kIOPreviewImageIndexLockScreen], bytes, 2869 VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_COREGRAPHICS_FRAMEBUFFERS)); 2870 connectRef->imageSizes[kIOPreviewImageIndexLockScreen] = bytes; 2871 bytes >>= 2; 2872 while (--bytes) ((uint32_t *)connectRef->imageBuffers[kIOPreviewImageIndexLockScreen])[bytes] = 0xff00ff00; 2873 } 2874#endif 2875 } 2876 while (false); 2877 2878 { 2879 // save images to files 2880 struct stat stat_buf; 2881 if (0 == stat(kIOGraphicsLogfilePath, &stat_buf)) do 2882 { 2883 err = _IOFBGetCurrentDisplayModeAndDepth(connectRef, &mode, &depth); 2884 if (err) continue; 2885 err = _IOFBGetPixelInformation(connectRef, mode, depth, 2886 kIOFBSystemAperture, &pixelInfo); 2887 if (err) continue; 2888 for (idx = 0; idx < kIOPreviewImageCount; idx++) 2889 { 2890 struct { 2891 uint8_t identLength; 2892 uint8_t colorMapType; 2893 uint8_t dataType; 2894 uint8_t colorMap[5]; 2895 uint16_t origin[2]; 2896 uint16_t width; 2897 uint16_t height; 2898 uint8_t bitsPerPixel; 2899 uint8_t imageDesc; 2900 } hdr; 2901 FILE * f; 2902 uint8_t * bits; 2903 uint32_t y; 2904 2905 if (!connectRef->imageBuffers[idx]) continue; 2906 2907 bzero(&hdr, sizeof(hdr)); 2908 hdr.dataType = 2; 2909 hdr.width = OSSwapHostToLittleInt16(pixelInfo.activeWidth); 2910 hdr.height = OSSwapHostToLittleInt16(pixelInfo.activeHeight); 2911 hdr.bitsPerPixel = pixelInfo.bitsPerPixel; 2912 hdr.imageDesc = (1<<5) | 8; 2913 2914 f = fopen(gIOGraphicsImageFiles[idx], "w" /*"r+"*/); 2915 if (!f) continue; 2916 fwrite(&hdr, sizeof(hdr), 1, f); 2917 bits = (uint8_t *)(uintptr_t) connectRef->imageBuffers[idx]; 2918 for (y = 0; y < pixelInfo.activeHeight; y++) 2919 { 2920 fwrite(bits, sizeof(uint32_t), hdr.width, f); 2921 bits += pixelInfo.bytesPerRow; 2922 } 2923 fclose(f); 2924 } 2925 } 2926 while (false); 2927 } 2928 2929 err = IOConnectCallMethod(connect, 14, // Index 2930 &connectRef->imageBuffers[0], 2 * arrayCnt(connectRef->imageBuffers), 2931 NULL, 0, // Input 2932 NULL, NULL, NULL, NULL); // Output 2933 2934 for (idx = 0; idx < arrayCnt(connectRef->imageBuffers); idx++) 2935 { 2936 if (!connectRef->imageBuffers[idx]) continue; 2937 mach_vm_deallocate(mach_task_self(), connectRef->imageBuffers[idx], connectRef->imageSizes[idx]); 2938 connectRef->imageBuffers[idx] = connectRef->imageSizes[idx] = 0; 2939 } 2940 2941 return (err); 2942} 2943 2944// Display mode information 2945 2946static void 2947IOFBCreateOverrides( IOFBConnectRef connectRef ) 2948{ 2949 io_service_t framebuffer = connectRef->framebuffer; 2950 CFDictionaryRef oldOvr = 0; 2951 CFMutableDictionaryRef newDict, ovr = 0; 2952 CFTypeRef obj; 2953 CFNumberRef num; 2954 2955 if( connectRef->overrides) { 2956 CFRelease( connectRef->overrides ); 2957 connectRef->overrides = NULL; 2958 } 2959 2960 do { 2961 2962 oldOvr = _IODisplayCreateInfoDictionary( connectRef, framebuffer, kIODisplayNoProductName ); 2963 if( !oldOvr) 2964 continue; 2965 2966 num = CFDictionaryGetValue( oldOvr, CFSTR("IOGFlags") ); 2967 if( num) 2968 CFNumberGetValue( num, kCFNumberSInt32Type, (SInt32 *) &connectRef->ovrFlags ); 2969 else 2970 connectRef->ovrFlags = 0; 2971 2972 num = CFDictionaryGetValue( oldOvr, CFSTR(kDisplayVendorID) ); 2973 if( num) 2974 CFNumberGetValue( num, kCFNumberSInt32Type, (SInt32 *) &connectRef->displayVendor ); 2975 num = CFDictionaryGetValue( oldOvr, CFSTR(kDisplayProductID) ); 2976 if( num) 2977 CFNumberGetValue( num, kCFNumberSInt32Type, (SInt32 *) &connectRef->displayProduct ); 2978 2979 ovr = CFDictionaryCreateMutable( kCFAllocatorDefault, (CFIndex) 0, 2980 &kCFTypeDictionaryKeyCallBacks, 2981 &kCFTypeDictionaryValueCallBacks ); 2982 if( !ovr) 2983 continue; 2984 2985 if ((newDict = IOFBMakeIntegerKeys(CFDictionaryGetValue(oldOvr, CFSTR("tovr")), false))) 2986 { 2987 CFDictionarySetValue( ovr, CFSTR("tovr"), newDict ); 2988 CFRelease( newDict ); 2989 } 2990 if ((newDict = IOFBMakeIntegerKeys(CFDictionaryGetValue(oldOvr, CFSTR("tinf")), false))) 2991 { 2992 CFDictionarySetValue( ovr, CFSTR("tinf"), newDict ); 2993 CFRelease( newDict ); 2994 } 2995 2996 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR(kIODisplayEDIDKey)) )) 2997 CFDictionarySetValue( ovr, CFSTR(kIODisplayEDIDKey), obj ); 2998 2999 if ((obj = CFDictionaryGetValue(oldOvr, CFSTR(kIODisplayPrefKeyKey)))) 3000 CFDictionarySetValue( ovr, CFSTR(kIODisplayPrefKeyKey), obj ); 3001 3002 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR(kDisplayHorizontalImageSize)) )) 3003 CFDictionarySetValue( ovr, CFSTR(kDisplayHorizontalImageSize), obj ); 3004 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR(kDisplayVerticalImageSize)) )) 3005 CFDictionarySetValue( ovr, CFSTR(kDisplayVerticalImageSize), obj ); 3006 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR(kIODisplayIsDigitalKey)) )) 3007 CFDictionarySetValue( ovr, CFSTR(kIODisplayIsDigitalKey), obj ); 3008 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR(kDisplayFixedPixelFormat)) )) 3009 CFDictionarySetValue( ovr, CFSTR(kDisplayFixedPixelFormat), obj ); 3010 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR(kIODisplayAttributesKey)) )) 3011 CFDictionarySetValue( ovr, CFSTR(kIODisplayAttributesKey), obj ); 3012 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR("trng")) )) 3013 CFDictionarySetValue( ovr, CFSTR("trng"), obj ); 3014 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR("drng")) )) 3015 CFDictionarySetValue( ovr, CFSTR("drng"), obj ); 3016 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR("dspc")) )) 3017 CFDictionarySetValue( ovr, CFSTR("dspc"), obj ); 3018 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR("mdes")) )) 3019 CFDictionarySetValue( ovr, CFSTR("mdes"), obj ); 3020 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR("dims")) )) 3021 CFDictionarySetValue( ovr, CFSTR("dims"), obj ); 3022 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR("sync")) )) 3023 CFDictionarySetValue( ovr, CFSTR("sync"), obj ); 3024 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR("scale-resolutions")) )) 3025 CFDictionarySetValue( ovr, CFSTR("scale-resolutions"), obj ); 3026 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR("scale-resolutions-4k")) )) 3027 CFDictionarySetValue( ovr, CFSTR("scale-resolutions-4k"), obj ); 3028 if( (obj = CFDictionaryGetValue( oldOvr, CFSTR("default-resolution")) )) 3029 CFDictionarySetValue( ovr, CFSTR("default-resolution"), obj ); 3030 if( (obj = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &connectRef->ovrFlags ))) { 3031 CFDictionarySetValue( ovr, CFSTR("IOGFlags"), obj ); 3032 CFRelease(obj); 3033 } 3034 3035 } while( false ); 3036 3037 if( oldOvr) 3038 CFRelease( oldOvr ); 3039 3040 connectRef->overrides = ovr; 3041} 3042 3043static IOIndex 3044IOFBIndexForPixelBits( IOFBConnectRef connectRef, IODisplayModeID mode, 3045 IOIndex maxIndex, UInt32 bpp ) 3046{ 3047 IOPixelInformation pixelInfo; 3048 IOIndex index, depth = -1; 3049 kern_return_t err; 3050 3051 for( index = 0; index <= maxIndex; index++ ) { 3052 3053 err = _IOFBGetPixelInformation( connectRef, mode, index, 3054 kIOFBSystemAperture, &pixelInfo ); 3055 if( (kIOReturnSuccess == err) && (pixelInfo.bitsPerPixel >= bpp)) { 3056 depth = index; 3057 break; 3058 } 3059 } 3060 3061 return( depth ); 3062} 3063 3064static kern_return_t 3065IOFBLookDefaultDisplayMode( IOFBConnectRef connectRef ) 3066{ 3067 IOReturn err; 3068 CFDataRef data; 3069 CFIndex modeCount, i; 3070 SInt32 bestDefault, rDefault; 3071 SInt32 bestQuality, rQuality; 3072 CFDictionaryRef dict; 3073 IODisplayModeID mode, bestMode = 0; 3074 IODisplayModeInformation bestInfo = { .flags = 0 }; 3075 IODisplayModeInformation * info; 3076 SInt32 bestDepth, minDepth, otherDepth = 0; 3077 CFDictionaryRef ovr, tinf; 3078 CFDataRef modetinf; 3079 CFNumberRef num; 3080 SInt32 timingID; 3081 Boolean better, defaultToDependent; 3082 UInt32 desireRefresh; 3083 UInt32 biggest4By3; 3084 float desireHPix, desireVPix; 3085 3086 ovr = connectRef->overrides; 3087 if( ovr) 3088 tinf = CFDictionaryGetValue( ovr, CFSTR("tinf") ); 3089 else 3090 tinf = 0; 3091 3092 desireHPix = desireVPix = 0; 3093 desireRefresh = (86 << 16); 3094 3095 if( ovr 3096 && !CFDictionaryGetValue( ovr, CFSTR(kDisplayFixedPixelFormat)) 3097 && !CFDictionaryGetValue( ovr, CFSTR(kIODisplayIsDigitalKey))) { 3098 if( (num = CFDictionaryGetValue( ovr, CFSTR(kDisplayHorizontalImageSize) ))) { 3099 CFNumberGetValue( num, kCFNumberFloatType, &desireHPix ); 3100 if( desireHPix) 3101 desireHPix = desireHPix / mmPerInch * desireDPI; 3102 } 3103 if( (num = CFDictionaryGetValue( ovr, CFSTR(kDisplayVerticalImageSize) ))) { 3104 CFNumberGetValue( num, kCFNumberFloatType, &desireVPix ); 3105 if( desireVPix) 3106 desireVPix = desireVPix / mmPerInch * desireDPI; 3107 } 3108 } 3109 3110 if( ovr && (data = CFDictionaryGetValue( ovr, CFSTR("default-resolution") ))) { 3111 UInt32 * value = (UInt32 *) CFDataGetBytePtr((CFDataRef) data); 3112 desireHPix = (float) OSReadBigInt32(&value[0], 0); 3113 desireVPix = (float) OSReadBigInt32(&value[1], 0); 3114 desireRefresh = OSReadBigInt32(&value[2], 0); 3115 } 3116 3117 bestQuality = bestDefault = 0; 3118 bestDepth = 1; 3119 3120 if (kIOScaleSwapAxes & connectRef->transform) 3121 { 3122 float swap = desireHPix; 3123 desireHPix = desireVPix; 3124 desireVPix = swap; 3125 } 3126 3127 defaultToDependent = false; 3128 if( connectRef->defaultToDependent) do { 3129 3130 if( kIOReturnSuccess != _IOFBGetCurrentDisplayModeAndDepth( connectRef->nextDependent, 3131 &mode, &otherDepth )) 3132 continue; 3133 dict = CFDictionaryGetValue( connectRef->nextDependent->modes, (const void *) (uintptr_t) (UInt32) mode ); 3134 if( dict && (data = CFDictionaryGetValue( dict, CFSTR(kIOFBModeDMKey) ))) { 3135 info = (IODisplayModeInformation *) CFDataGetBytePtr(data); 3136 desireHPix = info->nominalWidth; 3137 desireVPix = info->nominalHeight; 3138 defaultToDependent = true; 3139 } 3140 3141 } while( false ); 3142 3143 biggest4By3 = 0; 3144 connectRef->default4By3Mode = 0; 3145 3146 modeCount = CFArrayGetCount( connectRef->modesArray ); 3147 for( i = 0; i < modeCount; i++) { 3148 3149 dict = CFArrayGetValueAtIndex( connectRef->modesArray, i ); 3150 better = false; 3151 data = (CFDataRef) CFDictionaryGetValue( dict, CFSTR(kIOFBModeDMKey) ); 3152 if (!data) continue; 3153 info = (IODisplayModeInformation *) CFDataGetBytePtr(data); 3154 3155 num = CFDictionaryGetValue( dict, CFSTR(kIOFBModeIDKey) ); 3156 if (!num) continue; 3157 CFNumberGetValue( num, kCFNumberSInt32Type, &mode ); 3158 3159 num = CFDictionaryGetValue( dict, CFSTR(kIOFBModeAIDKey) ); 3160 if( num) 3161 CFNumberGetValue( num, kCFNumberSInt32Type, &timingID ); 3162 else 3163 timingID = 0; 3164 3165 if (mode == connectRef->startMode) connectRef->startDepth = IOFBIndexForPixelBits(connectRef, mode, info->maxDepthIndex, 32); 3166 3167 if( 0 == (info->flags & kDisplayModeValidFlag)) continue; 3168 if (kMirrorOnlyFlags & info->flags) continue; 3169 3170 // make sure it does >= 16bpp 3171 minDepth = IOFBIndexForPixelBits( connectRef, mode, info->maxDepthIndex, 16); 3172 3173 if( minDepth < 0) 3174 continue; 3175 if( defaultToDependent) 3176 minDepth = otherDepth; 3177 3178 if( (info->flags & kDisplayModeSafeFlag) 3179 && (info->nominalWidth > biggest4By3) 3180 && (ratioOver(((float)info->nominalWidth) / ((float)info->nominalHeight), 4.0 / 3.0) <= 1.03125)) { 3181 biggest4By3 = info->nominalWidth; 3182 connectRef->default4By3Mode = mode; 3183 } 3184 3185 if( timingID && tinf && !defaultToDependent 3186 && (modetinf = CFDictionaryGetValue( tinf, (const void *) (uintptr_t) (UInt32) timingID ))) { 3187 DMDisplayTimingInfoRec * tinfRec; 3188 tinfRec = (DMDisplayTimingInfoRec *) CFDataGetBytePtr(modetinf); 3189 rQuality = OSReadBigInt32(&tinfRec->timingInfoRelativeQuality, 0); 3190 rDefault = OSReadBigInt32(&tinfRec->timingInfoRelativeDefault, 0); 3191 } else 3192 rQuality = rDefault = 0; 3193 3194 if( (info->nominalWidth < connectRef->defaultMinWidth) || (info->nominalHeight < connectRef->defaultMinHeight)) 3195 rDefault--; 3196 else if (!defaultToDependent && (0 != (info->flags & kDisplayModeDefaultFlag))) 3197 { 3198 rDefault++; 3199 if (mode & 0x80000000) 3200 rDefault++; 3201 } 3202 3203 if( !bestMode 3204 || ((info->flags & kDisplayModeSafeFlag) && (0 == (bestInfo.flags & kDisplayModeSafeFlag)))) 3205 better = true; 3206 else { 3207#if 1 3208 if( (!defaultToDependent) 3209 && (bestInfo.flags & kDisplayModeSafeFlag) 3210 && (0 == (info->flags & kDisplayModeSafeFlag))) 3211 continue; 3212#else 3213 if( 0 == (info->flags & kDisplayModeSafeFlag)) 3214 continue; 3215#endif 3216 if( rDefault < bestDefault) 3217 continue; 3218 better = (rDefault > bestDefault); 3219 3220 if( !better) { 3221 3222 if( (info->nominalWidth == bestInfo.nominalWidth) 3223 && (info->nominalHeight == bestInfo.nominalHeight)) { 3224 3225 if( defaultToDependent && (0 == (info->flags & kDisplayModeSafeFlag)) ) 3226 better = (info->refreshRate < (61 << 16)) 3227 && (info->refreshRate > bestInfo.refreshRate); 3228 else { 3229 better = (info->refreshRate < desireRefresh) 3230 && ((info->refreshRate > bestInfo.refreshRate) 3231 || (bestInfo.refreshRate >= desireRefresh)); 3232 } 3233 3234 } else { 3235 if (desireHPix && desireVPix) { 3236 SInt32 delta1, delta2; 3237 3238 delta1 = ((abs(info->nominalWidth - ((SInt32)desireHPix) )) 3239 + abs(info->nominalHeight - ((SInt32)desireVPix) )); 3240 delta2 = (abs(bestInfo.nominalWidth - ((SInt32)desireHPix) ) 3241 + abs(bestInfo.nominalHeight - ((SInt32)desireVPix) )); 3242 better = (delta1 < delta2); 3243 } 3244 else 3245 { 3246 better = ((info->nominalWidth * info->nominalHeight) 3247 > (bestInfo.nominalWidth * bestInfo.nominalHeight)); 3248 } 3249 } 3250 } 3251 } 3252 3253 if( better) { 3254 bestMode = mode; 3255 bestQuality = rQuality; 3256 bestDefault = rDefault; 3257 bestInfo = *info; 3258 bestDepth = minDepth; 3259 } 3260 } 3261 3262 if( bestMode) { 3263 3264 connectRef->defaultMode = bestMode; 3265 if( !defaultToDependent 3266 && (bestInfo.maxDepthIndex > bestDepth)) 3267 bestDepth++; 3268 connectRef->defaultDepth = bestDepth; 3269 3270 connectRef->defaultNot4By3 = (ratioOver(((float)bestInfo.nominalWidth) / ((float)bestInfo.nominalHeight), 4.0 / 3.0) > 1.03125); 3271 3272 err = kIOReturnSuccess; 3273 } else 3274 err = _IOFBGetCurrentDisplayModeAndDepth( connectRef, 3275 &connectRef->defaultMode, &connectRef->defaultDepth ); 3276 3277 DEBG(connectRef, " 0x%x, 0x%x\n", (int)connectRef->defaultMode, connectRef->defaultDepth); 3278 3279 return( err ); 3280} 3281 3282kern_return_t 3283IOFBGetDefaultDisplayMode( io_connect_t connect, 3284 IODisplayModeID * displayMode, IOIndex * displayDepth ) 3285{ 3286 IOFBConnectRef connectRef; 3287 3288 connectRef = IOFBConnectToRef( connect); 3289 if( !connectRef) 3290 return( kIOReturnBadArgument ); 3291 3292 *displayMode = connectRef->defaultMode; 3293 *displayDepth = connectRef->defaultDepth; 3294 3295 return( kIOReturnSuccess ); 3296} 3297 3298 3299static Boolean 3300IOFBCheckScaleDupMode( IOFBConnectRef connectRef, 3301 IOFBDisplayModeDescription * desc, 3302 IOOptionBits installFlags ) 3303{ 3304 CFDictionaryRef dict; 3305 CFDataRef data; 3306 CFIndex i, modeCount; 3307 IODisplayModeInformation * info; 3308 Boolean dup = false; 3309 3310 if ((0 == (kMirrorOnlyFlags & desc->info.flags)) 3311 && (kScaleInstallAlways & installFlags)) return (false); 3312 3313 modeCount = CFArrayGetCount( connectRef->modesArray ); 3314 3315 for( i = 0; (i < modeCount) && !dup; i++ ) 3316 { 3317 dict = CFArrayGetValueAtIndex( connectRef->modesArray, i ); 3318 if( !dict) continue; 3319 data = (CFDataRef) CFDictionaryGetValue( dict, CFSTR(kIOFBModeDMKey) ); 3320 if( !data) continue; 3321 info = (IODisplayModeInformation *) CFDataGetBytePtr(data); 3322 3323 do 3324 { 3325 if (0 == (kDisplayModeValidFlag & info->flags)) continue; 3326 if (kDisplayModeBuiltInFlag & info->flags) continue; 3327 3328 if (kMirrorOnlyFlags & desc->info.flags) 3329 { 3330 if (info->nominalWidth != desc->info.nominalWidth) continue; 3331 if (info->nominalHeight != desc->info.nominalHeight) continue; 3332 } 3333 else 3334 { 3335 if (kDisplayModeStretchedFlag & (info->flags ^ desc->info.flags)) continue; 3336 if (info->nominalWidth < (desc->info.nominalWidth - 20)) continue; 3337 if (info->nominalWidth > (desc->info.nominalWidth + 20)) continue; 3338 if (info->nominalHeight < (desc->info.nominalHeight - 20)) continue; 3339 if (info->nominalHeight > (desc->info.nominalHeight + 20)) continue; 3340 } 3341 dup = true; 3342 } 3343 while( false ); 3344 } 3345 3346 return( dup ); 3347} 3348 3349static kern_return_t 3350IOFBInstallScaledMode( IOFBConnectRef connectRef, 3351 IOFBDisplayModeDescription * _desc, 3352 IOOptionBits installFlags) 3353{ 3354 IOFBDisplayModeDescription * desc = _desc; 3355 IOFBDisplayModeDescription __desc; 3356 UInt32 insetH, insetV, width, height, swap; 3357 kern_return_t kr; 3358 3359 __desc = *_desc; 3360 desc = &__desc; 3361 3362 kr = IOFBDriverPreflight(connectRef, desc); 3363 3364 if ((kIOReturnSuccess != kr) 3365 && !(kIOScaleCanBorderInsetOnly & connectRef->scalerInfo->scalerFeatures)) 3366 { 3367 insetH = desc->timingInfo.detailedInfo.v2.horizontalScaledInset; 3368 insetV = desc->timingInfo.detailedInfo.v2.verticalScaledInset; 3369 3370 if (insetH || insetV) 3371 { 3372 width = desc->timingInfo.detailedInfo.v2.horizontalScaled; 3373 height = desc->timingInfo.detailedInfo.v2.verticalScaled; 3374 3375 if (kIOScaleSwapAxes & desc->timingInfo.detailedInfo.v2.scalerFlags) 3376 { 3377 swap = width; 3378 width = height; 3379 height = swap; 3380 } 3381 3382 if ((width == desc->timingInfo.detailedInfo.v2.horizontalActive) 3383 && (height == desc->timingInfo.detailedInfo.v2.verticalActive)) 3384 { 3385 if (kIOScaleSwapAxes & desc->timingInfo.detailedInfo.v2.scalerFlags) 3386 { 3387 swap = insetH; 3388 insetH = insetV; 3389 insetV = swap; 3390 } 3391 desc->timingInfo.detailedInfo.v2.horizontalScaled -= 2*insetH; 3392 desc->timingInfo.detailedInfo.v2.verticalScaled -= 2*insetV; 3393 3394 kr = IOFBDriverPreflight(connectRef, desc); 3395 } 3396 } 3397 } 3398 if (kIOReturnSuccess != kr) 3399 return (kr); 3400 3401 if (IOFBCheckScaleDupMode( connectRef, desc, installFlags )) 3402 return( 9 ); 3403 3404 IOFBSetImageSize(connectRef, desc); 3405 3406 return(IOFBInstallMode( connectRef, 0xffffffff, desc, 0, kIOFBScaledMode)); 3407} 3408 3409__private_extern__ void 3410UpdateTimingInfoForTransform(IOFBConnectRef connectRef, 3411 IOFBDisplayModeDescription * desc, 3412 IOOptionBits flags ) 3413{ 3414 Boolean doUnderscan = (connectRef->useScalerUnderscan 3415 && (kIOFBScalerUnderscan & connectRef->transform)); 3416 UInt32 width, height, swap; 3417 3418 desc->timingInfo.detailedInfo.v2.scalerFlags &= ~kIOScaleRotateFlags; 3419 3420 if (!(kIOScaleRotateFlags & connectRef->transform) && !doUnderscan) 3421 return; 3422 3423 width = desc->timingInfo.detailedInfo.v2.horizontalScaled; 3424 if (!width) 3425 width = desc->timingInfo.detailedInfo.v2.horizontalActive; 3426 height = desc->timingInfo.detailedInfo.v2.verticalScaled; 3427 if (!height) 3428 height = desc->timingInfo.detailedInfo.v2.verticalActive; 3429 3430 if ((kIOScaleSwapAxes & connectRef->transform) 3431 && !(kScaleInstallNoResTransform & flags)) 3432 { 3433 swap = width; 3434 width = height; 3435 height = swap; 3436 } 3437 desc->timingInfo.detailedInfo.v2.horizontalScaled = width; 3438 desc->timingInfo.detailedInfo.v2.verticalScaled = height; 3439 if (doUnderscan) 3440 { 3441 width = desc->timingInfo.detailedInfo.v2.horizontalActive; 3442 height = desc->timingInfo.detailedInfo.v2.verticalActive; 3443 width = (width >> 4) & ~7; 3444 height = (height >> 4) & ~1; 3445 desc->timingInfo.detailedInfo.v2.horizontalScaledInset = width; 3446 desc->timingInfo.detailedInfo.v2.verticalScaledInset = height; 3447 3448 if (kIOScaleCanBorderInsetOnly & connectRef->scalerInfo->scalerFeatures) 3449 { 3450 if ((kIOScaleSwapAxes & connectRef->transform) 3451 && !(kScaleInstallNoResTransform & flags)) 3452 { 3453 swap = width; 3454 width = height; 3455 height = swap; 3456 } 3457 desc->timingInfo.detailedInfo.v2.horizontalScaled -= 2*width; 3458 desc->timingInfo.detailedInfo.v2.verticalScaled -= 2*height; 3459 } 3460 } 3461 3462 desc->timingInfo.detailedInfo.v2.scalerFlags |= (connectRef->transform & kIOScaleRotateFlags); 3463 3464#if RLOG 3465 if (desc->timingInfo.detailedInfo.v2.horizontalScaledInset 3466 || desc->timingInfo.detailedInfo.v2.verticalScaledInset) 3467 { 3468 DEBG(connectRef, "using inset:\n"); 3469 IOFBLogTiming(connectRef, &desc->timingInfo); 3470 } 3471#endif 3472} 3473 3474static int 3475_IOFBInstallScaledResolution( IOFBConnectRef connectRef, 3476 IOFBDisplayModeDescription * baseDesc, 3477 float nativeWidth, float nativeHeight, 3478 float width, float height, 3479 IOOptionBits flags, 3480 uint32_t setModeFlags, uint32_t clrModeFlags ) 3481{ 3482 IOFBDisplayModeDescription newDesc; 3483 IOFBDisplayModeDescription * desc = &newDesc; 3484 UInt32 need = 0; 3485 float aspectDiff; 3486 float ratio; 3487 Boolean okToStretch, bordered, allowArbRatio; 3488 UInt32 rotateFlags; 3489 3490 if( width < 640.0) 3491 return( 1 ); 3492 if( height < 480.0) 3493 return( 2 ); 3494 3495 if( width > connectRef->scalerInfo->maxHorizontalPixels) 3496 return( 3 ); 3497 if( height > connectRef->scalerInfo->maxVerticalPixels) 3498 return( 4 ); 3499 3500 if( width < nativeWidth) 3501 need |= kIOScaleCanUpSamplePixels; 3502 else if( width != nativeWidth) 3503 need |= kIOScaleCanDownSamplePixels; 3504 if( height < nativeHeight) 3505 need |= kIOScaleCanUpSamplePixels; 3506 else if( height != nativeHeight) 3507 need |= kIOScaleCanDownSamplePixels; 3508 3509 rotateFlags = kIOScaleRotateFlags & connectRef->transform; 3510 if (rotateFlags) 3511 need |= kIOScaleCanRotate; 3512 3513 if( need != (need & connectRef->scalerInfo->scalerFeatures)) 3514 return( 5 ); 3515 3516 aspectDiff = ratioOver( nativeWidth / nativeHeight, width / height ); 3517 3518 bordered = ((width == nativeWidth) || (height == nativeHeight)); 3519 allowArbRatio = (0 != ((kIOScaleCanScaleInterlaced | kIOScaleCanRotate) & connectRef->scalerInfo->scalerFeatures)); 3520 3521 okToStretch = ((0 == (kScaleInstallNoStretch & flags)) && (aspectDiff > 1.03125) && (aspectDiff < 1.5)); 3522 3523 if (0 == (kScaleInstallAlways & flags)) 3524 { 3525 ratio = (width / nativeWidth); 3526 if( (ratio < 1.18) && (ratio > 0.82)) 3527 { 3528 if (bordered || allowArbRatio) 3529 okToStretch = false; 3530 else 3531 return( 6 ); 3532 } 3533 ratio = (height / nativeHeight); 3534 if( (ratio < 1.18) && (ratio > 0.82)) 3535 { 3536 if (bordered || allowArbRatio) 3537 okToStretch = false; 3538 else 3539 return( 7 ); 3540 } 3541 if( aspectDiff > 2.0) 3542 return( 8 ); 3543 } 3544 3545 *desc = *baseDesc; 3546 3547 desc->timingInfo.detailedInfo.v2.horizontalScaled = ((UInt32) ceilf(width)); 3548 desc->timingInfo.detailedInfo.v2.verticalScaled = ~1 & ((UInt32) ceilf(height)); 3549 desc->timingInfo.detailedInfo.v2.scalerFlags = 0; 3550 3551 UpdateTimingInfoForTransform(connectRef, desc, flags); 3552 3553 desc->info.flags = (desc->info.flags & ~(kDisplayModeSafetyFlags | kDisplayModeNativeFlag)) 3554 | kDisplayModeValidFlag | kDisplayModeSafeFlag; 3555 3556 if( aspectDiff > 1.03125) 3557 desc->info.flags |= kDisplayModeNotPresetFlag; 3558 3559 desc->info.flags |= setModeFlags; 3560 desc->info.flags &= ~clrModeFlags; 3561 3562 if( 0 == (kIOScaleStretchOnly & connectRef->scalerInfo->scalerFeatures)) 3563 { 3564 IOFBInstallScaledMode( connectRef, desc, flags ); 3565 } 3566 3567 if (false && okToStretch) 3568 { 3569 desc->info.flags |= kDisplayModeStretchedFlag; 3570 desc->info.flags &= ~clrModeFlags; 3571 desc->timingInfo.detailedInfo.v2.scalerFlags |= kIOScaleStretchToFit; 3572 IOFBInstallScaledMode( connectRef, desc, flags ); 3573 } 3574 3575 return( 0 ); 3576} 3577 3578static kern_return_t 3579IOFBInstallScaledResolution( IOFBConnectRef connectRef, 3580 IOFBDisplayModeDescription * desc, 3581 float nativeWidth, float nativeHeight, 3582 float width, float height, 3583 IOOptionBits flags, 3584 uint32_t setModeFlags, uint32_t clrModeFlags ) 3585{ 3586 int diag1, diag2; 3587 3588 diag1 = _IOFBInstallScaledResolution(connectRef, desc, nativeWidth, nativeHeight, width, height, 3589 flags, setModeFlags, clrModeFlags); 3590 DEBG(connectRef, "(%d) %f x %f, %08x\n", diag1, width, height, (int) flags); 3591 3592 if ((kIOFBSwapAxes | kIOScaleSwapAxes) & connectRef->transform) 3593 { 3594 if (ratioOver(width / height, 4.0 / 3.0) <= 1.03125) 3595 { 3596 flags |= kScaleInstallNoResTransform; 3597 diag2 = _IOFBInstallScaledResolution(connectRef, desc, nativeWidth, nativeHeight, width, height, 3598 flags, setModeFlags, clrModeFlags); 3599 DEBG(connectRef, "(%d) %f x %f, %08x\n", diag2, width, height, (int) flags ); 3600 } 3601 } 3602 3603 return (diag1 ? kIOReturnUnsupported : kIOReturnSuccess); 3604} 3605 3606static Boolean 3607IOFBLookScaleBaseMode( IOFBConnectRef connectRef, IOFBDisplayModeDescription * scaleBase, 3608 IOFBDisplayModeDescription * scaleDesc ) 3609{ 3610 Boolean found = false; 3611 UInt32 h, v; 3612 3613 DEBG(connectRef, "%d: %dx%d %fHz scale %dx%d %08x %08x\n", 3614 (int) scaleBase->timingInfo.appleTimingID, 3615 (int) scaleBase->timingInfo.detailedInfo.v2.horizontalActive, 3616 (int) scaleBase->timingInfo.detailedInfo.v2.verticalActive, 3617 RefreshRateFromDetailedTiming(&scaleBase->timingInfo.detailedInfo.v2), 3618 (int) scaleBase->timingInfo.detailedInfo.v2.horizontalScaled, 3619 (int) scaleBase->timingInfo.detailedInfo.v2.verticalScaled, 3620 (int) scaleBase->info.flags, (int) scaleBase->timingInfo.flags); 3621 3622 do { 3623 if( 0 == (kIODetailedTimingValid & scaleBase->timingInfo.flags)) 3624 continue; 3625 3626 if( (kDisplayModeValidFlag | kDisplayModeSafeFlag) != 3627 ((kDisplayModeValidFlag | kDisplayModeSafeFlag) & scaleBase->info.flags)) 3628 continue; 3629 3630 if( (kDisplayModeBuiltInFlag 3631 | kDisplayModeNeverShowFlag 3632 | kDisplayModeStretchedFlag 3633 | kDisplayModeNotGraphicsQualityFlag 3634 | kDisplayModeNotPresetFlag) & scaleBase->info.flags) 3635 continue; 3636 3637 if ((kDisplayModeInterlacedFlag & scaleBase->info.flags) 3638 && (!(kIOScaleCanScaleInterlaced & connectRef->scalerInfo->scalerFeatures))) 3639 continue; 3640 3641 if ((kDisplayModeNativeFlag & scaleDesc->info.flags) 3642 && !(kDisplayModeNativeFlag & scaleBase->info.flags)) 3643 continue; 3644 3645 if (!(kDisplayModeNativeFlag & scaleDesc->info.flags) && (kDisplayModeDefaultFlag & scaleDesc->info.flags) 3646 && !(kDisplayModeDefaultFlag & scaleBase->info.flags)) 3647 continue; 3648 3649#if 0 3650 if(connectRef->driverModeCount 3651 && (kIOTimingIDApple_FixedRateLCD != scaleBase->timingInfo.appleTimingID)) 3652 continue; 3653#endif 3654 3655 if (kIOScaleSwapAxes & connectRef->transform) 3656 { 3657 h = scaleBase->timingInfo.detailedInfo.v2.verticalScaled; 3658 v = scaleBase->timingInfo.detailedInfo.v2.horizontalScaled; 3659 } 3660 else 3661 { 3662 h = scaleBase->timingInfo.detailedInfo.v2.horizontalScaled; 3663 v = scaleBase->timingInfo.detailedInfo.v2.verticalScaled; 3664 } 3665 if (h && (h != scaleBase->timingInfo.detailedInfo.v2.horizontalActive)) 3666 continue; 3667 if (v && (v != scaleBase->timingInfo.detailedInfo.v2.verticalActive)) 3668 continue; 3669 3670 if( scaleBase->timingInfo.detailedInfo.v2.horizontalActive 3671 < scaleDesc->timingInfo.detailedInfo.v2.horizontalActive) 3672 continue; 3673 if( scaleBase->timingInfo.detailedInfo.v2.verticalActive 3674 < scaleDesc->timingInfo.detailedInfo.v2.verticalActive) 3675 continue; 3676 3677 if((scaleBase->timingInfo.detailedInfo.v2.horizontalActive 3678 == scaleDesc->timingInfo.detailedInfo.v2.horizontalActive) 3679 && (scaleBase->timingInfo.detailedInfo.v2.verticalActive 3680 == scaleDesc->timingInfo.detailedInfo.v2.verticalActive) 3681 && (RefreshRateFromDetailedTiming(&scaleBase->timingInfo.detailedInfo.v2) 3682 < RefreshRateFromDetailedTiming(&scaleDesc->timingInfo.detailedInfo.v2))) 3683 continue; 3684 3685 if ((kDisplayModeInterlacedFlag & scaleBase->info.flags) 3686 && (!(kDisplayModeInterlacedFlag & scaleDesc->info.flags))) 3687 continue; 3688 3689 DEBG(connectRef, "choosing\n"); 3690 3691 found = true; 3692 *scaleDesc = *scaleBase; 3693 scaleDesc->timingInfo.appleTimingID = 0; 3694 scaleDesc->timingInfo.flags = kIODetailedTimingValid; 3695 3696 } while( false ); 3697 3698 return( found ); 3699} 3700 3701static kern_return_t 3702IOFBInstallScaledModes( IOFBConnectRef connectRef, IOFBDisplayModeDescription * scaleBase, 3703 Boolean onlyMirrorModes ) 3704{ 3705 IOReturn err = kIOReturnSuccess; 3706 IOFBConnectRef next; 3707 CFMutableArrayRef arrays; 3708 CFArrayRef iogArray = NULL; 3709 CFArrayRef displayArray = NULL; 3710 CFArrayRef otherArray = NULL; 3711 CFIndex count, arraysCount; 3712 SInt32 i, arraysIdx; 3713 float h, v, nh, nv; 3714 Boolean displayNot4By3, displayNot16By9, display4k, other4k; 3715 3716 if( !connectRef->scalerInfo) return( kIOReturnSuccess ); 3717 if( kOvrFlagDisableScaling & connectRef->ovrFlags) return( kIOReturnSuccess ); 3718 3719 arrays = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks ); 3720 if (!arrays) return( kIOReturnNoMemory ); 3721 3722 nh = (float) scaleBase->timingInfo.detailedInfo.v2.horizontalActive; 3723 nv = (float) scaleBase->timingInfo.detailedInfo.v2.verticalActive; 3724 3725 DEBG(connectRef, "Scaling mode (%f,%f)\n", nh, nv); 3726 3727 display4k = ((nh >= 3840) || (nv >= 3840)); // Include rotated 4k displays. Consider kIOMinPixelsWithDownscaleModes 3728 3729 if( display4k ) { 3730 iogArray = CFDictionaryGetValue( gIOGraphicsProperties, CFSTR("scale-resolutions-4k") ); 3731 } else { 3732 iogArray = CFDictionaryGetValue( gIOGraphicsProperties, CFSTR("scale-resolutions") ); 3733 } 3734 3735 next = connectRef; 3736 do { 3737 if (next->overrides) { 3738 other4k = ((next->defaultWidth >= 3840) || (next->defaultHeight >= 3840)) && (next != connectRef); 3739 3740 otherArray = CFDictionaryGetValue( next->overrides, CFSTR("scale-resolutions") ); 3741 3742 if(other4k && (otherArray == NULL)) { 3743 otherArray = CFDictionaryGetValue( gIOGraphicsProperties, CFSTR("scale-resolutions-4k") ); 3744 } 3745 3746 if (otherArray) { 3747 count = CFArrayGetCount(otherArray); 3748 3749 CFMutableArrayRef arrayWithHeight = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks); 3750 3751 for( i = 0; i < count; i++) { 3752 CFTypeRef obj; 3753 IOOptionBits flags; 3754 uint32_t setModeFlags = 0; 3755 uint32_t clrModeFlags = 0; 3756 3757 obj = CFArrayGetValueAtIndex(otherArray, i); 3758 if( CFDataGetTypeID() == CFGetTypeID(obj)) { 3759 CFIndex length = CFDataGetLength((CFDataRef) obj); 3760 3761 UInt32 updatedValue[5]; 3762 UInt32 * value = (UInt32 *) CFDataGetBytePtr((CFDataRef) obj); 3763 h = (float) OSReadBigInt32(&value[0], 0); 3764 v = (float) OSReadBigInt32(&value[1], 0); 3765 flags = OSReadBigInt32(&value[2], 0); 3766 updatedValue[0] = value[0]; 3767 updatedValue[1] = value[1]; 3768 updatedValue[2] = value[2]; 3769 if (length >= (CFIndex)(4 * sizeof(*value))) { 3770 setModeFlags = OSReadBigInt32(&value[3], 0); 3771 updatedValue[3] = value[3]; 3772 } 3773 if (length >= (CFIndex)(5 * sizeof(*value))) { 3774 clrModeFlags = OSReadBigInt32(&value[4], 0); 3775 updatedValue[4] = value[4]; 3776 } 3777 3778 if (v == 0) { 3779 v = h / next->nativeAspect; 3780 UInt32 intV = (UInt32) v; 3781 OSWriteBigInt32(&updatedValue[1], 0, intV); 3782 } 3783 3784 CFDataRef updatedData = CFDataCreate(kCFAllocatorDefault, (UInt8 *)updatedValue, length); 3785 CFArrayAppendValue(arrayWithHeight, updatedData); 3786 CFRelease(updatedData); 3787 3788 } else 3789 CFArrayAppendValue(arrayWithHeight, obj); 3790 } 3791 3792 CFArrayAppendValue( arrays, arrayWithHeight ); 3793 CFRelease(arrayWithHeight); 3794 otherArray = arrayWithHeight; 3795 } 3796 3797 if (next == connectRef) 3798 { 3799 displayArray = otherArray; 3800 if (iogArray) CFArrayAppendValue(arrays, iogArray); 3801 } 3802 } 3803 next = next->nextDependent; 3804 } while( next && (next != connectRef) ); 3805 3806 if (!onlyMirrorModes 3807 && ((nh <= (2 * kAquaMinWidth)) || (nv >= (2 * kAquaMinHeight)))) 3808 IOFBInstallScaledResolution( connectRef, scaleBase, nh, nv, nh / 2.0, nv / 2.0, 0, 0, 0 ); 3809 3810 displayNot4By3 = (ratioOver(nh / nv, 4.0 / 3.0) > 1.03125); 3811 displayNot16By9 = (ratioOver(nh / nv, 16.0 / 9.0) > 1.03125); 3812 3813 arraysCount = CFArrayGetCount(arrays); 3814 for(arraysIdx = 0; arraysIdx < arraysCount; arraysIdx++) 3815 { 3816 CFArrayRef array = CFArrayGetValueAtIndex(arrays, arraysIdx); 3817 count = CFArrayGetCount(array); 3818 for( i = 0; i < count; i++) { 3819 CFTypeRef obj; 3820 IOReturn r; 3821 IOOptionBits flags; 3822 uint32_t setModeFlags = 0; 3823 uint32_t clrModeFlags = 0; 3824 3825 obj = CFArrayGetValueAtIndex(array, i); 3826 if( CFNumberGetTypeID() == CFGetTypeID(obj)) { 3827 SInt32 value; 3828 CFNumberGetValue( (CFNumberRef) obj, kCFNumberSInt32Type, &value ); 3829 h = (float)(value & 0xffff); 3830 v = (float)(value >> 16); 3831 3832 flags = (array == displayArray) ? (kScaleInstallAlways | kScaleInstallNoStretch) : 0; 3833 3834 } else if( CFDataGetTypeID() == CFGetTypeID(obj)) { 3835 UInt32 * value = (UInt32 *) CFDataGetBytePtr((CFDataRef) obj); 3836 h = (float) OSReadBigInt32(&value[0], 0); 3837 v = (float) OSReadBigInt32(&value[1], 0); 3838 flags = OSReadBigInt32(&value[2], 0); 3839 if (CFDataGetLength((CFDataRef) obj) >= (CFIndex)(4 * sizeof(*value))) { 3840 setModeFlags = OSReadBigInt32(&value[3], 0); 3841 } 3842 if (CFDataGetLength((CFDataRef) obj) >= (CFIndex)(5 * sizeof(*value))) { 3843 clrModeFlags = OSReadBigInt32(&value[4], 0); 3844 } 3845 3846 } else 3847 continue; 3848 3849 DEBG(connectRef, "Scaling to (%f,%f), 0x%x, |0x%x, &0x%x\n", h, v, (int) flags, setModeFlags, clrModeFlags); 3850 3851 bool downscaleOk = ((array != iogArray) 3852 || (kMirrorOnlyFlags & setModeFlags) 3853 || display4k ); 3854 3855 if ((kOvrFlagDisableGenerated & connectRef->ovrFlags) && (array == iogArray)) { 3856 if ((0 == (kMirrorOnlyFlags & setModeFlags))) continue; 3857 } 3858 3859 if ((array == iogArray) || (array == displayArray)) { 3860 if (onlyMirrorModes && (0 == (kMirrorOnlyFlags & setModeFlags))) continue; 3861 } else { 3862 if (!(kScaleInstallMirrorDeps & flags)) continue; 3863 } 3864 3865 // downsampled modes from override only 3866 if ((!downscaleOk) && (h > nh)) continue; 3867 3868 if( v) { 3869 if ((!downscaleOk) && (v > nv)) continue; 3870 if( (h != (nh / 2.0)) || (v != (nv / 2.0))) { 3871 r = IOFBInstallScaledResolution( connectRef, scaleBase, 3872 nh, nv, h, v, flags, setModeFlags, clrModeFlags ); 3873 } 3874 } else { 3875 if( displayNot4By3 && (h < 1920) && (v < 1920)) { // Add legacy 4:3 modes but not for larger sizes 3876 v = (h * 3.0) / 4.0; 3877 if ((downscaleOk) || (v <= nv)) { 3878 r = IOFBInstallScaledResolution( connectRef, scaleBase, 3879 nh, nv, h, v, flags, setModeFlags, clrModeFlags ); 3880 } 3881 } 3882 if((h != nh) && (h != (nh / 2.0))) { 3883 v = (h * nv) / nh; 3884 if ((downscaleOk) || (v <= nv)) { 3885 r = IOFBInstallScaledResolution( connectRef, scaleBase, 3886 nh, nv, h, v, flags, setModeFlags, clrModeFlags ); 3887 } 3888 } 3889 } 3890 } 3891 } 3892 3893 if( displayNot16By9) { 3894 h = nh; 3895 v = (h * 9.0) / 16.0; 3896 IOFBInstallScaledResolution( connectRef, scaleBase, 3897 nh, nv, h, v, kScaleInstallAlways, kDisplayModeValidForAirPlayFlag, 0 ); 3898 } 3899 3900 CFRelease( arrays ); 3901 3902 return( err ); 3903} 3904 3905 3906__private_extern__ Boolean 3907IOFBTimingSanity(IOTimingInformation * timingInfo) 3908{ 3909 if (true 3910 && (timingInfo->detailedInfo.v2.horizontalScaled == timingInfo->detailedInfo.v2.horizontalActive) 3911 && (timingInfo->detailedInfo.v2.verticalScaled == timingInfo->detailedInfo.v2.verticalActive) 3912 && (!timingInfo->detailedInfo.v2.horizontalScaledInset) 3913 && (!timingInfo->detailedInfo.v2.verticalScaledInset) 3914 && (!(kIOScaleRotateFlags & timingInfo->detailedInfo.v2.scalerFlags))) 3915 { 3916 timingInfo->detailedInfo.v2.horizontalScaled = 0; 3917 timingInfo->detailedInfo.v2.verticalScaled = 0; 3918 timingInfo->detailedInfo.v2.scalerFlags = 0; 3919 } 3920 3921 return (true); 3922} 3923 3924__private_extern__ kern_return_t 3925IOFBDriverPreflight(IOFBConnectRef connectRef, IOFBDisplayModeDescription * desc) 3926{ 3927 kern_return_t result; 3928 IOFBDisplayModeDescription descOut; 3929 3930 if (kIOFBConnectStateUnusable & connectRef->state) 3931 { 3932 return (kIOReturnOffline); 3933 } 3934 3935 size_t len = sizeof(IOFBDisplayModeDescription); 3936 result = IOConnectCallStructMethod(connectRef->connect, 17, // Index 3937 desc, len, &descOut, &len); 3938 3939 if ((kIOReturnSuccess != result) 3940 || !IOFBTimingSanity(&desc->timingInfo) 3941 || !ValidateTimingInformation(connectRef, &desc->timingInfo)) 3942 { 3943#if RLOG 3944 DEBG(connectRef, "preflight fail (%x)\n", result); 3945 IOFBLogTiming(connectRef, &desc->timingInfo); 3946#endif 3947 result = kIOReturnUnsupportedMode; 3948 } 3949 3950 DEBG(connectRef, "preflight (%x) %d x %d %f Hz\n", 3951 result, (int) descOut.info.nominalWidth, (int) descOut.info.nominalHeight, 3952 descOut.info.refreshRate / 65536.0); 3953 3954 if (kIOReturnSuccess == result) 3955 { 3956 desc->info.nominalWidth = descOut.info.nominalWidth; 3957 desc->info.nominalHeight = descOut.info.nominalHeight; 3958// desc->info.refreshRate = descOut.info.refreshRate; 3959 desc->info.maxDepthIndex = descOut.info.maxDepthIndex; 3960 desc->info.flags = desc->info.flags 3961 | (kDisplayModeAcceleratorBackedFlag & descOut.info.flags); 3962// desc->info.reserved = descOut.info.reserved; 3963 } 3964 3965 return (result); 3966} 3967 3968static kern_return_t 3969IOFBCreateDisplayModeInformation( 3970 IOFBConnectRef connectRef, 3971 IODisplayModeID displayMode, 3972 IOFBDisplayModeDescription * allInfo ) 3973{ 3974 kern_return_t kr; 3975 3976 if (kIOFBSWOfflineDisplayModeID == displayMode) 3977 { 3978 allInfo->info.nominalWidth = 1; 3979 allInfo->info.nominalHeight = 1; 3980 allInfo->info.refreshRate = 0; 3981 allInfo->info.maxDepthIndex = 0; 3982 allInfo->info.flags = kDisplayModeValidFlag 3983 | kDisplayModeSafeFlag 3984 | kDisplayModeDefaultFlag; 3985 allInfo->timingInfo.flags = 0; 3986 allInfo->timingInfo.appleTimingID = kIOTimingIDApple_0x0_0hz_Offline; 3987 3988 return (kIOReturnSuccess); 3989 } 3990 3991 uint64_t inData = displayMode; 3992 size_t len = sizeof(IOFBDisplayModeDescription); 3993 kr = IOConnectCallMethod(connectRef->connect, 5, // index 3994 &inData, 1, NULL, 0, // Input 3995 NULL, NULL, allInfo, &len); // Output 3996 3997 if (len < sizeof(IOFBDisplayModeDescription)) 3998 kr = kIOReturnUnderrun; 3999 4000 if (kIOReturnSuccess == kr) 4001 IOFBTimingSanity(&allInfo->timingInfo); 4002 4003 return( kr ); 4004} 4005 4006static kern_return_t 4007IOFBAdjustDisplayModeInformation( 4008 IOFBConnectRef connectRef, 4009 IODisplayModeID displayMode, 4010 IOFBDisplayModeDescription * allInfo ) 4011{ 4012 IOReturn result; 4013 CFDataRef edidData; 4014 EDID * edid = 0; 4015 CFDictionaryRef ovr = 0; 4016 IOAppleTimingID appleTimingID; 4017 UInt8 manufacturerFlag; 4018 bool addSafeFlag; 4019 4020 appleTimingID = allInfo->timingInfo.appleTimingID; 4021 4022 DEBG(connectRef, "%d x %d @ %d (%x,%d): %08x %08x\n", 4023 (int) allInfo->info.nominalWidth, (int) allInfo->info.nominalHeight, 4024 (int) (allInfo->info.refreshRate + 0x8000) >> 16, (int) displayMode, (int) appleTimingID, 4025 (int) allInfo->info.flags, (int) allInfo->timingInfo.flags); 4026 4027 switch( appleTimingID ) { 4028 case kIOTimingIDAppleNTSC_ST: 4029 case kIOTimingIDAppleNTSC_FF: 4030 case kIOTimingIDAppleNTSC_STconv: 4031 case kIOTimingIDAppleNTSC_FFconv: 4032 allInfo->info.flags |= kDisplayModeTelevisionFlag; 4033 manufacturerFlag = kAppleNTSCManufacturerFlag | kAppleNTSCDefaultPALManufacturerFlag; 4034 break; 4035 4036 case kIOTimingIDApplePAL_ST: 4037 case kIOTimingIDApplePAL_FF: 4038 case kIOTimingIDApplePAL_STconv: 4039 case kIOTimingIDApplePAL_FFconv: 4040 allInfo->info.flags |= kDisplayModeTelevisionFlag; 4041 manufacturerFlag = kApplePALManufacturerFlag; 4042 break; 4043 4044 default: 4045 manufacturerFlag = 0x00; 4046 break; 4047 } 4048 4049 if (connectRef->addTVFlag) 4050 allInfo->info.flags |= kDisplayModeTelevisionFlag; 4051 4052 do { 4053 ovr = connectRef->overrides; 4054 if( !ovr) 4055 continue; 4056 4057 edidData = CFDictionaryGetValue(ovr, CFSTR(kIODisplayEDIDKey)); 4058 if( edidData) 4059 edid = (EDID *) CFDataGetBytePtr(edidData); 4060 4061 addSafeFlag = ((kAddSafeFlags == (kAddSafeFlags & allInfo->info.flags)) && !connectRef->hasCEAExt); 4062 4063 if((kDisplayModeBuiltInFlag & allInfo->info.flags) && !addSafeFlag) 4064 continue; 4065 4066 if (0 == (kDisplayModeNeverShowFlag & allInfo->info.flags)) 4067 { 4068 if (GetTovr(connectRef, appleTimingID, &allInfo->info.flags, NULL)) 4069 continue; 4070 } 4071 4072 if( kOvrFlagDisableNonScaled & connectRef->ovrFlags) { 4073 if( (displayMode > 0) && (0 == (kDisplayModeDefaultFlag & allInfo->info.flags))) 4074 allInfo->info.flags &= ~kDisplayModeSafetyFlags; 4075 } 4076 4077#if 1 4078 if((kDisplayModeValidFlag & allInfo->info.flags) && !addSafeFlag) 4079 continue; 4080#endif 4081 if( displayMode < 0) // programmed mode 4082 continue; 4083 4084 // 2488698, 3052614 4085 if( appleTimingID == kIOTimingIDApple_FixedRateLCD 4086 /*&& !CFDictionaryGetValue( ovr, CFSTR(kIODisplayIsDigitalKey))*/) 4087 continue; 4088 4089 if ((allInfo->timingInfo.detailedInfo.v2.scalerFlags) && !addSafeFlag) 4090 continue; 4091 4092 if( appleTimingID == kIOTimingIDApple_0x0_0hz_Offline) 4093 continue; 4094#if 1 4095 if( kDisplayModeNeverShowFlag & allInfo->info.flags) 4096 continue; 4097#endif 4098 4099 if( (kDisplayAppleVendorID == connectRef->displayVendor) 4100 && edid && edid->version 4101 && ((edid->version > 1) || (edid->revision >= 3))) { 4102 4103 if( manufacturerFlag & edid->establishedTimings[2]) { 4104 allInfo->info.flags |= kDisplayModeValidFlag | kDisplayModeSafeFlag; 4105 4106 if ((kApplePALManufacturerFlag == manufacturerFlag) 4107 && (kApplePALManufacturerFlag == ((kAppleNTSCManufacturerFlag | kApplePALManufacturerFlag) 4108 & edid->establishedTimings[2]))) 4109 allInfo->info.flags |= kDisplayModeDefaultFlag; 4110 continue; 4111 } 4112 } 4113 4114 if((kDisplayModeInterlacedFlag & allInfo->info.flags) && !addSafeFlag) 4115 continue; 4116 4117 result = IOCheckTimingWithDisplay(connectRef, allInfo, kIOFBDriverMode); 4118 if (kIOReturnNotFound == result) 4119 continue; 4120 allInfo->info.flags &= ~kDisplayModeSafetyFlags; 4121 if (kIOReturnSuccess != result) 4122 continue; 4123 4124 allInfo->info.flags |= kDisplayModeValidFlag | kDisplayModeSafeFlag; 4125 4126 if( (allInfo->timingInfo.detailedInfo.v2.horizontalActive > connectRef->dimensions.width) 4127 || (allInfo->timingInfo.detailedInfo.v2.verticalActive > connectRef->dimensions.height)) { 4128 allInfo->info.flags |= connectRef->dimensions.setFlags; 4129 allInfo->info.flags &= ~connectRef->dimensions.clearFlags; 4130 } 4131 4132 } while( false ); 4133 4134 if ((kDisplayModeValidFlag & allInfo->info.flags) 4135 && !edid 4136 && (kIOFBConnectStateOnline & connectRef->state)) 4137 { 4138 allInfo->info.flags |= kDisplayModeAlwaysShowFlag; 4139 } 4140 4141 return( kIOReturnSuccess ); 4142} 4143 4144kern_return_t 4145_IOFBGetDisplayModeInformation(IOFBConnectRef connectRef, 4146 IODisplayModeID displayMode, 4147 IODisplayModeInformation * out ) 4148{ 4149 kern_return_t kr = kIOReturnSuccess; 4150 CFDataRef data; 4151 CFMutableDataRef piData; 4152 CFMutableDictionaryRef dict; 4153 IODisplayModeInformation * info; 4154 4155 dict = (CFMutableDictionaryRef) CFDictionaryGetValue( connectRef->modes, 4156 (const void *) (uintptr_t) (UInt32) displayMode ); 4157 if( dict && (data = CFDictionaryGetValue( dict, CFSTR(kIOFBModeDMKey) ))) 4158 info = (IODisplayModeInformation *) CFDataGetBytePtr(data); 4159 else 4160 { 4161 DEBG(connectRef, "invalid mode 0x%x\n", (int) displayMode); 4162 kr = kIOReturnBadArgument; 4163 } 4164 4165 if( kr == kIOReturnSuccess) 4166 { 4167 *out = *info; 4168 if( (displayMode == connectRef->defaultMode) && (out->flags & kDisplayModeValidFlag)) 4169 out->flags |= kDisplayModeDefaultFlag; 4170 else 4171 out->flags &= ~kDisplayModeDefaultFlag; 4172 4173// if (kMirrorOnlyFlags & out->flags) 4174// out->flags &= ~kDisplayModeValidFlag; 4175 4176 if(true && connectRef->suppressRefresh) 4177 out->refreshRate = 0; 4178 else if(connectRef->detailedRefresh) 4179 { 4180 // /panther prefs workaround 4181 out->refreshRate += 0x00000800; 4182 out->refreshRate &= 0xffffe000; 4183 out->refreshRate |= 1; 4184 // panther prefs workaround/ 4185 } 4186 else 4187 { 4188 out->refreshRate += 0x00008000; 4189 out->refreshRate &= 0xffff0000; 4190 } 4191 if (kIOFBSwapAxes & connectRef->transform) 4192 { 4193 SInt32 width = out->nominalWidth; 4194 out->nominalWidth = out->nominalHeight; 4195 out->nominalHeight = width; 4196 } 4197 4198 piData = (CFMutableDataRef) CFDictionaryGetValue(dict, CFSTR(kIOFBModePIKey)); 4199 if (!piData && (piData = CFDataCreateMutable(kCFAllocatorDefault, 0))) 4200 { 4201 IOReturn err; 4202 IOPixelInformation pixelInfo; 4203 IOIndex depth; 4204 4205 for (depth = 0; depth <= out->maxDepthIndex; depth++) 4206 { 4207 err = _IOFBGetPixelInformation(connectRef, displayMode, depth, 4208 kIOFBSystemAperture, &pixelInfo); 4209 if (kIOReturnSuccess != err) 4210 break; 4211 if (pixelInfo.bitsPerPixel > FILTER_MAXDEPTH) 4212 break; 4213 CFDataAppendBytes(piData, (UInt8 *) &pixelInfo, sizeof(IOPixelInformation)); 4214 } 4215 CFDictionarySetValue(dict, CFSTR(kIOFBModePIKey), piData); 4216 CFRelease(piData); 4217 } 4218 if (piData) 4219 { 4220 out->maxDepthIndex = CFDataGetLength(piData) / sizeof(IOPixelInformation); 4221 if (out->maxDepthIndex) 4222 out->maxDepthIndex--; 4223 } 4224 } 4225 4226 return( kr ); 4227} 4228kern_return_t 4229IOFBGetDisplayModeInformation( io_connect_t connect, 4230 IODisplayModeID displayMode, 4231 IODisplayModeInformation * out ) 4232{ 4233 IOFBConnectRef connectRef; 4234 4235 connectRef = IOFBConnectToRef( connect); 4236 if( !connectRef) 4237 return( kIOReturnBadArgument ); 4238 4239 return (_IOFBGetDisplayModeInformation(connectRef, displayMode, out)); 4240} 4241 4242 4243kern_return_t 4244IOFBGetDisplayModeTimingInformation( io_connect_t connect, 4245 IODisplayModeID displayMode, 4246 IODetailedTimingInformation * out ) 4247{ 4248 kern_return_t kr = kIOReturnSuccess; 4249 IOFBConnectRef connectRef; 4250 CFDataRef data; 4251 CFMutableDictionaryRef dict; 4252 IODetailedTimingInformation * info; 4253 4254 connectRef = IOFBConnectToRef( connect); 4255 if( !connectRef) 4256 return( kIOReturnBadArgument ); 4257 4258 dict = (CFMutableDictionaryRef) CFDictionaryGetValue( connectRef->modes, 4259 (const void *) (uintptr_t) (UInt32) displayMode ); 4260 if( dict && (data = CFDictionaryGetValue( dict, CFSTR(kIOFBModeTMKey) ))) 4261 info = (IODetailedTimingInformation *) CFDataGetBytePtr(data); 4262 else 4263 { 4264 DEBG(connectRef, "invalid mode 0x%x\n", (int) displayMode); 4265 kr = kIOReturnBadArgument; 4266 } 4267 4268 if( kr == kIOReturnSuccess) 4269 { 4270 *out = *info; 4271 } 4272 4273 return (kr); 4274} 4275 4276__private_extern__ 4277IOFBConnectRef IOFBConnectToRef( io_connect_t connect ) 4278{ 4279 return((IOFBConnectRef) CFDictionaryGetValue( gConnectRefDict, (void *) (uintptr_t) connect )); 4280} 4281 4282static kern_return_t 4283IOFramebufferServerOpen( mach_port_t connect ) 4284{ 4285 mach_port_t masterPort; 4286 IOFBConnectRef connectRef, next; 4287 IOReturn err; 4288 CFNumberRef num; 4289 4290 if (gConnectRefDict && IOFBConnectToRef(connect)) 4291 return (kIOReturnSuccess); 4292 4293 do { 4294 4295 err = kIOReturnNoMemory; 4296 4297 IOMasterPort( MACH_PORT_NULL, &masterPort ); 4298 4299 if( !gConnectRefDict) 4300 gConnectRefDict = CFDictionaryCreateMutable( 4301 kCFAllocatorDefault, (CFIndex) 0, 4302 (CFDictionaryKeyCallBacks *) 0, 4303 (CFDictionaryValueCallBacks *) 0 ); //&kCFTypeDictionaryValueCallBacks 4304 if( !gConnectRefDict) 4305 return( kIOReturnNoMemory ); 4306 4307 connectRef = calloc( 1, sizeof( struct IOFBConnect)); 4308 if( !connectRef) 4309 continue; 4310 4311 connectRef->connect = connect; 4312 err = IOConnectGetService( connect, &connectRef->framebuffer ); 4313 if( kIOReturnSuccess != err) 4314 continue; 4315 4316 connectRef->iographicsProperties = gIOGraphicsProperties; 4317 connectRef->defaultMinWidth = gIOGraphicsInstallBoot ? kInstallMinWidth : kAquaMinWidth; 4318 connectRef->defaultMinHeight = gIOGraphicsInstallBoot ? kInstallMinHeight : kAquaMinHeight; 4319 connectRef->inMuxSwitch = false; 4320 4321#if RLOG 4322 if (gAllConnects) 4323 { 4324 connectRef->logfile = gAllConnects->logfile; 4325 connectRef->time0 = gAllConnects->time0; 4326 } 4327 else 4328 { 4329 connectRef->logfile = fopen(kIOGraphicsLogfilePath, "w" /*"r+"*/); 4330 connectRef->time0 = mach_absolute_time(); 4331 } 4332 DEBG(connectRef, "\n" ); 4333#endif 4334 4335 CFDictionarySetValue( gConnectRefDict, (const void *) (uintptr_t) connect, connectRef ); 4336 4337 num = IORegistryEntryCreateCFProperty( connectRef->framebuffer, CFSTR(kIOFBDependentIDKey), 4338 kCFAllocatorDefault, kNilOptions ); 4339 if( num) { 4340 CFNumberGetValue( num, kCFNumberSInt64Type, &connectRef->dependentID ); 4341 CFRelease(num); 4342 } 4343 num = IORegistryEntryCreateCFProperty( connectRef->framebuffer, CFSTR(kIOFBDependentIndexKey), 4344 kCFAllocatorDefault, kNilOptions ); 4345 if( num) { 4346 CFNumberGetValue( num, kCFNumberSInt32Type, &connectRef->dependentIndex ); 4347 CFRelease(num); 4348 } else 4349 connectRef->dependentID = 0; 4350 4351 // add to dependent list 4352 if( connectRef->dependentID) { 4353 for( next = gAllConnects; next; next = next->next) { 4354 if( next->dependentID == connectRef->dependentID) { 4355 4356 if( next->nextDependent) 4357 connectRef->nextDependent = next->nextDependent; 4358 else 4359 connectRef->nextDependent = next; 4360 next->nextDependent = connectRef; 4361 break; 4362 } 4363 } 4364 } 4365 // add to all list 4366 connectRef->next = gAllConnects; 4367 gAllConnects = connectRef; 4368 // -- 4369 4370 connectRef->notifyPort = IONotificationPortCreate( masterPort ); 4371 if( !connectRef->notifyPort) 4372 return( kIOReturnError ); 4373 4374 IOConnectSetNotificationPort( connect, 0, 4375 IONotificationPortGetMachPort( connectRef->notifyPort ), 0); 4376 4377 err = IOServiceAddInterestNotification( 4378 connectRef->notifyPort, 4379 connectRef->framebuffer, 4380 kIOGeneralInterest, 4381 &IOFBInterestCallback, connectRef, 4382 &connectRef->interestNotifier ); 4383 4384 } while( false ); 4385 4386 return (kIOReturnSuccess); 4387} 4388 4389kern_return_t 4390IOFramebufferServerFinishOpen( io_connect_t connect ) 4391{ 4392 IOFBConnectRef next, connectRef; 4393 SInt32 pass, dependentIndex; 4394 4395 connectRef = IOFBConnectToRef(connect); 4396 if (!connectRef) return(kIOReturnBadArgument); 4397 4398 if (connectRef->opened) return (kIOReturnSuccess); 4399 4400 DEBG(connectRef, "IOFramebufferServerFinishOpen start\n"); 4401 4402 uint32_t onlineCount = 0; 4403 for (pass = 0; pass < 3; pass++) 4404 { 4405 for (dependentIndex = 0; dependentIndex < 32; dependentIndex++) 4406 { 4407 next = connectRef; 4408 do 4409 { 4410 if (next->dependentIndex == dependentIndex) 4411 { 4412 if (pass == 0) 4413 { 4414 next->opened = true; 4415 next->setKernelDisplayConfig = true; 4416 IOFBUpdateConnectState(next); 4417 if (kIOFBConnectStateOnline & next->state) onlineCount++; 4418 } 4419 if (pass <= 1) 4420 { 4421 IOFBRebuild(next, false); 4422 if (kIOFBConnectStateUnusable & next->state) 4423 { 4424 next->state &= ~kIOFBConnectStateOnline; 4425 } 4426 } 4427 4428 if (pass == 2) IOFramebufferFinishOpen(next); 4429 } 4430 next = next->nextDependent; 4431 } 4432 while (next && (next != connectRef)); 4433 } 4434 if ((pass == 0) && (onlineCount <= 1)) pass++; 4435 } 4436 4437 DEBG(connectRef, "IOFramebufferServerFinishOpen end\n"); 4438 4439 return (kIOReturnSuccess); 4440} 4441 4442static kern_return_t 4443IOFramebufferFinishOpen(IOFBConnectRef connectRef) 4444{ 4445 IODisplayModeID mode, otherMode; 4446 IOIndex depth, minDepth, otherDepth; 4447 IODisplayModeID startMode; 4448 IOIndex startDepth; 4449 UInt32 startFlags = 0; 4450 IOReturn err; 4451 IODisplayModeInformation * otherInfo, info; 4452 CFDictionaryRef dict; 4453 CFDataRef data; 4454 4455 if (!(kIOFBConnectStateOnline & connectRef->state)) return (kIOReturnSuccess); 4456 4457 do 4458 { 4459 err = _IOFBGetCurrentDisplayModeAndDepth( connectRef, &mode, &depth ); 4460 startMode = mode; 4461 startDepth = depth; 4462 if( err) 4463 continue; 4464 4465 err = _IOFBGetDisplayModeInformation( connectRef, startMode, &info); 4466 if( err) 4467 continue; 4468 4469 startFlags = info.flags; 4470 if( (info.nominalWidth < connectRef->defaultMinWidth) 4471 || (info.nominalHeight < connectRef->defaultMinHeight)) { 4472 err = kIOReturnNoResources; 4473 continue; 4474 } 4475 4476 if( !connectRef->relaunch) { 4477 if( connectRef->make4By3 && connectRef->default4By3Mode 4478 && ratioOver(((float)info.nominalWidth) / ((float)info.nominalHeight), 4.0 / 3.0) > 1.03125) { 4479 err = kIOReturnNoResources; 4480 continue; 4481 } 4482 4483 if( connectRef->defaultToDependent 4484 && (kIOReturnSuccess == _IOFBGetCurrentDisplayModeAndDepth( connectRef->nextDependent, 4485 &otherMode, &otherDepth )) 4486 && (dict = CFDictionaryGetValue( connectRef->nextDependent->modes, (const void *) (uintptr_t) (UInt32) otherMode )) 4487 && (data = CFDictionaryGetValue( dict, CFSTR(kIOFBModeDMKey) ))) { 4488 4489 otherInfo = (IODisplayModeInformation *) CFDataGetBytePtr(data); 4490 if( (otherInfo->nominalWidth != info.nominalWidth) 4491 || (otherInfo->nominalHeight != info.nominalHeight)) { 4492 err = kIOReturnNoResources; 4493 continue; 4494 } 4495 startDepth = otherDepth; 4496 } 4497 } 4498 4499 // make sure it does >= 16bpp 4500 minDepth = IOFBIndexForPixelBits( connectRef, startMode, info.maxDepthIndex, 16 ); 4501 if( minDepth < 0) { 4502 err = kIOReturnNoResources; 4503 continue; 4504 } 4505 4506 if( connectRef->firstBoot) { 4507 // default depth on first boot 4508 startDepth = minDepth; 4509 if( info.maxDepthIndex > minDepth) 4510 startDepth++; 4511 } else if( startDepth < minDepth) 4512 startDepth = minDepth; 4513 4514 } while( false ); 4515 4516 if( err 4517 || (connectRef->firstBoot && (kDisplayVendorIDUnknown != connectRef->displayVendor) 4518 && (kDisplayProductIDGeneric != connectRef->displayProduct)) 4519 || (startMode == (IODisplayModeID) kIODisplayModeIDBootProgrammable) 4520 || (0 == (startFlags & (kDisplayModeValidFlag | kMirrorOnlyFlags)))) 4521 { 4522 // go to default 4523 if( connectRef->defaultMode) { 4524 startMode = connectRef->defaultMode; 4525 startDepth = connectRef->defaultDepth; 4526 } 4527 if( connectRef->make4By3 && connectRef->default4By3Mode) 4528 startMode = connectRef->default4By3Mode; 4529 } 4530 4531 if ((startMode == mode) && (startDepth == depth)) 4532 { 4533 startMode = kIODisplayModeIDCurrent; 4534 } 4535 4536 DEBG(connectRef, "setMode %x, %d from %x, %d\n", 4537 (int) startMode, (int) startDepth, (int) mode, (int) depth); 4538 IOFBSetDisplayModeAndDepth( connectRef->connect, startMode, startDepth ); 4539 4540 if (kIODisplayModeIDCurrent != startMode) 4541 { 4542 IOFBSetStartupDisplayModeAndDepth(connectRef->connect, startMode, startDepth); 4543 } 4544 4545 return( kIOReturnSuccess ); 4546} 4547 4548kern_return_t 4549IOFBGetConnectState( io_connect_t connect, IOOptionBits * state ) 4550{ 4551 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 4552 4553 if( !connectRef) 4554 return( kIOReturnBadArgument ); 4555 4556 *state = connectRef->state; 4557 4558 DEBG(connectRef, "IOFBGetConnectState 0x%x\n", connectRef->state); 4559 4560 return( kIOReturnSuccess ); 4561} 4562 4563 4564// Mask of pixel formats available in mode and depth 4565 4566kern_return_t 4567IOFBGetPixelFormats( io_connect_t connect __unused, 4568 IODisplayModeID __unused displayMode, 4569 IOIndex __unused depth, 4570 UInt32 * mask ) 4571{ 4572 *mask = 1; 4573 return( kIOReturnSuccess); 4574} 4575 4576kern_return_t 4577__IOFBGetPixelInformation( 4578 IOFBConnectRef connectRef, 4579 IODisplayModeID displayMode, 4580 IOIndex depth, 4581 IOPixelAperture aperture, 4582 IOPixelInformation * pixelInfo ) 4583{ 4584 kern_return_t kr; 4585 4586 uint64_t inData[] = { displayMode, depth, aperture }; 4587 size_t len = sizeof( IOPixelInformation); 4588 kr = IOConnectCallMethod(connectRef->connect, 1, // Index 4589 inData, arrayCnt(inData), NULL, 0, // Input 4590 NULL, NULL, pixelInfo, &len); // Output 4591 4592 if (kIOFBSwapAxes & connectRef->transform) 4593 { 4594 UInt32 width = pixelInfo->activeWidth; 4595 pixelInfo->activeWidth = pixelInfo->activeHeight; 4596 pixelInfo->activeHeight = width; 4597// pixelInfo->bytesPerRow = pixelInfo->activeHeight * 4; 4598 } 4599 4600 return( kr ); 4601} 4602 4603kern_return_t 4604_IOFBGetPixelInformation( 4605 IOFBConnectRef connectRef, 4606 IODisplayModeID displayMode, 4607 IOIndex depth, 4608 IOPixelAperture aperture, 4609 IOPixelInformation * pixelInfo ) 4610{ 4611 kern_return_t kr; 4612 4613 if (displayMode == kIOFBSWOfflineDisplayModeID) 4614 { 4615 bzero(pixelInfo, sizeof(IOPixelInformation)); 4616 pixelInfo->bytesPerRow = 32; 4617 pixelInfo->bytesPerPlane = 0; 4618 pixelInfo->flags = 0; 4619 pixelInfo->activeWidth = 1; 4620 pixelInfo->activeHeight = 1; 4621 strlcpy(pixelInfo->pixelFormat, "--------RRRRRRRRGGGGGGGGBBBBBBBB", 4622 sizeof(pixelInfo->pixelFormat)); 4623 pixelInfo->pixelType = kIORGBDirectPixels; 4624 pixelInfo->componentMasks[0] = 0x00ff0000; 4625 pixelInfo->componentMasks[1] = 0x0000ff00; 4626 pixelInfo->componentMasks[2] = 0x000000ff; 4627 pixelInfo->bitsPerPixel = 32; 4628 pixelInfo->componentCount = 3; 4629 pixelInfo->bitsPerComponent = 8; 4630 4631 return (kIOReturnSuccess); 4632 } 4633 4634 kr = __IOFBGetPixelInformation(connectRef, displayMode, depth, aperture, pixelInfo); 4635 4636 return( kr ); 4637} 4638 4639kern_return_t 4640IOFBGetPixelInformation( io_connect_t connect, 4641 IODisplayModeID displayMode, 4642 IOIndex depth, 4643 IOPixelAperture aperture, 4644 IOPixelInformation * pixelInfo ) 4645{ 4646 IOFBConnectRef connectRef; 4647 CFDictionaryRef dict; 4648 CFDataRef data = NULL; 4649 size_t offset; 4650 4651 connectRef = IOFBConnectToRef(connect); 4652 if (!connectRef) 4653 return( kIOReturnBadArgument ); 4654 4655 dict = CFDictionaryGetValue( connectRef->modes, (const void *) (uintptr_t) (UInt32) displayMode ); 4656 if (dict && !(data = CFDictionaryGetValue(dict, CFSTR(kIOFBModePIKey)))) 4657 { 4658 IODisplayModeInformation modeInfo; 4659 _IOFBGetDisplayModeInformation(connectRef, displayMode, &modeInfo); 4660 data = CFDictionaryGetValue(dict, CFSTR(kIOFBModePIKey)); 4661 } 4662 if (!data) 4663 { 4664 return (_IOFBGetPixelInformation(connectRef, displayMode, depth, 4665 aperture, pixelInfo)); 4666 } 4667 4668 if (kIOFBSystemAperture != aperture) 4669 return (kIOReturnBadArgument); 4670 4671 offset = depth * sizeof(IOPixelInformation); 4672 if ((offset + sizeof(IOPixelInformation)) > (size_t) CFDataGetLength(data)) 4673 return (kIOReturnBadArgument); 4674 4675 CFDataGetBytes(data, CFRangeMake(offset, sizeof(IOPixelInformation)), 4676 (UInt8 *) pixelInfo); 4677 4678 return (kIOReturnSuccess); 4679} 4680 4681kern_return_t 4682IOFBSetDisplayModeAndDepth( io_connect_t connect, 4683 IODisplayModeID displayMode, 4684 IOIndex depth ) 4685{ 4686 kern_return_t err; 4687 IOFBConnectRef connectRef; 4688 4689 if (kIOFBSWOfflineDisplayModeID == displayMode) 4690 { 4691 return (kIOReturnSuccess); 4692 } 4693 4694 connectRef = IOFBConnectToRef(connect); 4695 if( !connectRef) 4696 return( kIOReturnBadArgument ); 4697 4698 DEBG(connectRef, "setMode %x, %d \n", (int) displayMode, (int) depth); 4699 4700 uint64_t inData[] = { displayMode, depth }; 4701 err = IOConnectCallMethod(connect, 4, // Index 4702 inData, arrayCnt(inData), NULL, 0, // Input 4703 NULL, NULL, NULL, NULL); // Output 4704 4705 DEBG(connectRef, "did setMode(%x)\n", err); 4706 4707 if (kIOReturnSuccess == err) 4708 { 4709 IOFBResetTransform( connectRef ); 4710 } 4711 4712 return (err); 4713} 4714 4715kern_return_t 4716IOFBSetStartupDisplayModeAndDepth( io_connect_t connect, 4717 IODisplayModeID displayMode, 4718 IOIndex depth ) 4719{ 4720 uint64_t inData[] = { displayMode, depth }; 4721 4722 if (kIOFBSWOfflineDisplayModeID == displayMode) 4723 return (kIOReturnSuccess); 4724 4725 return IOConnectCallMethod(connect, 3, // Index 4726 inData, arrayCnt(inData), NULL, 0, // Input 4727 NULL, NULL, NULL, NULL); // Output 4728} 4729 4730kern_return_t 4731IOFBSetNewCursor( io_connect_t connect, 4732 void * cursor, 4733 IOIndex frame, 4734 IOOptionBits options ) 4735{ 4736 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 4737 4738 if( !connectRef) 4739 return( kIOReturnBadArgument ); 4740 4741 if (kIOFBConnectStateUnusable & connectRef->state) 4742 return( kIOReturnBadArgument ); 4743 4744 uint64_t inData[] = { (uintptr_t) cursor, frame, options }; 4745 return IOConnectCallMethod(connect, 10, // Index 4746 inData, arrayCnt(inData), NULL, 0, // Input 4747 NULL, NULL, NULL, NULL); // Output 4748} 4749 4750kern_return_t 4751IOFBSetCursorVisible( io_connect_t connect, 4752 int visible ) 4753{ 4754 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 4755 4756 if( !connectRef) 4757 return( kIOReturnBadArgument ); 4758 4759 if (kIOFBConnectStateUnusable & connectRef->state) 4760 return( kIOReturnSuccess ); 4761 4762 uint64_t inData[] = { visible }; 4763 return IOConnectCallMethod(connect, 12, // Index 4764 inData, arrayCnt(inData), NULL, 0, // Input 4765 NULL, NULL, NULL, NULL); // Output 4766} 4767 4768kern_return_t 4769IOFBSetCursorPosition( io_connect_t connect, 4770 long int x, 4771 long int y ) 4772{ 4773 IOFBConnectRef connectRef = IOFBConnectToRef( connect ); 4774 4775 if( !connectRef) 4776 return( kIOReturnBadArgument ); 4777 4778 if (kIOFBConnectStateUnusable & connectRef->state) 4779 return( kIOReturnSuccess ); 4780 4781 uint64_t inData[] = { x, y }; 4782 return IOConnectCallMethod(connect, 13, // Index 4783 inData, arrayCnt(inData), NULL, 0, // Input 4784 NULL, NULL, NULL, NULL); // Output 4785} 4786 4787/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 4788 4789CFDictionaryRef 4790IOFBCreateModeInfoDictionary( 4791 io_service_t framebuffer __unused, 4792 IOOptionBits options __unused, 4793 IODisplayModeID displayMode __unused, 4794 IODisplayModeInformation * info) 4795{ 4796 CFMutableDictionaryRef dict; 4797 CFStringRef string; 4798 char buffer[128]; 4799 4800 dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 4801 &kCFTypeDictionaryKeyCallBacks, 4802 &kCFTypeDictionaryValueCallBacks); 4803 if (!dict) 4804 return (dict); 4805 4806 snprintf(buffer, sizeof(buffer), "%d x %d", (int) info->nominalWidth, (int) info->nominalHeight); 4807 string = CFStringCreateWithCString(kCFAllocatorDefault, buffer, 4808 kCFStringEncodingMacRoman); 4809 if (string) 4810 { 4811 CFDictionarySetValue(dict, CFSTR(kIOFBModeResolutionNameKey), string); 4812 CFRelease(string); 4813 } 4814 4815 snprintf(buffer, sizeof(buffer), "%f Hertz", ((float) info->refreshRate) / 65536.0); 4816 string = CFStringCreateWithCString( kCFAllocatorDefault, buffer, 4817 kCFStringEncodingMacRoman); 4818 if (string) 4819 { 4820 CFDictionarySetValue(dict, CFSTR(kIOFBModeRefreshNameKey), string); 4821 CFRelease(string); 4822 } 4823 4824 return (dict); 4825} 4826 4827 4828CFDictionaryRef 4829IOFBCreateDisplayModeDictionary( io_service_t framebuffer, 4830 IODisplayModeID displayMode ) 4831{ 4832 CFDictionaryRef infoDict; 4833 CFStringRef string; 4834 CFDictionaryRef modeDict = 0; 4835 char keyBuf[12]; 4836 4837 infoDict = IORegistryEntryCreateCFProperty( framebuffer, CFSTR(kIOFramebufferInfoKey), 4838 kCFAllocatorDefault, kNilOptions ); 4839 if( infoDict ) { 4840 snprintf(keyBuf, sizeof(keyBuf), "%x", (unsigned) displayMode ); 4841 string = CFStringCreateWithCString( kCFAllocatorDefault, keyBuf, 4842 kCFStringEncodingMacRoman ); 4843 if( string) { 4844 modeDict = CFDictionaryGetValue( infoDict, string ); 4845 CFRelease( string ); 4846 } 4847 if( modeDict) 4848 CFRetain( modeDict ); 4849 CFRelease( infoDict ); 4850 } 4851 4852 return( modeDict ); 4853} 4854 4855CFDictionaryRef 4856IOFBGetPixelInfoDictionary( 4857 CFDictionaryRef modeDictionary, 4858 IOIndex depth, 4859 IOPixelAperture aperture ) 4860{ 4861 char keyBuf[12]; 4862 CFStringRef string; 4863 CFDictionaryRef pixelInfo = 0; 4864 4865 if( !modeDictionary) 4866 return( 0 ); 4867 4868 snprintf(keyBuf, sizeof(keyBuf), "%dx", (int) (depth + (aperture << 16)) ); 4869 string = CFStringCreateWithCString( kCFAllocatorDefault, keyBuf, 4870 kCFStringEncodingMacRoman ); 4871 if( string) { 4872 pixelInfo = CFDictionaryGetValue( modeDictionary, string ); 4873 CFRelease( string ); 4874 } 4875 4876 return( pixelInfo ); 4877} 4878 4879/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 4880 4881IOReturn 4882IOFBGetInterruptSemaphore( io_connect_t connect, 4883 IOSelect interruptType, 4884 semaphore_t * semaphore ) 4885{ 4886 uint64_t inData = interruptType; 4887 uint64_t outData = 0; 4888 uint32_t outCnt = 1; 4889 return IOConnectCallMethod(connect, 15, // Index 4890 &inData, 1, NULL, 0, // Input 4891 &outData, &outCnt, NULL, NULL); // Output 4892 *semaphore = (semaphore_t) outData; 4893} 4894 4895/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 4896 4897#include <IOKit/graphics/IOGraphicsInterface.h> 4898 4899#ifndef NO_CFPLUGIN 4900 4901struct _BlitterVars { 4902 IOGraphicsAcceleratorInterface ** interface; 4903 IOBlitterPtr copyProc; 4904 IOBlitterPtr fillProc; 4905 IOBlitterPtr memCopyProc; 4906 IOBlitSurface dest; 4907 void * sid; 4908 IOBlitterPtr copyRegionProc; 4909}; 4910typedef struct _BlitterVars _BlitterVars; 4911 4912kern_return_t 4913IOPSAllocateBlitEngine( io_service_t service, 4914 void ** blitterRef, int * quality) 4915{ 4916 IOReturn err = kIOReturnSuccess; 4917 _BlitterVars * vars; 4918 IOGraphicsAcceleratorInterface ** interface = 0; 4919 4920 vars = (_BlitterVars *) calloc( 1, sizeof( _BlitterVars )); 4921 if( !vars) 4922 return( kIOReturnNoMemory); 4923 4924 do { 4925 err = IOCreatePlugInInterfaceForService( service, 4926 kIOGraphicsAcceleratorTypeID, 4927 kIOGraphicsAcceleratorInterfaceID, 4928 (IOCFPlugInInterface ***)&interface, (SInt32 *) quality ); 4929 if( err) 4930 continue; 4931 vars->interface = interface; 4932 4933 if( (*interface)->SetDestination) { 4934 err = (*interface)->SetDestination(interface, 4935 kIOBlitFramebufferDestination, NULL); 4936 if( err) 4937 continue; 4938 } 4939 err = (*interface)->GetBlitter(interface, 4940 kIOBlitAllOptions, 4941 (kIOBlitTypeCopyRects | kIOBlitCopyOperation), 4942 kIOBlitSourceDefault, 4943 &vars->copyProc); 4944 if( err) 4945 continue; 4946 err = (*interface)->GetBlitter(interface, 4947 kIOBlitAllOptions, 4948 (kIOBlitTypeRects | kIOBlitCopyOperation), 4949 kIOBlitSourceSolid, 4950 &vars->fillProc); 4951 if( err) 4952 continue; 4953 4954 4955 if( kIOReturnSuccess != (*interface)->GetBlitter(interface, 4956 kIOBlitAllOptions, 4957 (kIOBlitTypeCopyRegion | kIOBlitTypeOperationType0), 4958 kIOBlitSourceFramebuffer, 4959 &vars->copyRegionProc)) 4960 vars->copyRegionProc = 0; 4961 4962 if( kIOReturnSuccess != (*interface)->GetBlitter(interface, 4963 kIOBlitAllOptions, 4964 (kIOBlitTypeCopyRects | kIOBlitCopyOperation), 4965 kIOBlitSourceMemory, 4966 &vars->memCopyProc)) 4967 vars->memCopyProc = 0; 4968 4969 } while( FALSE ); 4970 4971 if( err) { 4972 if (interface) 4973 IODestroyPlugInInterface((IOCFPlugInInterface **)interface); 4974 free( vars ); 4975 vars = 0; 4976 } 4977 4978 *blitterRef = (void *) vars; 4979 4980 return( err); 4981} 4982 4983kern_return_t 4984IOPSBlitReset( void * blitterRef) 4985{ 4986 _BlitterVars * vars = (_BlitterVars *) blitterRef; 4987 IOGraphicsAcceleratorInterface ** interface = vars->interface; 4988 kern_return_t err = kIOReturnSuccess; 4989 4990 if( interface) { 4991 if( vars->sid) { 4992 err = (*interface)->SetDestination(interface, kIOBlitFramebufferDestination, 0); 4993 } 4994 err = (*interface)->Reset(interface, kNilOptions); 4995 } 4996 vars->sid = 0; 4997 return( err ); 4998} 4999 5000kern_return_t 5001IOPSBlitDeallocate( void * blitterRef) 5002{ 5003 _BlitterVars * vars = (_BlitterVars *) blitterRef; 5004 IOGraphicsAcceleratorInterface ** interface = vars->interface; 5005 kern_return_t err; 5006 5007 err = IODestroyPlugInInterface((IOCFPlugInInterface **)interface); 5008 free( vars ); 5009 5010 return( err ); 5011} 5012 5013kern_return_t 5014IOPSBlitIdle( void * blitterRef) 5015{ 5016 _BlitterVars * vars = (_BlitterVars *) blitterRef; 5017 IOGraphicsAcceleratorInterface ** interface = vars->interface; 5018 kern_return_t err; 5019 5020 err = (*interface)->WaitComplete(interface, kIOBlitWaitAll2D ); 5021 5022 return( err ); 5023} 5024 5025 5026kern_return_t 5027IOFBSynchronize( void * blitterRef, 5028 UInt32 x, UInt32 y, UInt32 w, UInt32 h, UInt32 options ) 5029{ 5030 _BlitterVars * vars = (_BlitterVars *) blitterRef; 5031 IOGraphicsAcceleratorInterface ** interface; 5032 IOReturn err; 5033 5034 if( !vars) 5035 return( kIOReturnBadArgument); 5036 interface = vars->interface; 5037 err = (*interface)->Synchronize(interface, options, x, y, w, h ); 5038 5039 return( err ); 5040} 5041 5042kern_return_t 5043IOFBBeamPosition( void * blitterRef, UInt32 options, SInt32 * position ) 5044{ 5045 _BlitterVars * vars = (_BlitterVars *) blitterRef; 5046 IOGraphicsAcceleratorInterface ** interface = vars->interface; 5047 IOReturn err; 5048 5049 err = (*interface)->GetBeamPosition(interface, options, position); 5050 5051 return( err ); 5052} 5053 5054 5055kern_return_t 5056IOPSBlitFill( void * blitterRef, 5057 int x, int y, int w, int h, int data ) 5058{ 5059 _BlitterVars * vars = (_BlitterVars *) blitterRef; 5060 IOGraphicsAcceleratorInterface ** interface = vars->interface; 5061 IOReturn err; 5062 IOBlitRectangles rects; 5063 5064 if( vars->sid) { 5065 err = (*interface)->SetDestination(interface, kIOBlitFramebufferDestination, 0); 5066 vars->sid = 0; 5067 if( err) 5068 return( err ); 5069 } 5070 5071 rects.count = 1; 5072 rects.rects[0].x = x; 5073 rects.rects[0].y = y; 5074 rects.rects[0].width = w; 5075 rects.rects[0].height = h; 5076 5077 err = (*vars->fillProc)(interface, 5078 kNilOptions, 5079 (kIOBlitTypeRects | kIOBlitCopyOperation), 5080 (kIOBlitSourceSolid | kIOBlitDestFramebuffer), 5081 &rects.operation, 5082 (void *) (uintptr_t) data); 5083 5084 if( kIOReturnSuccess == err) 5085 (*interface)->Flush(interface, kNilOptions); 5086 5087 return( err ); 5088} 5089 5090kern_return_t 5091IOPSBlitInvert( void * blitterRef, 5092 int x, int y, int w, int h ) 5093{ 5094 _BlitterVars * vars = (_BlitterVars *) blitterRef; 5095 IOGraphicsAcceleratorInterface ** interface = vars->interface; 5096 IOReturn err; 5097 IOBlitRectangles rects; 5098 5099 if( vars->sid) { 5100 err = (*interface)->SetDestination(interface, kIOBlitFramebufferDestination, 0); 5101 vars->sid = 0; 5102 if( err) 5103 return( err ); 5104 } 5105 5106 rects.count = 1; 5107 rects.rects[0].x = x; 5108 rects.rects[0].y = y; 5109 rects.rects[0].width = w; 5110 rects.rects[0].height = h; 5111 5112 err = (*vars->fillProc)(interface, 5113 kNilOptions, 5114 (kIOBlitTypeRects | kIOBlitCopyOperation), 5115 (kIOBlitSourceSolid | kIOBlitDestFramebuffer), 5116 &rects.operation, 5117 (void *) 0xffffffff); 5118 5119 if( kIOReturnSuccess == err) 5120 (*interface)->Flush(interface, kNilOptions); 5121 5122 return( err ); 5123} 5124 5125 5126kern_return_t 5127IOPSBlitCopy( void * blitterRef, 5128 int src_x, int src_y, int width, int height, 5129 int dst_x, int dst_y ) 5130{ 5131 return( IOFBBlitVRAMCopy( blitterRef, src_x, src_y, width, height, 5132 dst_x, dst_y, 1 * (kIOFBBlitBeamSync) )); 5133} 5134 5135kern_return_t 5136IOFBBlitVRAMCopy( void * blitterRef, 5137 int sourceX, int sourceY, int width, int height, 5138 int x, int y, IOOptionBits options ) 5139{ 5140 _BlitterVars * vars = (_BlitterVars *) blitterRef; 5141 IOGraphicsAcceleratorInterface ** interface = vars->interface; 5142 IOReturn err; 5143 IOBlitCopyRectangles rects; 5144 5145 if( vars->sid) { 5146 err = (*interface)->SetDestination(interface, kIOBlitFramebufferDestination, 0); 5147 vars->sid = 0; 5148 if( err) 5149 return( err ); 5150 } 5151 5152 rects.count = 1; 5153 rects.rects[0].x = x; 5154 rects.rects[0].y = y; 5155 rects.rects[0].width = width; 5156 rects.rects[0].height = height; 5157 rects.rects[0].sourceX = sourceX; 5158 rects.rects[0].sourceY = sourceY; 5159 5160 err = (*vars->copyProc)(interface, 5161 options, 5162 (kIOBlitTypeCopyRects | kIOBlitCopyOperation), 5163 kIOBlitSourceDefault, 5164 &rects.operation, 5165 0); 5166 5167 if( kIOReturnSuccess == err) 5168 (*interface)->Flush(interface, kNilOptions); 5169 5170 return( err ); 5171} 5172 5173kern_return_t 5174IOFBBlitSurfaceCopy( void * blitterRef, IOOptionBits options, void * surfaceID, 5175 IOAccelDeviceRegion * region, UInt32 surfaceX, UInt32 surfaceY ) 5176{ 5177 IOReturn err = kIOReturnSuccess; 5178 _BlitterVars * vars = (_BlitterVars *) blitterRef; 5179 IOGraphicsAcceleratorInterface ** interface = vars->interface; 5180 IOBlitCopyRegion op; 5181 5182 if( 0 == vars->copyRegionProc) 5183 return( kIOReturnUnsupported ); 5184 5185 if( surfaceID != vars->sid) do { 5186 if( surfaceID) { 5187 if (vars->dest.interfaceRef) 5188 (*interface)->FreeSurface(interface, kIOBlitHasCGSSurface, &vars->dest); 5189 err = (*interface)->AllocateSurface(interface, kIOBlitHasCGSSurface, &vars->dest, surfaceID); 5190 if( err) 5191 continue; 5192 err = (*interface)->SetDestination(interface, kIOBlitSurfaceDestination, &vars->dest); 5193 } else 5194 err = (*interface)->SetDestination(interface, kIOBlitFramebufferDestination, 0); 5195 5196 if( err) 5197 continue; 5198 5199 vars->sid = surfaceID; 5200 5201 } while( false ); 5202 5203 if( err) 5204 return( err ); 5205 5206 op.region = region; 5207 op.deltaX = surfaceX; 5208 op.deltaY = surfaceY; 5209 5210 err = (*vars->copyRegionProc)(interface, 5211 options, 5212 (kIOBlitTypeCopyRegion | kIOBlitTypeOperationType0), 5213 kIOBlitSourceFramebuffer, 5214 &op.operation, 5215 (void *) 0); 5216 5217 if( kIOReturnSuccess == err) 5218 (*interface)->Flush(interface, kNilOptions); 5219 5220 return( err ); 5221} 5222 5223kern_return_t 5224IOFBBlitSurfaceSurfaceCopy( void * blitterRef, IOOptionBits options, 5225 void * sourceSurfaceID, void * destSurfaceID, 5226 IOAccelDeviceRegion * region, UInt32 surfaceX, UInt32 surfaceY ) 5227{ 5228 IOReturn err = kIOReturnSuccess; 5229 _BlitterVars * vars = (_BlitterVars *) blitterRef; 5230 IOGraphicsAcceleratorInterface ** interface = vars->interface; 5231 IOBlitCopyRegion op; 5232 5233 if( 0 == vars->copyRegionProc) 5234 return( kIOReturnUnsupported ); 5235 5236 if( destSurfaceID != vars->sid) do { 5237 if( destSurfaceID) { 5238 if (vars->dest.interfaceRef) 5239 (*interface)->FreeSurface(interface, kIOBlitHasCGSSurface, &vars->dest); 5240 err = (*interface)->AllocateSurface(interface, kIOBlitHasCGSSurface, &vars->dest, destSurfaceID); 5241 if( err) 5242 continue; 5243 err = (*interface)->SetDestination(interface, kIOBlitSurfaceDestination, &vars->dest); 5244 } else 5245 err = (*interface)->SetDestination(interface, kIOBlitFramebufferDestination, 0); 5246 5247 if( err) 5248 continue; 5249 5250 vars->sid = destSurfaceID; 5251 5252 } while( false ); 5253 5254 if( err) 5255 return( err ); 5256 5257 op.region = region; 5258 op.deltaX = surfaceX; 5259 op.deltaY = surfaceY; 5260 5261 err = (*vars->copyRegionProc)(interface, 5262 options, 5263 (kIOBlitTypeCopyRegion | kIOBlitTypeOperationType0), 5264 kIOBlitSourceCGSSurface, 5265 &op.operation, 5266 (void *) sourceSurfaceID); 5267 5268 if( kIOReturnSuccess == err) 5269 (*interface)->Flush(interface, kNilOptions); 5270 5271 return( err ); 5272} 5273 5274#if 0 5275 5276kern_return_t 5277IOFBSetupFIFOBurst( void * blitterRef, 5278 UInt32 x, UInt32 y, UInt32 w, UInt32 h, 5279 UInt32 options, void ** burstRef ) 5280{ 5281 _BlitterVars * vars = (_BlitterVars *) blitterRef; 5282 IOReturn err; 5283 boolean_t wait; 5284 5285 do { 5286 IOSharedLockLock( &vars->context->contextLock ); 5287 wait = (kIOReturnBusy == ( 5288 err = vars->procs.setupFIFOBurst( vars->chipRef, x, y, w, h, 5289 options, burstRef ))); 5290 IOSharedLockUnlock( &vars->context->contextLock, wait ); 5291 } while( wait ); 5292 5293 return( err ); 5294} 5295 5296kern_return_t 5297IOFBCommitMemory( void * blitterRef, 5298 vm_address_t start, vm_size_t length, IOOptionBits options, 5299 void ** memoryRef, IOByteCount * offset ) 5300{ 5301 _BlitterVars * vars = (_BlitterVars *) blitterRef; 5302 IOReturn err; 5303 unsigned int len; 5304 int params[ 3 ]; 5305 5306 params[0] = start; 5307 params[1] = length; 5308 params[2] = options; 5309 len = 2; 5310 err = io_connect_method_scalarI_scalarO( vars->connect, 2, /*index*/ 5311 params, 3, params, &len); 5312 5313 if( kIOReturnSuccess == err) { 5314 *memoryRef = (void *) params[0]; 5315 *offset = params[1]; 5316 } 5317 5318 return( err ); 5319} 5320 5321kern_return_t 5322IOFBReleaseMemory( void * blitterRef, void * memoryRef ) 5323{ 5324 _BlitterVars * vars = (_BlitterVars *) blitterRef; 5325 IOReturn err; 5326 unsigned int len; 5327 5328 IOPSBlitIdle( blitterRef ); 5329 5330 len = 0; 5331 err = io_connect_method_scalarI_scalarO( vars->connect, 3, /*index*/ 5332 (int *) &memoryRef, 1, NULL, &len); 5333 5334 return( err ); 5335} 5336 5337#endif 5338 5339kern_return_t 5340IOFBMemoryCopy( void * blitterRef, 5341 UInt32 x, UInt32 y, 5342 UInt32 width, UInt32 height, 5343 UInt32 srcByteOffset, UInt32 srcRowBytes, 5344 SInt32 * token __unused) 5345{ 5346 _BlitterVars * vars = (_BlitterVars *) blitterRef; 5347 IOGraphicsAcceleratorInterface ** interface = vars->interface; 5348 IOReturn err; 5349 IOBlitMemory source; 5350 IOBlitCopyRectangles rects; 5351 5352 if( vars->sid) { 5353 err = (*interface)->SetDestination(interface, kIOBlitFramebufferDestination, 0); 5354 vars->sid = 0; 5355 if( err) 5356 return( err ); 5357 } 5358 5359 rects.count = 1; 5360 rects.rects[0].x = x; 5361 rects.rects[0].y = y; 5362 rects.rects[0].width = width; 5363 rects.rects[0].height = height; 5364 rects.rects[0].sourceX = 0; 5365 rects.rects[0].sourceY = 0; 5366 5367 source.memory.ref = 0; // !! 5368 source.byteOffset = srcByteOffset; 5369 source.rowBytes = srcRowBytes; 5370 5371 err = (*vars->memCopyProc)(interface, 5372 kNilOptions, 5373 (kIOBlitTypeCopyRects | kIOBlitCopyOperation), 5374 kIOBlitSourceMemory, 5375 &rects.operation, 5376 (void *) &source); 5377 5378 return( err ); 5379} 5380 5381#else /* NO_CFPLUGIN */ 5382 5383/* We need these symbols to exist to prevent link errors in clients. Have them all return an error. */ 5384 5385kern_return_t 5386IOPSAllocateBlitEngine( io_connect_t framebuffer, void ** blitterRef, int * quality) 5387{ return kIOReturnUnsupported; } 5388 5389kern_return_t 5390IOPSBlitReset( void * blitterRef) 5391{ return kIOReturnUnsupported; } 5392 5393kern_return_t 5394IOPSBlitDeallocate( void * blitterRef ) 5395{ return kIOReturnUnsupported; } 5396 5397kern_return_t 5398IOPSBlitIdle( void * blitterRef ) 5399{ return kIOReturnUnsupported; } 5400 5401kern_return_t 5402IOFBWaitForCompletion( void * blitterRef, SInt32 token ) 5403{ return kIOReturnUnsupported; } 5404 5405kern_return_t 5406IOFBSynchronize( void * blitterRef, UInt32 x, UInt32 y, UInt32 w, UInt32 h, UInt32 options ) 5407{ return kIOReturnUnsupported; } 5408 5409kern_return_t 5410IOFBBeamPosition( void * blitterRef, UInt32 options, SInt32 * position ) 5411{ return kIOReturnUnsupported; } 5412 5413kern_return_t 5414IOPSBlitFill( void * blitterRef, int dst_x, int dst_y, int width, int height, int data ) 5415{ return kIOReturnUnsupported; } 5416 5417kern_return_t 5418IOPSBlitInvert( void * blitterRef, int x, int y, int w, int h ) 5419{ return kIOReturnUnsupported; } 5420 5421kern_return_t 5422IOPSBlitCopy( void * blitterRef, int src_x, int src_y, int width, int height, int dst_x, int dst_y ) 5423{ return kIOReturnUnsupported; } 5424 5425kern_return_t 5426IOFBBlitVRAMCopy( void * blitterRef, int sourceX, int sourceY, int width, int height, int x, int y, IOOptionBits options ) 5427{ return kIOReturnUnsupported; } 5428 5429kern_return_t 5430IOFBMemoryCopy( void * blitterRef, UInt32 x, UInt32 y, UInt32 width, UInt32 height, UInt32 srcByteOffset, UInt32 srcRowBytes, SInt32 * token) 5431{ return kIOReturnUnsupported; } 5432 5433kern_return_t 5434IOFBSetupFIFOBurst( void * blitterRef, UInt32 x, UInt32 y, UInt32 w, UInt32 h, UInt32 options, void ** burstRef ) 5435{ return kIOReturnUnsupported; } 5436 5437void 5438IOFBBurstWrite32( void * p1, void * p2, void * p3, void * p4, void * p5, void * p6, void * p7, void * p8 ) 5439{ return kIOReturnUnsupported; } 5440 5441void 5442IOFBSetBurstRef( void * burstRef ) 5443{ return kIOReturnUnsupported; } 5444 5445kern_return_t 5446IOFBCommitMemory( void * blitterRef, vm_address_t start, vm_size_t length, IOOptionBits options, void ** memoryRef, IOByteCount * offset ) 5447{ return kIOReturnUnsupported; } 5448 5449kern_return_t 5450IOFBReleaseMemory( void * blitterRef, void * memoryRef ) 5451{ return kIOReturnUnsupported; } 5452 5453#endif /* !NO_CFPLUGIN */ 5454 5455/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 5456 5457#include <IOKit/i2c/IOI2CInterfacePrivate.h> 5458 5459struct IOI2CConnect 5460{ 5461 io_connect_t connect; 5462}; 5463 5464 5465IOReturn IOI2CCopyInterfaceForID( CFTypeRef identifier, io_service_t * interface ) 5466{ 5467 CFMutableDictionaryRef dict, matching; 5468 mach_port_t masterPort; 5469 kern_return_t kr; 5470 io_iterator_t iter; 5471 5472 IOMasterPort( MACH_PORT_NULL, &masterPort ); 5473 5474 matching = IOServiceMatching(kIOI2CInterfaceClassName); 5475 if(!matching) 5476 return( kIOReturnNoMemory ); 5477 5478 dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, 5479 &kCFTypeDictionaryKeyCallBacks, 5480 &kCFTypeDictionaryValueCallBacks); 5481 if(!dict) 5482 return( kIOReturnNoMemory ); 5483 5484 CFDictionarySetValue(dict, CFSTR(kIOI2CInterfaceIDKey), identifier); 5485 CFDictionarySetValue(matching, CFSTR(kIOPropertyMatchKey), dict); 5486 CFRelease(dict); 5487 5488 kr = IOServiceGetMatchingServices( masterPort, matching, &iter); 5489 if( kIOReturnSuccess == kr) { 5490 *interface = IOIteratorNext( iter ); 5491 IOObjectRelease( iter ); 5492 } 5493 5494 return( kr ); 5495} 5496 5497IOReturn IOFBGetI2CInterfaceCount( io_service_t framebuffer, IOItemCount * count ) 5498{ 5499 CFArrayRef array; 5500 5501 array = IORegistryEntryCreateCFProperty( framebuffer, CFSTR(kIOFBI2CInterfaceIDsKey), 5502 kCFAllocatorDefault, kNilOptions ); 5503 if( array) { 5504 *count = CFArrayGetCount(array); 5505 CFRelease( array ); 5506 } else 5507 *count = 0; 5508 5509 return( kIOReturnSuccess ); 5510} 5511 5512IOReturn IOFBCopyI2CInterfaceForBus( io_service_t framebuffer, IOOptionBits bus, io_service_t * interface ) 5513{ 5514 IOReturn kr = kIOReturnNoDevice; 5515 CFArrayRef array; 5516 CFIndex index; 5517 CFTypeRef ident; 5518 5519 array = IORegistryEntryCreateCFProperty( framebuffer, CFSTR(kIOFBI2CInterfaceIDsKey), 5520 kCFAllocatorDefault, kNilOptions ); 5521 if( !array) 5522 return( kIOReturnNoDevice ); 5523 5524 index = bus & kIOI2CBusNumberMask; 5525 5526 do { 5527 if( index >= CFArrayGetCount(array)) { 5528 kr = kIOReturnNoDevice; 5529 continue; 5530 } 5531 5532 ident = CFArrayGetValueAtIndex(array, index); 5533 kr = IOI2CCopyInterfaceForID( ident, interface ); 5534 5535 } while( false ); 5536 5537 CFRelease( array ); 5538 5539 return( kr ); 5540} 5541 5542IOReturn IOI2CInterfaceOpen( io_service_t interface, IOOptionBits options, 5543 IOI2CConnectRef * connect ) 5544{ 5545 kern_return_t kr; 5546 struct IOI2CConnect * connectRef; 5547 5548 if( !IOObjectConformsTo(interface, kIOI2CInterfaceClassName)) 5549 return( kIOReturnBadArgument ); 5550 5551 connectRef = calloc(1, sizeof(struct IOI2CConnect)); 5552 if( !connectRef) 5553 return( kIOReturnNoMemory ); 5554 5555 kr = IOServiceOpen( interface, mach_task_self(), options, &connectRef->connect ); 5556 5557 if( (kr != kIOReturnSuccess) && connectRef) { 5558 free(connectRef); 5559 connectRef = NULL; 5560 } 5561 *connect = connectRef; 5562 5563 return( kr ); 5564} 5565 5566IOReturn IOI2CInterfaceClose( IOI2CConnectRef connect, IOOptionBits options __unused ) 5567{ 5568 kern_return_t kr; 5569 5570 kr = IOServiceClose( connect->connect ); 5571 5572 free( connect ); 5573 5574 return( kr ); 5575} 5576 5577IOReturn IOI2CSendRequest( IOI2CConnectRef connect, IOOptionBits options __unused, 5578 IOI2CRequest * request ) 5579{ 5580 kern_return_t kr; 5581 IOI2CBuffer buffer; 5582 5583 if( request->sendBytes > sizeof(buffer.inlineBuffer)) 5584 return( kIOReturnOverrun ); 5585 if( request->replyBytes > sizeof(buffer.inlineBuffer)) 5586 return( kIOReturnOverrun ); 5587 5588 kr = IOConnectCallMethod(connect->connect, 0, // Index 5589 NULL, 0, NULL, 0, // Input 5590 NULL, NULL, NULL, NULL); // Output 5591 if( kIOReturnSuccess != kr) 5592 return( kr ); 5593 5594 buffer.request = *request; 5595 buffer.request.replyBuffer = 0; 5596 buffer.request.sendBuffer = 0; 5597 5598 if( request->sendBytes) 5599 bcopy( (void *) request->sendBuffer, &buffer.inlineBuffer[0], request->sendBytes ); 5600 5601 size_t len = sizeof( buffer); 5602 kr = IOConnectCallMethod(connect->connect, 2, // Index 5603 NULL, 0, &buffer, len, // Input 5604 NULL, NULL, &buffer, &len); // Output 5605 5606 if( buffer.request.replyBytes) 5607 bcopy( &buffer.inlineBuffer[0], (void *) request->replyBuffer, buffer.request.replyBytes ); 5608 *request = buffer.request; 5609 5610 return IOConnectCallMethod(connect->connect, 1, // Index 5611 NULL, 0, NULL, 0, // Input 5612 NULL, NULL, NULL, NULL); // Output 5613} 5614 5615/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 5616 5617