1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include <IOKit/IOLib.h>
24#include <IOKit/platform/ApplePlatformExpert.h>
25#include <IOKit/IODeviceTreeSupport.h>
26#include <IOKit/IOSubMemoryDescriptor.h>
27#include <IOKit/IOLocks.h>
28#include <IOKit/IOMessage.h>
29#include <IOKit/pwr_mgt/RootDomain.h>
30#include <IOKit/IOHibernatePrivate.h>
31#include <IOKit/graphics/IOGraphicsPrivate.h>
32#include <IOKit/graphics/IOGraphicsInterfaceTypes.h>
33#include <IOKit/ndrvsupport/IONDRVFramebuffer.h>
34#include <IOKit/i2c/IOI2CInterface.h>
35#include <IOKit/pci/IOAGPDevice.h>
36#include <IOKit/IOTimerEventSource.h>
37#include <IOKit/assert.h>
38
39#include <libkern/c++/OSContainers.h>
40#include <string.h>
41
42#include "IONDRV.h"
43#include "IONDRVFramebufferPrivate.h"
44
45#define sizeof32(x) ((int)sizeof(x))
46
47/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
48
49extern "C" IOReturn _IONDRVLibrariesInitialize( IOService * provider );
50extern "C" IOReturn _IONDRVLibrariesFinalize( IOService * provider );
51
52#if RLOG
53#define IONDRVCHECK     1
54#endif
55#define IONDRVCHECK     1
56#define IONDRVI2CLOG    0
57#define TIME_LOGS       0
58
59#define kFirstDepth     kDepthMode1
60
61enum
62{
63    kModePreflight = 1,
64    kDisplayModeIDPreflight = kDisplayModeIDReservedBase + 1000
65};
66
67#define arbMode2Index(index)    \
68    (index & 0x3ff)
69
70#if TIME_LOGS
71
72#define TIMESTART()									\
73{													\
74    AbsoluteTime startTime, endTime;				\
75    uint64_t nsec;									\
76	AbsoluteTime_to_scalar(&startTime) = mach_absolute_time();
77
78#define TIMEEND(name, fmt, args...)								\
79    AbsoluteTime_to_scalar(&endTime) = mach_absolute_time();    \
80    absolutetime_to_nanoseconds(endTime, &nsec);                  \
81    kprintf("%08d [%s]: ", (uint32_t) (nsec / 1000000ULL), name); \
82    SUB_ABSOLUTETIME(&endTime, &startTime);			\
83    absolutetime_to_nanoseconds(endTime, &nsec);	\
84    nsec /= 1000000ULL;								\
85    kprintf(fmt, ## args , nsec);     \
86}
87
88
89#else	/* !TIME_LOGS */
90
91#define TIMESTART()
92#define TIMEEND(name, fmt, args...)
93
94#endif
95
96
97/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
98
99struct IONDRVFramebufferPrivate
100{
101    IOOptionBits                displayConnectFlags;
102    unsigned int                ackConnectChange:1;
103    unsigned int                postWakeProbe:1;
104    unsigned int                i2cPowerState:1;
105    unsigned int                deferCLUTSet:1;
106    unsigned int                removable:1;
107    unsigned int                pad1:27;
108    UInt32                      desiredGammaWidth;
109    UInt32                      desiredGammaCount;
110    IOTimerEventSource *        probeInterrupt;
111    UInt32                      currentModeTiming;
112    UInt32                      reducedSpeed;
113    IODisplayModeID             depthMapModeID;
114    UInt8                       indexToDepthMode[kDepthMode6 - kDepthMode1 + 1];
115    UInt8                       depthModeToIndex[kDepthMode6 - kDepthMode1 + 1];
116    IOPhysicalAddress64         physicalFramebuffer;
117
118};
119
120/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
121
122class IOBootNDRV : public IONDRV
123{
124    OSDeclareDefaultStructors(IOBootNDRV)
125
126public:
127    enum { kIOBootNDRVDisplayMode = 100 };
128
129    IOMemoryDescriptor * fVRAMDesc;
130    UInt32               fRowBytes;
131    UInt32               fWidth;
132    UInt32               fHeight;
133    UInt32               fBitsPerPixel;
134
135    static IONDRV * fromRegistryEntry( IORegistryEntry * regEntry );
136
137    virtual void free( void );
138
139    virtual IOReturn getSymbol( const char * symbolName,
140                                IOLogicalAddress * address );
141
142    virtual const char * driverName( void );
143
144    virtual IOReturn doDriverIO( UInt32 commandID, void * contents,
145                                 UInt32 commandCode, UInt32 commandKind );
146
147private:
148
149    static bool getUInt32Property( IORegistryEntry * regEntry, const char * name,
150                                   UInt32 * result );
151    IOReturn doControl( UInt32 code, void * params );
152    IOReturn doStatus( UInt32 code, void * params );
153};
154
155/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
156
157/* generic nub for multihead devices */
158
159class IONDRVDevice : public IOPlatformDevice
160{
161    OSDeclareDefaultStructors(IONDRVDevice)
162
163public:
164    virtual bool compareName( OSString * name, OSString ** matched = 0 ) const;
165    virtual IOService * matchLocation( IOService * client );
166    virtual IOReturn getResources( void );
167    virtual void joinPMtree( IOService * driver );
168};
169
170#undef super
171#define super IOPlatformDevice
172
173OSDefineMetaClassAndStructors(IONDRVDevice, IOPlatformDevice)
174
175void IONDRVDevice::joinPMtree( IOService * driver )
176{
177    IOService * realDevice;
178    realDevice = OSDynamicCast( IOService, getParentEntry(gIODTPlane) );
179    if (realDevice)
180        realDevice->addPowerChild(driver);
181    else
182        super::joinPMtree( driver );
183}
184
185bool IONDRVDevice::compareName( OSString * name,
186                                        OSString ** matched ) const
187{
188    return (IODTCompareNubName(this, name, matched)
189          || IORegistryEntry::compareName(name, matched));
190}
191
192IOService * IONDRVDevice::matchLocation( IOService * client )
193{
194    return (this);
195}
196
197IOReturn IONDRVDevice::getResources( void )
198{
199    if (getDeviceMemory())
200        return (kIOReturnSuccess);
201
202    IODTResolveAddressing(this, "reg", 0);
203
204    return (kIOReturnSuccess);
205}
206
207/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
208
209struct _VSLService
210{
211    class IONDRVFramebuffer *   framebuffer;
212    IOSelect                    type;
213    IOFBInterruptProc           handler;
214    OSObject *                  target;
215    void *                      ref;
216    _VSLService *               next;
217};
218
219/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
220
221// IONDRVFramebuffer has three power states: sleep, doze, wake.
222
223enum {
224    kNDRVFramebufferSleepState          = 0,
225    kNDRVFramebufferDozeState           = 1,
226    kNDRVFramebufferWakeState           = 2,
227    kIONDRVFramebufferPowerStateCount   = 3,
228    kIONDRVFramebufferPowerStateMax     = kIONDRVFramebufferPowerStateCount - 1
229};
230
231/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
232
233#undef super
234#define super IOFramebuffer
235
236OSDefineMetaClassAndStructors(IONDRVFramebuffer, IOFramebuffer)
237
238static int gIONDRVFramebufferGeneration[2] = { 0, 0 };
239
240/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
241
242IOService * IONDRVFramebuffer::probe( IOService * provider, SInt32 * score )
243{
244    IOService *  inst;
245
246    if (0 != provider->getProperty(kIONDRVIgnoreKey))
247        return (0);
248
249    inst = super::probe(provider, score);
250    if (!inst)
251        return (0);
252
253    if (getProperty(gIONameMatchedKey))
254    {
255        // matched
256        provider->setProperty(kIONDRVForXKey, gIOFBOne32Data);
257    }
258
259    return (inst);
260}
261
262IOReturn IONDRVFramebuffer::setProperties( OSObject * properties )
263{
264    OSDictionary *      dict;
265    OSData *            data;
266    IOReturn            kr = kIOReturnUnsupported;
267
268    if (!(dict = OSDynamicCast(OSDictionary, properties)))
269        return (kIOReturnBadArgument);
270
271    if ((data = OSDynamicCast(OSData,
272                              dict->getObject("driver,AAPL,MacOS,PowerPC"))))
273    {
274        gIONDRVFramebufferGeneration[1] = gIONDRVFramebufferGeneration[0];
275        if (ndrvState)
276            return (kIOReturnStillOpen);
277
278        if (ndrv)
279            ndrv->release();
280        ndrv = NULL;
281        if (ndrv)
282        {
283            setName( ndrv->driverName());
284            setProperty("driver,AAPL,MacOS,PowerPC", nub->getProperty("driver,AAPL,MacOS,PowerPC"));
285        }
286        kr = kIOReturnSuccess;
287    }
288    else
289        kr = super::setProperties(properties);
290
291    return (kr);
292}
293
294void IONDRVFramebuffer::stop( IOService * provider )
295{
296    UInt32 state = ndrvState;
297
298    super::stop( provider );
299
300    if (state)
301    {
302        IOMemoryDescriptor * vram;
303        if ((vram = getVRAMRange()))
304        {
305            vram->redirect( kernel_task, false );
306            vram->release();
307        }
308        online = false;
309        device = 0;
310        nub    = 0;
311        _IONDRVLibrariesFinalize(provider);
312    }
313    provider->removeProperty(kIONDRVForXKey);
314}
315
316bool IONDRVFramebuffer::start( IOService * provider )
317{
318    bool                ok = false;
319    IOService *         parent = 0;
320    OSData *            data;
321
322    if (0 == getProperty(gIONameMatchedKey))
323    {
324        // !matched
325        IORegistryIterator * iter;
326        IORegistryEntry *    next;
327        IOService *          nub;
328        OSArray *            toDo = 0;
329        bool                 firstLevel;
330
331        if (0 == provider->getProperty("AAPL,ndrv-dev"))
332        {
333            provider->setProperty("AAPL,ndrv-dev", kOSBooleanTrue);
334
335            if (provider->getProperty("@0,name"))
336            {
337                OSDictionary *         dict;
338                OSCollectionIterator * keys;
339                const OSSymbol *       key;
340                char                   buffer[80];
341                const char *           keyChrs;
342                size_t                 len;
343                char                   c;
344
345                dict = provider->dictionaryWithProperties();
346                keys = OSCollectionIterator::withCollection(dict);
347                if (dict)
348                    dict->release();
349                if (keys)
350                {
351                    while ((key = OSDynamicCast(OSSymbol, keys->getNextObject())))
352                    {
353                        keyChrs = key->getCStringNoCopy();
354                        if ('@' != keyChrs[0])
355                            continue;
356
357                        len = 0;
358                        do
359                        {
360                            c = keyChrs[len];
361                            if (!c || (c == ','))
362                                break;
363                            buffer[len] = c;
364                            len++;
365                        }
366                        while (len < (sizeof(buffer) - 1));
367                        if (!c)
368                            continue;
369
370                        buffer[len] = 0;
371                        keyChrs += len + 1;
372
373                        next = provider->childFromPath(buffer, gIODTPlane);
374                        if (!next)
375                        {
376                            next = new IOService;
377                            if (next && !next->init())
378                            {
379                                next->release();
380                                next = 0;
381                            }
382                            if (!next)
383                                continue;
384                            next->setLocation(&buffer[1]);
385                            if (!next->attachToParent(provider, gIODTPlane))
386                                continue;
387                        }
388
389                        OSObject * obj = dict->getObject(key);
390                        next->setProperty(keyChrs, dict->getObject(key));
391                        if (!strcmp(keyChrs, "name"))
392                        {
393                            OSData * data = OSDynamicCast(OSData, obj);
394                            if (data)
395                                next->setName((const char *) data->getBytesNoCopy());
396                        }
397                        next->release();
398                        provider->removeProperty(key);
399                    }
400                    keys->release();
401                }
402            }
403
404            iter = IORegistryIterator::iterateOver( provider, gIODTPlane, 0 );
405            toDo = OSArray::withCapacity(2);
406
407            if (iter && toDo)
408            {
409                bool haveDoneLibInit = false;
410                UInt32 index = 0;
411                do
412                {
413                    while ((next = (IORegistryEntry *) iter->getNextObject()))
414                    {
415                        firstLevel = (provider == next->getParentEntry(gIODTPlane));
416                        if (firstLevel)
417                        {
418                            data = OSDynamicCast( OSData, next->getProperty("device_type"));
419                            if (!data || (0 != strcmp("display", (char *) data->getBytesNoCopy())))
420                                continue;
421
422                            if (!haveDoneLibInit)
423                            {
424                                haveDoneLibInit = (kIOReturnSuccess == _IONDRVLibrariesInitialize(provider));
425                                if (!haveDoneLibInit)
426                                    continue;
427                            }
428                            next->setProperty( kIOFBDependentIDKey, provider->getRegistryEntryID(), 64 );
429                            next->setProperty( kIOFBDependentIndexKey, index, 32 );
430                            index++;
431                        }
432
433                        toDo->setObject( next );
434                        iter->enterEntry();
435                    }
436                }
437                while (iter->exitEntry());
438            }
439            if (iter)
440                iter->release();
441
442            if (toDo)
443            {
444                OSObject * obj;
445                OSArray  * deviceMemory;
446                obj = provider->copyProperty(gIODeviceMemoryKey);
447                deviceMemory = OSDynamicCast(OSArray, obj);
448
449                for (unsigned int i = 0;
450                        (next = (IORegistryEntry *) toDo->getObject(i));
451                        i++)
452                {
453                    nub = new IONDRVDevice;
454                    if (!nub)
455                        continue;
456                    if (!nub->init(next, gIODTPlane))
457                    {
458                        nub->free();
459                        nub = 0;
460                        continue;
461                    }
462                    if (deviceMemory)
463                        nub->setDeviceMemory(deviceMemory);
464                    nub->attach(provider);
465                    nub->registerService(kIOServiceSynchronous);
466                }
467                if (obj)
468                    obj->release();
469                toDo->release();
470            }
471        }
472        return (false);
473    }
474
475    data = OSDynamicCast(OSData, provider->getProperty("device_type"));
476    if (data && (0 != strcmp("display", (char *) data->getBytesNoCopy())))
477        return (false);
478
479    do
480    {
481        cachedVDResolution.csDisplayModeID = kDisplayModeIDInvalid;
482
483        if (!__private)
484        {
485            __private = IONew( IONDRVFramebufferPrivate, 1 );
486            if (!__private)
487                continue;
488            bzero( __private, sizeof(IONDRVFramebufferPrivate) );
489        }
490
491        __private->depthMapModeID = kDisplayModeIDInvalid;
492
493        nub = provider;
494
495        gIONDRVFramebufferGeneration[0]++;
496        data = OSData::withBytesNoCopy(&gIONDRVFramebufferGeneration, sizeof32(gIONDRVFramebufferGeneration));
497        if (data)
498        {
499            setProperty(kIONDRVFramebufferGenerationKey, data);
500            getRegistryRoot()->setProperty(kIONDRVFramebufferGenerationKey, data);
501            data->release();
502        }
503
504        if ((data = OSDynamicCast(OSData, getProperty("driver,AAPL,MacOS,PowerPC"))))
505            nub->setProperty("driver,AAPL,MacOS,PowerPC", data);
506
507        ndrv = NULL;
508        if (ndrv)
509            setName( ndrv->driverName());
510        consoleDevice = (0 != provider->getProperty("AAPL,boot-display"));
511
512        powerState = kIONDRVFramebufferPowerStateMax;
513
514        if (OSDynamicCast(IONDRVDevice, nub))
515            parent = OSDynamicCast(IOService, nub->getParentEntry(gIODTPlane));
516        if (parent)
517            device = parent;
518        else
519            device = nub;
520
521        RegEntryID regEntry;
522        MAKE_REG_ENTRY( &regEntry, nub);
523        nub->setProperty( kAAPLRegEntryIDKey, &regEntry, sizeof32(regEntry) );
524
525        if (false == super::start(nub))
526            continue;
527
528        OSObject * obj;
529        if ((obj = nub->getProperty(kIOFBDependentIDKey)))
530            setProperty( kIOFBDependentIDKey, obj );
531        if ((obj = nub->getProperty(kIOFBDependentIndexKey)))
532            setProperty( kIOFBDependentIndexKey, obj );
533
534        platformSleep = false;
535        __private->removable = (0 != device->metaCast("IOCardBusDevice"));
536
537        IOOptionBits flags = getPMRootDomain()->getSleepSupported();
538        getPMRootDomain()->setSleepSupported(flags & ~kFrameBufferDeepSleepSupported);
539
540        // default flags can be overriden
541        accessFlags = 0;
542        if (0 == strncmp("3Dfx", provider->getName(), strlen("3Dfx")))
543            accessFlags |= kFramebufferDisableAltivecAccess;
544
545        if ((data = OSDynamicCast(OSData, provider->getProperty(kIOFBHostAccessFlagsKey))))
546            accessFlags = *((UInt32 *) data->getBytesNoCopy());
547
548        ok = true;                      // Success
549    }
550    while (false);
551
552    return (ok);
553}
554
555bool IONDRVFramebuffer::isConsoleDevice( void )
556{
557    return (consoleDevice);
558}
559
560IOReturn IONDRVFramebuffer::enableController( void )
561{
562    IOReturn            err;
563    const char *        logname;
564
565    logname = getProvider()->getName();
566    do
567    {
568        gIONDRVFramebufferGeneration[1] = gIONDRVFramebufferGeneration[0];
569
570        getProvider()->setProperty("AAPL,ndrv-dev", kOSBooleanTrue);
571
572        // wait for accelerator module, display parameter drivers
573        // device->waitQuiet();
574        // find out about onboard audio/video jack state
575        // OSObject * notify =
576        addMatchingNotification( gIOPublishNotification,
577                                 resourceMatching(kAppleAudioVideoJackStateKey),
578                                 _videoJackStateChangeHandler, this, 0 );
579
580        err = checkDriver();
581        if (err)
582        {
583            IOLog("%s: Not usable\n", logname );
584            if (err == -999)
585                IOLog("%s: driver incompatible.\n", logname );
586            continue;
587        }
588        uintptr_t isOnline = true;
589        if ((kIOReturnSuccess != getAttributeForConnection(0, kConnectionCheckEnable, &isOnline))
590                || isOnline || true)
591        {
592            getCurrentConfiguration();
593
594            if (!device->getProperty("IONVRAMProperty"))
595                setStartupDisplayMode( currentDisplayMode, currentDepth );
596
597            if (currentDisplayMode == kDisplayModeIDBootProgrammable)
598            {
599                VDScalerRec scaler;
600
601                bzero( &scaler, sizeof( VDScalerRec) );
602                scaler.csScalerSize = sizeof32(VDScalerRec);
603                scaler.csDisplayModeID = kDisplayModeIDBootProgrammable;
604                if (noErr == _doStatus(this, cscGetScaler, &scaler))
605                {
606                    DEBG(thisName, " boot scalerFlags 0x%x\n", (uint32_t) scaler.csScalerFlags);
607                    if (kIOScaleRotateFlags & scaler.csScalerFlags)
608                        setProperty(kIOFBTransformKey, kIOScaleRotateFlags & scaler.csScalerFlags, 64);
609                }
610            }
611        }
612        online = isOnline;
613//        vramMemory = findVRAM();
614
615        OSData * data;
616        if ((data = OSDynamicCast(OSData, device->getProperty(kIOAGPCommandValueKey))))
617            accessFlags |= (kIOAGPFastWrite & (*((UInt32 *) data->getBytesNoCopy())))
618                           ? kFramebufferAGPFastWriteAccess : 0;
619
620        // initialize power management of the device
621        initForPM();
622        device->setProperty(kIOPMIsPowerManagedKey, true);
623
624        if ((data = OSDynamicCast(OSData, getPMRootDomain()->getProperty(kIOHibernateStateKey))))
625            device->setProperty(kIOHibernateStateKey, gIOFBZero32Data);
626    }
627    while (false);
628
629    return (err);
630}
631
632bool IONDRVFramebuffer::_videoJackStateChangeHandler( void * target, void * ref,
633        IOService * resourceService, IONotifier * notifier )
634{
635    IONDRVFramebuffer * self = (IONDRVFramebuffer *) target;
636    uint32_t            jackData;
637
638    OSObject * jackValue = resourceService->getProperty(kAppleAudioVideoJackStateKey);
639    if (!jackValue)
640        return (true);
641
642    jackData = (jackValue == kOSBooleanTrue);
643    IOLog(kAppleAudioVideoJackStateKey " %d\n", jackData);
644
645    self->nub->setProperty( kAppleAudioVideoJackStateKey, &jackData, sizeof32(jackData) );
646    resourceService->removeProperty(kAppleAudioVideoJackStateKey);
647
648    if (!self->__private->probeInterrupt)
649    {
650        self->__private->probeInterrupt = IOTimerEventSource::timerEventSource(
651                                            self, &IONDRVFramebuffer::_avProbeAction);
652        if (self->__private->probeInterrupt)
653            self->getControllerWorkLoop()->addEventSource(self->__private->probeInterrupt);
654    }
655    if (self->__private->probeInterrupt && (self->avJackState != jackData))
656    {
657        self->avJackState = jackData;
658        self->__private->probeInterrupt->setTimeoutMS(kIONDRVAVJackProbeDelayMS);
659    }
660
661    return (true);
662}
663
664void IONDRVFramebuffer::_avProbeAction( OSObject * p0, IOTimerEventSource * evtSrc )
665{
666    _probeAction( (IONDRVFramebuffer *) p0, kIOFBAVProbe );
667}
668
669IOReturn IONDRVFramebuffer::_probeAction( IONDRVFramebuffer * self, IOOptionBits options )
670{
671    IOReturn err = kIOReturnSuccess;
672
673    if (self->captured)
674    {
675        err = kIOReturnBusy;
676    }
677    else if (options & (kIOFBUserRequestProbe | kIOFBAVProbe))
678    {
679        if ((options & kIOFBUserRequestProbe) && !self->supportsProbe)
680        {
681            err = kIOReturnUnsupported;
682        }
683        else
684        {
685#if 1
686            err = self->_doControl( self, cscProbeConnection, 0 );
687#else
688            do
689            {
690                OSNumber * num = OSDynamicCast(OSNumber, self->getProperty(kIOFBDependentIndexKey));
691                if (num && (0 != num->unsigned32BitValue()))
692                    continue;
693
694				IONDRVFramebuffer * next = self;
695				do
696				{
697					next->_doControl( next, cscProbeConnection, 0 );
698					next = OSDynamicCast(IONDRVFramebuffer, next->nextDependent);
699				}
700				while (next && (next != self));
701            }
702            while (false);
703#endif
704        }
705    }
706    else if (options & kIOFBForceReadEDID)
707    {
708        if (!self->forceReadEDID)
709        {
710            _VSLService *       service;
711            IOFBInterruptProc   proc;
712
713            self->forceReadEDID = 1;
714
715            for (service = self->vslServices;
716                    service && (kIOFBConnectInterruptType != service->type);
717                    service = service->next)
718            {}
719            if (service && (proc = service->handler))
720                (*proc) (service->target, service->ref);
721        }
722        err = kIOReturnSuccess;
723    }
724    else
725        err = kIOReturnBadArgument;
726
727    return (err);
728}
729
730IOReturn IONDRVFramebuffer::requestProbe( IOOptionBits options )
731{
732    IOReturn     err;
733
734    err = super::requestProbe(options);
735
736    return (err);
737}
738
739IODeviceMemory * IONDRVFramebuffer::getVRAMRange( void )
740{
741    if (ndrvState && !vramMemory)
742        vramMemory = findVRAM();
743
744    if (vramMemory)
745        vramMemory->retain();
746
747    return (vramMemory);
748}
749
750const IOTVector * IONDRVFramebuffer::_undefinedSymbolHandler( void * self,
751        const char * libraryName, const char * symbolName )
752{
753    return (((IONDRVFramebuffer *)self)->undefinedSymbolHandler(libraryName, symbolName));
754}
755
756const IOTVector * IONDRVFramebuffer::undefinedSymbolHandler( const char * libraryName,
757        const char * symbolName )
758{
759    return (0);
760}
761
762void IONDRVFramebuffer::free( void )
763{
764    if (__private)
765    {
766        IODelete( __private, IONDRVFramebufferPrivate, 1 );
767        __private = 0;
768    }
769    super::free();
770}
771
772/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
773
774IOReturn IONDRVFramebuffer::registerForInterruptType( IOSelect interruptType,
775        IOFBInterruptProc proc, OSObject * target, void * ref,
776        void ** interruptRef )
777
778{
779    _VSLService * service;
780    IOReturn      err;
781
782    if ((interruptType == kIOFBVBLInterruptType)
783            && (getProvider()->getProperty("Ignore VBL")))
784        return (kIOReturnUnsupported);
785
786    for (service = vslServices;
787            service && (service->type != interruptType);
788            service = service->next)
789        {}
790
791    if (service)
792    {
793        if (service->handler)
794            err = kIOReturnBusy;
795        else
796        {
797            service->target     = target;
798            service->ref        = ref;
799            service->handler    = proc;
800            *interruptRef       = service;
801            err                 = kIOReturnSuccess;
802        }
803    }
804    else
805    {
806        err = super::registerForInterruptType(interruptType, proc, target, ref, interruptRef);
807    }
808
809    return (err);
810}
811
812IOReturn IONDRVFramebuffer::unregisterInterrupt( void * interruptRef )
813{
814    _VSLService * service;
815    IOReturn      err;
816
817    for (service = vslServices;
818            service && (service != interruptRef);
819            service = service->next)
820        {}
821
822    if (service)
823    {
824        service->handler = 0;
825        err = kIOReturnSuccess;
826    }
827    else
828    {
829        err = super::unregisterInterrupt(interruptRef);
830    }
831
832    return (err);
833}
834
835IOReturn IONDRVFramebuffer::setInterruptState( void * interruptRef,
836        UInt32 state )
837{
838    _VSLService * service;
839    IOReturn      err;
840
841    for (service = vslServices;
842            service && (service != interruptRef);
843            service = service->next)
844        {}
845
846    if (service)
847    {
848        err = kIOReturnUnsupported;
849    }
850    else
851    {
852        err = super::setInterruptState(interruptRef, state);
853    }
854
855    return (err);
856}
857
858/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
859
860//// VSL calls
861
862OSStatus IONDRVFramebuffer::VSLNewInterruptService(
863    void * entryID,
864    IOSelect serviceType,
865    _VSLService ** vslService )
866{
867    IORegistryEntry *   regEntry;
868    IOService *         device;
869    IOService *         client = NULL;
870    IONDRVFramebuffer * fb = NULL;
871    _VSLService *       service;
872    IOReturn            err = kIOReturnSuccess;
873
874    REG_ENTRY_TO_OBJ( (const RegEntryID *) entryID, regEntry)
875
876    if ((device = OSDynamicCast(IOService, regEntry)))
877        client = device->copyClientWithCategory(gIOFramebufferKey);
878
879    if ((fb = OSDynamicCast(IONDRVFramebuffer, client)))
880    {
881        service = IONew( _VSLService, 1 );
882
883        if (service)
884        {
885            service->framebuffer        = fb;
886            service->type               = serviceType;
887            service->handler            = 0;
888            service->next = fb->vslServices;
889            fb->vslServices = service;
890
891            *vslService = service;
892        }
893        else
894            err = kIOReturnNoMemory;
895    }
896    else
897        err = kIOReturnBadArgument;
898
899    if (client)
900        client->release();
901
902    return (err);
903}
904
905OSStatus IONDRVFramebuffer::VSLDisposeInterruptService(_VSLService * vslService)
906{
907    IONDRVFramebuffer * fb;
908    _VSLService *       next;
909    _VSLService *       prev;
910
911    if (vslService)
912    {
913        fb = vslService->framebuffer;
914
915        prev = fb->vslServices;
916        if (prev == vslService)
917            fb->vslServices = vslService->next;
918        else
919        {
920            while (((next = prev->next) != vslService) && next)
921                prev = next;
922            if (next)
923                prev->next = vslService->next;
924        }
925
926        IODelete( vslService, _VSLService, 1 );
927    }
928
929    return (kIOReturnSuccess);
930}
931
932OSStatus IONDRVFramebuffer::VSLDoInterruptService( _VSLService * vslService )
933{
934    IOReturn          ret = kIOReturnSuccess;
935    IOFBInterruptProc proc;
936
937    if (vslService)
938    {
939        if (kIOFBConnectInterruptType == vslService->type)
940            vslService->framebuffer->__private->ackConnectChange = true;
941        else if (kIOFBWakeInterruptType == vslService->type)
942            ret = vslService->framebuffer->handleEvent(kIOFBNotifyVRAMReady);
943
944        if ((proc = vslService->handler))
945            (*proc) (vslService->target, vslService->ref);
946    }
947
948    return (ret);
949}
950
951/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
952
953struct _VSLCursorRef
954{
955    IOFramebuffer *     framebuffer;
956    void *              cursorImage;
957};
958
959Boolean IONDRVFramebuffer::VSLPrepareCursorForHardwareCursor(
960    void * cursorRef,
961    IOHardwareCursorDescriptor * hwDesc,
962    IOHardwareCursorInfo * hwCursorInfo )
963{
964    _VSLCursorRef *     cursor = (_VSLCursorRef *) cursorRef;
965    bool                ok;
966
967    if (hwCursorInfo->colorMap)
968        hwCursorInfo->colorMap += 1;
969    ok = cursor->framebuffer->convertCursorImage(
970             cursor->cursorImage, hwDesc, hwCursorInfo );
971    if (hwCursorInfo->colorMap)
972        hwCursorInfo->colorMap -= 1;
973
974    return (ok);
975}
976
977IOReturn IONDRVFramebuffer::setCursorImage( void * cursorImage )
978{
979    _VSLCursorRef               cursorRef;
980    VDSetHardwareCursorRec      setCursor;
981    IOReturn                    err;
982
983    if (0 == powerState)
984        return (kIOReturnSuccess);
985    if (!online)
986        return (kIOReturnSuccess);
987
988    cursorRef.framebuffer = this;
989    cursorRef.cursorImage = cursorImage;
990
991    setCursor.csCursorRef = (void *) &cursorRef;
992    setCursor.csReserved1 = 0;
993    setCursor.csReserved2 = 0;
994
995    err = _doControl( this, cscSetHardwareCursor, &setCursor );
996
997    mirrorSWCursor = (mirrored && !mirrorPrimary && (kIOReturnSuccess != err));
998    if (mirrorSWCursor)
999        err = kIOReturnSuccess;
1000
1001    return (err);
1002}
1003
1004IOReturn IONDRVFramebuffer::setCursorState( SInt32 x, SInt32 y, bool visible )
1005{
1006    VDDrawHardwareCursorRec     drawCursor;
1007    IOReturn                    err;
1008
1009    if (mirrorSWCursor || !online)
1010        return (kIOReturnSuccess);
1011
1012    if (0 == powerState)
1013        return (kIOReturnSuccess);
1014
1015    if (0 == OSIncrementAtomic(&ndrvEnter))
1016    {
1017        drawCursor.csCursorX    = x;
1018        drawCursor.csCursorY    = y;
1019        drawCursor.csCursorVisible      = visible;
1020        drawCursor.csReserved1  = 0;
1021        drawCursor.csReserved2  = 0;
1022
1023        err = _doControl( this, cscDrawHardwareCursor, &drawCursor );
1024    }
1025    else
1026    {
1027        err = kIOReturnBusy;
1028    }
1029
1030    OSDecrementAtomic( &ndrvEnter );
1031
1032    return (err);
1033}
1034
1035/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1036
1037IOReturn IONDRVFramebuffer::doDriverIO( UInt32 commandID, void * contents,
1038                                        UInt32 commandCode, UInt32 commandKind )
1039{
1040    IOReturn err;
1041
1042    if (kIONDRVInitializeCommand == commandCode)
1043    {
1044        if (!ndrv)
1045        {
1046			uint32_t debugFlags;
1047			if (PE_parse_boot_argn("iog", &debugFlags, sizeof(debugFlags))
1048					&& (kIOGDbgDumbPanic & debugFlags))
1049			{
1050				panic("dumb FB start");
1051			}
1052            ndrv = IOBootNDRV::fromRegistryEntry( nub );
1053            if (ndrv)
1054                setName( ndrv->driverName());
1055        }
1056    }
1057
1058    if (ndrv)
1059    {
1060        OSIncrementAtomic( &ndrvEnter );
1061        err = ndrv->doDriverIO( commandID, contents, commandCode, commandKind );
1062        OSDecrementAtomic( &ndrvEnter );
1063    }
1064    else
1065        err = kIOReturnUnsupported;
1066
1067    return (err);
1068}
1069
1070/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1071
1072IOReturn IONDRVFramebuffer::_doControl( IONDRVFramebuffer * self, UInt32 code, void * params )
1073{
1074    IOReturn                    err;
1075    IONDRVControlParameters     pb;
1076
1077#if IONDRVCHECK
1078    IOWorkLoop * wl;
1079    if (!ml_at_interrupt_context() && (wl = self->getControllerWorkLoop()) && !wl->inGate())
1080        OSReportWithBacktrace("%s::_doControl(%d) not gated\n", self->thisName, code);
1081#endif
1082
1083    if (self->ndrvState == 0)
1084        return (kIOReturnNotOpen);
1085
1086    pb.code = code;
1087    pb.params = params;
1088
1089    err = self->doDriverIO( /*ID*/ 1, &pb,
1090                                   kIONDRVControlCommand, kIONDRVImmediateIOCommandKind );
1091
1092#if FORCE_CONNECT_CHANGE
1093    if (cscProbeConnection == code)
1094    {
1095        _VSLService * vslService  = self->vslServices;
1096        while (vslService && (kIOFBConnectInterruptType != vslService->type))
1097            vslService = vslService->next;
1098        if (vslService)
1099            VSLDoInterruptService(vslService);
1100    }
1101#endif
1102
1103    return (err);
1104}
1105
1106IOReturn IONDRVFramebuffer::_doStatus( IONDRVFramebuffer * self, UInt32 code, void * params )
1107{
1108    IOReturn                    err;
1109    IONDRVControlParameters     pb;
1110
1111    if (self->ndrvState == 0)
1112        return (kIOReturnNotOpen);
1113
1114#if IONDRVCHECK
1115    IOWorkLoop * wl;
1116    if (!ml_at_interrupt_context() && (wl = self->getControllerWorkLoop()) && !wl->inGate())
1117        OSReportWithBacktrace("%s::_doStatus(%d) not gated\n", self->thisName, code);
1118#endif
1119
1120    pb.code = code;
1121    pb.params = params;
1122
1123    err = self->doDriverIO( /*ID*/ 1, &pb,
1124                                   kIONDRVStatusCommand, kIONDRVImmediateIOCommandKind );
1125
1126    return (err);
1127}
1128
1129IOReturn IONDRVFramebuffer::extControl( OSObject * owner, void * code, void * params )
1130{
1131    IONDRVFramebuffer * self = (IONDRVFramebuffer *) owner;
1132    IOReturn            err;
1133
1134    if (self->powerState)
1135        err = _doControl( self, (UInt32)(uintptr_t) code, params );
1136    else
1137        err = kIOReturnNotReady;
1138
1139    return (err);
1140}
1141
1142IOReturn IONDRVFramebuffer::extStatus( OSObject * owner, void * code, void * params )
1143{
1144    IONDRVFramebuffer * self = (IONDRVFramebuffer *) owner;
1145    IOReturn            err;
1146
1147    if (self->powerState)
1148        err = _doStatus( self, (UInt32)(uintptr_t) code, params );
1149    else
1150        err = kIOReturnNotReady;
1151
1152    return (err);
1153}
1154
1155IOReturn IONDRVFramebuffer::doControl( UInt32 code, void * params )
1156{
1157    return (getControllerWorkLoop()->runAction((IOWorkLoop::Action) &extControl, this, (void *)(uintptr_t) code, params));
1158}
1159
1160IOReturn IONDRVFramebuffer::doStatus( UInt32 code, void * params )
1161{
1162    return (getControllerWorkLoop()->runAction((IOWorkLoop::Action) &extStatus, this, (void *)(uintptr_t) code, params));
1163}
1164
1165/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1166
1167IOReturn IONDRVFramebuffer::checkDriver( void )
1168{
1169    OSStatus                    err = noErr;
1170    IONDRVControlParameters     pb;
1171    VDClutBehavior              clutSetting;
1172    VDGammaRecord               gammaRec;
1173    VDSwitchInfoRec             switchInfo;
1174    VDPageInfo                  pageInfo;
1175
1176    if (ndrvState == 0)
1177    {
1178        do
1179        {
1180            err = doDriverIO( 0, nub,
1181                              kIONDRVInitializeCommand, kIONDRVImmediateIOCommandKind );
1182            if (err)
1183                continue;
1184            err = doDriverIO( 0, &pb,
1185                              kIONDRVOpenCommand, kIONDRVImmediateIOCommandKind );
1186        }
1187        while (false);
1188        if (err)
1189            return (err);
1190
1191        // allow calls to ndrv
1192        ndrvState = 2;
1193
1194        createI2C();
1195
1196#if IONDRVI2CLOG
1197        do
1198        {
1199            VDCommunicationInfoRec      commInfo;
1200
1201            bzero( &commInfo, sizeof( commInfo));
1202            commInfo.csBusID = kVideoDefaultBus;
1203
1204            err = _doStatus( this, cscGetCommunicationInfo, &commInfo );
1205            IOLog("%s: cscGetCommunicationInfo: ", getName());
1206            if (kIOReturnSuccess != err)
1207            {
1208                IOLog("fails with %ld\n", err);
1209                continue;
1210            }
1211            IOLog("csBusType %lx, csMinBus %lx, csMaxBus %lx\n"
1212                  "csSupportedTypes %lx, csSupportedCommFlags %lx\n",
1213                  commInfo.csBusType,
1214                  commInfo.csMinBus, commInfo.csMaxBus,
1215                  commInfo.csSupportedTypes, commInfo.csSupportedCommFlags);
1216
1217            if (commInfo.csSupportedTypes & (1<<kVideoDDCciReplyType))
1218                IOLog("supports kVideoDDCciReplyType, ");
1219            if (commInfo.csSupportedTypes & (1<<kVideoSimpleI2CType))
1220            {
1221                IOLog("supports kVideoSimpleI2CType");
1222                VDCommunicationRec      comm;
1223                UInt8                   edidData[132];
1224                UInt8                   edidRequest[2];
1225
1226                memset( edidData, 0xAA, sizeof( edidData));
1227
1228                edidRequest[0]          = 0;
1229                edidRequest[1]          = 0;
1230
1231                comm.csBusID            = kVideoDefaultBus;
1232                comm.csCommFlags        = 0;
1233                comm.csMinReplyDelay    = 0;
1234                comm.csReserved2        = 0;
1235
1236                comm.csSendAddress      = 0xA0;
1237                comm.csSendType         = kVideoSimpleI2CType;
1238                comm.csSendBuffer       = &edidRequest[0];
1239                comm.csSendSize         = 0x01;
1240
1241                comm.csReplyAddress     = 0xA1;
1242                comm.csReplyType        = kVideoSimpleI2CType;
1243                comm.csReplyBuffer      = &edidData[0];
1244                comm.csReplySize        = 128;
1245
1246                comm.csReserved3        = 0;
1247                comm.csReserved4        = 0;
1248                comm.csReserved5        = 0;
1249                comm.csReserved6        = 0;
1250
1251                do
1252                {
1253                    err = _doControl( this, cscDoCommunication, &comm );
1254                    IOLog("\nI2C read block[%x](%ld)\n", edidRequest[0], err);
1255                    if (kIOReturnSuccess != err)
1256                        break;
1257                    IOLog("    0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
1258                    for (int i = 0; i < 128; i++)
1259                    {
1260                        if (0 == (i & 15))
1261                            IOLog("\n%02x: ", i);
1262                        IOLog("%02x ", edidData[i]);
1263                    }
1264                    IOLog("\n");
1265                    if (edidRequest[0] || (0 == edidData[126]))
1266                        break;
1267                    edidRequest[0] = 0x80;
1268                }
1269                while (true);
1270            }
1271        }
1272        while (false);
1273#endif /* IONDRVI2CLOG */
1274
1275        // duplicate QD InitGDevice
1276        _doStatus( this, cscGetCurMode, &switchInfo );
1277        pageInfo.csMode = switchInfo.csMode;
1278        pageInfo.csData = 0;
1279        pageInfo.csPage = 0;
1280        _doControl( this, cscGrayPage, &pageInfo);
1281
1282        clutSetting = kSetClutAtSetEntries;
1283        lastClutSetting = clutSetting;
1284        __private->deferCLUTSet = (kIOReturnSuccess ==
1285                _doControl( this, cscSetClutBehavior, &clutSetting));
1286
1287        setInfoProperties();
1288
1289        VDGetGammaListRec scan;
1290        GammaTbl *        table;
1291
1292        err = _doStatus( this, cscGetGamma, &gammaRec );
1293        table = (GammaTbl *) gammaRec.csGTable;
1294        if (table && (err == kIOReturnSuccess))
1295        {
1296            __private->desiredGammaWidth = table->gDataWidth;
1297            __private->desiredGammaCount = table->gDataCnt;
1298        }
1299        else
1300        {
1301            __private->desiredGammaWidth = 8;
1302            __private->desiredGammaCount = (1 << 8);
1303        }
1304
1305        for (scan.csPreviousGammaTableID = kGammaTableIDFindFirst;
1306                ;
1307                scan.csPreviousGammaTableID = scan.csGammaTableID)
1308        {
1309            VDRetrieveGammaRec  get;
1310            char                name[ 64 ];
1311
1312            scan.csGammaTableName = name;
1313            err = _doStatus( this, cscGetGammaInfoList, &scan);
1314            if (err || (scan.csGammaTableID == (GammaTableID) kGammaTableIDNoMoreTables))
1315                break;
1316
1317            table = (GammaTbl *) IOMalloc(scan.csGammaTableSize);
1318            if (0 == table)
1319                continue;
1320            get.csGammaTableID  = scan.csGammaTableID;
1321            get.csGammaTablePtr = table;
1322
1323            err = _doStatus( this, cscRetrieveGammaTable, &get );
1324            if (noErr == err)
1325            {
1326                DEBG(thisName, " gamma %s: %d * %d\n", scan.csGammaTableName,
1327                     table->gDataWidth, table->gDataCnt);
1328                if (((UInt32) table->gDataWidth) > __private->desiredGammaWidth)
1329                {
1330                    __private->desiredGammaWidth = table->gDataWidth;
1331                    __private->desiredGammaCount = table->gDataCnt;
1332                }
1333            }
1334
1335            IOFree( table, scan.csGammaTableSize);
1336        }
1337
1338        setProperty(kIOFBGammaWidthKey, __private->desiredGammaWidth, 32);
1339        setProperty(kIOFBGammaCountKey, __private->desiredGammaCount, 32);
1340        setProperty(kIOFBGammaHeaderSizeKey, sizeof32(GammaTbl) - sizeof32(table->gFormulaData), 32);
1341    }
1342    return (noErr);
1343}
1344
1345void IONDRVFramebuffer::setInfoProperties( void )
1346{
1347    IOReturn                    err;
1348    VDDisplayTimingRangeRec     rangeRec;
1349    VDScalerInfoRec             scalerRec;
1350    UInt32                      probeOptions = 0;
1351
1352//    UInt8                       probeType[32];
1353//    if (noErr == _doStatus(this, cscProbeConnection, &probeType))
1354    {
1355        probeOptions |= kIOFBUserRequestProbe;
1356        supportsProbe = true;
1357    }
1358
1359    removeProperty( kIOFBTimingRangeKey );
1360    bzero( &rangeRec, sizeof( rangeRec));
1361    rangeRec.csRangeSize = sizeof32( rangeRec);
1362    err = _doStatus( this, cscGetTimingRanges, &rangeRec );
1363    if (kIOReturnSuccess == err)
1364        setProperty( kIOFBTimingRangeKey, &rangeRec, sizeof32( rangeRec));
1365
1366    removeProperty( kIOFBScalerInfoKey );
1367    bzero( &scalerRec, sizeof( scalerRec));
1368    scalerRec.csScalerInfoSize = sizeof32( scalerRec);
1369    err = _doStatus( this, cscGetScalerInfo, &scalerRec );
1370    if (kIOReturnSuccess == err)
1371    {
1372        setProperty( kIOFBScalerInfoKey, &scalerRec, sizeof32( scalerRec));
1373        if (kScaleCanRotateMask & scalerRec.csScalerFeatures)
1374            probeOptions |= kIOFBSetTransform;
1375    }
1376
1377    if (probeOptions)
1378        setProperty( kIOFBProbeOptionsKey, probeOptions, 32);
1379
1380    nub->setProperty(kIONDRVDisplayConnectFlagsKey,
1381        &__private->displayConnectFlags, sizeof32(__private->displayConnectFlags));
1382}
1383
1384UInt32 IONDRVFramebuffer::iterateAllModes( IODisplayModeID * displayModeIDs )
1385{
1386    VDResolutionInfoRec info;
1387    UInt32              num = 0;
1388
1389    info.csPreviousDisplayModeID = kDisplayModeIDFindFirstResolution;
1390
1391    while (
1392        (noErr == _doStatus(this, cscGetNextResolution, &info))
1393        && ((SInt32) info.csDisplayModeID > 0))
1394    {
1395        if (displayModeIDs)
1396            displayModeIDs[ num ] = info.csDisplayModeID;
1397
1398        info.csPreviousDisplayModeID = info.csDisplayModeID;
1399        num++;
1400    }
1401
1402    return (num);
1403}
1404
1405IOIndex IONDRVFramebuffer::mapDepthIndex(
1406        IODisplayModeID modeID, IOIndex depth, bool fromDepthMode )
1407{
1408    VDVideoParametersInfoRec    pixelParams;
1409    VPBlock                     pixelInfo;
1410    IOIndex                     mapped, index, lastDepth, lastIndex;
1411    IOReturn                    err;
1412
1413    if ((modeID == kDisplayModeIDPreflight)
1414        || (modeID != __private->depthMapModeID))
1415    {
1416        lastDepth = kDepthMode1;
1417        lastIndex = 0;
1418        for (mapped = kDepthMode1, index = 0; mapped <= kDepthMode6; mapped++)
1419        {
1420            pixelParams.csDisplayModeID = modeID;
1421            pixelParams.csDepthMode     = mapped;
1422            pixelParams.csVPBlockPtr    = &pixelInfo;
1423            err = _doStatus( this, cscGetVideoParameters, &pixelParams );
1424            if (kIOReturnSuccess == err)
1425            {
1426                __private->indexToDepthMode[index] = mapped;
1427                lastDepth = mapped;
1428                lastIndex = index;
1429                index++;
1430            }
1431            __private->depthModeToIndex[mapped - kDepthMode1] = lastIndex;
1432        }
1433
1434        for (; index <= (kDepthMode6 - kDepthMode1); index++)
1435            __private->indexToDepthMode[index] = lastDepth;
1436
1437        __private->depthMapModeID = modeID;
1438//      DEBG(thisName, " cache miss for %08lx\n", modeID);
1439    }
1440
1441    if (fromDepthMode)
1442    {
1443        if (depth > kDepthMode6)
1444            depth = kDepthMode6;
1445        mapped = __private->depthModeToIndex[depth - kDepthMode1];
1446
1447//      DEBG(thisName, " mode %x -> index %x\n", depth, mapped);
1448    }
1449    else
1450    {
1451        if (depth > (kDepthMode6 - kDepthMode1))
1452            depth = (kDepthMode6 - kDepthMode1);
1453        mapped = __private->indexToDepthMode[depth];
1454
1455//      DEBG(thisName, " index %x -> mode %x\n", depth, mapped);
1456    }
1457
1458    return (mapped);
1459}
1460
1461static IOFixed1616
1462DetailedRefreshRate(IODetailedTimingInformationV2 * detailed)
1463{
1464    UInt64 pixelCount;
1465    pixelCount = ((detailed->verticalActive + detailed->verticalBlanking)
1466                * (detailed->horizontalActive + detailed->horizontalBlanking));
1467    return (pixelCount ? ((detailed->pixelClock * 65536ULL) / pixelCount) : 0);
1468}
1469
1470IOReturn IONDRVFramebuffer::getResInfoForDetailed(
1471        IODisplayModeID modeID,
1472        VDDetailedTimingRec * detailed,
1473        IODisplayModeInformation * info )
1474{
1475    IODetailedTimingInformationV2 * desc = (IODetailedTimingInformationV2 *) detailed;
1476
1477    info->maxDepthIndex = mapDepthIndex(modeID, kDepthMode6, true);
1478//    DEBG(thisName, " %x maxDepthIndex %x\n", modeID, info->maxDepthIndex);
1479
1480    if (desc->horizontalScaled && desc->verticalScaled)
1481    {
1482        info->nominalWidth      = desc->horizontalScaled;
1483        info->nominalHeight     = desc->verticalScaled;
1484    }
1485    else
1486    {
1487        info->nominalWidth      = detailed->csHorizontalActive;
1488        info->nominalHeight     = detailed->csVerticalActive;
1489    }
1490    info->refreshRate   = DetailedRefreshRate(desc);
1491
1492    if (kIOInterlacedCEATiming & detailed->csSignalConfig)
1493        info->refreshRate *= 2;
1494
1495    return (kIOReturnSuccess);
1496}
1497
1498IOReturn IONDRVFramebuffer::getResInfoForArbMode( IODisplayModeID modeID,
1499        IODisplayModeInformation * info )
1500{
1501    IOReturn              err;
1502    VDDetailedTimingRec * detailed;
1503    VDDetailedTimingRec   _detailed;
1504
1505    if (modeID == kDisplayModeIDBootProgrammable)
1506    {
1507        detailed = &_detailed;
1508        bzero(detailed, sizeof(VDDetailedTimingRec));
1509        detailed->csTimingSize    = sizeof32(VDDetailedTimingRec);
1510        detailed->csDisplayModeID = kDisplayModeIDBootProgrammable;
1511        err = _doStatus(this, cscGetDetailedTiming, detailed);
1512    }
1513    else
1514        err = validateDisplayMode( modeID, 0, &detailed );
1515
1516    if (kIOReturnSuccess == err)
1517        err = getResInfoForDetailed(modeID, detailed, info);
1518
1519    return (err);
1520}
1521
1522IOReturn IONDRVFramebuffer::getResInfoForMode( IODisplayModeID modeID,
1523        IODisplayModeInformation * info )
1524{
1525    bzero( info, sizeof( *info));
1526
1527    if ((UInt32) modeID >= (UInt32) kDisplayModeIDReservedBase)
1528        return (getResInfoForArbMode(modeID, info));
1529
1530    // unfortunately, there is no "kDisplayModeIDFindSpecific"
1531    if (cachedVDResolution.csDisplayModeID != modeID)
1532    {
1533        // try the next after cached mode
1534        cachedVDResolution.csPreviousDisplayModeID = cachedVDResolution.csDisplayModeID;
1535        if ((noErr != _doStatus(this, cscGetNextResolution, &cachedVDResolution))
1536                || (cachedVDResolution.csDisplayModeID != modeID))
1537        {
1538            // else full blown iterate
1539            cachedVDResolution.csPreviousDisplayModeID = kDisplayModeIDFindFirstResolution;
1540            while (
1541                (noErr == _doStatus(this, cscGetNextResolution, &cachedVDResolution))
1542                && (cachedVDResolution.csDisplayModeID != modeID)
1543                && ((SInt32) cachedVDResolution.csDisplayModeID > 0))
1544            {
1545                cachedVDResolution.csPreviousDisplayModeID = cachedVDResolution.csDisplayModeID;
1546            }
1547        }
1548    }
1549
1550    if (cachedVDResolution.csDisplayModeID != modeID)
1551    {
1552        cachedVDResolution.csDisplayModeID = kDisplayModeIDInvalid;
1553        return (kIOReturnUnsupportedMode);
1554    }
1555    else
1556    {
1557        info->nominalWidth  = cachedVDResolution.csHorizontalPixels;
1558        info->nominalHeight = cachedVDResolution.csVerticalLines;
1559        info->refreshRate   = cachedVDResolution.csRefreshRate;
1560
1561        info->maxDepthIndex = mapDepthIndex(modeID, kDepthMode6, true);
1562//      DEBG(thisName, " %x maxDepthIndex %x\n", modeID, info->maxDepthIndex);
1563
1564        return (noErr);
1565    }
1566}
1567
1568IOReturn IONDRVFramebuffer::setDetailedTiming(
1569    IODisplayModeID mode, IOOptionBits options,
1570    void * _desc, IOByteCount descripSize )
1571{
1572    IOReturn                        err;
1573    VDResolutionInfoRec             info;
1574    IODetailedTimingInformationV2 * desc = (IODetailedTimingInformationV2 *)_desc;
1575    VDDetailedTimingRec             look;
1576    VDDetailedTimingRec             newTiming;
1577    VDSwitchInfoRec                 switchInfo;
1578    IOIndex                         index;
1579    UInt32                          checkCurrent;
1580    UInt32                          checkBoot;
1581    bool                            notPreflight = (0 == (options & kModePreflight));
1582    bool                            hasScale;
1583
1584    index = arbMode2Index(mode);
1585
1586    bzero( &look, sizeof( VDDetailedTimingRec) );
1587    look.csTimingSize = sizeof32( VDDetailedTimingRec);
1588
1589    // current must be ok
1590    if ((mode == currentDisplayMode)
1591            && notPreflight
1592        && (detailedTimingsCurrent[index] == detailedTimingsSeed))
1593    {
1594            return (kIOReturnSuccess);
1595    }
1596
1597    err = _doStatus( this, cscGetCurMode, &switchInfo );
1598    if ((err == noErr) && (switchInfo.csData == kDisplayModeIDBootProgrammable))
1599        checkBoot = (UInt32) kDisplayModeIDBootProgrammable;
1600    else
1601        checkBoot = 0xffffffff;
1602    checkCurrent = (UInt32) currentDisplayMode;
1603
1604    // look for a programmable
1605    for (
1606        info.csPreviousDisplayModeID = kDisplayModeIDFindFirstProgrammable;
1607        (noErr == (err = _doStatus(this, cscGetNextResolution, &info)));
1608        info.csPreviousDisplayModeID = info.csDisplayModeID)
1609    {
1610        if ((SInt32) info.csDisplayModeID < 0)
1611        {
1612            err = kIOReturnNoResources;
1613            break;
1614        }
1615
1616        look.csDisplayModeID = info.csDisplayModeID;
1617        err = _doStatus( this, cscGetDetailedTiming, &look );
1618        if (err != kIOReturnSuccess)
1619            continue;
1620
1621        // don't toss current
1622        if (look.csDisplayModeAlias == checkCurrent)
1623        {
1624            checkCurrent = 0xffffffff;
1625            continue;
1626        }
1627        // don't toss kDisplayModeIDBootProgrammable if the driver is in that mode
1628        if (look.csDisplayModeAlias == checkBoot)
1629        {
1630            checkBoot = 0xffffffff;
1631            continue;
1632        }
1633
1634        // see if already set to the right timing
1635        if ((look.csDisplayModeAlias == (UInt32) mode)
1636                && (look.csDisplayModeState == kDMSModeReady)
1637                && (notPreflight)
1638                && (detailedTimingsCurrent[index] == detailedTimingsSeed))
1639            break;
1640
1641        // set it free
1642        if (look.csDisplayModeState != kDMSModeFree)
1643        {
1644            look.csDisplayModeID    = info.csDisplayModeID;
1645            look.csDisplayModeAlias = 0;
1646            look.csDisplayModeState = kDMSModeFree;
1647            err = _doControl( this, cscSetDetailedTiming, &look );
1648            if (err != kIOReturnSuccess)
1649                continue;
1650        }
1651
1652        // set it
1653        hasScale = (desc->horizontalScaled && desc->verticalScaled);
1654
1655
1656        newTiming = *((VDDetailedTimingRec *) desc);
1657        newTiming.csTimingSize       = sizeof32(VDDetailedTimingRec);
1658        newTiming.csDisplayModeID    = info.csDisplayModeID;
1659        newTiming.csDisplayModeAlias = mode;
1660        newTiming.csDisplayModeSeed  = look.csDisplayModeSeed;
1661        newTiming.csDisplayModeState = hasScale ? kDMSModeNotReady : kDMSModeReady;
1662        err = _doControl( this, cscSetDetailedTiming, &newTiming );
1663
1664        if (hasScale && (kIOReturnSuccess == err))
1665        {
1666            VDScalerRec scaler;
1667
1668            // set scale
1669            bzero( &scaler, sizeof( scaler));
1670            scaler.csScalerSize       = sizeof32( scaler);
1671            scaler.csScalerFlags      = desc->scalerFlags;
1672            scaler.csHorizontalPixels = desc->horizontalScaled;
1673            scaler.csVerticalPixels   = desc->verticalScaled;
1674            scaler.csHorizontalInset  = desc->horizontalScaledInset;
1675            scaler.csVerticalInset    = desc->verticalScaledInset;
1676            scaler.csDisplayModeID    = info.csDisplayModeID;
1677            scaler.csDisplayModeSeed  = newTiming.csDisplayModeSeed;
1678            scaler.csDisplayModeState = kDMSModeReady;
1679
1680            err = _doControl( this, cscSetScaler, &scaler );
1681
1682            newTiming.csDisplayModeSeed  = scaler.csDisplayModeSeed;
1683        }
1684
1685        if (kIOReturnSuccess == err)
1686        {
1687            err = _doStatus( this, cscGetDetailedTiming, &newTiming );
1688
1689            if (!notPreflight && (kIOReturnSuccess == err))
1690            {
1691                desc->signalConfig              = newTiming.csSignalConfig;
1692                desc->signalLevels              = newTiming.csSignalLevels;
1693
1694                desc->pixelClock                = newTiming.csPixelClock;
1695                desc->minPixelClock             = newTiming.csMinPixelClock;
1696                desc->maxPixelClock             = newTiming.csMaxPixelClock;
1697
1698                desc->horizontalActive          = newTiming.csHorizontalActive;
1699                desc->horizontalBlanking        = newTiming.csHorizontalBlanking;
1700                desc->horizontalSyncOffset      = newTiming.csHorizontalSyncOffset;
1701                desc->horizontalSyncPulseWidth  = newTiming.csHorizontalSyncPulseWidth;
1702
1703                desc->verticalActive            = newTiming.csVerticalActive;
1704                desc->verticalBlanking          = newTiming.csVerticalBlanking;
1705                desc->verticalSyncOffset        = newTiming.csVerticalSyncOffset;
1706                desc->verticalSyncPulseWidth    = newTiming.csVerticalSyncPulseWidth;
1707
1708                desc->horizontalBorderLeft      = newTiming.csHorizontalBorderLeft;
1709                desc->horizontalBorderRight     = newTiming.csHorizontalBorderRight;
1710                desc->verticalBorderTop         = newTiming.csVerticalBorderTop;
1711                desc->verticalBorderBottom      = newTiming.csVerticalBorderBottom;
1712
1713                desc->horizontalSyncConfig      = newTiming.csHorizontalSyncConfig;
1714                desc->horizontalSyncLevel       = newTiming.csHorizontalSyncLevel;
1715                desc->verticalSyncConfig        = newTiming.csVerticalSyncConfig;
1716                desc->verticalSyncLevel         = newTiming.csVerticalSyncLevel;
1717            }
1718        }
1719        if (notPreflight && (kIOReturnSuccess == err))
1720            detailedTimingsCurrent[index] = detailedTimingsSeed;
1721
1722        break;
1723    }
1724
1725    return (err);
1726}
1727
1728IOReturn IONDRVFramebuffer::validateDisplayMode(
1729    IODisplayModeID _mode, IOOptionBits flags,
1730    VDDetailedTimingRec ** detailed )
1731{
1732    UInt32              mode = _mode;
1733    IOReturn            err = kIOReturnSuccess;
1734    OSData *            data;
1735    const void *        bytes;
1736
1737    if (detailed)
1738        *detailed = (VDDetailedTimingRec *) 0;
1739
1740    if (mode >= (UInt32) kDisplayModeIDReservedBase)
1741    {
1742        do
1743        {
1744            if (mode == (UInt32) kDisplayModeIDBootProgrammable)
1745                continue;
1746
1747            err = kIOReturnBadArgument;
1748            if (!detailedTimings)
1749                continue;
1750
1751            data = OSDynamicCast( OSData, detailedTimings->getObject(
1752                                      arbMode2Index(mode)));
1753            if (!data)
1754                continue;
1755
1756            bytes = data->getBytesNoCopy();
1757            err = setDetailedTiming( mode, 0, (void *) bytes, data->getLength() );
1758            if (err != kIOReturnSuccess)
1759                continue;
1760
1761            if (detailed)
1762                *detailed = (VDDetailedTimingRec *) bytes;
1763        }
1764        while (false);
1765    }
1766
1767    if (err)
1768        DEBG(thisName, " failed (%x) %x\n", (int32_t) mode, err);
1769
1770    return (err);
1771}
1772
1773void IONDRVFramebuffer::getCurrentConfiguration( void )
1774{
1775    IOReturn            err;
1776    VDSwitchInfoRec     switchInfo;
1777    VDTimingInfoRec     timingInfo;
1778    VDGrayRecord        grayRec;
1779
1780    grayRec.csMode = 0;                 // turn off luminance map
1781    err = _doControl( this, cscSetGray, &grayRec );
1782    // driver refused => mono display
1783    grayMode = ((noErr == err) && (0 != grayRec.csMode));
1784
1785#if 0
1786    VDPageInfo          pageInfo;
1787    if (noErr == _doStatus(this, cscGetMode, &pageInfo))
1788    {
1789        _doControl( this, cscSetMode, &pageInfo);
1790        _doControl( this, cscGrayPage, &pageInfo);
1791    }
1792#endif
1793
1794    err = _doStatus( this, cscGetCurMode, &switchInfo );
1795    if (err != noErr)
1796    {
1797        DEBG(thisName, " cscGetCurMode failed\n");
1798    }
1799    else
1800    {
1801        if ((kDisplayModeIDBootProgrammable != switchInfo.csData) || !currentDisplayMode)
1802        {
1803			currentDisplayMode = switchInfo.csData;
1804		}
1805        currentDepth       = mapDepthIndex(currentDisplayMode, (IOIndex) switchInfo.csMode, true);
1806        currentPage        = switchInfo.csPage;
1807
1808        timingInfo.csTimingMode   = currentDisplayMode;
1809        timingInfo.csTimingFormat = kDeclROMtables;
1810        err = _doStatus( this, cscGetModeTiming, &timingInfo );
1811        if ((noErr == err) && (kDeclROMtables == timingInfo.csTimingFormat))
1812            __private->currentModeTiming = timingInfo.csTimingData;
1813        else
1814            __private->currentModeTiming = timingInvalid;
1815
1816        mach_vm_address_t vAddr = (mach_vm_address_t) switchInfo.csBaseAddr;
1817        ppnum_t           page  = 0;
1818
1819
1820        if (!vramMemory)
1821            vramMemory = getVRAMRange();
1822
1823        if (vAddr)
1824        {
1825			if (vAddr & 1) page = atop_64(vAddr);
1826			else           page = pmap_find_phys(kernel_pmap, vAddr);
1827            if (!page) panic("pmap_find_phys %qx", vAddr);
1828            __private->physicalFramebuffer = ptoa_64(page) + (PAGE_MASK & vAddr & ~1);
1829        }
1830    }
1831}
1832
1833IOReturn IONDRVFramebuffer::setupForCurrentConfig( void )
1834{
1835	getCurrentConfiguration();
1836	return (super::setupForCurrentConfig());
1837}
1838
1839IODeviceMemory * IONDRVFramebuffer::makeSubRange(
1840    IOPhysicalAddress64   start,
1841    IOPhysicalLength64    length )
1842{
1843    IOMemoryDescriptor * mem = 0;
1844    UInt32               numMaps, i;
1845    IOService *          device;
1846
1847    device = nub;
1848    numMaps = device->getDeviceMemoryCount();
1849
1850    for (i = 0; (!mem) && (i < numMaps); i++)
1851    {
1852        mem = device->getDeviceMemoryWithIndex(i);
1853        if (!mem)
1854            continue;
1855
1856        mem = IOSubMemoryDescriptor::withSubRange(
1857                             mem,
1858                             start - mem->getPhysicalSegment(0, 0, kIOMemoryMapperNone),
1859                             length, kIODirectionNone);
1860    }
1861    if (!mem)
1862        mem = IOMemoryDescriptor::withAddressRange(
1863			start, length, kIODirectionNone | kIOMemoryMapperNone, NULL);
1864
1865    return ((IODeviceMemory *) mem);
1866}
1867
1868IODeviceMemory * IONDRVFramebuffer::getApertureRange( IOPixelAperture aper )
1869{
1870    IOReturn                    err;
1871    IOPixelInformation          info;
1872    IOByteCount                 bytes;
1873
1874    if (!__private->physicalFramebuffer)
1875        return (NULL);
1876
1877    err = getPixelInformation( currentDisplayMode, currentDepth, aper,
1878                               &info );
1879    if (err)
1880    {
1881        DEBG(thisName, " getPixelInformation(%x) 0x%x\n", err, (uint32_t )currentDisplayMode);
1882        return (NULL);
1883    }
1884
1885    bytes = (info.bytesPerRow * info.activeHeight) + 128;
1886
1887    return (makeSubRange(__private->physicalFramebuffer, bytes));
1888}
1889
1890IODeviceMemory * IONDRVFramebuffer::findVRAM( void )
1891{
1892    IOBootNDRV * bootndrv;
1893    if ((bootndrv = OSDynamicCast(IOBootNDRV, ndrv)))
1894    {
1895        bootndrv->fVRAMDesc->retain();
1896        return ((IODeviceMemory *) bootndrv->fVRAMDesc);
1897    }
1898
1899    return (NULL);
1900}
1901
1902const char * IONDRVFramebuffer::getPixelFormats( void )
1903{
1904    static const char * ndrvPixelFormats =
1905        IO1BitIndexedPixels "\0"
1906        IO2BitIndexedPixels "\0"
1907        IO4BitIndexedPixels "\0"
1908        IO8BitIndexedPixels "\0"
1909        IO16BitDirectPixels "\0"
1910        IO32BitDirectPixels "\0"
1911        "\0";
1912
1913    return (ndrvPixelFormats);
1914}
1915
1916IOItemCount IONDRVFramebuffer::getDisplayModeCount( void )
1917{
1918    return (iterateAllModes(0));
1919}
1920
1921IOReturn IONDRVFramebuffer::getDisplayModes( IODisplayModeID * allDisplayModes )
1922{
1923    iterateAllModes( allDisplayModes );
1924    return (kIOReturnSuccess);
1925}
1926
1927IOReturn IONDRVFramebuffer::validateDetailedTiming(
1928    void * _desc, IOByteCount descripSize )
1929{
1930    IOReturn err;
1931
1932    if (descripSize == sizeof(IOFBDisplayModeDescription))
1933    {
1934        IOFBDisplayModeDescription * desc = (IOFBDisplayModeDescription *) _desc;
1935        VDDetailedTimingRec *        detailed = (VDDetailedTimingRec *) &desc->timingInfo.detailedInfo.v2;
1936
1937        err = setDetailedTiming( kDisplayModeIDPreflight,
1938                                kModePreflight, detailed, sizeof(VDDetailedTimingRec));
1939
1940        if (kIOReturnSuccess == err)
1941            err = getResInfoForDetailed(kDisplayModeIDPreflight, detailed, &desc->info);
1942    }
1943    else
1944        err = setDetailedTiming( kDisplayModeIDPreflight,
1945                                 kModePreflight, _desc, descripSize);
1946
1947    return (err);
1948}
1949
1950IOReturn IONDRVFramebuffer::setDetailedTimings( OSArray * array )
1951{
1952    IOReturn    err;
1953    UInt32 *    newCurrent;
1954    IOItemCount newCount;
1955
1956    if (!array)
1957    {
1958        if (detailedTimings)
1959        {
1960            IODelete( detailedTimingsCurrent, UInt32, detailedTimings->getCount());
1961            detailedTimingsCurrent = 0;
1962        }
1963        removeProperty( kIOFBDetailedTimingsKey );
1964        detailedTimings = 0;
1965        detailedTimingsSeed++;
1966        return (kIOReturnSuccess);
1967    }
1968
1969    newCount = array->getCount();
1970    newCurrent = IONew(UInt32, newCount);
1971    if (newCurrent)
1972    {
1973        if (detailedTimings)
1974            IODelete( detailedTimingsCurrent, UInt32, detailedTimings->getCount());
1975        detailedTimingsCurrent = newCurrent;
1976        bzero( newCurrent, newCount * sizeof( UInt32));
1977        setProperty( kIOFBDetailedTimingsKey, array );  // retains
1978        detailedTimings = array;
1979        detailedTimingsSeed++;
1980
1981//      if (((UInt32) currentDisplayMode) >= ((UInt32) kDisplayModeIDReservedBase))
1982        if (currentDisplayMode == kDisplayModeIDBootProgrammable)
1983        {
1984            VDDetailedTimingRec                 look;
1985            VDScalerRec                         scaler;
1986            IODetailedTimingInformationV2 *     detailed;
1987            OSData *                            data;
1988            IODisplayModeID                     newDisplayMode;
1989            bool                                bootScaled;
1990
1991            newDisplayMode = currentDisplayMode;
1992
1993            bzero( &look, sizeof( VDDetailedTimingRec) );
1994            look.csTimingSize = sizeof32( VDDetailedTimingRec);
1995            look.csDisplayModeID = currentDisplayMode;
1996            err = _doStatus( this, cscGetDetailedTiming, &look );
1997
1998            bzero( &scaler, sizeof( VDScalerRec) );
1999            scaler.csScalerSize = sizeof32( VDScalerRec);
2000            scaler.csDisplayModeID = currentDisplayMode;
2001            bootScaled = (noErr == _doStatus( this, cscGetScaler, &scaler ));
2002
2003            if (bootScaled
2004              && (scaler.csHorizontalPixels == look.csHorizontalActive)
2005              && (scaler.csVerticalPixels   == look.csVerticalActive)
2006              && (!(kIOScaleRotateFlags      & scaler.csScalerFlags))
2007              && (!scaler.csHorizontalInset)
2008              && (!scaler.csVerticalInset))
2009            {
2010                scaler.csHorizontalPixels = 0;
2011                scaler.csVerticalPixels   = 0;
2012                scaler.csScalerFlags      = 0;
2013            }
2014
2015            if (kIOReturnSuccess == err)
2016            {
2017                for (int i = 0;
2018                        (data = OSDynamicCast(OSData, detailedTimings->getObject(i)));
2019                        i++)
2020                {
2021                    detailed = (IODetailedTimingInformationV2 *) data->getBytesNoCopy();
2022
2023                    if ((detailed->horizontalActive != look.csHorizontalActive)
2024                            || (detailed->verticalActive != look.csVerticalActive))
2025                        continue;
2026
2027                    if (!bootScaled || (!scaler.csHorizontalPixels && !scaler.csVerticalPixels))
2028                    {
2029                        IOFixed1616 refreshRate1, refreshRate2;
2030                        refreshRate1 = DetailedRefreshRate(detailed);
2031                        refreshRate2 = DetailedRefreshRate((IODetailedTimingInformationV2 *) &look);
2032                        refreshRate1 = (refreshRate1 + 0x8000) >> 16;
2033                        refreshRate2 = (refreshRate2 + 0x8000) >> 16;
2034                        if (refreshRate1 != refreshRate2)
2035                            continue;
2036                    }
2037
2038                    if (bootScaled
2039                            && ((detailed->horizontalScaled      != scaler.csHorizontalPixels)
2040                             || (detailed->verticalScaled        != scaler.csVerticalPixels)
2041                             || (detailed->horizontalScaledInset != scaler.csHorizontalInset)
2042                             || (detailed->verticalScaledInset   != scaler.csVerticalInset)
2043                             || (detailed->scalerFlags           != scaler.csScalerFlags)))
2044                        continue;
2045
2046                    newDisplayMode = detailed->detailedTimingModeID;
2047                    break;
2048                }
2049            }
2050
2051            if (newDisplayMode != currentDisplayMode)
2052            {
2053                err = validateDisplayMode( newDisplayMode, 0, 0 );
2054                currentDisplayMode = newDisplayMode;
2055            }
2056        }
2057
2058        err = kIOReturnSuccess;
2059    }
2060    else
2061        err = kIOReturnNoMemory;
2062
2063    return (err);
2064}
2065
2066IOReturn IONDRVFramebuffer::getInformationForDisplayMode(
2067    IODisplayModeID displayMode, IODisplayModeInformation * info )
2068{
2069    IOReturn                    err;
2070
2071    err = getResInfoForMode( displayMode, info );
2072    if (err)
2073        err = kIOReturnUnsupportedMode;
2074
2075    return (err);
2076}
2077
2078
2079UInt64 IONDRVFramebuffer::getPixelFormatsForDisplayMode(
2080    IODisplayModeID /* displayMode */, IOIndex depthIndex )
2081{
2082    return (1 << depthIndex);
2083}
2084
2085IOReturn IONDRVFramebuffer::getPixelInformation(
2086    IODisplayModeID displayMode, IOIndex depth,
2087    IOPixelAperture aperture, IOPixelInformation * info )
2088{
2089    SInt32                      err;
2090    VDVideoParametersInfoRec    pixelParams;
2091    VPBlock                     pixelInfo;
2092    UInt32                      pixelType;
2093    const char *                pixelFormat;
2094
2095
2096    bzero( info, sizeof( *info));
2097
2098    if (aperture)
2099        return (kIOReturnUnsupportedMode);
2100
2101    err = validateDisplayMode( displayMode, 0, 0 );
2102    if (err)
2103        return (err);
2104
2105    do
2106    {
2107        pixelParams.csDisplayModeID = displayMode;
2108        pixelParams.csDepthMode     = mapDepthIndex(displayMode, depth, false);
2109        pixelParams.csVPBlockPtr    = &pixelInfo;
2110        err = _doStatus( this, cscGetVideoParameters, &pixelParams );
2111        if (err)
2112            continue;
2113
2114        info->flags             = accessFlags;
2115
2116        info->activeWidth       = pixelInfo.vpBounds.right;
2117        info->activeHeight      = pixelInfo.vpBounds.bottom;
2118#if __LP64__
2119        info->bytesPerRow       = pixelInfo.vpRowBytes;
2120#else
2121        info->bytesPerRow       = pixelInfo.vpRowBytes & 0x7fff;
2122#endif
2123        info->bytesPerPlane     = pixelInfo.vpPlaneBytes;
2124        info->bitsPerPixel      = pixelInfo.vpPixelSize;
2125
2126        switch (pixelInfo.vpPixelSize / 8)
2127        {
2128            default:
2129                pixelInfo.vpPixelSize = 8;
2130            case 0:
2131            case 1:
2132                strlcpy(info->pixelFormat, IO8BitIndexedPixels, sizeof(info->pixelFormat));
2133                info->pixelType = kIOCLUTPixels;
2134                info->componentMasks[0] = (1 << pixelInfo.vpPixelSize) - 1;
2135                info->bitsPerPixel = pixelInfo.vpPixelSize;
2136                info->componentCount = 1;
2137                info->bitsPerComponent = pixelInfo.vpPixelSize;
2138                break;
2139
2140            case 2:
2141                strlcpy(info->pixelFormat, IO16BitDirectPixels, sizeof(info->pixelFormat));
2142                info->pixelType = kIORGBDirectPixels;
2143                info->componentMasks[0] = 0x7c00;
2144                info->componentMasks[1] = 0x03e0;
2145                info->componentMasks[2] = 0x001f;
2146                info->bitsPerPixel = 16;
2147                info->componentCount = 3;
2148                info->bitsPerComponent = 5;
2149                break;
2150
2151            case 4:
2152            case 8:
2153                info->bitsPerPixel     = pixelInfo.vpPixelSize;
2154                info->componentCount   = pixelInfo.vpCmpCount;
2155                info->bitsPerComponent = pixelInfo.vpCmpSize;
2156
2157                pixelType = kIORGBDirectPixels;
2158                switch (pixelInfo.vpPixelType)
2159                {
2160                    case kIORGBSignedFloatingPointPixels:
2161                        pixelType = pixelInfo.vpPixelType;
2162                        if (info->bitsPerComponent == 16)
2163                            pixelFormat = kIO16BitFloatPixels;
2164                        else
2165                            pixelFormat = kIO32BitFloatPixels;
2166                        break;
2167
2168                    case kIORGBSignedDirectPixels:
2169                        pixelType = pixelInfo.vpPixelType;
2170                        // fall thru
2171                    default:
2172                        if (info->bitsPerComponent == 10)
2173                            pixelFormat = kIO30BitDirectPixels;
2174                        else if (info->bitsPerComponent == 16)
2175                            pixelFormat = kIO64BitDirectPixels;
2176                        else
2177                            pixelFormat = IO32BitDirectPixels;
2178                        break;
2179                }
2180
2181                strlcpy(info->pixelFormat, pixelFormat, sizeof(info->pixelFormat));
2182                info->pixelType = pixelType;
2183
2184                switch (info->bitsPerComponent)
2185                {
2186                    default:
2187                    case 8:
2188                        info->componentMasks[0] = 0x00ff0000;
2189                        info->componentMasks[1] = 0x0000ff00;
2190                        info->componentMasks[2] = 0x000000ff;
2191                        break;
2192
2193                    case 10:
2194                        info->componentMasks[0] = 0x3ff00000;
2195                        info->componentMasks[1] = 0x000ffc00;
2196                        info->componentMasks[2] = 0x000003ff;
2197                        break;
2198
2199                    case 16:
2200                        info->componentMasks[0] = 0x0000ffff;
2201//                      info->componentMasks[1] = 0x00000000;
2202
2203//                      info->componentMasks[2] = 0x00000000;
2204                        info->componentMasks[3] = 0xffff0000;
2205
2206//                      info->componentMasks[4] = 0x00000000;
2207                        info->componentMasks[5] = 0x0000ffff;
2208                        break;
2209
2210                    case 32:
2211//                      info->componentMasks[0]  = 0x00000000;
2212                        info->componentMasks[1]  = 0xffffffff;
2213//                      info->componentMasks[2]  = 0x00000000;
2214//                      info->componentMasks[3]  = 0x00000000;
2215
2216//                      info->componentMasks[4]  = 0x00000000;
2217//                      info->componentMasks[5]  = 0x00000000;
2218                        info->componentMasks[6]  = 0xffffffff;
2219//                      info->componentMasks[7]  = 0x00000000;
2220
2221//                      info->componentMasks[8]  = 0x00000000;
2222//                      info->componentMasks[9]  = 0x00000000;
2223//                      info->componentMasks[10] = 0x00000000;
2224                        info->componentMasks[11] = 0xffffffff;
2225                        break;
2226                }
2227                break;
2228        }
2229    }
2230    while (false);
2231
2232    return (err);
2233}
2234
2235IOReturn IONDRVFramebuffer::getTimingInfoForDisplayMode(
2236    IODisplayModeID displayMode, IOTimingInformation * info )
2237{
2238    VDTimingInfoRec             timingInfo;
2239
2240    OSStatus                    err;
2241
2242    err = validateDisplayMode( displayMode, 0, 0 );
2243    if (err)
2244        return (err);
2245
2246    timingInfo.csTimingMode = displayMode;
2247    // in case the driver doesn't do it:
2248    timingInfo.csTimingFormat = kDeclROMtables;
2249    err = _doStatus( this, cscGetModeTiming, &timingInfo);
2250    if (err == noErr)
2251    {
2252        if (timingInfo.csTimingFormat == kDeclROMtables)
2253            info->appleTimingID = timingInfo.csTimingData;
2254        else
2255            info->appleTimingID = timingInvalid;
2256
2257        if (info->flags & kIODetailedTimingValid)
2258        {
2259            VDDetailedTimingRec * look = (VDDetailedTimingRec *) &info->detailedInfo.v2;
2260            VDScalerRec           scaler;
2261
2262            bzero( look, sizeof( VDDetailedTimingRec) );
2263            look->csTimingSize = sizeof32( VDDetailedTimingRec);
2264            look->csDisplayModeID = displayMode;
2265            err = _doStatus( this, cscGetDetailedTiming, look );
2266            if (kIOReturnSuccess != err)
2267                info->flags &= ~kIODetailedTimingValid;
2268            else
2269            {
2270                bzero( &info->detailedInfo.v2.__reservedA[0], sizeof( info->detailedInfo.v2.__reservedA));
2271                bzero( &info->detailedInfo.v2.__reservedB[0], sizeof( info->detailedInfo.v2.__reservedB));
2272
2273                bzero( &scaler, sizeof( VDScalerRec) );
2274                scaler.csScalerSize = sizeof32( VDScalerRec);
2275                scaler.csDisplayModeID = displayMode;
2276                err = _doStatus( this, cscGetScaler, &scaler );
2277                if (kIOReturnSuccess == err)
2278                {
2279                    info->flags |= kIOScalingInfoValid;
2280                    info->detailedInfo.v2.scalerFlags           = scaler.csScalerFlags;
2281                    info->detailedInfo.v2.horizontalScaled      = scaler.csHorizontalPixels;
2282                    info->detailedInfo.v2.verticalScaled        = scaler.csVerticalPixels;
2283                    info->detailedInfo.v2.horizontalScaledInset = scaler.csHorizontalInset;
2284                    info->detailedInfo.v2.verticalScaledInset   = scaler.csVerticalInset;
2285                }
2286                else
2287                {
2288                    info->detailedInfo.v2.scalerFlags      = 0;
2289                    info->detailedInfo.v2.horizontalScaled = 0;
2290                    info->detailedInfo.v2.verticalScaled   = 0;
2291                }
2292            }
2293        }
2294
2295        return (kIOReturnSuccess);
2296    }
2297
2298    return (kIOReturnUnsupportedMode);
2299}
2300
2301IOReturn IONDRVFramebuffer::getCurrentDisplayMode(
2302    IODisplayModeID * displayMode, IOIndex * depth )
2303{
2304    if (displayMode)
2305        *displayMode = currentDisplayMode;
2306    if (depth)
2307        *depth = currentDepth;
2308
2309    return (kIOReturnSuccess);
2310}
2311
2312IOReturn IONDRVFramebuffer::setDisplayMode( IODisplayModeID displayMode, IOIndex depth )
2313{
2314    SInt32              err;
2315    VDSwitchInfoRec     switchInfo;
2316    VDPageInfo          pageInfo;
2317    VDTimingInfoRec     timingInfo;
2318    UInt32              timingID;
2319
2320    if (0 == powerState)
2321        return (kIOReturnNotReady);
2322
2323    timingInfo.csTimingMode   = displayMode;
2324    timingInfo.csTimingFormat = kDeclROMtables;
2325    err = _doStatus( this, cscGetModeTiming, &timingInfo );
2326    if ((noErr == err) && (kDeclROMtables == timingInfo.csTimingFormat))
2327        timingID = timingInfo.csTimingData;
2328    else
2329        timingID = timingInvalid;
2330
2331#if 1
2332    if (!online && (timingApple_0x0_0hz_Offline != timingID))
2333    {
2334        DEBG(thisName, " offline\n");
2335        return (kIOReturnSuccess);
2336    }
2337#endif
2338
2339    err = validateDisplayMode( displayMode, 0, 0 );
2340    if (err)
2341        return (err);
2342
2343    switchInfo.csData = displayMode;
2344    switchInfo.csMode = mapDepthIndex(displayMode, depth, false);
2345    switchInfo.csPage = 0;
2346    err = _doControl( this, cscSwitchMode, &switchInfo);
2347    if (err)
2348        DEBG(thisName, " %d: cscSwitchMode(0x%08x) %d\n",
2349              online, (int32_t) displayMode, (int) err);
2350
2351    // duplicate QD InitGDevice
2352    pageInfo.csMode = switchInfo.csMode;
2353    pageInfo.csData = 0;
2354    pageInfo.csPage = 0;
2355    _doControl( this, cscSetMode, &pageInfo);
2356
2357#if 0
2358    if (mirrored)
2359    {
2360        VDGammaRecord   gammaRec;
2361        OSStatus                gammaErr;
2362
2363        gammaErr = _doStatus( this, cscGetGamma, &gammaRec );
2364        if (noErr == gammaErr)
2365            _doControl( this, cscSetGamma, &gammaRec );
2366        else
2367            _doControl( this, cscGrayPage, &pageInfo);
2368    }
2369    else
2370        _doControl( this, cscGrayPage, &pageInfo);
2371#endif
2372
2373    return (err);
2374}
2375
2376IOReturn IONDRVFramebuffer::setStartupDisplayMode(
2377    IODisplayModeID displayMode, IOIndex depth )
2378{
2379    SInt32              err;
2380    VDSwitchInfoRec     switchInfo;
2381
2382    err = validateDisplayMode( displayMode, 0, 0 );
2383    if (err)
2384        return (err);
2385
2386    switchInfo.csData = displayMode;
2387    switchInfo.csMode = mapDepthIndex(displayMode, depth, false);
2388    err = _doControl( this, cscSavePreferredConfiguration, &switchInfo);
2389    return (err);
2390}
2391
2392IOReturn IONDRVFramebuffer::getStartupDisplayMode(
2393    IODisplayModeID * displayMode, IOIndex * depth )
2394{
2395    SInt32              err;
2396    VDSwitchInfoRec     switchInfo;
2397
2398    err = _doStatus( this, cscGetPreferredConfiguration, &switchInfo);
2399    if (err == noErr)
2400    {
2401        *displayMode = switchInfo.csData;
2402        *depth       = mapDepthIndex(switchInfo.csData, (IOIndex) switchInfo.csMode, true);
2403    }
2404    return (err);
2405}
2406
2407IOReturn IONDRVFramebuffer::setApertureEnable( IOPixelAperture /* aperture */,
2408        IOOptionBits /* enable */ )
2409{
2410    return (kIOReturnSuccess);
2411}
2412
2413IOReturn IONDRVFramebuffer::setCLUTWithEntries(
2414    IOColorEntry * colors, UInt32 index, UInt32 numEntries,
2415    IOOptionBits options )
2416{
2417    IOReturn            err;
2418    VDSetEntryRecord    setEntryRec;
2419    VDClutBehavior      clutSetting;
2420    VDGrayRecord        grayRec;
2421
2422    if (0 == powerState)
2423        return (kIOReturnSuccess);
2424
2425    if (options & kSetCLUTWithLuminance)
2426        grayRec.csMode = 1;             // turn on luminance map
2427    else
2428        grayRec.csMode = 0;             // turn off luminance map
2429
2430    if (grayRec.csMode != lastGrayMode)
2431    {
2432        _doControl( this, cscSetGray, &grayRec);
2433        lastGrayMode = grayRec.csMode;
2434    }
2435
2436    if (options & kSetCLUTImmediately)
2437        clutSetting = kSetClutAtSetEntries;
2438    else
2439        clutSetting = kSetClutAtVBL;
2440
2441    if (clutSetting != lastClutSetting)
2442    {
2443        _doControl( this, cscSetClutBehavior, &clutSetting);
2444        lastClutSetting = clutSetting;
2445    }
2446
2447    if (options & kSetCLUTByValue)
2448        setEntryRec.csStart = -1;
2449    else
2450        setEntryRec.csStart = index;
2451
2452    setEntryRec.csTable = (ColorSpec *) colors;
2453    setEntryRec.csCount = numEntries - 1;
2454    err = _doControl( this, cscSetEntries, &setEntryRec);
2455
2456    return (err);
2457}
2458
2459IOReturn IONDRVFramebuffer::setGammaTable(
2460        UInt32 channelCount, UInt32 dataCount,
2461        UInt32 dataWidth, void * data )
2462{
2463    IOReturn            err;
2464    VDClutBehavior      clutSetting;
2465    VDGammaRecord       gammaRec;
2466    GammaTbl *          table = (GammaTbl *) data;
2467
2468    if (0 == powerState)
2469        return (kIOReturnSuccess);
2470    if (!data)
2471        return (kIOReturnBadArgument);
2472
2473    if (__private->deferCLUTSet)
2474    {
2475        clutSetting = kSetClutAtSetEntries;
2476        if (clutSetting != lastClutSetting)
2477        {
2478            _doControl( this, cscSetClutBehavior, &clutSetting);
2479            lastClutSetting = clutSetting;
2480        }
2481    }
2482
2483    table->gVersion     = 0;
2484    table->gType        = 0;
2485    table->gFormulaSize = 0;
2486    table->gChanCnt     = channelCount;
2487    table->gDataCnt     = dataCount;
2488    table->gDataWidth   = dataWidth;
2489
2490    gammaRec.csGTable = (Ptr) table;
2491    err = _doControl( this, cscSetGamma, &gammaRec );
2492
2493    if (kIOReturnSuccess != err)
2494        DEBG(thisName, " cscSetGamma(%d, %d, %d) set: %d\n",
2495                (uint32_t) channelCount, (uint32_t) dataCount, (uint32_t) dataWidth, err);
2496
2497    return (err);
2498}
2499
2500IOReturn IONDRVFramebuffer::setMirror( IONDRVFramebuffer * other )
2501{
2502    IOReturn            err = kIOReturnSuccess;
2503//    IONDRVFramebuffer * next;
2504    VDMirrorRec         mirror;
2505
2506    if (mirrored == (other != 0))
2507        return (kIOReturnSuccess);
2508
2509    if (!nextDependent)
2510        return (kIOReturnUnsupported);
2511//    if (other && (other != nextDependent))
2512//        return (kIOReturnUnsupported);
2513
2514    do
2515    {
2516        bzero( &mirror, sizeof( mirror));
2517        mirror.csMirrorSize = sizeof32(VDMirrorRec);
2518        mirror.csMirrorFlags = 0
2519                               | kMirrorCanMirrorMask
2520                               | kMirrorAreMirroredMask
2521                               | kMirrorUnclippedMirrorMask
2522                               | kMirrorClippedMirrorMask
2523                               | kMirrorHAlignCenterMirrorMask
2524                               | kMirrorVAlignCenterMirrorMask;
2525        MAKE_REG_ENTRY( (RegEntryID *)&mirror.csMirrorResultID, 0 );
2526        if (0 == other)
2527        {
2528            MAKE_REG_ENTRY( ((RegEntryID *)&mirror.csMirrorRequestID), 0 );
2529        }
2530        else
2531        {
2532            MAKE_REG_ENTRY( ((RegEntryID *)&mirror.csMirrorRequestID), other->getProvider() );
2533        }
2534
2535        err = _doControl( this, cscSetMirror, &mirror );
2536        if (err)
2537            continue;
2538
2539        mirrored = (other != 0);
2540//        if ((next = OSDynamicCast(IONDRVFramebuffer, nextDependent)))
2541//            next->setMirror( (other != 0) ? this : 0 );
2542    }
2543    while (false);
2544
2545    return (err);
2546}
2547
2548
2549IOReturn IONDRVFramebuffer::setAttribute( IOSelect attribute, uintptr_t _value )
2550{
2551    IOReturn            err = kIOReturnSuccess;
2552    IONDRVFramebuffer * other = 0;
2553    uintptr_t *         data = (uintptr_t *) _value;
2554    UInt32              value;
2555
2556    switch (attribute)
2557    {
2558        case kIOPowerStateAttribute:
2559            err = ndrvSetPowerState( (UInt32)_value );
2560            break;
2561
2562        case kIODriverPowerAttribute:
2563            err = ndrvSetPowerState( (UInt32)_value );
2564            break;
2565
2566        case kIOSystemPowerAttribute:
2567            switch (_value)
2568            {
2569              case kIOMessageSystemWillPowerOff:
2570                if ((kIODVIPowerEnableFlag & __private->displayConnectFlags) && powerState)
2571                {
2572                    err = ndrvGetSetFeature( kDVIPowerSwitchFeature, 0, NULL );
2573                    if (kIOReturnSuccess == err)
2574                        IOSleep( kDVIPowerSwitchPowerOffDelay );
2575                }
2576                /* fall thru */
2577              case kIOMessageSystemWillRestart:
2578                if (ndrvState && powerState)
2579                {
2580                    IONDRVControlParameters pb;
2581
2582                    err = doDriverIO( 0, &pb,
2583                                    kIONDRVCloseCommand, kIONDRVImmediateIOCommandKind );
2584                    err = doDriverIO( 0, nub,
2585                                    kIONDRVFinalizeCommand, kIONDRVImmediateIOCommandKind );
2586                    ndrvState = 0;
2587
2588                    DEBG(thisName, " kIOSystemPowerAttribute finalize(%d)\n", err);
2589                }
2590            }
2591            err = kIOReturnSuccess;
2592            break;
2593
2594        case kIOFBSpeedAttribute:
2595            __private->reducedSpeed = (UInt32) _value;
2596            if (powerState)
2597                err = ndrvUpdatePowerState();
2598            break;
2599
2600        case kIOMirrorAttribute:
2601
2602            do
2603            {
2604                value = data[0] & 1;
2605                if (value)
2606                {
2607                    other = OSDynamicCast( IONDRVFramebuffer, (OSObject *) data[1] );
2608                    if (!other)
2609                    {
2610                        err = kIOReturnBadArgument;
2611                        continue;
2612                    }
2613                }
2614
2615                err = setMirror( other );
2616                if (kIOReturnSuccess != err)
2617                    continue;
2618
2619                OSNumber * num = OSDynamicCast(OSNumber, getProperty(kIOFBDependentIndexKey));
2620                mirrorPrimary = mirrored && (!num || (1 == num->unsigned32BitValue()));
2621
2622//                (void) setDisplayMode( currentDisplayMode, currentDepth );
2623            }
2624            while (false);
2625
2626            break;
2627
2628        default:
2629            err = super::setAttribute( attribute, _value );
2630    }
2631
2632    return (err);
2633}
2634
2635IOReturn IONDRVFramebuffer::getAttribute( IOSelect attribute, uintptr_t * value )
2636{
2637    IOReturn                    err = kIOReturnSuccess;
2638    VDSupportsHardwareCursorRec hwCrsrSupport;
2639    VDMirrorRec                 mirror;
2640    IONDRVFramebuffer *         other;
2641
2642    switch (attribute)
2643    {
2644        case kIOHardwareCursorAttribute:
2645
2646            UInt32 flags;
2647
2648            hwCrsrSupport.csReserved1 = 0;
2649            hwCrsrSupport.csReserved2 = 0;
2650            flags = ((kIOReturnSuccess == _doStatus( this, cscSupportsHardwareCursor, &hwCrsrSupport))
2651                        && true && (hwCrsrSupport.csSupportsHardwareCursor))
2652                        ? kIOFBHWCursorSupported : 0;
2653            if (flags)
2654                flags |= (hwCrsrSupport.csReserved1 & ~kIOFBHWCursorSupported);
2655            *value = flags;
2656            break;
2657
2658        case kIODeferCLUTSetAttribute:
2659
2660            *value = __private->deferCLUTSet;
2661            break;
2662
2663        case kIOMirrorAttribute:
2664
2665            bzero( &mirror, sizeof( mirror));
2666            mirror.csMirrorSize = sizeof32(VDMirrorRec);
2667
2668            other = OSDynamicCast( IONDRVFramebuffer, (OSObject *) value[0] );
2669            if (other)
2670            {
2671                MAKE_REG_ENTRY( ((RegEntryID *)&mirror.csMirrorRequestID), other->getProvider() );
2672            }
2673            else
2674            {
2675                MAKE_REG_ENTRY( ((RegEntryID *)&mirror.csMirrorRequestID), 0 );
2676            }
2677            err = _doStatus( this, cscGetMirror, &mirror );
2678            value[0] = mirror.csMirrorSupportedFlags;
2679
2680            if (kIOReturnSuccess == err)
2681            {
2682                OSNumber * num = OSDynamicCast(OSNumber, getProperty(kIOFBDependentIndexKey));
2683                if (!num || (1 == num->unsigned32BitValue()))
2684                    value[0] |= kIOMirrorIsPrimary;
2685
2686                if (kMirrorClippedMirrorMask & mirror.csMirrorSupportedFlags)
2687                    value[0] |= kIOMirrorHWClipped;
2688
2689                do
2690                {
2691                    VDVideoParametersInfoRec    pixelParams;
2692                    VPBlock                     pixelInfo;
2693                    IODisplayModeInformation    modeInfo;
2694                    IOReturn                    err;
2695
2696                    pixelParams.csDisplayModeID = currentDisplayMode;
2697                    pixelParams.csDepthMode     = mapDepthIndex(currentDisplayMode, currentDepth, false);
2698                    pixelParams.csVPBlockPtr    = &pixelInfo;
2699                    err = _doStatus( this, cscGetVideoParameters, &pixelParams );
2700                    if (err)
2701                        continue;
2702                    err = getResInfoForMode( currentDisplayMode, &modeInfo );
2703                    if (err)
2704                        continue;
2705                    if ((modeInfo.nominalWidth != (UInt32) pixelInfo.vpBounds.right)
2706                            || (modeInfo.nominalHeight != (UInt32) pixelInfo.vpBounds.bottom))
2707                        value[0] |= kIOMirrorHWClipped;
2708                }
2709                while (false);
2710
2711                DEBG(thisName, " kIOMirrorAttribute %08lx csMirrorSupportedFlags %08x, csMirrorFeatures %08x\n",
2712                     value[0], (uint32_t) mirror.csMirrorSupportedFlags, (uint32_t) mirror.csMirrorFeatures);
2713
2714                err = kIOReturnSuccess;
2715            }
2716            break;
2717
2718        case kIOMirrorDefaultAttribute:
2719            {
2720                IORegistryEntry   * entry;
2721                IORegistryEntry   * root;
2722                IONDRVFramebuffer * next;
2723                OSNumber *              num;
2724                OSData *                data = 0;
2725                enum { kIOMirrorHint = 0x10000 };
2726
2727                num = OSDynamicCast(OSNumber, getProperty("graphic-options"));
2728                if (num)
2729                    value[0] = num->unsigned32BitValue();
2730                else
2731                {
2732                    value[0] = 0;
2733
2734                    data = OSDynamicCast(OSData, nub->getProperty("graphic-options"));
2735                    if (!data && (root = IORegistryEntry::fromPath("/", gIODTPlane)))
2736                    {
2737                        data = OSDynamicCast(OSData, root->getProperty("graphic-options"));
2738                        root->release();
2739                    }
2740
2741                    if (data)
2742                        value[0] = *((UInt32 *) data->getBytesNoCopy());
2743                    else if ((entry = IORegistryEntry::fromPath("mac-io/battery", gIODTPlane))
2744                             || (entry = IORegistryEntry::fromPath("mac-io/via-pmu/battery", gIODTPlane)))
2745                    {
2746                        value[0] &= ~kIOMirrorDefault;
2747                        entry->release();
2748                    }
2749                    setProperty("graphic-options", value[0], 32);
2750                }
2751
2752                if (online
2753                        && (kIOMirrorDefault & value[0])
2754                        && (next = OSDynamicCast(IONDRVFramebuffer, nextDependent))
2755                        && next->getOnlineState())
2756                    value[0] |= kIOMirrorHint;
2757                err = kIOReturnSuccess;
2758                break;
2759            }
2760
2761        case kIOVRAMSaveAttribute:
2762            DEBG1(thisName, " kIOVRAMSaveAttribute on(%d), mirr(%d), prim(%d)\n",
2763                 online, mirrored, mirrorPrimary );
2764            *value = (online && (!mirrored || !mirrorPrimary));
2765            break;
2766
2767        default:
2768            err = super::getAttribute( attribute, value );
2769    }
2770
2771    return (err);
2772}
2773
2774UInt32 IONDRVFramebuffer::getConnectionCount( void )
2775{
2776    VDMultiConnectInfoRec       multiConnection;
2777
2778    multiConnection.csDisplayCountOrNumber = kGetConnectionCount;
2779    if (noErr == _doStatus(this, cscGetMultiConnect, &multiConnection))
2780        return (multiConnection.csDisplayCountOrNumber);
2781    else
2782        return (1);
2783}
2784
2785/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2786
2787IOReturn IONDRVFramebuffer::createI2C( void )
2788{
2789    IOReturn                    err;
2790    VDCommunicationInfoRec      commInfo;
2791    SInt32                      busID, minBus, maxBus;
2792    OSArray *                   array;
2793    OSDictionary *              dict;
2794    bool                        ok = false;
2795
2796    array = OSArray::withCapacity(1);
2797    if (!array)
2798        return (kIOReturnNoMemory);
2799
2800    do
2801    {
2802        bzero( &commInfo, sizeof( commInfo));
2803        commInfo.csBusID = kVideoDefaultBus;
2804
2805        err = _doStatus( this, cscGetCommunicationInfo, &commInfo );
2806        DEBG(thisName, " cscGetCommunicationInfo(%d): csBusType %x, csMinBus %x, csMaxBus %x\n"
2807              "csSupportedTypes %x, csSupportedCommFlags %x\n",
2808              err, (uint32_t) commInfo.csBusType,
2809              (uint32_t) commInfo.csMinBus, (uint32_t) commInfo.csMaxBus,
2810              (uint32_t) commInfo.csSupportedTypes, (uint32_t) commInfo.csSupportedCommFlags);
2811
2812        if (kIOReturnSuccess != err)
2813            continue;
2814
2815        minBus = commInfo.csMinBus;
2816        maxBus = commInfo.csMaxBus;
2817        if (maxBus < minBus)
2818            continue;
2819        for (busID = minBus;
2820                busID <= maxBus;
2821                busID++)
2822        {
2823            bzero(&commInfo, sizeof(commInfo));
2824            commInfo.csBusID = busID;
2825            err = _doStatus(this, cscGetCommunicationInfo, &commInfo);
2826            if (kIOReturnSuccess != err)
2827                break;
2828
2829            dict = OSDictionary::withCapacity(4);
2830            if (!dict)
2831                break;
2832
2833            setNumber(dict, kIOI2CInterfaceIDKey,        busID);
2834            setNumber(dict, kIOI2CBusTypeKey,            commInfo.csBusType);
2835            setNumber(dict, kIOI2CTransactionTypesKey,   commInfo.csSupportedTypes);
2836            setNumber(dict, kIOI2CSupportedCommFlagsKey, commInfo.csSupportedCommFlags);
2837            array->setObject(dict);
2838            dict->release();
2839        }
2840
2841        ok = (busID > maxBus);
2842    }
2843    while (false);
2844
2845    if (ok)
2846        setProperty(kIOFBI2CInterfaceInfoKey, array);
2847
2848    array->release();
2849
2850    return (kIOReturnSuccess);
2851}
2852
2853IOReturn IONDRVFramebuffer::doI2CRequest( UInt32 bus, IOI2CBusTiming * timing, IOI2CRequest * request )
2854{
2855    IOReturn            err;
2856    VDCommunicationRec  comm;
2857
2858    bzero( &comm, sizeof( comm));
2859
2860    do
2861    {
2862        comm.csBusID            = bus;
2863        comm.csCommFlags        = request->commFlags;
2864
2865        comm.csMinReplyDelay    = request->minReplyDelay * 1000;    // ms -> us
2866        if (comm.csMinReplyDelay)
2867            comm.csCommFlags    |= kVideoReplyMicroSecDelayMask;
2868
2869        if (kIOI2CUseSubAddressCommFlag & request->commFlags)
2870            comm.csSendAddress  = (request->sendAddress << 8) | request->sendSubAddress;
2871        else
2872            comm.csSendAddress  = request->sendAddress;
2873
2874        comm.csSendType         = request->sendTransactionType;
2875        comm.csSendBuffer       = (LogicalAddress) request->sendBuffer;
2876        comm.csSendSize         = request->sendBytes;
2877
2878        if (kIOI2CUseSubAddressCommFlag & request->commFlags)
2879            comm.csReplyAddress = (request->replyAddress << 8) | request->replySubAddress;
2880        else
2881            comm.csReplyAddress = request->replyAddress;
2882
2883        comm.csReplyType        = request->replyTransactionType;
2884        comm.csReplyBuffer      = (LogicalAddress) request->replyBuffer;
2885        comm.csReplySize        = request->replyBytes;
2886
2887        err = _doControl(this, cscDoCommunication, &comm);
2888    }
2889    while (false);
2890
2891    switch (err)
2892    {
2893        case kVideoI2CReplyPendingErr:
2894            err = kIOReturnNoCompletion;
2895            break;
2896        case kVideoI2CTransactionErr:
2897            err = kIOReturnNoDevice;
2898            break;
2899        case kVideoI2CBusyErr:
2900            err = kIOReturnBusy;
2901            break;
2902        case kVideoI2CTransactionTypeErr:
2903            err = kIOReturnUnsupportedMode;
2904            break;
2905        case kVideoBufferSizeErr:
2906            err = kIOReturnOverrun;
2907            break;
2908    }
2909
2910    request->result = err;
2911    if (request->completion)
2912        (*request->completion)(request);
2913
2914    err = kIOReturnSuccess;
2915
2916    return (err);
2917}
2918
2919/*
2920    File:       DDCPowerOnOffUtils.c <CS3>
2921*/
2922
2923enum{
2924    kVCPSendSize                        = 8,
2925    kVCPReplySize                       = 64,
2926    kI2CDisplayWriteAddress             = 0x6E,
2927    kI2CDisplayReadAddress              = 0x6F,
2928    // Messed up specification says checksum should be calculated with ACCESS.bus value of 50.
2929    kI2CDisplayReadHostCheckSumAddress  = 0x50,
2930    // Messed up specification says checksum should be calculated with ACCESS.bus value of 50.
2931    kI2CDisplayReadHostAddress          = 0x51,
2932
2933    kI2CVCPGetCode                      = 0x01,
2934    kI2CVCPGetLength                    = 0x82,
2935    kI2CVCPGetMessageSize               = 0x05,
2936
2937    kI2CVCPReplyLength                  = 0x88,
2938    kI2CNullReplyLength                 = 0x80,
2939    kI2CNullReplyCheckSum               = 0xBE,
2940
2941    kI2CVCPSetCode                      = 0x03,
2942    kI2CVCPSetLength                    = 0x84,
2943    kI2CVCPReplyCode                    = 0x02,
2944
2945    kDDCPowerOn                         = 0x01,
2946    kDDCPowerOff                        = 0x04
2947};
2948enum {
2949    kBasicI2CCommTransactionsMask = ( (1<<kVideoNoTransactionType) | (1<<kVideoSimpleI2CType)
2950                                      | (1<<kVideoDDCciReplyType) )
2951};
2952
2953void IONDRVFramebuffer::displayI2CPower( bool enable )
2954{
2955    VDCommunicationRec  i2CRecord;
2956    VDCommunicationInfoRec i2cInfoRecord;
2957    Byte                sendBuffer[8];
2958    Byte                replyBuffer[kVCPReplySize];
2959    UInt32              supportedCommFlags = 0;
2960    // Don't do it if we're told it's not supported
2961    bool                setThisDisplay = true;
2962
2963    if (enable == __private->i2cPowerState)
2964        return;
2965
2966    __private->i2cPowerState = enable;
2967
2968    //
2969    // Some displays (like Fiji) do not support the reading
2970    // of the current power state.  Others (like Mitsubishi
2971    // Diamond Pro 710) report that they do not support
2972    // power management calls.
2973    //
2974    // I'll avoid sending the power command only in the
2975    // case that I get a valid reply that does says
2976    // it does not support the power selector.
2977    //
2978
2979    bzero( &i2cInfoRecord, sizeof(i2cInfoRecord) );
2980    if (noErr != _doStatus(this, cscGetCommunicationInfo, &i2cInfoRecord))
2981        return ;
2982    if (kBasicI2CCommTransactionsMask != (i2cInfoRecord.csSupportedTypes & kBasicI2CCommTransactionsMask))
2983        return ;
2984
2985    supportedCommFlags = i2cInfoRecord.csSupportedCommFlags;
2986    bzero( &i2CRecord, sizeof(i2CRecord) );
2987    bzero( &sendBuffer, sizeof(sendBuffer) );
2988    bzero( &replyBuffer, sizeof(replyBuffer) );
2989
2990    sendBuffer[0]       = kI2CDisplayReadHostAddress;
2991    sendBuffer[1]       = kI2CVCPGetLength;
2992    sendBuffer[2]       = kI2CVCPGetCode;               // GetVCP command
2993    sendBuffer[3]       = 0xD6;
2994    sendBuffer[4]       = kI2CDisplayWriteAddress ^
2995                    sendBuffer[0] ^ sendBuffer[1] ^
2996                    sendBuffer[2] ^ sendBuffer[3];
2997
2998    i2CRecord.csBusID           = kVideoDefaultBus;
2999    i2CRecord.csSendType        = kVideoSimpleI2CType;
3000    i2CRecord.csSendAddress     = kI2CDisplayWriteAddress;
3001    i2CRecord.csSendBuffer      = &sendBuffer;
3002    i2CRecord.csSendSize        = 7;
3003    i2CRecord.csReplyType       = kVideoDDCciReplyType;
3004    i2CRecord.csReplyAddress    = kI2CDisplayReadAddress;
3005    i2CRecord.csReplyBuffer     = &replyBuffer;
3006    i2CRecord.csReplySize       = kVCPReplySize;
3007
3008    if (supportedCommFlags & kVideoReplyMicroSecDelayMask)
3009    {
3010        // We know some displays are slow, this is an important call to get right
3011        i2CRecord.csCommFlags   |= kVideoReplyMicroSecDelayMask;
3012        // 50 milliseconds should be enough time for the display to respond.
3013        i2CRecord.csMinReplyDelay = 50 * 1000;
3014    }
3015
3016    if ((noErr == _doControl(this, cscDoCommunication, &i2CRecord))
3017            && (kI2CDisplayWriteAddress == replyBuffer[0])
3018            && (kI2CVCPReplyLength == replyBuffer[1])
3019            && (kI2CVCPReplyCode == replyBuffer[2]))
3020    {
3021        Byte checkSum = kI2CDisplayReadHostCheckSumAddress ^    // host address
3022                        replyBuffer[0] ^        // source address
3023                        replyBuffer[1] ^        // message length (0x88)
3024                        replyBuffer[2] ^        // VCP type code
3025                        replyBuffer[3] ^        // result code
3026                        replyBuffer[4] ^        // VCP op code
3027                        replyBuffer[5] ^        // VCP type code
3028                        replyBuffer[6] ^        // Max value MSB
3029                        replyBuffer[7] ^        // Max value LSB
3030                        replyBuffer[8] ^        // Current value MSB
3031                        replyBuffer[9]; // Current value LSB
3032
3033        if ((checkSum == replyBuffer[10]) &&            // Did the check sum match AND
3034                (0 != replyBuffer[3]))          // Are we not supposed to support this feature?
3035            setThisDisplay = false;                     // Don't do it if we're told it's not supported
3036    }
3037
3038    if (setThisDisplay)
3039    {
3040        bzero( &i2CRecord, sizeof(i2CRecord) );
3041        bzero( &sendBuffer, sizeof(sendBuffer) );
3042        bzero( &replyBuffer, sizeof(replyBuffer) );
3043
3044        sendBuffer[0]   = kI2CDisplayReadHostAddress;
3045        sendBuffer[1]   = kI2CVCPSetLength;
3046        sendBuffer[2]   = kI2CVCPSetCode;                       // SetVCP command
3047        sendBuffer[3]   = 0xD6;
3048        sendBuffer[4]   = 0;                                    // MSB
3049        sendBuffer[5]   = enable ? kDDCPowerOn : kDDCPowerOff;  // LSB
3050        sendBuffer[6]   = kI2CDisplayWriteAddress ^
3051                        sendBuffer[0] ^ sendBuffer[1] ^
3052                        sendBuffer[2] ^ sendBuffer[3] ^
3053                        sendBuffer[4] ^ sendBuffer[5];
3054
3055        i2CRecord.csBusID               = kVideoDefaultBus;
3056        i2CRecord.csSendAddress         = kI2CDisplayWriteAddress;
3057        i2CRecord.csSendType            = kVideoSimpleI2CType;
3058        i2CRecord.csSendBuffer          = &sendBuffer;
3059        i2CRecord.csSendSize            = 7;
3060        i2CRecord.csReplyType           = kVideoNoTransactionType;
3061        i2CRecord.csReplyAddress        = 0;
3062        i2CRecord.csReplyBuffer         = 0;
3063        i2CRecord.csReplySize           = 0;
3064
3065        if (supportedCommFlags & kVideoReplyMicroSecDelayMask)
3066        {
3067            // We know some displays are slow, this is an important call to get right
3068            i2CRecord.csCommFlags |= kVideoReplyMicroSecDelayMask;
3069            // 50 milliseconds should be enough time for the display to respond.
3070            i2CRecord.csMinReplyDelay   = 50 * 1000;
3071        }
3072
3073        _doControl(this, cscDoCommunication, &i2CRecord);
3074    }
3075}
3076
3077bool IONDRVFramebuffer::getOnlineState( void )
3078{
3079    return (online);
3080}
3081
3082IOReturn IONDRVFramebuffer::ndrvGetSetFeature( UInt32 feature,
3083                                               uintptr_t newValue, uintptr_t * currentValue )
3084{
3085#define CHAR(c)    ((c) ? (char) (c) : '0')
3086#define FEAT(f)    CHAR(f>>24), CHAR(f>>16), CHAR(f>>8), CHAR(f>>0)
3087
3088    IOReturn err;
3089    VDConfigurationRec configRec;
3090
3091    bzero( &configRec, sizeof( configRec));
3092    configRec.csConfigFeature = feature;
3093
3094    DEBG(thisName, "(0x%08x '%c%c%c%c')\n", (int) feature, FEAT(feature));
3095
3096    TIMESTART();
3097    err = _doStatus( this, cscGetFeatureConfiguration, &configRec );
3098    TIMEEND(thisName, "cscGetFeatureConfiguration: '%c%c%c%c' %qd ms\n", FEAT(feature));
3099
3100    DEBG1(thisName, " cscGetFeatureConfiguration(%d), %08x %08lx %08lx %08lx\n", err,
3101         (uint32_t) configRec.csConfigSupport, configRec.csConfigValue, configRec.csReserved1, configRec.csReserved2);
3102
3103    if ((kIOReturnSuccess != err) || !configRec.csConfigSupport)
3104        err = kIOReturnUnsupported;
3105
3106    if (kIOReturnSuccess == err)
3107    {
3108        if (currentValue)
3109        {
3110            currentValue[0] = configRec.csConfigValue;
3111            currentValue[1] = configRec.csReserved1;
3112            currentValue[2] = configRec.csReserved2;
3113        }
3114        else if (configRec.csConfigValue != newValue)
3115        {
3116            configRec.csConfigFeature = feature;
3117            configRec.csConfigValue   = newValue;
3118            TIMESTART();
3119            err = _doControl( this, cscSetFeatureConfiguration, &configRec );
3120            TIMEEND(thisName, "cscSetFeatureConfiguration: '%c%c%c%c' = 0x%lx %qd ms\n",
3121                    FEAT(feature), newValue);
3122
3123            DEBG1(thisName, " cscSetFeatureConfiguration(%d) %08lx\n", err, configRec.csConfigValue);
3124        }
3125        else
3126            DEBG1(thisName, " skipped cscSetFeatureConfiguration(%d) %08lx\n", err, configRec.csConfigValue);
3127    }
3128
3129    return (err);
3130}
3131
3132IOReturn IONDRVFramebuffer::setConnectionFlags( void )
3133{
3134    if (kIODVIPowerEnableFlag & __private->displayConnectFlags)
3135        ndrvGetSetFeature( kDVIPowerSwitchFeature, kDVIPowerSwitchActiveMask, NULL );
3136
3137    shouldDoI2CPower |= (0 != ( kIOI2CPowerEnableFlag & __private->displayConnectFlags));
3138
3139    if (shouldDoI2CPower)
3140        displayI2CPower( (powerState == kIONDRVFramebufferPowerStateMax) );
3141
3142    return (kIOReturnSuccess);
3143}
3144
3145IOReturn IONDRVFramebuffer::setAttributeForConnection( IOIndex connectIndex,
3146        IOSelect attribute, uintptr_t value )
3147{
3148    IOReturn            err;
3149    VDSyncInfoRec       syncInfo;
3150
3151    // -- temp
3152    if (ndrvState == 0)
3153        return (kIOReturnNotOpen);
3154    if (!getControllerWorkLoop()->inGate())
3155    {
3156        if ((attribute != kConnectionProbe) && (attribute != 0x696772))
3157        {
3158            OSReportWithBacktrace("%s::setAttributeForConnection(0x%x) not gated\n",
3159                                    thisName, (int) attribute);
3160        }
3161        return (super::setAttributeForConnectionExt(connectIndex, attribute, value));
3162    }
3163    // --
3164
3165    switch (attribute)
3166    {
3167        case kConnectionPower:
3168            err = kIOReturnSuccess;
3169            break;
3170
3171        case kConnectionSyncEnable:
3172            syncInfo.csMode = (UInt8) (value >> 8);
3173            syncInfo.csFlags = (UInt8) (value & 0xFF);
3174            _doControl( this, cscSetSync, &syncInfo);
3175            err = kIOReturnSuccess;
3176            break;
3177
3178        case kConnectionFlags:
3179            __private->displayConnectFlags |= (UInt32) value;
3180            nub->setProperty(kIONDRVDisplayConnectFlagsKey,
3181                &__private->displayConnectFlags, sizeof32(__private->displayConnectFlags));
3182            err = setConnectionFlags();
3183            break;
3184
3185        case kConnectionProbe:
3186            DEBG1(thisName, " kConnectionProbe\n");
3187            err = _probeAction(this, (IOOptionBits) value);
3188            break;
3189
3190        default:
3191
3192            err = super::setAttributeForConnection( connectIndex,
3193                                                    attribute, value );
3194            if (kIOReturnUnsupported == err)
3195                err = ndrvGetSetFeature(attribute, value, NULL);
3196           break;
3197    }
3198
3199    return (err);
3200}
3201
3202bool IONDRVFramebuffer::searchOfflineMode( IODisplayModeID * offlineMode )
3203{
3204    VDResolutionInfoRec info;
3205    VDTimingInfoRec     timingInfo;
3206    bool                ret = false;
3207
3208    info.csPreviousDisplayModeID = kDisplayModeIDFindFirstResolution;
3209    while (
3210        (noErr == _doStatus(this, cscGetNextResolution, &info))
3211        && ((SInt32) info.csDisplayModeID > 0))
3212    {
3213        timingInfo.csTimingMode   = info.csDisplayModeID;
3214        timingInfo.csTimingFormat = kDeclROMtables;
3215        ret = _doStatus( this, cscGetModeTiming, &timingInfo);
3216
3217        if ((noErr == ret)
3218                && (kDeclROMtables == timingInfo.csTimingFormat)
3219                && (timingApple_0x0_0hz_Offline == timingInfo.csTimingData)
3220                && (kDisplayModeSafeFlag & timingInfo.csTimingFlags))
3221        {
3222            if (offlineMode)
3223                *offlineMode = info.csDisplayModeID;
3224            ret = true;
3225            break;
3226        }
3227        info.csPreviousDisplayModeID = info.csDisplayModeID;
3228    }
3229
3230    return (ret);
3231}
3232
3233IOReturn IONDRVFramebuffer::processConnectChange( uintptr_t * value )
3234{
3235    IOReturn  ret;
3236    uintptr_t connectEnabled;
3237
3238    DEBG(thisName, "\n");
3239
3240    ret = getAttributeForConnection( 0, kConnectionCheckEnable, &connectEnabled );
3241
3242    setDetailedTimings( 0 );
3243    removeProperty( kIOFBConfigKey );
3244    __private->displayConnectFlags     = 0;
3245    __private->i2cPowerState           = 0;
3246    shouldDoI2CPower                   = 0;
3247    cachedVDResolution.csDisplayModeID = kDisplayModeIDInvalid;
3248    __private->depthMapModeID          = kDisplayModeIDInvalid;
3249
3250    setInfoProperties();
3251    if (mirrored)
3252        setMirror( 0 );
3253
3254    IODisplayModeID offlineMode;
3255    if (!online
3256            && searchOfflineMode(&offlineMode)
3257            && (offlineMode != currentDisplayMode))
3258    {
3259        setDisplayMode( offlineMode, currentDepth );
3260    }
3261
3262    __private->ackConnectChange = false;
3263
3264    ret = kIOReturnSuccess;
3265
3266    return (ret);
3267}
3268
3269IOReturn IONDRVFramebuffer::getAttributeForConnection( IOIndex connectIndex,
3270        IOSelect attribute, uintptr_t * value )
3271{
3272    IOReturn                      ret, thisRet;
3273    UInt32                        thisCount = 0;
3274    VDSyncInfoRec                 syncInfo;
3275    VDConfigurationFeatureListRec featureList;
3276
3277    switch (attribute)
3278    {
3279        case kConnectionSyncFlags:
3280            // find out current state of sync lines
3281            syncInfo.csMode = 0x00;
3282            _doStatus( this, cscGetSync, &syncInfo);
3283            *value = syncInfo.csMode;
3284            ret = kIOReturnSuccess;
3285            break;
3286
3287        case kConnectionSyncEnable:
3288            // what are the sync-controlling capabilities of the ndrv?
3289            syncInfo.csMode = 0xFF;
3290            _doStatus( this, cscGetSync, &syncInfo);
3291            *value = (UInt32) syncInfo.csMode;
3292            ret = kIOReturnSuccess;
3293            break;
3294
3295        case kConnectionSupportsHLDDCSense:
3296        case kConnectionSupportsAppleSense:
3297            ret = kIOReturnSuccess;
3298            break;
3299
3300        case kConnectionFlags:
3301            VDMultiConnectInfoRec multiConnect;
3302            if (connectIndex == 0)
3303                ret = _doStatus( this, cscGetConnection, &multiConnect.csConnectInfo);
3304            else
3305            {
3306                multiConnect.csDisplayCountOrNumber = connectIndex;
3307                ret = _doStatus( this, cscGetMultiConnect, &multiConnect);
3308            }
3309            if (__private->removable)
3310                multiConnect.csConnectInfo.csConnectFlags &= ~(1<<kBuiltInConnection);
3311
3312            if (kIOReturnSuccess == ret)
3313                *value = multiConnect.csConnectInfo.csConnectFlags;
3314            else
3315                *value = 0;
3316            break;
3317
3318        case kConnectionCheckEnable:
3319
3320            if (connectIndex == 0)
3321                ret = _doStatus( this, cscGetConnection, &multiConnect.csConnectInfo);
3322            else
3323            {
3324                multiConnect.csDisplayCountOrNumber = connectIndex;
3325                ret = _doStatus( this, cscGetMultiConnect, &multiConnect);
3326            }
3327            if ((kIOReturnSuccess == ret)
3328                    && ((1 << kConnectionInactive) & multiConnect.csConnectInfo.csConnectFlags))
3329            {
3330                online = false;
3331                *value = online;
3332                break;
3333            }
3334            online = !searchOfflineMode( 0 );
3335            /* fall thru */
3336
3337        case kConnectionEnable:
3338
3339            *value = online;
3340            ret = kIOReturnSuccess;
3341            break;
3342
3343        case kConnectionPostWake:
3344            ret = kIOReturnSuccess;
3345            break;
3346
3347        case kConnectionChanged:
3348            if (value)
3349                ret = processConnectChange(value);
3350            else if (__private->postWakeProbe)
3351            {
3352                DEBG1(thisName, " kConnectionPostWake\n");
3353                ret = _doControl( this, cscProbeConnection, 0 );
3354                __private->postWakeProbe = false;
3355                if (!__private->ackConnectChange)
3356                    setConnectionFlags();
3357            } else
3358                ret = kIOReturnSuccess;
3359            break;
3360
3361        case kConnectionInTVMode:
3362
3363            switch (__private->currentModeTiming)
3364            {
3365                case timingAppleNTSC_ST:
3366                case timingAppleNTSC_FF:
3367                case timingAppleNTSC_STconv:
3368                case timingAppleNTSC_FFconv:
3369                    *value = kConnectionNTSCMode;
3370                    break;
3371                case timingApplePAL_ST:
3372                case timingApplePAL_FF:
3373                case timingApplePAL_STconv:
3374                case timingApplePAL_FFconv:
3375                    *value = kConnectionPALMode;
3376                    break;
3377
3378                default:
3379                    *value = kConnectionNonTVMode;
3380                    break;
3381            }
3382            ret = kIOReturnSuccess;
3383            break;
3384
3385        case kConnectionDisplayParameterCount:
3386
3387            bzero(&featureList, sizeof(featureList));
3388            TIMESTART();
3389            thisRet = _doStatus(this, cscGetFeatureList, &featureList);
3390            TIMEEND(thisName, "cscGetFeatureList: %qd ms\n");
3391            if (kIOReturnSuccess == thisRet)
3392                thisCount = featureList.csNumConfigFeatures;
3393
3394            ret = super::getAttributeForConnection( connectIndex, attribute, value );
3395            if (kIOReturnSuccess != ret)
3396            {
3397                *value = thisCount;
3398                ret = thisRet;
3399            }
3400            else
3401                *value += thisCount;
3402            break;
3403
3404        case kConnectionDisplayParameters:
3405
3406            bzero(&featureList, sizeof(featureList));
3407            featureList.csConfigFeatureList = (OSType *) value;
3408            featureList.csNumConfigFeatures = 0x7fff;
3409            thisRet = _doStatus(this, cscGetFeatureList, &featureList);
3410            if (kIOReturnSuccess == thisRet)
3411            {
3412                thisCount = featureList.csNumConfigFeatures;
3413                for (uint32_t idx = thisCount; idx > 0; idx--)
3414                    value[idx - 1] = ((OSType *)value)[idx - 1];
3415            }
3416
3417            ret = super::getAttributeForConnection( connectIndex,
3418                                                    attribute, value + thisCount );
3419            if (kIOReturnSuccess != ret)
3420                ret = thisRet;
3421            break;
3422
3423        default:
3424
3425            ret = super::getAttributeForConnection( connectIndex,
3426                                                    attribute, value );
3427            if (kIOReturnUnsupported == ret)
3428                ret = ndrvGetSetFeature(attribute, 0, value);
3429            break;
3430    }
3431
3432    return (ret);
3433}
3434
3435IOReturn IONDRVFramebuffer::getAppleSense( IOIndex  connectIndex,
3436        UInt32 * senseType,
3437        UInt32 * primary,
3438        UInt32 * extended,
3439        UInt32 * displayType )
3440{
3441    OSStatus            err;
3442    VDMultiConnectInfoRec       multiConnect;
3443    UInt32                      sense, extSense;
3444
3445    if (connectIndex == 0)
3446        err = _doStatus( this, cscGetConnection, &multiConnect.csConnectInfo);
3447    else
3448    {
3449        multiConnect.csDisplayCountOrNumber = connectIndex;
3450        err = _doStatus( this, cscGetMultiConnect, &multiConnect);
3451    }
3452    if (err)
3453        return (err);
3454
3455    if ((primary || extended)
3456            && (0 == ((1<<kReportsTagging) & multiConnect.csConnectInfo.csConnectFlags)))
3457
3458        err = kIOReturnUnsupported;
3459
3460    else
3461    {
3462        sense           = multiConnect.csConnectInfo.csConnectTaggedType;
3463        extSense        = multiConnect.csConnectInfo.csConnectTaggedData;
3464        // bug fixes for really old ATI driver
3465        if (sense == 0)
3466        {
3467            if (extSense == 6)
3468            {
3469                sense           = kRSCSix;
3470                extSense        = kESCSixStandard;
3471            }
3472            else if (extSense == 4)
3473            {
3474                sense           = kRSCFour;
3475                extSense        = kESCFourNTSC;
3476            }
3477        }
3478        if (primary)
3479            *primary = sense;
3480        if (extended)
3481            *extended = extSense;
3482        if (senseType)
3483            *senseType = (0 != ((1<<kTaggingInfoNonStandard) & multiConnect.csConnectInfo.csConnectFlags));
3484        if (displayType)
3485            *displayType = multiConnect.csConnectInfo.csDisplayType;
3486    }
3487    return (err);
3488}
3489
3490IOReturn IONDRVFramebuffer::connectFlags( IOIndex /* connectIndex */,
3491        IODisplayModeID displayMode, IOOptionBits * flags )
3492{
3493    VDTimingInfoRec             timingInfo;
3494    OSStatus                    err;
3495
3496    timingInfo.csTimingMode = displayMode;
3497    // in case the driver doesn't do it:
3498    timingInfo.csTimingFormat = kDeclROMtables;
3499    err = _doStatus( this, cscGetModeTiming, &timingInfo);
3500
3501    if (kDetailedTimingFormat == timingInfo.csTimingFormat)
3502        *flags = kDisplayModeValidFlag | kDisplayModeSafeFlag;
3503    else
3504        *flags = timingInfo.csTimingFlags;
3505
3506    return (err);
3507}
3508
3509
3510bool IONDRVFramebuffer::hasDDCConnect( IOIndex  connectIndex )
3511{
3512    OSStatus              err;
3513    VDMultiConnectInfoRec multiConnect;
3514    enum {                kNeedFlags = (1<<kReportsDDCConnection) | (1<<kHasDDCConnection) };
3515
3516    if (connectIndex == 0)
3517        err = _doStatus( this, cscGetConnection, &multiConnect.csConnectInfo);
3518    else
3519    {
3520        multiConnect.csDisplayCountOrNumber = connectIndex;
3521        err = _doStatus( this, cscGetMultiConnect, &multiConnect);
3522    }
3523    if (err)
3524        return (err);
3525
3526    return (forceReadEDID
3527            || (kNeedFlags == (multiConnect.csConnectInfo.csConnectFlags & kNeedFlags)));
3528}
3529
3530// I2C first year for Apple displays.
3531// Apple monitors older than this (and Manta)
3532// are never called with I2C commands
3533enum {
3534    kFirstAppleI2CYear  = 1999,
3535    kAppleVESAVendorID  = 0x0610
3536};
3537
3538struct EDID
3539{
3540    UInt8       header[8];
3541    UInt8       vendorProduct[4];
3542    UInt8       serialNumber[4];
3543    UInt8       weekOfManufacture;
3544    UInt8       yearOfManufacture;
3545    UInt8       version;
3546    UInt8       revision;
3547    UInt8       displayParams[5];
3548    UInt8       colorCharacteristics[10];
3549    UInt8       establishedTimings[3];
3550    UInt16      standardTimings[8];
3551    UInt8       descriptors[4][18];
3552    UInt8       extension;
3553    UInt8       checksum;
3554};
3555
3556static bool IsApplePowerBlock(UInt8 * theBlock)
3557{
3558    return (theBlock &&
3559            0x00000000          == *(UInt32 *)&theBlock[0] &&
3560            0x00                == theBlock[4] &&
3561            0x06                == theBlock[5] &&
3562            0x10                == theBlock[6]);
3563}
3564
3565IOReturn IONDRVFramebuffer::getDDCBlock( IOIndex /* connectIndex */,
3566        UInt32 blockNumber,
3567        IOSelect blockType,
3568        IOOptionBits options,
3569        UInt8 * data, IOByteCount * length )
3570
3571{
3572    OSStatus            err = 0;
3573    VDDDCBlockRec       ddcRec;
3574    IOByteCount         actualLength = *length;
3575
3576    if (forceReadEDID)
3577    {
3578        forceReadEDID = 0;
3579        options |= kDDCForceReadMask;
3580    }
3581
3582    ddcRec.ddcBlockNumber       = blockNumber;
3583    ddcRec.ddcBlockType         = blockType;
3584    ddcRec.ddcFlags             = options;
3585
3586    err = _doStatus( this, cscGetDDCBlock, &ddcRec);
3587
3588    if (err == noErr)
3589    {
3590        if (actualLength > kDDCBlockSize)
3591            actualLength = kDDCBlockSize;
3592        bcopy( ddcRec.ddcBlockData, data, actualLength);
3593        *length = actualLength;
3594
3595        if ((1 == blockNumber) && (kIODDCBlockTypeEDID == blockType)
3596                && (actualLength >= sizeof(EDID)))
3597            do
3598            {
3599                EDID * edid;
3600                UInt32 vendor;
3601                UInt32 product;
3602
3603                edid = (EDID *) data;
3604                vendor = (edid->vendorProduct[0] << 8) | edid->vendorProduct[1];
3605                product = (edid->vendorProduct[3] << 8) | edid->vendorProduct[2];
3606                if (kAppleVESAVendorID == vendor)
3607                {
3608                    if ((0x01F4 == product) || (0x9D02 == product) || (0x9216 == product))
3609                        continue;
3610                    if (edid->yearOfManufacture && ((edid->yearOfManufacture + 1990) < kFirstAppleI2CYear))
3611                        continue;
3612                }
3613                shouldDoI2CPower =    (IsApplePowerBlock( &edid->descriptors[1][0])
3614                                       || IsApplePowerBlock( &edid->descriptors[2][0])
3615                                       || IsApplePowerBlock( &edid->descriptors[3][0]));
3616
3617                if (shouldDoI2CPower)
3618                    __private->displayConnectFlags |= kIODVIPowerEnableFlag;
3619
3620                err = kIOReturnSuccess;
3621            }
3622            while (false);
3623    }
3624
3625    if (1 == blockNumber)
3626        DEBG(thisName, " i2cPower %d\n", shouldDoI2CPower);
3627
3628    return (err);
3629}
3630
3631/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3632// initForPM
3633//
3634/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3635
3636void IONDRVFramebuffer::initForPM( void )
3637{
3638    IOPMPowerState powerStates[ kIONDRVFramebufferPowerStateCount ] =
3639    {
3640        // version,
3641        // capabilityFlags, outputPowerCharacter, inputPowerRequirement,
3642        { 1, 0,              0,           0,           0, 0, 0, 0, 0, 0, 0, 0 },
3643        { 1, 0,                0,           IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 },
3644        { 1, IOPMDeviceUsable, IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 }
3645        // staticPower, unbudgetedPower, powerToAttain, timeToAttain, settleUpTime,
3646        // timeToLower, settleDownTime, powerDomainBudget
3647    };
3648    VDPowerStateRec sleepInfo;
3649    IOReturn err;
3650    bool dozeOnly;
3651
3652    dozeOnly = false;
3653    {
3654        sleepInfo.powerState = 0;
3655        sleepInfo.powerFlags = 0;
3656        sleepInfo.powerReserved1 = 0;
3657        sleepInfo.powerReserved2 = 0;
3658        // can this ndrv power off?
3659        err = _doStatus( this, cscGetPowerState, &sleepInfo);
3660        dozeOnly = ((kIOReturnSuccess != err)
3661                    || (0 == (kPowerStateSleepCanPowerOffMask & sleepInfo.powerFlags)));
3662    }
3663
3664    if (OSDynamicCast(IOBootNDRV, ndrv))
3665        dozeOnly = true;
3666
3667    if (dozeOnly)
3668    {
3669        powerStates[kNDRVFramebufferSleepState].capabilityFlags |= kIOPMPreventSystemSleep;
3670        powerStates[kNDRVFramebufferDozeState].capabilityFlags  |= kIOPMPreventSystemSleep;
3671        powerStates[kNDRVFramebufferWakeState].capabilityFlags  |= kIOPMPreventSystemSleep;
3672    }
3673
3674    // register ourselves with superclass policy-maker
3675    registerPowerDriver( this, powerStates, kIONDRVFramebufferPowerStateCount );
3676    // no sleep until children
3677    temporaryPowerClampOn();
3678    // not below doze until system sleep
3679    changePowerStateTo( kNDRVFramebufferDozeState );
3680}
3681
3682
3683/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3684// maxCapabilityForDomainState
3685//
3686// This simple device needs only power.  If the power domain is supplying
3687// power, the frame buffer can be on.  If there is no power it can only be off.
3688/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3689
3690unsigned long IONDRVFramebuffer::maxCapabilityForDomainState(
3691    IOPMPowerFlags domainState )
3692{
3693    if (domainState & IOPMPowerOn)
3694        return (kIONDRVFramebufferPowerStateMax);
3695    else
3696        return (kNDRVFramebufferSleepState);
3697}
3698
3699/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3700// initialPowerStateForDomainState
3701//
3702// The power domain may be changing state.  If power is on in the new
3703// state, that will not affect our state at all.  If domain power is off,
3704// we can attain only our lowest state, which is off.
3705/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3706
3707unsigned long IONDRVFramebuffer::initialPowerStateForDomainState(
3708    IOPMPowerFlags domainState )
3709{
3710    if (domainState & IOPMPowerOn)
3711        return (kIONDRVFramebufferPowerStateMax);
3712    else
3713        return (kNDRVFramebufferSleepState);
3714}
3715
3716
3717/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3718// powerStateForDomainState
3719//
3720// The power domain may be changing state.  If power is on in the new
3721// state, that will not affect our state at all.  If domain power is off,
3722// we can attain only our lowest state, which is off.
3723/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3724
3725unsigned long IONDRVFramebuffer::powerStateForDomainState(
3726    IOPMPowerFlags domainState )
3727{
3728    if (domainState & IOPMPowerOn)
3729        return (getPowerState());
3730    else
3731        return (kNDRVFramebufferSleepState);
3732}
3733
3734/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3735
3736IOReturn IONDRVFramebuffer::ndrvSetDisplayPowerState( UInt32 state )
3737{
3738    IOReturn            err;
3739    VDSyncInfoRec       syncInfo;
3740
3741    state = state ? true : false;
3742
3743    // what are the sync-controlling capabilities of the ndrv?
3744    syncInfo.csMode = 0xff;
3745    err = _doStatus( this, cscGetSync, &syncInfo );
3746    if (kIOReturnSuccess == err)
3747    {
3748        // pick new sync state
3749        if (state)
3750            syncInfo.csMode = kDPMSSyncOn;
3751        else
3752            syncInfo.csMode = kDPMSSyncOff;
3753        syncInfo.csFlags = kDPMSSyncMask;
3754        _doControl( this, cscSetSync, &syncInfo);
3755
3756        DEBG(thisName, " sync->%02x\n", syncInfo.csMode);
3757    }
3758
3759    if (shouldDoI2CPower)
3760    {
3761        displayI2CPower( state );
3762        DEBG(thisName, " i2c->%02x\n", state ? true : false);
3763    }
3764
3765    err = kIOReturnSuccess;
3766
3767    return (err);
3768}
3769
3770/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3771// ndrvSetPowerState
3772//
3773// Called by the superclass to turn the frame buffer on and off.
3774/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3775
3776IOReturn IONDRVFramebuffer::ndrvUpdatePowerState( void )
3777{
3778    IOReturn            err;
3779    VDPowerStateRec     sleepInfo;
3780    bool                supportsReducedPower;
3781
3782    super::handleEvent( kIOFBNotifyWillChangeSpeed, (void *)(uintptr_t) __private->reducedSpeed );
3783
3784    sleepInfo.powerState = 0;
3785    sleepInfo.powerFlags = 0;
3786    sleepInfo.powerReserved1 = 0;
3787    sleepInfo.powerReserved2 = 0;
3788
3789    err = _doStatus( this, cscGetPowerState, &sleepInfo);
3790
3791    supportsReducedPower = (kIOReturnSuccess == err) && (0 !=
3792                (( kPowerStateSupportsReducedPower1BitMask
3793                | kPowerStateSupportsReducedPower2BitMask
3794                | kPowerStateSupportsReducedPower3BitMask) & sleepInfo.powerFlags));
3795
3796    if (supportsReducedPower)
3797    {
3798        sleepInfo.powerFlags = (__private->reducedSpeed << 8);
3799        sleepInfo.powerReserved1 = kPowerStateSleepWakeNeedsProbeMask;
3800        sleepInfo.powerReserved2 = 0;
3801
3802        err = _doControl(this, cscSetPowerState, &sleepInfo);
3803    }
3804    else
3805        err = kIOReturnUnsupported;
3806
3807    super::handleEvent( kIOFBNotifyDidChangeSpeed, (void *)(uintptr_t) __private->reducedSpeed );
3808
3809    return (err);
3810}
3811
3812IOReturn IONDRVFramebuffer::ndrvSetPowerState( UInt32 newState )
3813{
3814    static const UInt32
3815    // [sleep][fromState][toState]
3816    states[2][kIONDRVFramebufferPowerStateCount][kIONDRVFramebufferPowerStateCount] =
3817    {
3818        {
3819            { 0, kAVPowerOff, kAVPowerOn },
3820            { kAVPowerOff, 0, kAVPowerOn },
3821            { kAVPowerOff, kAVPowerOff, 0 },
3822        }, {
3823            { 0, kHardwareWakeToDoze, kHardwareWake },
3824            { kHardwareSleep, 0, kAVPowerOn },
3825            { kHardwareSleep, kAVPowerSuspend, 0 }
3826        }
3827    };
3828
3829    IOReturn            err;
3830    UInt32              sleep = 0;
3831    UInt32              ndrvPowerState;
3832    UInt32              oldState;
3833    IOIndex             postEvent = 0;
3834    IOAGPDevice *       agpDev;
3835    IODTPlatformExpert * pe;
3836    bool                supportsReducedPower;
3837
3838    if (newState == powerState)
3839        return (kIOReturnSuccess);
3840
3841    if (newState > kIONDRVFramebufferPowerStateMax)
3842        newState = kIONDRVFramebufferPowerStateMax;
3843
3844    oldState = powerState;
3845
3846    if (kIONDRVFramebufferPowerStateMax == oldState)
3847    {
3848        super::handleEvent( kIOFBNotifyWillPowerOff );
3849        postEvent = kIOFBNotifyDidPowerOff;
3850        ndrvSetDisplayPowerState( false );
3851    }
3852    else if (kIONDRVFramebufferPowerStateMax == newState)
3853    {
3854        super::handleEvent( kIOFBNotifyWillPowerOn );
3855        postEvent = kIOFBNotifyDidPowerOn;
3856    }
3857
3858    if (kNDRVFramebufferSleepState == newState)
3859    {
3860        if (kIODVIPowerEnableFlag & __private->displayConnectFlags)
3861        {
3862            err = ndrvGetSetFeature( kDVIPowerSwitchFeature, 0, 0 );
3863            if (kIOReturnSuccess == err)
3864                IOSleep( kDVIPowerSwitchPowerOffDelay );
3865        }
3866
3867        IOMemoryDescriptor * vram;
3868        if ((vram = getVRAMRange()))
3869        {
3870            vram->redirect( kernel_task, true );
3871            vram->release();
3872        }
3873        // tell accelerators to protect HW also
3874        super::handleEvent( kIOFBNotifyWillSleep, (void *) true );
3875    }
3876
3877    if (platformSleep
3878            && !__private->removable
3879            && (pe = OSDynamicCast(IODTPlatformExpert, getPlatform()))
3880            && (pe->getChipSetType() < kChipSetTypeCore99))
3881    {
3882        VDSleepWakeInfo sleepInfo;
3883
3884        ndrvPowerState = newState ? vdWakeState : vdSleepState;
3885
3886        err = _doStatus( this, cscSleepWake, &sleepInfo);
3887
3888        powerState = newState;
3889
3890        if ((kIOReturnSuccess == err) && (sleepWakeSig == sleepInfo.csData)
3891                && (ndrvPowerState != sleepInfo.csMode))
3892        {
3893            sleepInfo.csMode = ndrvPowerState;
3894
3895            err = _doControl( this, cscSleepWake, &sleepInfo);
3896        }
3897    }
3898    else
3899    {
3900        VDPowerStateRec sleepInfo;
3901
3902        sleepInfo.powerState = 0;
3903        sleepInfo.powerFlags = 0;
3904        sleepInfo.powerReserved1 = 0;
3905        sleepInfo.powerReserved2 = 0;
3906
3907        err = _doStatus( this, cscGetPowerState, &sleepInfo);
3908
3909        if (((kIOReturnSuccess == err) && (kPowerStateSleepCanPowerOffMask & sleepInfo.powerFlags))
3910          || (platformSleep && !__private->removable))
3911            sleep = 1;
3912
3913        supportsReducedPower = (kIOReturnSuccess == err) && (0 !=
3914                    (( kPowerStateSupportsReducedPower1BitMask
3915                    | kPowerStateSupportsReducedPower2BitMask
3916                    | kPowerStateSupportsReducedPower3BitMask) & sleepInfo.powerFlags));
3917
3918        ndrvPowerState = states[sleep][oldState][newState];
3919
3920        if ((kHardwareWakeToDoze == ndrvPowerState)
3921                && (0 == (kPowerStateSleepWaketoDozeMask & sleepInfo.powerFlags)))
3922        {
3923        	DEBG1(thisName, " no kHardwareWakeToDoze support\n");
3924            ndrvPowerState = kHardwareWake;
3925		}
3926        else if (kAVPowerSuspend == ndrvPowerState)
3927        {
3928        }
3929
3930
3931        DEBG1(thisName, " idx %d powerFlags %08x, state->%02x\n",
3932             (uint32_t) newState, (uint32_t) sleepInfo.powerFlags, (uint32_t) ndrvPowerState);
3933
3934        powerState = newState;
3935
3936        if ((kIOReturnSuccess != err) || (sleepInfo.powerState != ndrvPowerState))
3937        {
3938            sleepInfo.powerState = ndrvPowerState;
3939
3940            if (supportsReducedPower)
3941                sleepInfo.powerFlags = (__private->reducedSpeed << 8);
3942            else
3943                sleepInfo.powerFlags = 0;
3944            sleepInfo.powerReserved1 = kPowerStateSleepWakeNeedsProbeMask;
3945            sleepInfo.powerReserved2 = 0;
3946
3947            err = _doControl( this, cscSetPowerState, &sleepInfo);
3948
3949            DEBG(thisName, " done powerFlags %08x\n", (uint32_t) sleepInfo.powerFlags);
3950
3951            if (kNDRVFramebufferSleepState == oldState)
3952                __private->postWakeProbe = (0 != (kPowerStateSleepWakeNeedsProbeMask & sleepInfo.powerFlags));
3953            else if (kNDRVFramebufferSleepState == newState)
3954                __private->postWakeProbe = false;
3955        }
3956    }
3957
3958    agpDev = OSDynamicCast(IOAGPDevice, device);
3959
3960    if (kNDRVFramebufferSleepState == oldState)
3961    {
3962        uintptr_t isOnline, wasOnline = online;
3963        if (__private->postWakeProbe)
3964            isOnline = wasOnline;
3965        else if (kIOReturnSuccess != getAttributeForConnection(0, kConnectionCheckEnable, &isOnline))
3966            isOnline = true;
3967        if (isOnline != wasOnline)
3968        {
3969            online = isOnline;
3970            // vramMemory = findVRAM();
3971            if (isOnline)
3972                getCurrentConfiguration();
3973        }
3974        if (agpDev)
3975            agpDev->resetAGP();
3976    }
3977
3978    if (kNDRVFramebufferSleepState == oldState)
3979    {
3980        IOMemoryDescriptor * vram;
3981        if ((vram = getVRAMRange()))
3982        {
3983            vram->redirect( kernel_task, false );
3984            vram->release();
3985        }
3986        // tell accelerators to unprotect HW also
3987        super::handleEvent( kIOFBNotifyDidWake, (void *) true );
3988    }
3989
3990    if (postEvent)
3991    {
3992        super::handleEvent( postEvent );
3993        if (kIOFBNotifyDidPowerOn == postEvent)
3994        {
3995            ndrvSetDisplayPowerState( true );
3996        }
3997    }
3998
3999    IONDRVFramebuffer * next;
4000    next = OSDynamicCast(IONDRVFramebuffer, nextDependent);
4001    if (true && next
4002            && ((newState > oldState)))
4003//                 /*|| ((newState == kNDRVFramebufferDozeState)&& !other->getOnlineState()*/)))
4004	{
4005		while (next && (next != this))
4006		{
4007		    next->ndrvSetPowerState( newState );
4008			next = OSDynamicCast(IONDRVFramebuffer, next->nextDependent);
4009		}
4010	}
4011
4012    if ((kNDRVFramebufferSleepState == oldState)
4013      && !__private->ackConnectChange
4014      && !__private->postWakeProbe)
4015        setConnectionFlags();
4016
4017    return (kIOReturnSuccess);
4018}
4019
4020/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4021
4022#undef super
4023#define super IONDRV
4024OSDefineMetaClassAndStructors(IOBootNDRV, IONDRV)
4025
4026/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4027
4028bool IOBootNDRV::getUInt32Property( IORegistryEntry * regEntry, const char * name,
4029                                    UInt32 * result )
4030{
4031    OSData * data;
4032
4033    data = OSDynamicCast(OSData, regEntry->getProperty(name));
4034    if (data)
4035        *result = *((UInt32 *) data->getBytesNoCopy());
4036
4037    return (data != 0);
4038}
4039
4040IONDRV * IOBootNDRV::fromRegistryEntry( IORegistryEntry * regEntry )
4041{
4042    IOBootNDRV *  inst;
4043    IOBootNDRV *  result = NULL;
4044    IOService *   device;
4045    IOByteCount   bytes;
4046
4047    inst = new IOBootNDRV;
4048    if (inst && !inst->init())
4049    {
4050        inst->release();
4051        inst = NULL;
4052    }
4053
4054    if (inst && (device = OSDynamicCast(IOService, regEntry)))
4055    do
4056    {
4057        PE_Video        bootDisplay;
4058        UInt32          bpp;
4059
4060        IOService::getPlatform()->getConsoleInfo( &bootDisplay);
4061
4062		IOPhysicalAddress64 consolePhysAddress = bootDisplay.v_baseAddr & ~3;
4063#ifndef __LP64__
4064		consolePhysAddress |= (((uint64_t) bootDisplay.v_baseAddrHigh) << 32);
4065#endif
4066
4067        IOMemoryDescriptor * mem = NULL;
4068        IOPCIDevice *        pciDevice;
4069        UInt32               numMaps, i;
4070
4071        OSNumber * num = OSDynamicCast(OSNumber, device->getProperty(kIOFBDependentIndexKey));
4072        if (num && (0 != num->unsigned32BitValue()))
4073            break;
4074        else if ((pciDevice = OSDynamicCast(IOPCIDevice, device))
4075                    && pciDevice->getFunctionNumber())
4076            break;
4077
4078        bytes = (bootDisplay.v_rowBytes * bootDisplay.v_height);
4079        numMaps = device->getDeviceMemoryCount();
4080        for (i = 0; (!mem) && (i < numMaps); i++)
4081        {
4082            addr64_t pa;
4083            mem = device->getDeviceMemoryWithIndex(i);
4084            if (!mem)
4085                continue;
4086            pa = mem->getPhysicalSegment(0, 0, kIOMemoryMapperNone);
4087            if ((consolePhysAddress < pa) || (consolePhysAddress >= (pa + mem->getLength())))
4088                mem = NULL;
4089            else
4090            {
4091                mem = IOSubMemoryDescriptor::withSubRange(mem,
4092                                            consolePhysAddress - pa,
4093                                            bytes, kIODirectionNone);
4094            }
4095        }
4096
4097        if (mem)
4098        {
4099            inst->fVRAMDesc = mem;
4100            inst->fRowBytes = (UInt32) bootDisplay.v_rowBytes;
4101            inst->fWidth    = (UInt32) bootDisplay.v_width;
4102            inst->fHeight   = (UInt32) bootDisplay.v_height;
4103            bpp = (UInt32) bootDisplay.v_depth;
4104            if (bpp == 15)
4105                bpp = 16;
4106            else if (bpp == 24)
4107                bpp = 32;
4108            inst->fBitsPerPixel = bpp;
4109
4110            result = inst;
4111        }
4112    }
4113    while (false);
4114
4115    if (inst && !result)
4116        inst->release();
4117
4118    return (result);
4119}
4120
4121void IOBootNDRV::free( void )
4122{
4123    super::free();
4124}
4125
4126IOReturn IOBootNDRV::getSymbol( const char * symbolName,
4127                                IOLogicalAddress * address )
4128{
4129    return (kIOReturnUnsupported);
4130}
4131
4132const char * IOBootNDRV::driverName( void )
4133{
4134    return (".Display_boot");
4135}
4136
4137IOReturn IOBootNDRV::doDriverIO( UInt32 commandID, void * contents,
4138                                 UInt32 commandCode, UInt32 commandKind )
4139{
4140    IONDRVControlParameters * pb = (IONDRVControlParameters *) contents;
4141    IOReturn    ret;
4142
4143    switch (commandCode)
4144    {
4145        case kIONDRVInitializeCommand:
4146        case kIONDRVOpenCommand:
4147            ret = kIOReturnSuccess;
4148            break;
4149
4150        case kIONDRVControlCommand:
4151            ret = doControl( pb->code, pb->params );
4152            break;
4153        case kIONDRVStatusCommand:
4154            ret = doStatus( pb->code, pb->params );
4155            break;
4156
4157        default:
4158            ret = kIOReturnUnsupported;
4159            break;
4160    }
4161
4162    return (ret);
4163}
4164
4165IOReturn IOBootNDRV::doControl( UInt32 code, void * params )
4166{
4167    IOReturn            ret;
4168
4169    switch (code)
4170    {
4171        case cscSetEntries:
4172        case cscSetGamma:
4173            ret = kIOReturnSuccess;
4174            break;
4175
4176        default:
4177            ret = kIOReturnUnsupported;
4178            break;
4179    }
4180
4181    return (ret);
4182}
4183
4184IOReturn IOBootNDRV::doStatus( UInt32 code, void * params )
4185{
4186    IOReturn            ret;
4187
4188    switch (code)
4189    {
4190        case cscGetCurMode:
4191            {
4192                VDSwitchInfoRec * switchInfo = (VDSwitchInfoRec *) params;
4193
4194                switchInfo->csData     = kIOBootNDRVDisplayMode;
4195                switchInfo->csMode     = kDepthMode1;
4196                switchInfo->csPage     = 1;
4197                switchInfo->csBaseAddr = (char *)(1 | fVRAMDesc->getPhysicalSegment(0, NULL, kIOMemoryMapperNone));
4198                ret = kIOReturnSuccess;
4199            }
4200            break;
4201
4202        case cscGetNextResolution:
4203            {
4204                VDResolutionInfoRec * resInfo = (VDResolutionInfoRec *) params;
4205
4206                if ((kDisplayModeIDFindFirstResolution == (SInt32) resInfo->csPreviousDisplayModeID)
4207                        || (kDisplayModeIDCurrent == (SInt32) resInfo->csPreviousDisplayModeID))
4208                {
4209                    resInfo->csDisplayModeID    = kIOBootNDRVDisplayMode;
4210                    resInfo->csMaxDepthMode             = kDepthMode1;
4211                    resInfo->csHorizontalPixels = fWidth;
4212                    resInfo->csVerticalLines    = fHeight;
4213                    resInfo->csRefreshRate              = 0 << 16;
4214                    ret = kIOReturnSuccess;
4215                }
4216                else if (kIOBootNDRVDisplayMode == resInfo->csPreviousDisplayModeID)
4217                {
4218                    resInfo->csDisplayModeID = kDisplayModeIDNoMoreResolutions;
4219                    ret = kIOReturnSuccess;
4220                }
4221                else
4222                {
4223                    resInfo->csDisplayModeID = kDisplayModeIDInvalid;
4224                    ret = kIOReturnBadArgument;
4225                }
4226            }
4227            break;
4228
4229        case cscGetVideoParameters:
4230            {
4231                VDVideoParametersInfoRec * pixelParams = (VDVideoParametersInfoRec *) params;
4232
4233                if ((kIOBootNDRVDisplayMode != pixelParams->csDisplayModeID)
4234                        || (kDepthMode1 != pixelParams->csDepthMode))
4235                {
4236                    ret = kIOReturnBadArgument;
4237                    break;
4238                }
4239                VPBlock *       pixelInfo = pixelParams->csVPBlockPtr;
4240
4241                bzero(pixelInfo, sizeof(VPBlock));
4242                pixelInfo->vpBounds.right  = fWidth;
4243                pixelInfo->vpBounds.bottom = fHeight;
4244                pixelInfo->vpRowBytes      = fRowBytes;
4245                pixelInfo->vpPixelSize     = fBitsPerPixel;
4246                pixelInfo->vpPixelType     = kIORGBDirectPixels;
4247                pixelInfo->vpCmpCount      = 3;
4248                pixelInfo->vpCmpSize       = (fBitsPerPixel <= 16) ? 5 : 8;
4249                ret = kIOReturnSuccess;
4250            }
4251            break;
4252
4253        case cscGetModeTiming:
4254            {
4255                VDTimingInfoRec * timingInfo = (VDTimingInfoRec *) params;
4256
4257                if (kIOBootNDRVDisplayMode != timingInfo->csTimingMode)
4258                {
4259                    ret = kIOReturnBadArgument;
4260                    break;
4261                }
4262                timingInfo->csTimingFormat = kDeclROMtables;
4263                timingInfo->csTimingFlags  = kDisplayModeValidFlag | kDisplayModeSafeFlag;
4264                ret = kIOReturnSuccess;
4265            }
4266            break;
4267
4268        default:
4269            ret = kIOReturnUnsupported;
4270            break;
4271    }
4272
4273    return (ret);
4274}
4275
4276/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4277
4278OSMetaClassDefineReservedUsed(IONDRVFramebuffer, 0);
4279
4280OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 1);
4281OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 2);
4282OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 3);
4283OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 4);
4284OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 5);
4285OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 6);
4286OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 7);
4287OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 8);
4288OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 9);
4289OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 10);
4290OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 11);
4291OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 12);
4292OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 13);
4293OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 14);
4294OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 15);
4295OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 16);
4296OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 17);
4297OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 18);
4298OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 19);
4299OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 20);
4300OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 21);
4301OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 22);
4302OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 23);
4303OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 24);
4304OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 25);
4305OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 26);
4306OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 27);
4307OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 28);
4308OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 29);
4309OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 30);
4310OSMetaClassDefineReservedUnused(IONDRVFramebuffer, 31);
4311