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(&currentTiming, 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, &currentMode, &currentDepth);
1717        if (((kIODisplayModeIDReservedBase | kIODisplayModeIDAliasBase) != currentMode) && !connectRef->inMuxSwitch)
1718            break;
1719        err = IOFBCreateDisplayModeInformation(connectRef, currentMode, &currentTiming);
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 *) &currentTiming.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                                    &currentTiming.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                                    &copyRegionProc);
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