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//#define IOFB_DISABLEFB 1
23
24#include <IOKit/IOLib.h>
25#include <libkern/c++/OSContainers.h>
26#include <libkern/OSByteOrder.h>
27
28#include <IOKit/IOWorkLoop.h>
29#include <IOKit/IOTimerEventSource.h>
30#include <IOKit/IOCommandGate.h>
31#include <IOKit/IOMessage.h>
32#include <IOKit/IOPlatformExpert.h>
33#include <IOKit/IOBufferMemoryDescriptor.h>
34#include <IOKit/IOHibernatePrivate.h>
35#include <IOKit/IOUserClient.h>
36#include <IOKit/IOKitKeysPrivate.h>
37#include <IOKit/IODeviceTreeSupport.h>
38
39#define IOFRAMEBUFFER_PRIVATE
40#include <IOKit/graphics/IOGraphicsPrivate.h>
41#include <IOKit/graphics/IOFramebuffer.h>
42#include <IOKit/graphics/IODisplay.h>
43#include <IOKit/i2c/IOI2CInterface.h>
44#if defined(__ppc__) && !defined(OSTYPES_K64_REV)
45#include <IOKit/i2c/PPCI2CInterface.h>
46#endif
47#include <IOKit/acpi/IOACPIPlatformExpert.h>
48
49#include "IOFramebufferUserClient.h"
50#include "IODisplayWrangler.h"
51#include "IOFramebufferReallyPrivate.h"
52#include <IOKit/pwr_mgt/RootDomain.h>
53#include <IOKit/pwr_mgt/IOPMPrivate.h>
54
55#include <string.h>
56#include <IOKit/assert.h>
57#include <sys/kdebug.h>
58
59/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
60
61#ifndef VERSION_MAJOR
62#error no VERSION_MAJOR
63#endif
64
65#define SINGLE_THREAD	0
66#define TIME_LOGS		RLOG1
67#define TIME_CURSOR		RLOG1
68#define ASYNC_GAMMA		1
69
70#define GAMMA_ADJ		0
71
72#define DOANIO        0
73#define VRAM_SAVE     1
74#define VRAM_COMPRESS 1
75
76enum { kIOFBVRAMCompressSpeed = 0 };
77enum { kVBLThrottleTimeMS     = 5000 };
78enum { kInitFBTimeoutNS = 1000000000ULL };
79
80enum { k2xDPI = (150*10) };
81
82//#define AUTO_COLOR_MODE		kIODisplayColorModeRGB
83#define AUTO_COLOR_MODE		kIODisplayColorModeYCbCr444
84
85
86#if defined(__i386__) || defined(__x86_64__)
87enum { kIOFBMapCacheMode = kIOMapWriteCombineCache };
88#else
89enum { kIOFBMapCacheMode = kIOMapInhibitCache };
90#endif
91
92#ifndef kBootArgsFlagBlack
93#define kBootArgsFlagBlack		(1 << 2)
94#endif
95
96#ifndef kIOPMUserTriggeredFullWakeKey
97#define kIOPMUserTriggeredFullWakeKey       "IOPMUserTriggeredFullWake"
98#endif
99
100#if VRAM_COMPRESS
101#include "bmcompress.h"
102#endif
103
104#if DOANIO
105#include <sys/uio.h>
106#include <sys/conf.h>
107#endif
108
109enum {
110    kIOFBClamshellProbeDelayMS = 1*1000
111};
112enum {
113    kIOFBClamshellEnableDelayMS = 15*1000
114};
115
116enum
117{
118	// all seconds:
119	kSystemWillSleepTimeout = 90,   // 90
120	kServerAckTimeout       = 25,	// 25
121	kPowerStateTimeout      = 45,
122	kDarkWokeTimeout        = 5,
123};
124
125enum
126{
127	kIOFBEventCaptureSetting     = 0x00000001,
128    kIOFBEventDisplayDimsSetting = 0x00000002,
129	kIOFBEventReadClamshell	 	 = 0x00000004,
130    kIOFBEventResetClamshell	 = 0x00000008,
131    kIOFBEventEnableClamshell    = 0x00000010,
132    kIOFBEventProbeAll			 = 0x00000020,
133    kIOFBEventDisplaysPowerState = 0x00000040,
134    kIOFBEventSystemPowerOn      = 0x00000080
135};
136
137enum
138{
139    fg    = 1,
140    bg    = 2,
141    fgOff = 3,
142    bgOff = 4,
143};
144
145#if RLOG1
146static const char * processConnectChangeModeNames[] =
147	{ "", "fg", "bg", "fgOff", "bgOff" };
148#endif
149
150#define CHAR(c)    ((c) ? ((char) (c)) : '0')
151#define FEAT(f)    CHAR(f>>24), CHAR(f>>16), CHAR(f>>8), CHAR(f>>0)
152
153/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
154
155static class IOGraphicsWorkLoop * gIOFBSystemWorkLoop;
156static struct IOFBController *    gIOFBAllControllers;
157static struct IOFBController *    gIOFBLastController;
158
159static OSArray *            gAllFramebuffers;
160static OSArray *            gStartedFramebuffers;
161static OSArray *            gRunawayFramebuffers;
162static IOWorkLoop *         gIOFBHIDWorkLoop;
163static IOTimerEventSource * gIOFBDelayedPrefsEvent;
164static IOTimerEventSource * gIOFBServerAckTimer;
165static IONotifier *         gIOFBRootNotifier;
166static IONotifier *         gIOFBClamshellNotify;
167static IONotifier *         gIOFBGCNotifier;
168static IOInterruptEventSource * gIOFBWorkES;
169static volatile UInt32      gIOFBGlobalEvents;
170static IORegistryEntry *    gChosenEntry;
171static IOService *          gIOFBSystemPowerAckTo;
172static void *               gIOFBSystemPowerAckRef;
173static IOService *          gIOFBSystemPowerMuxAckTo;
174static uint32_t             gIOFBSystemPowerMuxAckRef;
175static UInt32               gIOFBLastMuxMessage = kIOMessageSystemHasPoweredOn;
176static bool					gIOFBSwitching;
177bool                        gIOFBSystemPower = true;
178bool						gIOFBSystemDark;
179static bool					gIOFBServerInit;
180static bool					gIOFBWSState = true;
181static bool					gIOFBPostWakeNeeded;
182static bool					gIOFBProbeCaptured;
183static uint32_t             gIOFBCaptureState;
184bool                        gIOGraphicsSystemPower = true;
185static thread_call_t        gIOFBClamshellCallout;
186static SInt32               gIOFBDisplayCount;
187static SInt32               gIOFBBacklightDisplayCount;
188static IOOptionBits         gIOFBClamshellState;
189static IOFramebuffer *      gIOFBConsoleFramebuffer;
190static bool                 gIOFBDesktopModeAllowed = true;
191IOOptionBits                gIOFBCurrentClamshellState;
192static IOOptionBits         gIOFBLastClamshellState;
193int32_t                     gIOFBHaveBacklight = -1;
194static IOOptionBits         gIOFBLastReadClamshellState;
195const OSSymbol *            gIOFBGetSensorValueKey;
196const OSSymbol *            gIOFramebufferKey;
197const OSSymbol *            gIOFBRotateKey;
198const OSSymbol *            gIOFBStartupModeTimingKey;
199const OSSymbol *            gIOFBPMSettingDisplaySleepUsesDimKey;
200const OSSymbol *            gIOFBConfigKey;
201const OSSymbol *            gIOFBModesKey;
202const OSSymbol *            gIOFBModeIDKey;
203const OSSymbol *            gIOFBModeDMKey;
204static OSDictionary *       gIOFBPrefs;
205static OSDictionary *       gIOFBPrefsParameters;
206static OSDictionary *       gIOFBIgnoreParameters;
207static OSSerializer *       gIOFBPrefsSerializer;
208static IOService *          gIOGraphicsControl;
209static OSObject *           gIOResourcesAppleClamshellState;
210static AbsoluteTime         gIOFBNextProbeAllTime;
211static AbsoluteTime         gIOFBMaxVBLDelta;
212OSData *                    gIOFBZero32Data;
213OSData *                    gIOFBOne32Data;
214uint32_t             		gIOFBGrayValue = kIOFBBootGrayValue;
215OSData *                    gIOFBGray32Data;
216static uint8_t				gIOFBBlackBoot;
217static const OSSymbol *     gIOGraphicsPrefsVersionKey;
218static OSNumber *           gIOGraphicsPrefsVersionValue;
219static uint8_t				gIOFBLidOpenMode;
220static uint8_t				gIOFBVBLThrottle;
221static uint8_t				gIOFBVBLDrift;
222uint32_t					gIOGDebugFlags;
223uint32_t					gIOGNotifyTO;
224static bool                 gIOGFades;
225
226#define kIOFBGetSensorValueKey  "getSensorValue"
227
228enum { kIOFBDefaultScalerUnderscan = 0*kIOFBScalerUnderscan };
229
230// console clut
231extern UInt8 appleClut8[256 * 3];
232
233/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
234
235enum { kIOFBControllerMaxFBs = 32 };
236
237struct IOFBController
238{
239    IOFBController *            nextController;
240    IOFramebuffer  *            fbs[kIOFBControllerMaxFBs + 1];
241    class IOGraphicsWorkLoop *  wl;
242	IOInterruptEventSource *    workES;
243    IOService      *            device;
244    const char     *            name;
245	AbsoluteTime				initTime;
246
247	thread_t					powerThread;
248
249	uint32_t					vendorID;
250    uint32_t                    maxFB;
251    uint32_t                    onlineMask;
252
253    int32_t                     connectChange;
254    int32_t                     lastForceRetrain;
255    int32_t                     lastMessagedChange;
256    int32_t                     lastFinishedChange;
257	int32_t						postWakeChange;
258
259    uint8_t                     mute;
260
261    uint8_t                     wsWait;
262
263	uint8_t						needsWork;
264	uint8_t						didWork;
265	uint8_t						asyncWork;
266	uint8_t						pendingMuxPowerChange;
267	uint8_t						integrated;
268
269	uint32_t					state;
270	uint32_t					aliasID;
271#if IOFB_DISABLEFB
272    uintptr_t                   saveGAR;
273#endif
274};
275
276struct IOFBInterruptRegister
277{
278    IOFBInterruptProc           handler;
279    OSObject *                  target;
280    void *                      ref;
281    UInt32						state;
282};
283enum
284{
285	kIOFBMCCSInterruptRegister = 0,
286	kIOFBNumInterruptRegister  = 1
287};
288
289struct IOFramebufferPrivate
290{
291    IOFBController *            controller;
292    IODisplay *					display;
293    IOFramebuffer *				nextMirror;
294    uint64_t					regID;
295	uint32_t					displayOptions;
296    uint32_t					controllerIndex;
297    IOGSize                     maxWaitCursorSize;
298    UInt32                      numCursorFrames;
299    uint32_t                    cursorBytesPerPixel;
300    UInt8 *                     cursorFlags;
301    volatile unsigned char **   cursorImages;
302    volatile unsigned char **   cursorMasks;
303    IOMemoryDescriptor *        saveBitsMD[kIOPreviewImageCount];
304
305	IOGBounds					screenBounds[2];			// phys & virtual bounds
306
307    class IOFramebufferParameterHandler * paramHandler;
308
309    void *              		vblInterrupt;
310    void *              		connectInterrupt;
311	IOTimerEventSource *        vblUpdateTimer;
312	IOTimerEventSource *        deferredCLUTSetTimerEvent;
313	IOInterruptEventSource *    deferredVBLDisableEvent;
314    uint64_t					actualVBLCount;
315	OSObject *                  displayAttributes;
316
317	IOFBInterruptRegister		interruptRegisters[kIOFBNumInterruptRegister];
318
319    OSArray *                   cursorAttributes;
320    IOFBCursorControlAttribute  cursorControl;
321    IOInterruptEventSource *    cursorThread;
322    IOOptionBits                cursorToDo;
323    UInt32                      framePending;
324    SInt32                      xPending;
325    SInt32                      yPending;
326    IOGPoint                    cursorHotSpotAdjust[2];
327    IOGPoint                    lastHotSpot;
328    void *                      waitVBLEvent;
329
330    IOByteCount                 gammaHeaderSize;
331    UInt32                      desiredGammaDataWidth;
332    UInt32                      desiredGammaDataCount;
333
334    IOInterruptEventSource *    deferredCLUTSetEvent;
335    IOInterruptEventSource *    deferredSpeedChangeEvent;
336    IOTimerEventSource *        delayedConnectInterrupt;
337    UInt32                      delayedConnectTime;
338
339    IOTimerEventSource *        dpInterruptES;
340    void *                      dpInterruptRef;
341    UInt32                      dpInterrupDelayTime;
342
343	const OSSymbol *			displayPrefKey;
344
345    IOByteCount                 gammaDataLen;
346    UInt8 *                     gammaData;
347    UInt32                      gammaChannelCount;
348    UInt32                      gammaDataCount;
349    UInt32                      gammaDataWidth;
350
351    IOByteCount                 rawGammaDataLen;
352    UInt8 *                     rawGammaData;
353    UInt32                      rawGammaChannelCount;
354    UInt32                      rawGammaDataCount;
355    UInt32                      rawGammaDataWidth;
356
357    IOByteCount                 clutDataLen;
358    UInt8 *                     clutData;
359    UInt32                      clutIndex;
360    UInt32                      clutOptions;
361
362    uint32_t                    framebufferWidth;
363    uint32_t                    framebufferHeight;
364    uint32_t                    consoleDepth;
365	uint32_t					restoreType;
366	uint32_t					hibernateGfxStatus;
367    uint32_t                    saveLength;
368    void *                      saveFramebuffer;
369
370	UInt8						needGammaRestore;
371	UInt8						vblThrottle;
372	UInt8						vblEnabled;
373    UInt8                       gammaNeedSet;
374    UInt8                       gammaScaleChange;
375    UInt8                       scaledMode;
376    UInt8                       visiblePending;
377    UInt8                       testingCursor;
378    UInt8                       index;
379	UInt8						gammaSet;
380    UInt8                       cursorSlept;
381    UInt8                       cursorPanning;
382    UInt8                       pendingSpeedChange;
383
384    UInt8                       lli2c;
385    UInt8                       cursorClutDependent;
386    UInt8                       allowSpeedChanges;
387    UInt8                       dimDisable;
388
389    UInt8                       enableScalerUnderscan;
390    UInt8                       userSetTransform;
391    UInt8                       closed;
392    UInt8                       online;
393	UInt8						displaysOnline;
394    UInt8                       lastNotifyOnline;
395    UInt8						modeUpdate;
396    UInt8                       dpInterrupts;
397    SInt8                       dpSupported;
398    UInt8                       dpDongle;
399    UInt8                       dpDongleSinkCount;
400    UInt8                       dpBusID;
401	UInt8						colorModesAllowed;
402	UInt8						needsInit;
403	UInt8						audioStreaming;
404	uint32_t					uiScale;
405
406	uint32_t					colorModesSupported;
407
408    UInt64                      transform;
409    UInt64                      selectedTransform;
410    UInt32                      reducedSpeed;
411    IOService *                 temperatureSensor;
412    IOI2CBusTiming              defaultI2CTiming;
413
414    uintptr_t                   gammaScale[4];
415
416    IOPixelInformation          pixelInfo;
417	IOTimingInformation 		timingInfo;
418    IODisplayModeID             offlineMode;
419    IODisplayModeID             aliasMode;
420    IODisplayModeID             matchedMode;
421    IODisplayModeID             setupMode;
422    IOIndex                     currentDepth;
423
424    int32_t                     lastProcessedChange;
425};
426
427/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
428
429#define GetShmem(instance)      ((StdFBShmem_t *)(instance->priv))
430
431#define KICK_CURSOR(thread)     \
432            thread->interruptOccurred(0, 0, 0);
433
434#define CLEARSEMA(shmem, inst)                          \
435        if( inst->__private->cursorToDo ) {             \
436            KICK_CURSOR(inst->__private->cursorThread); \
437        }                                               \
438        OSSpinLockUnlock(&shmem->cursorSema)
439
440#define SETSEMA(shmem)          \
441        if (!OSSpinLockTry(&shmem->cursorSema)) return;
442#define TOUCHBOUNDS(one, two) \
443        (((one.minx < two.maxx) && (two.minx < one.maxx)) && \
444        ((one.miny < two.maxy) && (two.miny < one.maxy)))
445
446/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
447
448class IOGraphicsWorkLoop : public IOWorkLoop
449{
450    OSDeclareDefaultStructors(IOGraphicsWorkLoop)
451public:
452	typedef void GateFunction(IOWorkLoop * wl, OSObject * obj, void * reference, bool gate);
453
454	IOLock *        gateMutex;
455	thread_t		gateThread;
456	uint32_t		gateCount;
457
458	IOOptionBits   options;
459	GateFunction * func;
460	OSObject *     obj;
461	void *         reference;
462
463    static IOGraphicsWorkLoop * workLoop(IOOptionBits options = 0,
464  										 GateFunction * func = NULL,
465  										 OSObject * obj = NULL, void * reference = NULL);
466	virtual bool init();
467	virtual void free();
468
469	virtual void signalWorkAvailable() { IOWorkLoop::signalWorkAvailable(); }
470    virtual bool inGate() const;
471    virtual void closeGate();
472    virtual void openGate();
473    virtual bool tryCloseGate();
474    virtual int  sleepGate(void *event, UInt32 interuptibleType);
475    virtual int  sleepGate(void *event, AbsoluteTime deadline, UInt32 interuptibleType);
476    virtual void wakeupGate(void *event, bool oneThread);
477};
478
479OSDefineMetaClassAndStructors(IOGraphicsWorkLoop, IOWorkLoop)
480
481IOGraphicsWorkLoop * IOGraphicsWorkLoop::workLoop(IOOptionBits options,
482  										 GateFunction * func, OSObject * obj, void * reference)
483{
484    IOGraphicsWorkLoop *me = new IOGraphicsWorkLoop;
485
486    if (!me)
487		return (NULL);
488
489	me->options   = options;
490	me->func      = func;
491	me->obj       = obj;
492	me->reference = reference;
493	if (!me->init())
494	{
495		me->release();
496		me = NULL;
497	}
498
499    return (me);
500}
501
502bool IOGraphicsWorkLoop::init()
503{
504	bool ok;
505
506	gateMutex = IOLockAlloc();
507    if (!gateMutex)	return (false);
508
509	ok = IOWorkLoop::init();
510
511	if (gateLock)
512	{
513	    IORecursiveLockFree(gateLock);
514	    gateLock = NULL;
515	}
516
517	return (ok);
518}
519
520void IOGraphicsWorkLoop::free()
521{
522	if (gateMutex && !workThread)
523    {
524		IOLockFree(gateMutex);
525		gateMutex = NULL;
526	}
527	IOWorkLoop::free();
528}
529
530bool IOGraphicsWorkLoop::inGate() const
531{
532    return (gateThread == IOThreadSelf());
533}
534
535void IOGraphicsWorkLoop::closeGate()
536{
537	if (gateThread == IOThreadSelf())
538	{
539		if (!gateCount) panic("gateCount");
540		gateCount++;
541	}
542	else
543	{
544#if 0
545			AbsoluteTime startTime, endTime;
546			uint64_t nsec;
547			AbsoluteTime_to_scalar(&startTime) = mach_absolute_time();
548#endif
549        IOLockLock(gateMutex);
550#if 0
551			AbsoluteTime_to_scalar(&endTime) = mach_absolute_time();
552			SUB_ABSOLUTETIME(&endTime, &startTime);
553			absolutetime_to_nanoseconds(endTime, &nsec);
554			nsec /= 1000000ULL;
555			if (nsec >= 50)
556				OSReportWithBacktrace("wsloow %qd ms\n", nsec);
557#endif
558        assert (gateThread == 0);
559        assert (gateCount == 0);
560		if (gateThread) panic("gateThread");
561		if (gateCount)  panic("gateCount");
562
563        gateThread = IOThreadSelf();
564        gateCount  = 1;
565		if (func) (*func)(this, obj, reference, true);
566	}
567}
568
569void IOGraphicsWorkLoop::openGate()
570{
571    assert (gateThread == IOThreadSelf());
572    if (gateThread != IOThreadSelf()) panic("gateThread");
573    if (1 == gateCount)
574    {
575		if (func) (*func)(this, obj, reference, false);
576		if (gateThread != IOThreadSelf()) panic("gateThread");
577		if (gateCount != 1)  panic("gateCount");
578        gateThread = NULL;
579        gateCount = 0;
580        IOLockUnlock(gateMutex);
581        return;
582    }
583	gateCount--;
584}
585
586bool IOGraphicsWorkLoop::tryCloseGate()
587{
588	bool gotit = true;
589
590	if (gateThread == IOThreadSelf()) gateCount++;
591	else
592	{
593        if (!IOLockTryLock(gateMutex)) gotit = false;
594        else
595        {
596			assert (gateThread == 0);
597			assert (gateCount == 0);
598			if (gateThread) panic("gateThread");
599			if (gateCount)  panic("gateCount");
600			gateThread = IOThreadSelf();
601			gateCount  = 1;
602			if (func) (*func)(this, obj, reference, true);
603		}
604	}
605	return (gotit);
606}
607
608int IOGraphicsWorkLoop::sleepGate(void *event, UInt32 interuptibleType)
609{
610	int      result;
611	uint32_t count;
612
613    assert(gateThread == IOThreadSelf());
614    if (gateThread != IOThreadSelf()) panic("gateThread");
615
616	count     = gateCount;
617	gateCount = 0;
618	if (func) (*func)(this, obj, reference, false);
619
620	gateThread = NULL;
621	result = IOLockSleep(gateMutex, event, interuptibleType);
622
623	assert (gateThread == 0);
624	assert (gateCount == 0);
625	if (gateThread) panic("gateThread");
626	if (gateCount)  panic("gateCount");
627	gateThread = IOThreadSelf();
628	gateCount  = count;
629
630	if (func) (*func)(this, obj, reference, true);
631    return (result);
632}
633
634int IOGraphicsWorkLoop::sleepGate(void *event, AbsoluteTime deadline, UInt32 interuptibleType)
635{
636	int      result;
637	uint32_t count;
638
639    assert(gateThread == IOThreadSelf());
640
641	count     = gateCount;
642	gateCount = 0;
643	if (func) (*func)(this, obj, reference, false);
644
645	gateThread = NULL;
646	result = IOLockSleepDeadline(gateMutex, event, deadline, interuptibleType);
647
648	assert (gateThread == 0);
649	assert (gateCount == 0);
650	gateThread = IOThreadSelf();
651	gateCount  = count;
652
653	if (func) (*func)(this, obj, reference, true);
654
655    return (result);
656}
657
658void IOGraphicsWorkLoop::wakeupGate(void *event, bool oneThread)
659{
660	return (IOLockWakeup(gateMutex, event, oneThread));
661}
662
663/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
664
665#define SYSLOCK()         \
666    gIOFBSystemWorkLoop->closeGate()
667#define SYSUNLOCK()       \
668    gIOFBSystemWorkLoop->openGate()
669
670#define FCLOCK(fc)        \
671    fc->wl->closeGate()
672#define FCUNLOCK(fc)      \
673    fc->wl->openGate()
674
675#define FBWL(fb)          \
676    fb->__private->controller->wl
677
678#define _FBLOCK(fb)        	\
679    FBWL(fb)->closeGate()
680
681#define FBUNLOCK(fb)       \
682    FBWL(fb)->openGate()	\
683
684#if TIME_LOGS
685
686static void TIMELOCK(IOGraphicsWorkLoop * wl, const char * name, const char * fn)
687{
688    AbsoluteTime startTime, endTime;
689    uint64_t nsec;
690
691	AbsoluteTime_to_scalar(&startTime) = mach_absolute_time();
692
693    wl->closeGate();
694
695    AbsoluteTime_to_scalar(&endTime) = mach_absolute_time();
696    SUB_ABSOLUTETIME(&endTime, &startTime);
697    absolutetime_to_nanoseconds(endTime, &nsec);
698    nsec /= 1000000ULL;
699    if (nsec >= 5)
700        IOLog("%s: %s: sloow %qd ms\n", name, fn, nsec);
701}
702#define FBLOCK(fb) TIMELOCK(FBWL(fb), fb->thisName, __FUNCTION__)
703
704
705#define TIMESTART()									\
706{													\
707    AbsoluteTime startTime, endTime;				\
708    uint64_t nsec;									\
709	AbsoluteTime_to_scalar(&startTime) = mach_absolute_time();
710
711#define TIMEEND(name, fmt, args...)								\
712    AbsoluteTime_to_scalar(&endTime) = mach_absolute_time();    \
713    absolutetime_to_nanoseconds(endTime, &nsec);                  \
714    kprintf("%08d [%s]: ", (uint32_t) (nsec / 1000000ULL), name); \
715    SUB_ABSOLUTETIME(&endTime, &startTime);			\
716    absolutetime_to_nanoseconds(endTime, &nsec);	\
717    nsec /= 1000000ULL;								\
718    kprintf(fmt, ## args , nsec);						\
719}
720
721#else	/* !TIME_LOGS */
722
723#define FBLOCK(fb) 					_FBLOCK(fb)
724#define TIMELOCK(wl, name, fn)		wl->closeGate()
725#define TIMESTART()
726#define TIMEEND(name, fmt, args...)
727
728#endif
729
730#if TIME_CURSOR
731
732#define CURSORLOCK(fb) 													\
733    if (!cursorEnable) return;											\
734    AbsoluteTime startTime, endTime;									\
735    uint64_t nsec;														\
736	AbsoluteTime_to_scalar(&startTime) = mach_absolute_time();			\
737																		\
738    StdFBShmem_t *shmem = GetShmem(fb);									\
739    bool __checkTime = (2 == fb->getPowerState());						\
740    SETSEMA(shmem);														\
741    FBLOCK(this);														\
742																		\
743    AbsoluteTime_to_scalar(&endTime) = mach_absolute_time();			\
744    SUB_ABSOLUTETIME(&endTime, &startTime);								\
745    absolutetime_to_nanoseconds(endTime, &nsec);						\
746    nsec /= 1000000ULL;													\
747    if (__checkTime && (nsec >= 20))										\
748        IOLog("%s: %s: cursor lock stall %qd ms\n", fb->thisName, __FUNCTION__, nsec);
749
750#else	/* TIME_CURSOR */
751
752#define CURSORLOCK(fb) 													\
753    if (!cursorEnable) return;											\
754    StdFBShmem_t *shmem = GetShmem(fb);									\
755    SETSEMA(shmem);														\
756    FBLOCK(this);														\
757
758#endif	/* TIME_CURSOR */
759
760#define CURSORUNLOCK(fb)	\
761    FBUNLOCK(fb);			\
762    CLEARSEMA(shmem, fb);
763
764
765/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
766
767#define extEntry(allowOffline)  		_extEntry(false, allowOffline, __FUNCTION__)
768#define extExit(result)  				_extExit (false, result, __FUNCTION__)
769#define extEntrySys(allowOffline)  		_extEntry(true,  allowOffline, __FUNCTION__)
770#define extExitSys(result)  			_extExit (true,  result, __FUNCTION__)
771
772/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
773
774class IOFramebufferParameterHandler : public IODisplayParameterHandler
775{
776    OSDeclareDefaultStructors(IOFramebufferParameterHandler)
777
778    OSDictionary *      fDisplayParams;
779    IOFramebuffer *     fFramebuffer;
780    IODisplay *         fDisplay;
781
782public:
783    static IOFramebufferParameterHandler * withFramebuffer( IOFramebuffer * framebuffer );
784    virtual void free();
785
786    virtual bool setDisplay( IODisplay * display );
787    virtual bool doIntegerSet( OSDictionary * params,
788                               const OSSymbol * paramName, UInt32 value );
789    virtual bool doDataSet( const OSSymbol * paramName, OSData * value );
790    virtual bool doUpdate( void );
791
792    void displayModeChange( void );
793};
794
795class IOFramebufferSensor : public IOService
796{
797    OSDeclareDefaultStructors(IOFramebufferSensor)
798
799    IOFramebuffer *     fFramebuffer;
800
801public:
802    static IOFramebufferSensor * withFramebuffer( IOFramebuffer * framebuffer );
803    virtual void free();
804
805    virtual IOReturn callPlatformFunction( const OSSymbol * functionName,
806                                           bool waitForFunction,
807                                           void *param1, void *param2,
808                                           void *param3, void *param4 );
809
810    virtual IOReturn callPlatformFunction( const char * functionName,
811                                           bool waitForFunction,
812                                           void *param1, void *param2,
813                                           void *param3, void *param4 );
814};
815
816/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
817
818class IOFramebufferI2CInterface : public IOI2CInterface
819{
820    OSDeclareDefaultStructors(IOFramebufferI2CInterface)
821
822    IOFramebuffer *     fFramebuffer;
823    SInt32              fBusID;
824    UInt32              fSupportedTypes;
825    UInt32              fSupportedCommFlags;
826
827public:
828    virtual bool start( IOService * provider );
829    virtual IOReturn startIO( IOI2CRequest * request );
830
831    static IOFramebufferI2CInterface * withFramebuffer( IOFramebuffer * framebuffer,
832                                                        OSDictionary * info );
833    static IOReturn create( IOFramebuffer * framebuffer );
834};
835
836/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
837
838#undef super
839#define super IOGraphicsDevice
840
841OSDefineMetaClass( IOFramebuffer, IOGraphicsDevice )
842OSDefineAbstractStructors( IOFramebuffer, IOGraphicsDevice )
843
844/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
845
846void IOFramebuffer::fbLock( void )
847{
848	FBLOCK(this);
849}
850
851void IOFramebuffer::fbUnlock( void )
852{
853    FBUNLOCK(this);
854}
855
856/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
857
858/*
859 * Cursor rendering
860 */
861
862#include "IOCursorBlits.h"
863
864inline void IOFramebuffer::StdFBDisplayCursor( IOFramebuffer * inst )
865{
866    StdFBShmem_t *shmem;
867    IOGBounds saveRect;
868    volatile unsigned char *vramPtr;    /* screen data pointer */
869    unsigned int cursStart;
870    unsigned int cursorWidth;
871    int width;
872    int height;
873
874    shmem = GetShmem(inst);
875    saveRect = shmem->cursorRect;
876    /* Clip saveRect vertical within screen bounds */
877    if (saveRect.miny < shmem->screenBounds.miny)
878        saveRect.miny = shmem->screenBounds.miny;
879    if (saveRect.maxy > shmem->screenBounds.maxy)
880        saveRect.maxy = shmem->screenBounds.maxy;
881    if (saveRect.minx < shmem->screenBounds.minx)
882        saveRect.minx = shmem->screenBounds.minx;
883    if (saveRect.maxx > shmem->screenBounds.maxx)
884        saveRect.maxx = shmem->screenBounds.maxx;
885    shmem->saveRect = saveRect; /* Remember save rect for RemoveCursor */
886
887    vramPtr = inst->frameBuffer +
888              (inst->rowBytes * (saveRect.miny - shmem->screenBounds.miny)) +
889              (inst->bytesPerPixel * (saveRect.minx - shmem->screenBounds.minx));
890
891    width = saveRect.maxx - saveRect.minx;
892    height = saveRect.maxy - saveRect.miny;
893    cursorWidth = shmem->cursorSize[0 != shmem->frame].width;
894
895    cursStart = (saveRect.miny - shmem->cursorRect.miny) * cursorWidth +
896                (saveRect.minx - shmem->cursorRect.minx);
897
898    if (inst->cursorBlitProc)
899        inst->cursorBlitProc( inst,
900                              (void *) shmem,
901                              vramPtr,
902                              cursStart,
903                              inst->totalWidth - width,   /* vramRow */
904                              cursorWidth - width,      /* cursRow */
905                              width,
906                              height);
907}
908
909// Description: RemoveCursor erases the cursor by replacing the background
910//              image that was saved by the previous call to DisplayCursor.
911//              If the frame buffer is cacheable, flush at the end of the
912//              drawing operation.
913
914inline void IOFramebuffer::StdFBRemoveCursor( IOFramebuffer * inst )
915{
916    StdFBShmem_t *shmem;
917    volatile unsigned char *vramPtr;    /* screen data pointer */
918    unsigned int vramRow;
919    int width;
920    int height;
921
922    shmem = GetShmem(inst);
923
924    /* Clip saveRect vertical within screen bounds */
925    if ((shmem->saveRect.miny < shmem->screenBounds.miny)
926     || (shmem->saveRect.maxy > shmem->screenBounds.maxy)
927     || (shmem->saveRect.minx < shmem->screenBounds.minx)
928     || (shmem->saveRect.maxx > shmem->screenBounds.maxx))
929	{
930		IOLog("%s: bad crsr saverect (%d, %d), (%d, %d) - (%d, %d), (%d, %d)\n",
931					inst->thisName,
932					shmem->saveRect.minx, shmem->saveRect.miny,
933					shmem->saveRect.maxx, shmem->saveRect.maxy,
934					shmem->screenBounds.minx, shmem->screenBounds.miny,
935					shmem->screenBounds.maxx, shmem->screenBounds.maxy);
936		return;
937	}
938
939    vramRow = inst->totalWidth; /* Scanline width in pixels */
940
941    vramPtr = inst->frameBuffer +
942              (inst->rowBytes * (shmem->saveRect.miny - shmem->screenBounds.miny))
943              + (inst->bytesPerPixel *
944                 (shmem->saveRect.minx - shmem->screenBounds.minx));
945
946    width = shmem->saveRect.maxx - shmem->saveRect.minx;
947    height = shmem->saveRect.maxy - shmem->saveRect.miny;
948    vramRow -= width;
949
950    if (inst->cursorRemoveProc)
951        inst->cursorRemoveProc( inst, (void *)shmem,
952                                vramPtr, vramRow, width, height);
953}
954
955inline void IOFramebuffer::RemoveCursor( IOFramebuffer * inst )
956{
957    StdFBShmem_t *      shmem = GetShmem(inst);
958
959    if (!inst->pagingState)
960        return;
961
962    if (shmem->hardwareCursorActive)
963    {
964        IOGPoint *              hs;
965
966        hs = &shmem->hotSpot[0 != shmem->frame];
967        inst->_setCursorState(
968            shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx,
969            shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny, false );
970    }
971    else
972        StdFBRemoveCursor(inst);
973}
974
975inline void IOFramebuffer::DisplayCursor( IOFramebuffer * inst )
976{
977    IOGPoint     *      hs;
978    StdFBShmem_t *      shmem = GetShmem(inst);
979    SInt32              x, y;
980
981    if (!inst->pagingState)
982        return;
983
984    hs = &shmem->hotSpot[0 != shmem->frame];
985    x  = shmem->cursorLoc.x - hs->x;
986    y  = shmem->cursorLoc.y - hs->y;
987
988    if (shmem->hardwareCursorActive)
989        inst->_setCursorState( x - shmem->screenBounds.minx,
990                               y - shmem->screenBounds.miny, true );
991    else
992    {
993        shmem->cursorRect.maxx = (shmem->cursorRect.minx = x)
994                                 + shmem->cursorSize[0 != shmem->frame].width;
995        shmem->cursorRect.maxy = (shmem->cursorRect.miny = y)
996                                 + shmem->cursorSize[0 != shmem->frame].height;
997        StdFBDisplayCursor(inst);
998        shmem->oldCursorRect = shmem->cursorRect;
999    }
1000}
1001
1002inline void IOFramebuffer::SysHideCursor( IOFramebuffer * inst )
1003{
1004    if (!GetShmem(inst)->cursorShow++)
1005        RemoveCursor(inst);
1006}
1007
1008inline void IOFramebuffer::SysShowCursor( IOFramebuffer * inst )
1009{
1010    StdFBShmem_t *shmem;
1011
1012    shmem = GetShmem(inst);
1013
1014    if (shmem->cursorShow)
1015        if (!--(shmem->cursorShow))
1016            DisplayCursor(inst);
1017}
1018
1019inline void IOFramebuffer::CheckShield( IOFramebuffer * inst )
1020{
1021    IOGPoint *          hs;
1022    int                 intersect;
1023    IOGBounds           tempRect;
1024    StdFBShmem_t *      shmem = GetShmem(inst);
1025
1026    /* Calculate temp cursorRect */
1027    hs = &shmem->hotSpot[0 != shmem->frame];
1028    tempRect.maxx = (tempRect.minx = (shmem->cursorLoc).x - hs->x)
1029                    + shmem->cursorSize[0 != shmem->frame].width;
1030    tempRect.maxy = (tempRect.miny = (shmem->cursorLoc).y - hs->y)
1031                    + shmem->cursorSize[0 != shmem->frame].height;
1032
1033    intersect = TOUCHBOUNDS(tempRect, shmem->shieldRect);
1034    if (intersect != shmem->shielded)
1035        (shmem->shielded = intersect) ?
1036        SysHideCursor(inst) : SysShowCursor(inst);
1037}
1038
1039#include "AppleLogo.h"
1040#include "AppleLogo2x.h"
1041
1042/**************************************************************
1043 LZSS.C -- A Data Compression Program
1044***************************************************************
1045    4/6/1989 Haruhiko Okumura
1046    Use, distribute, and modify this program freely.
1047    Please send me your improved versions.
1048        PC-VAN      SCIENCE
1049        NIFTY-Serve PAF01022
1050        CompuServe  74050,1022
1051
1052**************************************************************/
1053#define N         4096  /* size of ring buffer - must be power of 2 */
1054#define F         18    /* upper limit for match_length */
1055#define THRESHOLD 2     /* encode string into position and length
1056                           if match_length is greater than this */
1057
1058static void IOFramebufferBootInitFB(IOVirtualAddress frameBuffer,
1059			uint32_t framebufferWidth, uint32_t framebufferHeight,
1060			uint32_t totalWidth, uint32_t consoleDepth, uint8_t logo)
1061{
1062	const uint8_t  * src;
1063	uint32_t *       out;
1064	uint32_t         gray, data, x, y, ox, oy, sx, lw, lh;
1065
1066	if (gIOFBBlackBoot)
1067		gray = logo = 0;
1068	else if (32 == consoleDepth)
1069		gray = 0xbfbfbf;
1070	else if (30 == consoleDepth)
1071#define g10 ((0xbf << 2) | (0xbf >> 6))
1072		gray = (g10 | (g10 << 10 ) | (g10 << 20));
1073	else
1074		return;
1075
1076    src = (2 == logo) ? &gAppleLogo2XPacked[0] : &gAppleLogoPacked[0];
1077	lw  = (2 == logo) ? kAppleLogo2XWidth      : kAppleLogoWidth;
1078	lh  = (2 == logo) ? kAppleLogo2XHeight     : kAppleLogoHeight;
1079
1080	ox = (framebufferWidth - lw) / 2;
1081	oy = (framebufferHeight - lh) / 2;
1082
1083    out = (uint32_t *) frameBuffer;
1084
1085    /* ring buffer of size N, with extra F-1 bytes to aid string comparison */
1086    uint8_t text_buf[N + F - 1];
1087    int32_t  i, j, k, r;
1088    uint32_t flags;
1089
1090    for (i = 0; i < N - F; i++) text_buf[i] = ' ';
1091    r = N - F;
1092    flags = 0;
1093    j = 0;
1094    k = INT32_MAX;
1095
1096	for (y = 0; y < framebufferHeight; y++)
1097	{
1098		if ((!logo) || (y < oy) || (y >= (oy + lh)))
1099		{
1100			for (x = 0; x < framebufferWidth; x++) out[x] = gray;
1101		}
1102		else
1103		{
1104			for (x = 0; x < ox; x++) out[x] = gray;
1105			for (sx = 0; sx < lw; sx++)
1106			{
1107				if (k > j) {
1108					if (((flags >>= 1) & 0x100) == 0) {
1109						data = *src++;
1110						flags = data | 0xFF00;  /* uses higher byte cleverly */
1111					}   					    /* to count eight */
1112					if (flags & 1) data = *src++;
1113					else {
1114						i = *src++;
1115						j = *src++;
1116						i |= ((j & 0xF0) << 4);
1117						j  =  (j & 0x0F) + THRESHOLD;
1118						k = 0;
1119					}
1120				}
1121				if (k <= j) {
1122					data = text_buf[(i + k) & (N - 1)];
1123					k++;
1124				}
1125				text_buf[r++] = data;
1126				r &= (N - 1);
1127
1128				if (32 == consoleDepth)
1129					data |= (data << 8) | (data << 16);
1130				else if (30 == consoleDepth)
1131					data |= (data << 10) | (data << 20);
1132				out[x++] = data;
1133			}
1134			for (; x < framebufferWidth; x++) out[x] = gray;
1135		}
1136		out += totalWidth;
1137	}
1138}
1139
1140void IOFramebuffer::setupCursor(void)
1141{
1142    StdFBShmem_t *              shmem = GetShmem(this);
1143	IOPixelInformation *        info  = &__private->pixelInfo;
1144    volatile unsigned char *    bits;
1145    IOByteCount                 cursorImageBytes, waitCursorImageBytes;
1146
1147    rowBytes = info->bytesPerRow;
1148    totalWidth = (rowBytes * 8) / info->bitsPerPixel;
1149    bytesPerPixel = info->bitsPerPixel / 8;
1150    if (bytesPerPixel > 4)
1151        __private->cursorBytesPerPixel = 4;
1152    else
1153        __private->cursorBytesPerPixel = bytesPerPixel;
1154
1155    frameBuffer = (volatile unsigned char *) (vramMap ? vramMap->getVirtualAddress() : NULL);
1156    __private->framebufferWidth  = info->activeWidth;
1157    __private->framebufferHeight = info->activeHeight;
1158    if (info->bitsPerComponent > 8)
1159        __private->consoleDepth = info->componentCount * info->bitsPerComponent;
1160    else
1161        __private->consoleDepth = info->bitsPerPixel;
1162
1163    if (shmem)
1164    {
1165		DEBG1(thisName, " setupCursor online %d, (%d, %d) - (%d, %d)\n",
1166                __private->online,
1167                shmem->screenBounds.minx, shmem->screenBounds.miny,
1168                shmem->screenBounds.maxx, shmem->screenBounds.maxy);
1169        if (__private->online &&
1170                ((shmem->screenBounds.maxx == shmem->screenBounds.minx)
1171                || (shmem->screenBounds.maxy == shmem->screenBounds.miny)))
1172        {
1173            // a default if no one calls IOFBSetBounds()
1174            shmem->screenBounds.minx = 0;
1175            shmem->screenBounds.miny = 0;
1176            shmem->screenBounds.maxx = info->activeWidth;
1177            shmem->screenBounds.maxy = info->activeHeight;
1178			__private->screenBounds[0] = shmem->screenBounds;
1179			__private->screenBounds[1] = shmem->screenBounds;
1180
1181			shmem->cursorSize[0] = maxCursorSize;
1182			shmem->cursorSize[1] = __private->maxWaitCursorSize;
1183			shmem->cursorSize[2] = __private->maxWaitCursorSize;
1184			shmem->cursorSize[3] = __private->maxWaitCursorSize;
1185        }
1186		__private->actualVBLCount = 0;
1187
1188        cursorImageBytes = maxCursorSize.width * maxCursorSize.height
1189                           * __private->cursorBytesPerPixel;
1190        waitCursorImageBytes = __private->maxWaitCursorSize.width * __private->maxWaitCursorSize.height
1191                               * __private->cursorBytesPerPixel;
1192        bits = shmem->cursor;
1193
1194        for (UInt32 i = 0; i < __private->numCursorFrames; i++)
1195        {
1196            __private->cursorFlags[i] = kIOFBCursorImageNew;
1197            __private->cursorImages[i] = bits;
1198            bits += i ? waitCursorImageBytes : cursorImageBytes;
1199        }
1200        if (info->bitsPerPixel <= 8)
1201        {
1202            for (UInt32 i = 0; i < __private->numCursorFrames; i++)
1203            {
1204                __private->cursorMasks[i] = bits;
1205                bits += i ? waitCursorImageBytes : cursorImageBytes;
1206            }
1207        }
1208        cursorSave = bits;
1209		cursorEnable = true;
1210    }
1211
1212	cursorBlitProc = (CursorBlitProc) NULL;
1213	cursorRemoveProc = (CursorRemoveProc) NULL;
1214    if (vramMap) switch (info->bitsPerPixel)
1215    {
1216        case 8:
1217            if (colorConvert.t._bm256To38SampleTable
1218                    && colorConvert.t._bm38To256SampleTable)
1219            {
1220                cursorBlitProc = (CursorBlitProc) StdFBDisplayCursor8P;
1221                cursorRemoveProc = (CursorRemoveProc) StdFBRemoveCursor8;
1222            }
1223            break;
1224        case 16:
1225            if (colorConvert.t._bm34To35SampleTable
1226                    && colorConvert.t._bm35To34SampleTable)
1227            {
1228                cursorBlitProc = (CursorBlitProc) StdFBDisplayCursor555;
1229                cursorRemoveProc = (CursorRemoveProc) StdFBRemoveCursor16;
1230            }
1231            break;
1232        case 32:
1233        case 64:
1234			if (10 == info->bitsPerComponent)
1235				cursorBlitProc = (CursorBlitProc) StdFBDisplayCursor30Axxx;
1236			else
1237				cursorBlitProc = (CursorBlitProc) StdFBDisplayCursor32Axxx;
1238			cursorRemoveProc = (CursorRemoveProc) StdFBRemoveCursor32;
1239            break;
1240        default:
1241            break;
1242    }
1243
1244	if (!cursorBlitProc) DEBG1(thisName, " can't do sw cursor at depth %d\n",
1245                  				(uint32_t) info->bitsPerPixel);
1246}
1247
1248void IOFramebuffer::stopCursor( void )
1249{
1250    cursorEnable = false;
1251    cursorBlitProc = (CursorBlitProc) NULL;
1252    cursorRemoveProc = (CursorRemoveProc) NULL;
1253}
1254
1255IOReturn IOFramebuffer::extCreateSharedCursor(
1256        OSObject * target, void * reference, IOExternalMethodArguments * args)
1257{
1258    IOFramebuffer * inst         = (IOFramebuffer *) target;
1259    int             version      = args->scalarInput[0];
1260    int             maxWidth     = args->scalarInput[1];
1261    int             maxWaitWidth = args->scalarInput[2];
1262
1263    IOReturn err;
1264
1265    if ((err = inst->extEntry(true)))
1266        return (err);
1267
1268	err = inst->createSharedCursor( version, maxWidth, maxWaitWidth );
1269
1270    inst->extExit(err);
1271
1272    return (err);
1273}
1274
1275bool IOFramebuffer::deepFramebuffer(IOPixelInformation * pixelInfo)
1276{
1277    if ((pixelInfo->pixelType == kIORGBSignedFloatingPointPixels)
1278    || (pixelInfo->bitsPerComponent > 8))
1279        return (true);
1280    else
1281        return (false);
1282}
1283
1284bool IOFramebuffer::validFramebuffer(IOPixelInformation * pixelInfo)
1285{
1286    if (pixelInfo->pixelType == kIORGBSignedDirectPixels)
1287        return (false);
1288
1289    if (deepFramebuffer(pixelInfo))
1290        return (true);
1291
1292    return (true);
1293}
1294
1295IOIndex IOFramebuffer::closestDepth(IODisplayModeID mode, IOPixelInformation * matchInfo)
1296{
1297	IOReturn err;
1298	IOIndex  depth;
1299	IOPixelInformation pixelInfo;
1300
1301	depth = 0;
1302	for (depth = 0;; depth++)
1303	{
1304		err = getPixelInformation(mode, depth, kIOFBSystemAperture, &pixelInfo);
1305		if (kIOReturnSuccess != err)
1306		{
1307			depth = 0;
1308			break;
1309		}
1310		if ((pixelInfo.bitsPerPixel == matchInfo->bitsPerPixel)
1311		  && (pixelInfo.pixelType == matchInfo->pixelType)
1312		  && (pixelInfo.componentCount == matchInfo->componentCount)
1313		  && (pixelInfo.bitsPerComponent == matchInfo->bitsPerComponent))
1314			break;
1315	}
1316	return (depth);
1317}
1318
1319IOReturn IOFramebuffer::extGetPixelInformation(
1320        OSObject * target, void * reference, IOExternalMethodArguments * args)
1321{
1322    IOFramebuffer *      inst        = (IOFramebuffer *) target;
1323    IODisplayModeID      displayMode = args->scalarInput[0];
1324    IOIndex              depth       = args->scalarInput[1];
1325    IOPixelAperture      aperture    = args->scalarInput[2];
1326    IOPixelInformation * pixelInfo   = (IOPixelInformation *) args->structureOutput;
1327
1328    IOReturn err;
1329
1330    if ((err = inst->extEntry(false)))
1331        return (err);
1332
1333	err = inst->getPixelInformation(displayMode, depth, aperture, pixelInfo);
1334
1335    inst->extExit(err);
1336
1337    return (err);
1338}
1339
1340IOReturn IOFramebuffer::extGetCurrentDisplayMode(
1341        OSObject * target, void * reference, IOExternalMethodArguments * args)
1342{
1343    IOFramebuffer * inst = (IOFramebuffer *) target;
1344    IODisplayModeID displayMode;
1345    IOIndex         depth;
1346
1347    IOReturn err;
1348
1349    if ((err = inst->extEntry(false)))
1350        return (err);
1351
1352    if (kIODisplayModeIDInvalid != inst->__private->aliasMode)
1353    {
1354        displayMode = inst->__private->aliasMode;
1355        depth       = inst->__private->currentDepth;
1356    }
1357    else
1358    {
1359        err = inst->getCurrentDisplayMode(&displayMode, &depth);
1360    }
1361
1362    inst->extExit(err);
1363
1364    args->scalarOutput[0] = displayMode;
1365    args->scalarOutput[1] = depth;
1366
1367    return (err);
1368}
1369
1370IOReturn IOFramebuffer::extSetStartupDisplayMode(
1371        OSObject * target, void * reference, IOExternalMethodArguments * args)
1372{
1373    IOFramebuffer * inst        = (IOFramebuffer *) target;
1374    IODisplayModeID displayMode = args->scalarInput[0];
1375    IOIndex         depth       = args->scalarInput[1];
1376
1377    IOReturn err;
1378
1379    if ((err = inst->extEntry(false)))
1380        return (err);
1381
1382	err = inst->setStartupDisplayMode( displayMode, depth );
1383
1384	if (inst->__private->online && (kIODetailedTimingValid & inst->__private->timingInfo.flags))
1385	{
1386		OSData * data = OSData::withBytes(
1387			&inst->__private->timingInfo, sizeof(inst->__private->timingInfo));
1388		if (data)
1389		{
1390			inst->setPreference(NULL, gIOFBStartupModeTimingKey, data);
1391			data->release();
1392		}
1393	}
1394
1395    inst->extExit(err);
1396
1397    return (err);
1398}
1399
1400#if 0
1401static void IOFBLogGamma(
1402    uint32_t channelCount, uint32_t srcDataCount,
1403    uint32_t dataWidth, const void * data)
1404{
1405    uint32_t c, i;
1406	uint16_t * words;
1407	words = ((uint16_t *)data);
1408    kprintf("/*    0      1      2      3      4      5      6      7      8      9      A      B      C      D      E      F */");
1409	for (c = 0; c < channelCount; c++)
1410	{
1411		for (i = 0; i < srcDataCount; i++)
1412		{
1413			if( 0 == (i & 15))
1414				kprintf("\n    ");
1415			kprintf("0x%04x,", words[i]);
1416		}
1417		words += i;
1418		kprintf("\n\n\n");
1419	}
1420}
1421#endif
1422
1423enum { kIOFBGammaPointCountMax = 256 };
1424enum { kIOFBGammaDesiredError  = 127 };
1425
1426struct IOFBLineSeg
1427{
1428	// [start end]
1429    uint16_t start;
1430    uint16_t end;
1431    uint16_t dist;
1432    uint16_t split;
1433};
1434typedef struct IOFBLineSeg IOFBLineSeg;
1435
1436static void
1437IOFBSegDist(const uint16_t data[], IOFBLineSeg * seg)
1438{
1439	uint16_t start;
1440	uint16_t end;
1441	uint16_t idx;
1442	uint16_t interp;
1443	int16_t  dist;
1444
1445	seg->dist  = 0;
1446	start = seg->start;
1447	end   = seg->end;
1448	for (idx = start + 1; idx < end; idx++)
1449	{
1450		interp = data[start] + ((data[end] - data[start]) * (idx - start)) / (end - start);
1451		dist = data[idx] - interp;
1452		if (dist < 0) dist = -dist;
1453		if (dist > seg->dist)
1454		{
1455			seg->dist = dist;
1456			seg->split = idx;
1457		}
1458	}
1459}
1460
1461static void
1462IOFBSegInit(const uint16_t data[], IOFBLineSeg * seg, uint16_t start, uint16_t end)
1463{
1464	seg->start = start;
1465	seg->end   = end;
1466	IOFBSegDist(data, seg);
1467}
1468
1469static void
1470IOFBSimplifySegs(const uint16_t data[], uint16_t srcDataCount,
1471				uint16_t desiredError, uint16_t * maxError,
1472				IOFBLineSeg * segs, uint16_t count, uint16_t maxCount,
1473				IOFBBootGamma * bootGamma)
1474{
1475	IOFBGamma * channelGamma;
1476	uint16_t    idx;
1477	uint16_t    furthest;
1478	uint16_t    start;
1479
1480	while (count < maxCount)
1481	{
1482		furthest = 0;
1483		for (idx = 1; idx < count; idx++)
1484		{
1485			if (segs[idx].dist > segs[furthest].dist) furthest = idx;
1486		}
1487		if (segs[furthest].dist <= desiredError) break;
1488		bcopy(&segs[furthest+1], &segs[furthest+2], (count - furthest - 1) * sizeof(IOFBLineSeg));
1489		count++;
1490		IOFBSegInit(data, &segs[furthest+1], segs[furthest].split, segs[furthest].end);
1491		segs[furthest].end = segs[furthest].split;
1492		IOFBSegDist(data, &segs[furthest]);
1493	}
1494
1495	*maxError = 0;
1496	channelGamma = &bootGamma->gamma.red;
1497	for (idx = 0; idx < count; idx++)
1498	{
1499		if (segs[idx].dist > *maxError)
1500		{
1501			*maxError = segs[idx].dist;
1502			//IOLog("max error seg 0x%x, 0x%x count %d, target %d\n", segs[idx].start, segs[idx].end, count, maxCount);
1503		}
1504		start = segs[idx].start % srcDataCount;
1505		if (!start)
1506		{
1507			if (segs[idx].start)
1508			{
1509				channelGamma = (typeof(channelGamma)) &channelGamma->points[channelGamma->pointCount];
1510			}
1511			channelGamma->pointCount = 0;
1512			continue;
1513		}
1514		channelGamma->points[channelGamma->pointCount].in =
1515						(start * 65536 / srcDataCount)
1516						 | (start * 65536 / srcDataCount / srcDataCount);
1517		channelGamma->points[channelGamma->pointCount].out = data[segs[idx].start];
1518		channelGamma->pointCount++;
1519	}
1520}
1521
1522static bool
1523IOFBCompressGamma(
1524	IOFBBootGamma * bootGamma,
1525    uint16_t channelCount, uint16_t srcDataCount,
1526    uint16_t dataWidth, const void * _data,
1527    uint16_t desiredError, uint16_t maxCount,
1528    uint16_t * maxError)
1529{
1530	IOFBGamma *      channelGamma;
1531	const uint16_t * data = (typeof(data)) _data;
1532	IOFBLineSeg *    segs;
1533	uint16_t         idx;
1534
1535	if ((3 != channelCount) || (16 != dataWidth)) return (false);
1536
1537	maxCount += 3;
1538	segs = IONew(IOFBLineSeg, maxCount);
1539	if (!segs) return (false);
1540
1541	data = (typeof(data)) _data;
1542
1543	for (idx = 0; idx < 3; idx++) IOFBSegInit(data, &segs[idx], idx * srcDataCount, ((idx + 1) * srcDataCount) - 1);
1544
1545	IOFBSimplifySegs(data, srcDataCount, desiredError, maxError,
1546					segs, 3, maxCount,
1547					bootGamma);
1548
1549	IODelete(segs, IOFBLineSeg, maxCount);
1550
1551	channelGamma = &bootGamma->gamma.red;
1552	for (idx = 0; idx < channelCount; idx++)
1553	{
1554		channelGamma = (typeof(channelGamma)) &channelGamma->points[channelGamma->pointCount];
1555	}
1556	bootGamma->length = ((uintptr_t) channelGamma) - ((uintptr_t) bootGamma);
1557
1558	return (true);
1559}
1560
1561
1562static void __unused
1563IOFBDecompressGamma(const IOFBBootGamma * bootGamma, uint16_t * data, uint16_t count)
1564{
1565	const IOFBGamma * channelGamma;
1566	uint16_t channel, idx, maxIdx, seg;
1567	uint16_t startIn, startOut, point;
1568	uint16_t endIn, endOut;
1569
1570	maxIdx = count - 1;
1571	channelGamma = &bootGamma->gamma.red;
1572	for (channel = 0; channel < 3; channel++)
1573	{
1574		seg = 0;
1575		startIn = 0;
1576		startOut = 0x0000;
1577		endIn = 0;
1578		endOut = 0;
1579		for (idx = 0; idx <= maxIdx; idx++)
1580		{
1581			point = idx * 65535 / maxIdx;
1582			if ((point >= endIn) && (idx != maxIdx))
1583			{
1584				startIn = endIn;
1585				startOut = endOut;
1586				if (seg < channelGamma->pointCount)
1587				{
1588					endIn  = channelGamma->points[seg].in;
1589					endOut = channelGamma->points[seg].out;
1590					seg++;
1591				}
1592				else endIn = endOut = 0xFFFF;
1593			}
1594			data[channel * count + idx] = startOut + ((endOut - startOut) * (point - startIn)) / (endIn - startIn);
1595		}
1596		channelGamma = (typeof(channelGamma)) &channelGamma->points[channelGamma->pointCount];
1597	}
1598}
1599
1600void IOFramebuffer::saveGammaTables(void)
1601{
1602	IORegistryEntry * options;
1603	const OSSymbol *  sym;
1604	IOFBBootGamma *   bootGamma;
1605	IOFramebuffer *   fb;
1606	OSNumber *        num;
1607	OSData *          data;
1608	uint32_t          maxCount;
1609	uint16_t          maxError;
1610
1611	options = IORegistryEntry::fromPath("/options", gIODTPlane);
1612	if (!options) return;
1613
1614	maxCount = (gIOFBBacklightDisplayCount + gIOFBDisplayCount);
1615	if (!maxCount) return;
1616	maxCount = ((0x700 - (maxCount * sizeof(IOFBBootGamma))) / sizeof(IOFBGammaPoint) / maxCount);
1617	if (maxCount > kIOFBGammaPointCountMax) maxCount = kIOFBGammaPointCountMax;
1618
1619	bootGamma = (typeof(bootGamma)) IOMalloc(sizeof(IOFBBootGamma)
1620					+ maxCount * sizeof(IOFBGammaPoint));
1621	if (!bootGamma) return;
1622
1623	data = OSData::withCapacity(512);
1624	if (!data) return;
1625
1626	for (UInt32 index = 0;
1627		 (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
1628		 index++)
1629	{
1630		FBLOCK(fb);
1631		if (fb->__private->display) do
1632		{
1633			bootGamma->vendor  = 0;
1634			bootGamma->product = 0;
1635			bootGamma->serial  = 0;
1636			bootGamma->length  = 0;
1637			bootGamma->resvA   = 0;
1638			bootGamma->resvB   = 0;
1639
1640			if ((num = OSDynamicCast(OSNumber, fb->__private->display->getProperty(kDisplayVendorID))))
1641				bootGamma->vendor  = num->unsigned32BitValue();
1642			if ((num = OSDynamicCast(OSNumber, fb->__private->display->getProperty(kDisplayProductID))))
1643				bootGamma->product = num->unsigned32BitValue();
1644			if ((num = OSDynamicCast(OSNumber, fb->__private->display->getProperty(kDisplaySerialNumber))))
1645				bootGamma->serial  = num->unsigned32BitValue();
1646#if 0
1647        	IOFBLogGamma(fb->__private->rawGammaChannelCount,
1648        				 fb->__private->rawGammaDataCount,
1649        				 fb->__private->rawGammaDataWidth,
1650        				 fb->__private->rawGammaData);
1651#endif
1652        	if (IOFBCompressGamma(bootGamma,
1653        							fb->__private->rawGammaChannelCount,
1654        							fb->__private->rawGammaDataCount,
1655        							fb->__private->rawGammaDataWidth,
1656        							fb->__private->rawGammaData,
1657        						    kIOFBGammaDesiredError, maxCount,
1658        						    &maxError))
1659			{
1660				DEBG1(fb->thisName, " compressed gamma %d max error 0x%04x\n", bootGamma->length, maxError);
1661				if (bootGamma->gamma.red.pointCount)
1662				{
1663					data->appendBytes(bootGamma, bootGamma->length);
1664				}
1665			}
1666		}
1667		while (false);
1668		FBUNLOCK(fb);
1669	}
1670	IOFree(bootGamma, sizeof(IOFBBootGamma)
1671					+ maxCount * sizeof(IOFBGammaPoint));
1672	sym = OSSymbol::withCStringNoCopy(kIOFBBootGammaKey);
1673	if (sym && data->getLength())
1674	{
1675		options->setProperty(sym, data);
1676		sym->release();
1677	}
1678	data->release();
1679	options->release();
1680}
1681
1682IOReturn IOFramebuffer::extSetGammaTable(
1683        OSObject * target, void * reference, IOExternalMethodArguments * args)
1684{
1685    IOFramebuffer * inst          = (IOFramebuffer *) target;
1686    UInt32          channelCount  = args->scalarInput[0];
1687    UInt32          dataCount     = args->scalarInput[1];
1688    UInt32          dataWidth     = args->scalarInput[2];
1689    IOReturn        err;
1690    IOByteCount     dataLen;
1691
1692    if ((err = inst->extEntry(true)))
1693        return (err);
1694
1695    dataLen  = (dataWidth + 7) / 8;
1696    dataLen *= dataCount * channelCount;
1697
1698    if (dataLen != inst->__private->rawGammaDataLen)
1699    {
1700        if (inst->__private->rawGammaDataLen)
1701            IODelete(inst->__private->rawGammaData, UInt8, inst->__private->rawGammaDataLen);
1702        inst->__private->rawGammaData = IONew(UInt8, dataLen);
1703        inst->__private->rawGammaDataLen = dataLen;
1704    }
1705
1706    if (!inst->__private->rawGammaData)
1707        err = kIOReturnNoMemory;
1708    else
1709    {
1710        inst->__private->rawGammaChannelCount = channelCount;
1711        inst->__private->rawGammaDataCount    = dataCount;
1712        inst->__private->rawGammaDataWidth    = dataWidth;
1713
1714        if (args->structureInputDescriptor)
1715        {
1716            if (dataLen != args->structureInputDescriptor->getLength())
1717                err = kIOReturnBadArgument;
1718            else
1719            {
1720                err = args->structureInputDescriptor->prepare(kIODirectionOut);
1721                if ((kIOReturnSuccess == err)
1722                 && (dataLen != args->structureInputDescriptor->readBytes(
1723                                0, inst->__private->rawGammaData, dataLen)))
1724                {
1725                    err = kIOReturnVMError;
1726                }
1727                args->structureInputDescriptor->complete();
1728            }
1729        }
1730        else
1731        {
1732            if (dataLen == args->structureInputSize)
1733                bcopy(args->structureInput, inst->__private->rawGammaData, dataLen);
1734            else
1735                err = kIOReturnBadArgument;
1736        }
1737        if (kIOReturnSuccess == err)
1738        {
1739#if 0
1740        	IOFBLogGamma(inst->__private->rawGammaChannelCount,
1741        				 inst->__private->rawGammaDataCount,
1742        				 inst->__private->rawGammaDataWidth,
1743        				 inst->__private->rawGammaData);
1744#endif
1745            err = inst->updateGammaTable(channelCount, dataCount, dataWidth, inst->__private->rawGammaData);
1746        }
1747    }
1748#if 0
1749DEBG1(inst->thisName, " extSetGammaTable(%x) online %d %ld %ld data %x\n",
1750	err, inst->__private->online,
1751	channelCount, dataCount,
1752	*((uint32_t *) inst->__private->rawGammaData));
1753#endif
1754
1755	if (!inst->__private->gammaSet)
1756	{
1757		gIOFBGrayValue = kIOFBGrayValue;
1758	    inst->__private->gammaSet = 1;
1759	}
1760
1761    inst->extExit(err);
1762
1763    return (err);
1764}
1765
1766IOReturn IOFramebuffer::updateGammaTable(
1767    UInt32 channelCount, UInt32 srcDataCount,
1768    UInt32 dataWidth, const void * data,
1769    bool immediate)
1770{
1771    IOReturn    err = kIOReturnBadArgument;
1772    IOByteCount dataLen;
1773    UInt16 *    channelData;
1774    UInt32      dataCount;
1775    UInt32      tryWidth;
1776    UInt8 *     table = NULL;
1777    bool        needAlloc;
1778    bool        gammaHaveScale = ((1 << 16) != __private->gammaScale[0])
1779                                || ((1 << 16) != __private->gammaScale[1])
1780                                || ((1 << 16) != __private->gammaScale[2])
1781                                || ((1 << 16) != __private->gammaScale[3]);
1782	const uint32_t * adjustParams = NULL;
1783	const uint32_t * adjustNext   = NULL;
1784	uint32_t         gammaThresh;
1785	uint32_t         gammaAdjust;
1786
1787	if (GAMMA_ADJ && gIOGraphicsControl && (__private->desiredGammaDataWidth <= 8))
1788	{
1789		static const uint32_t _params[]  = { 138, 3, 256, 4 };
1790		adjustParams = &_params[0];
1791	}
1792	else
1793	{
1794		gammaThresh = -1U;
1795		gammaAdjust = 0;
1796	}
1797    do
1798    {
1799        if (!__private->online)
1800        {
1801			DEBG1(thisName, " offline updateGammaTable\n");
1802			err = kIOReturnOffline;
1803            break;
1804		}
1805        if (dataWidth != 16)
1806            break;
1807
1808        if (!__private->desiredGammaDataWidth)
1809        {
1810            __private->desiredGammaDataWidth = dataWidth;
1811            __private->desiredGammaDataCount = srcDataCount;
1812        }
1813
1814        dataCount = __private->desiredGammaDataCount;
1815        dataLen   = (__private->desiredGammaDataWidth + 7) / 8;
1816        dataLen  *= dataCount * channelCount;
1817        dataLen  += __private->gammaHeaderSize;
1818
1819        needAlloc = (0 == __private->gammaDataLen);
1820        if (!needAlloc)
1821        {
1822            table = __private->gammaData;
1823            if (__private->gammaDataLen != dataLen)
1824            {
1825                IODelete(table, UInt8, __private->gammaDataLen);
1826                __private->gammaData = NULL;
1827                needAlloc = true;
1828            }
1829            __private->gammaDataLen = 0;
1830            __private->gammaNeedSet = false;
1831        }
1832
1833        if (needAlloc)
1834        {
1835            table = IONew(UInt8, dataLen);
1836            if (!table)
1837            {
1838                err = kIOReturnNoMemory;
1839                continue;
1840            }
1841            __private->gammaData = table;
1842        }
1843
1844        __private->gammaChannelCount = channelCount;
1845        __private->gammaDataCount    = dataCount;
1846
1847        table += __private->gammaHeaderSize;
1848
1849        tryWidth = __private->desiredGammaDataWidth;
1850
1851#if 0
1852		OSData * ddata;
1853		if (data)
1854		{
1855			ddata = OSData::withBytes((void *)data, srcDataCount*channelCount*sizeof(UInt16));
1856			if (ddata)
1857			{
1858				setProperty("GammaIn", ddata);
1859				ddata->release();
1860			}
1861		}
1862        ddata = OSData::withBytesNoCopy(table, dataLen - __private->gammaHeaderSize);
1863		if (ddata)
1864		{
1865			setProperty("GammaOut", ddata);
1866			ddata->release();
1867		}
1868#endif
1869
1870        if ((__private->desiredGammaDataCount == dataCount)
1871          && (tryWidth == dataWidth)
1872          && !gammaHaveScale
1873          && data
1874          && !adjustParams)
1875            bcopy(data, table, dataLen - __private->gammaHeaderSize);
1876        else
1877        {
1878            uint32_t pin, pt5, in, out, channel, idx, maxSrc, maxDst, interpCount;
1879            int64_t value, value2;
1880
1881            pin = (1 << tryWidth) - 1;
1882            pt5 = 0; //(1 << (tryWidth - 1));               // truncate not round
1883            if (gammaHaveScale)
1884                dataWidth += 32;
1885
1886            channelData = (UInt16 *) data;
1887            maxSrc = (srcDataCount - 1);
1888            maxDst = (__private->desiredGammaDataCount - 1);
1889            if ((srcDataCount < __private->desiredGammaDataCount)
1890             && (0 == (__private->desiredGammaDataCount % srcDataCount)))
1891                interpCount = __private->desiredGammaDataCount / srcDataCount;
1892            else
1893                interpCount = 0;
1894
1895            for (out = 0, channel = 0; channel < channelCount; channel++)
1896            {
1897				if (adjustParams)
1898				{
1899					gammaThresh = 0;
1900					adjustNext = adjustParams;
1901				}
1902                for (idx = 0; idx <= maxDst; idx++)
1903                {
1904					if (idx >= gammaThresh)
1905					{
1906						gammaThresh = *adjustNext++;
1907						gammaAdjust = *adjustNext++;
1908					}
1909					if (channelData)
1910					{
1911						in = ((idx * maxSrc) + (idx ? (idx - 1) : 0)) / maxDst;
1912						value = (channelData[in] /*+ pt5*/);
1913						if (interpCount && (in < maxSrc))
1914						{
1915							value2 = (channelData[in+1] /*+ pt5*/);
1916							value += ((value2 - value) * (idx % interpCount) + (interpCount - 1)) / interpCount;
1917						}
1918					}
1919					else
1920					    value = (idx * ((1 << dataWidth) - 1)) / maxDst;
1921                    if (gammaHaveScale)
1922                    {
1923                        value = ((value * __private->gammaScale[channel] * __private->gammaScale[3]) + (1U << 31));
1924                    }
1925                    value = (value >> (dataWidth - tryWidth));
1926					if (value)
1927						value += gammaAdjust;
1928                    if (value > pin)
1929                        value = pin;
1930
1931                    if (tryWidth <= 8)
1932                        ((UInt8 *) table)[out] = (value & 0xff);
1933                    else
1934                        ((UInt16 *) table)[out] = value;
1935                    out++;
1936                }
1937                if (channelData) channelData += srcDataCount;
1938            }
1939        }
1940        __private->gammaDataWidth = tryWidth;
1941        __private->gammaDataLen   = dataLen;
1942
1943        if (ASYNC_GAMMA && !immediate)
1944        {
1945			if (__private->vblThrottle && __private->deferredCLUTSetTimerEvent)
1946			{
1947				AbsoluteTime deadline;
1948				getTimeOfVBL(&deadline, 1);
1949				__private->deferredCLUTSetTimerEvent->wakeAtTime(deadline);
1950				__private->gammaNeedSet = true;
1951				err = kIOReturnSuccess;
1952			}
1953			else if (__private->deferredCLUTSetEvent)
1954			{
1955				__private->gammaNeedSet = true;
1956				err = kIOReturnSuccess;
1957			}
1958		}
1959		if (!__private->gammaNeedSet)
1960        {
1961            err = setGammaTable( __private->gammaChannelCount, __private->gammaDataCount,
1962                                 __private->gammaDataWidth, __private->gammaData );
1963            updateCursorForCLUTSet();
1964        }
1965    }
1966    while (false);
1967
1968    return (err);
1969}
1970
1971
1972IOReturn IOFramebuffer::extSetCLUTWithEntries(
1973        OSObject * target, void * reference, IOExternalMethodArguments * args)
1974{
1975    IOFramebuffer * inst    = (IOFramebuffer *) target;
1976    UInt32          index   = args->scalarInput[0];
1977    IOOptionBits    options = args->scalarInput[1];
1978    IOColorEntry *  colors  = (IOColorEntry *) args->structureInput;
1979    IOByteCount     dataLen = args->structureInputSize;
1980
1981    IOReturn    err;
1982    UInt8 *     table;
1983    bool        needAlloc;
1984
1985    if ((err = inst->extEntry(false)))
1986        return (err);
1987
1988    err = kIOReturnBadArgument;
1989    if (inst->__private->deferredCLUTSetEvent)
1990    {
1991        do
1992        {
1993            needAlloc = (0 == inst->__private->clutDataLen);
1994            if (!needAlloc)
1995            {
1996                if (index || (inst->__private->clutDataLen != dataLen))
1997                {
1998                    inst->checkDeferredCLUTSet();
1999                    needAlloc = true;
2000                }
2001                inst->__private->clutDataLen = 0;
2002            }
2003
2004            if (needAlloc)
2005            {
2006                table = IONew(UInt8, dataLen);
2007                if (!table)
2008                {
2009                    err = kIOReturnNoMemory;
2010                    continue;
2011                }
2012                inst->__private->clutData = table;
2013            }
2014            else
2015                table = inst->__private->clutData;
2016
2017            inst->__private->clutIndex   = index;
2018            inst->__private->clutOptions = options;
2019            inst->__private->clutDataLen = dataLen;
2020
2021            bcopy(colors, table, dataLen);
2022
2023			if (inst->__private->vblThrottle && inst->__private->deferredCLUTSetTimerEvent)
2024			{
2025				AbsoluteTime deadline;
2026				inst->getTimeOfVBL(&deadline, 1);
2027				inst->__private->deferredCLUTSetTimerEvent->wakeAtTime(deadline);
2028			}
2029
2030            err = kIOReturnSuccess;
2031        }
2032        while (false);
2033    }
2034    else
2035    {
2036        err = inst->setCLUTWithEntries( colors, index,
2037                                  dataLen / sizeof( IOColorEntry), options );
2038        inst->updateCursorForCLUTSet();
2039    }
2040
2041    if (inst == gIOFBConsoleFramebuffer)
2042    {
2043        UInt32 count = index + dataLen / sizeof(IOColorEntry);
2044        if (count > 256)
2045            count = 256;
2046        for (; index < count; index++)
2047        {
2048            appleClut8[index * 3 + 0] = colors[index].red   >> 8;
2049            appleClut8[index * 3 + 1] = colors[index].green >> 8;
2050            appleClut8[index * 3 + 2] = colors[index].blue  >> 8;
2051        }
2052    }
2053
2054    inst->extExit(err);
2055
2056    return (err);
2057}
2058
2059void IOFramebuffer::updateCursorForCLUTSet( void )
2060{
2061    if (__private->cursorClutDependent)
2062    {
2063        StdFBShmem_t *shmem = GetShmem(this);
2064
2065        SETSEMA(shmem);
2066        if ((kIOFBHardwareCursorActive == shmem->hardwareCursorActive)
2067         && !shmem->cursorShow)
2068        {
2069            RemoveCursor(this);
2070            setCursorImage( (void *)(uintptr_t) shmem->frame );
2071            DisplayCursor(this);
2072        }
2073        CLEARSEMA(shmem, this);
2074    }
2075}
2076
2077void IOFramebuffer::deferredCLUTSetInterrupt( OSObject * owner,
2078                                              IOInterruptEventSource * evtSrc, int intCount )
2079{
2080    IOFramebuffer * self = (IOFramebuffer *) owner;
2081
2082    if (self->__private->waitVBLEvent)
2083    {
2084        FBWL(self)->wakeupGate(self->__private->waitVBLEvent, true);
2085        self->__private->waitVBLEvent = 0;
2086    }
2087
2088    self->checkDeferredCLUTSet();
2089}
2090
2091void IOFramebuffer::deferredCLUTSetTimer(OSObject * owner, IOTimerEventSource * source)
2092{
2093    IOFramebuffer * self = (IOFramebuffer *) owner;
2094    self->checkDeferredCLUTSet();
2095}
2096
2097void IOFramebuffer::checkDeferredCLUTSet( void )
2098{
2099    IOReturn    ret;
2100    bool        gammaNeedSet = __private->gammaNeedSet;
2101    IOByteCount clutLen      = __private->clutDataLen;
2102
2103    if( !gammaNeedSet && !clutLen)
2104        return;
2105
2106    __private->gammaNeedSet = false;
2107    __private->clutDataLen  = 0;
2108
2109    if (gammaNeedSet)
2110    {
2111        ret = setGammaTable( __private->gammaChannelCount, __private->gammaDataCount,
2112                             __private->gammaDataWidth, __private->gammaData );
2113    }
2114
2115    if (clutLen)
2116    {
2117        ret = setCLUTWithEntries( (IOColorEntry *) __private->clutData, __private->clutIndex,
2118                                  clutLen / sizeof( IOColorEntry), __private->clutOptions );
2119
2120        IODelete(__private->clutData, UInt8, clutLen);
2121    }
2122
2123    updateCursorForCLUTSet();
2124}
2125
2126IOReturn IOFramebuffer::createSharedCursor(
2127    int version, int maxWidth, int maxWaitWidth )
2128{
2129    StdFBShmem_t *      shmem;
2130    UInt32              shmemVersion;
2131    IOByteCount         size, maxImageSize, maxWaitImageSize;
2132    UInt32              numCursorFrames;
2133
2134    DEBG(thisName, " vers = %08x, %d x %d\n",
2135         version, maxWidth, maxWaitWidth);
2136
2137    shmemVersion = version & kIOFBShmemVersionMask;
2138
2139    if (shmemVersion == kIOFBTenPtTwoShmemVersion)
2140    {
2141        numCursorFrames = (kIOFBShmemCursorNumFramesMask & version) >> kIOFBShmemCursorNumFramesShift;
2142
2143        setProperty(kIOFBWaitCursorFramesKey, (numCursorFrames - 1), 32);
2144        setProperty(kIOFBWaitCursorPeriodKey, 33333333, 32);    /* 30 fps */
2145    }
2146    else if (shmemVersion == kIOFBTenPtOneShmemVersion)
2147    {
2148        numCursorFrames = 4;
2149    }
2150    else
2151        return (kIOReturnUnsupported);
2152
2153    shmemClientVersion = shmemVersion;
2154
2155    if (__private->cursorFlags)
2156    {
2157        IODelete( __private->cursorFlags, UInt8, __private->numCursorFrames );
2158        __private->cursorFlags = 0;
2159    }
2160    if (__private->cursorImages)
2161    {
2162        IODelete( __private->cursorImages, volatile unsigned char *, __private->numCursorFrames );
2163        __private->cursorImages = 0;
2164    }
2165    if (__private->cursorMasks)
2166    {
2167        IODelete( __private->cursorMasks, volatile unsigned char *, __private->numCursorFrames );
2168        __private->cursorMasks = 0;
2169    }
2170    __private->numCursorFrames = numCursorFrames;
2171    __private->cursorFlags     = IONew( UInt8, numCursorFrames );
2172    __private->cursorImages    = IONew( volatile unsigned char *, numCursorFrames );
2173    __private->cursorMasks     = IONew( volatile unsigned char *, numCursorFrames );
2174
2175    if (!__private->cursorFlags || !__private->cursorImages || !__private->cursorMasks)
2176        return (kIOReturnNoMemory);
2177
2178    bzero(__private->cursorFlags,  numCursorFrames * sizeof(UInt8));
2179    bzero(__private->cursorImages, numCursorFrames * sizeof(volatile unsigned char *));
2180    bzero(__private->cursorMasks,  numCursorFrames * sizeof(volatile unsigned char *));
2181
2182    maxImageSize = (maxWidth * maxWidth * kIOFBMaxCursorDepth) / 8;
2183    maxWaitImageSize = (maxWaitWidth * maxWaitWidth * kIOFBMaxCursorDepth) / 8;
2184
2185    size = sizeof( StdFBShmem_t)
2186           + maxImageSize
2187           + max(maxImageSize, maxWaitImageSize)
2188           + ((numCursorFrames - 1) * maxWaitImageSize);
2189
2190    if (!sharedCursor || (size != sharedCursor->getLength()))
2191    {
2192        IOBufferMemoryDescriptor * newDesc;
2193
2194        priv = 0;
2195        newDesc = IOBufferMemoryDescriptor::withOptions(
2196                      kIODirectionNone | kIOMemoryKernelUserShared, size );
2197        if (!newDesc)
2198            return (kIOReturnNoMemory);
2199
2200        if (sharedCursor)
2201            sharedCursor->release();
2202        sharedCursor = newDesc;
2203    }
2204    shmem = (StdFBShmem_t *) sharedCursor->getBytesNoCopy();
2205    priv = shmem;
2206
2207    // Init shared memory area
2208    bzero( shmem, size );
2209	shmem->version = shmemClientVersion;
2210    shmem->structSize = size;
2211    shmem->cursorShow = 1;
2212    shmem->hardwareCursorCapable = haveHWCursor;
2213    for (UInt32 i = 0; i < numCursorFrames; i++)
2214        __private->cursorFlags[i] = kIOFBCursorImageNew;
2215
2216    maxCursorSize.width = maxWidth;
2217    maxCursorSize.height = maxWidth;
2218    __private->maxWaitCursorSize.width = maxWaitWidth;
2219    __private->maxWaitCursorSize.height = maxWaitWidth;
2220
2221    doSetup( false );
2222
2223    return (kIOReturnSuccess);
2224}
2225
2226IOReturn IOFramebuffer::setBoundingRect( IOGBounds * bounds )
2227{
2228    return (kIOReturnUnsupported);
2229}
2230
2231/**
2232 ** IOUserClient methods
2233 **/
2234
2235IOReturn IOFramebuffer::newUserClient(  task_t          owningTask,
2236                                        void *          security_id,
2237                                        UInt32          type,
2238                                        IOUserClient ** handler )
2239
2240{
2241    IOReturn            err = kIOReturnSuccess;
2242    IOUserClient *      newConnect = 0;
2243    IOUserClient *      theConnect = 0;
2244
2245    switch (type)
2246    {
2247        case kIOFBServerConnectType:
2248            if (serverConnect)
2249                err = kIOReturnExclusiveAccess;
2250            else
2251            {
2252                if ((this == gIOFBConsoleFramebuffer) || !gIOFBConsoleFramebuffer)
2253                    getPlatform()->setConsoleInfo( 0, kPEReleaseScreen);
2254
2255                err = open();
2256                if (kIOReturnSuccess == err)
2257                    newConnect = IOFramebufferUserClient::withTask(owningTask);
2258            }
2259            break;
2260
2261        case kIOFBSharedConnectType:
2262            if (sharedConnect)
2263            {
2264                theConnect = sharedConnect;
2265                theConnect->retain();
2266            }
2267            else if (serverConnect)
2268            {
2269                newConnect = IOFramebufferSharedUserClient::withTask(owningTask);
2270                if (newConnect)
2271                    newConnect->retain();
2272            }
2273            else
2274                err = kIOReturnNotOpen;
2275            break;
2276
2277        default:
2278            err = kIOReturnBadArgument;
2279    }
2280
2281    if (newConnect)
2282    {
2283        if ((false == newConnect->attach(this))
2284                || (false == newConnect->start(this)))
2285        {
2286            newConnect->detach( this );
2287            newConnect->release();
2288        }
2289        else
2290            theConnect = newConnect;
2291    }
2292
2293    *handler = theConnect;
2294    return (err);
2295}
2296
2297IOReturn IOFramebuffer::extGetDisplayModeCount(
2298        OSObject * target, void * reference, IOExternalMethodArguments * args)
2299{
2300    IOFramebuffer * inst  = (IOFramebuffer *) target;
2301    uint64_t *      count = &args->scalarOutput[0];
2302
2303    IOReturn err;
2304
2305    if ((err = inst->extEntry(false)))
2306        return (err);
2307
2308	*count = inst->dead ? 0 : inst->getDisplayModeCount();
2309
2310    inst->extExit(err);
2311
2312    return (kIOReturnSuccess);
2313}
2314
2315IOReturn IOFramebuffer::extGetDisplayModes(
2316        OSObject * target, void * reference, IOExternalMethodArguments * args)
2317{
2318    IOFramebuffer *   inst     = (IOFramebuffer *) target;
2319    IODisplayModeID * allModes = (IODisplayModeID *) args->structureOutput;
2320    uint32_t *        size     = &args->structureOutputSize;
2321
2322    IOReturn    err;
2323    IOByteCount outSize;
2324
2325    if ((err = inst->extEntry(false)))
2326        return (err);
2327
2328	outSize = inst->getDisplayModeCount() * sizeof( IODisplayModeID);
2329	if (*size >= outSize)
2330	{
2331		*size = outSize;
2332		err = inst->getDisplayModes( allModes );
2333	}
2334	else
2335		err = kIOReturnBadArgument;
2336
2337    inst->extExit(err);
2338
2339    return (err);
2340}
2341
2342IOReturn IOFramebuffer::extGetVRAMMapOffset(
2343        OSObject * target, void * reference, IOExternalMethodArguments * args)
2344{
2345    IOFramebuffer * inst   = (IOFramebuffer *) target;
2346    // IOPixelAperture aperture = args->scalarInput[0];
2347    uint64_t *      offset = &args->scalarOutput[0];
2348
2349    IOReturn err;
2350
2351    if ((err = inst->extEntry(false)))
2352        return (err);
2353
2354	if (inst->vramMap) *offset = inst->vramMapOffset;
2355	else
2356    {
2357    	*offset = 0;
2358    	err = kIOReturnNoSpace;
2359    }
2360
2361    inst->extExit(err);
2362
2363    return (err);
2364}
2365
2366IOReturn IOFramebuffer::_extEntry(bool system, bool allowOffline, const char * where)
2367{
2368    IOReturn             err = kIOReturnSuccess;
2369
2370	if (system)
2371	{
2372		TIMELOCK(gIOFBSystemWorkLoop, thisName, where);
2373	}
2374
2375    TIMELOCK(FBWL(this), thisName, where);
2376
2377    while (!pagingState && !gIOFBSystemPowerAckTo)
2378    {
2379//		IODisplayWrangler::activityChange(this);
2380		if (system)
2381		{
2382			FBUNLOCK(this);
2383			err = gIOFBSystemWorkLoop->sleepGate(&serverConnect, false);
2384			FBLOCK(this);
2385		}
2386		else
2387			err = FBWL(this)->sleepGate(&serverConnect, false);
2388
2389        if (kIOReturnSuccess != err)
2390            break;
2391    }
2392
2393	if ((kIOReturnSuccess == err) && !__private->online && !allowOffline) err = kIOReturnOffline;
2394
2395	if (kIOReturnSuccess != err) DEBG1(thisName, " %s: err 0x%x\n", where, err);
2396
2397	if (kIOReturnSuccess != err)
2398		_extExit(system, err, where);
2399
2400    return (err);
2401}
2402
2403void IOFramebuffer::_extExit(bool system, IOReturn result, const char * where)
2404{
2405	FBUNLOCK(this);
2406	if (system)
2407		SYSUNLOCK();
2408}
2409
2410 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2411
2412IOReturn IOFramebuffer::extSetBounds(
2413        OSObject * target, void * reference, IOExternalMethodArguments * args)
2414{
2415    IOFramebuffer * inst   = (IOFramebuffer *) target;
2416    IOGBounds *     bounds = (IOGBounds *) args->structureInput;
2417    uint32_t		inSize = args->structureInputSize;
2418    uint32_t        virtIdx = 0;
2419    SInt16			ox, oy;
2420
2421    IOReturn       err;
2422    StdFBShmem_t * shmem;
2423
2424	if (inSize < sizeof(IOGBounds))
2425	    return (kIOReturnBadArgument);
2426	if (inSize >= (2 * sizeof(IOGBounds)))
2427		virtIdx = 1;
2428
2429	DEBG1(inst->thisName, " (%d, %d), (%d, %d)\n",
2430                bounds->minx, bounds->miny,
2431                bounds->maxx, bounds->maxy);
2432
2433    if (true &&
2434        (1 == (bounds->maxx - bounds->minx))
2435        && (1 == (bounds->maxy - bounds->miny)))
2436    {
2437        shmem = GetShmem(inst);
2438        if (shmem)
2439        {
2440			ox = shmem->screenBounds.minx;
2441			oy = shmem->screenBounds.miny;
2442
2443            shmem->screenBounds = *bounds;
2444			inst->__private->screenBounds[0] = bounds[0];
2445			inst->__private->screenBounds[1] = bounds[virtIdx];
2446
2447			ox = bounds->minx - ox;
2448			oy = bounds->miny - oy;
2449			shmem->saveRect.minx += ox;
2450			shmem->saveRect.maxx += ox;
2451			shmem->saveRect.miny += oy;
2452			shmem->saveRect.maxy += oy;
2453    	}
2454
2455        return (kIOReturnSuccess);
2456    }
2457
2458    if ((err = inst->extEntry(true)))
2459        return (err);
2460
2461	shmem = GetShmem(inst);
2462    if (shmem)
2463    {
2464    	ox = shmem->screenBounds.minx;
2465    	oy = shmem->screenBounds.miny;
2466
2467        if ((kIOFBHardwareCursorActive == shmem->hardwareCursorActive) && inst->__private->online)
2468        {
2469            IOReturn   err;
2470            IOGPoint * hs;
2471            hs = &shmem->hotSpot[0 != shmem->frame];
2472            err = inst->_setCursorState(
2473                      shmem->cursorLoc.x - hs->x - ox,
2474                      shmem->cursorLoc.y - hs->y - oy, false );
2475        }
2476
2477        shmem->screenBounds = *bounds;
2478		inst->__private->screenBounds[0] = bounds[0];
2479		inst->__private->screenBounds[1] = bounds[virtIdx];
2480
2481		ox = bounds->minx - ox;
2482		oy = bounds->miny - oy;
2483		shmem->saveRect.minx += ox;
2484		shmem->saveRect.maxx += ox;
2485		shmem->saveRect.miny += oy;
2486		shmem->saveRect.maxy += oy;
2487    }
2488
2489    inst->extExit(err);
2490
2491    return (kIOReturnSuccess);
2492}
2493
2494IOReturn IOFramebuffer::extValidateDetailedTiming(
2495        OSObject * target, void * reference, IOExternalMethodArguments * args)
2496{
2497    IOFramebuffer * inst           = (IOFramebuffer *) target;
2498    void *          description    = const_cast<void *>(args->structureInput);
2499    void *          outDescription = args->structureOutput;
2500    uint32_t        inSize         = args->structureInputSize;
2501    uint32_t *      outSize        = &args->structureOutputSize;
2502
2503    IOReturn    err;
2504
2505    if (*outSize != inSize)
2506        return (kIOReturnBadArgument);
2507
2508    if ((err = inst->extEntry(false)))
2509        return (err);
2510
2511	err = inst->validateDetailedTiming( description, inSize );
2512
2513    if (kIOReturnSuccess == err)
2514        bcopy( description, outDescription, inSize );
2515
2516    inst->extExit(err);
2517
2518    return (err);
2519}
2520
2521
2522IOReturn IOFramebuffer::extSetColorConvertTable(
2523        OSObject * target, void * reference, IOExternalMethodArguments * args)
2524{
2525    IOFramebuffer * inst   = (IOFramebuffer *) target;
2526    UInt32          select = args->scalarInput[0];
2527    UInt8 *         data   = (UInt8 *) args->structureInput;
2528    IOByteCount     length = args->structureInputSize;
2529
2530    static const IOByteCount checkLength[] = {
2531                16 * sizeof( UInt8),
2532                32 * sizeof( UInt8),
2533                256 * sizeof( UInt32),
2534                5 * 256 * sizeof( UInt8) };
2535
2536    IOReturn            err;
2537    UInt8 *             table;
2538
2539    if (select > 3)
2540        return (kIOReturnBadArgument);
2541
2542    if (length != checkLength[select])
2543        return (kIOReturnBadArgument);
2544
2545    if ((err = inst->extEntry(true)))
2546        return (err);
2547
2548    do
2549    {
2550        err = kIOReturnNoMemory;
2551        table = inst->colorConvert.tables[select];
2552        if (0 == table)
2553        {
2554            table = (UInt8 *) IOMalloc( length );
2555            inst->colorConvert.tables[select] = table;
2556        }
2557        if (!table)
2558            continue;
2559
2560        bcopy( data, table, length );
2561        if (select == 3)
2562            inst->white = data[data[255] + data[511] + data[767] + 1024];
2563
2564        if ((false == inst->cursorEnable)
2565                && inst->__private->online
2566                && inst->colorConvert.tables[0] && inst->colorConvert.tables[1]
2567                && inst->colorConvert.tables[2] && inst->colorConvert.tables[3]
2568//                && inst->vramMap
2569                && (inst->__private->pixelInfo.activeWidth >= 128))
2570            inst->setupCursor();
2571
2572        err = kIOReturnSuccess;
2573    }
2574    while (false);
2575
2576    inst->extExit(err);
2577
2578    return (err);
2579}
2580
2581/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2582
2583bool IOFramebuffer::requestTerminate( IOService * provider, IOOptionBits options )
2584{
2585    SYSLOCK();
2586
2587    if (opened)
2588    {
2589        if (!gRunawayFramebuffers)
2590            gRunawayFramebuffers = OSArray::withCapacity(4);
2591        if (gRunawayFramebuffers)
2592            gRunawayFramebuffers->setObject(this);
2593    }
2594
2595    SYSUNLOCK();
2596
2597    return (false);
2598}
2599
2600void IOFramebuffer::stop( IOService * provider )
2601{
2602
2603    if (opened)
2604    {
2605        SYSLOCK();
2606
2607        dead = true;
2608
2609        setAttribute( kIOSystemPowerAttribute, kIOMessageSystemWillPowerOff );
2610
2611        SYSUNLOCK();
2612
2613        temporaryPowerClampOn();        // only to clear out kIOPMPreventSystemSleep
2614        PMstop();
2615        initialized = false;
2616
2617        connectChangeInterrupt(this, 0);
2618    }
2619
2620    return (super::stop(provider));
2621}
2622
2623void IOFramebuffer::free()
2624{
2625    if (vblSemaphore)
2626        semaphore_destroy(kernel_task, vblSemaphore);
2627    if (__private)
2628    {
2629        IODelete( __private, IOFramebufferPrivate, 1 );
2630        __private = 0;
2631    }
2632    super::free();
2633}
2634
2635IOService * IOFramebuffer::probe( IOService * provider, SInt32 * score )
2636{
2637    IOFramebuffer * replace = 0;
2638
2639    if (gRunawayFramebuffers)
2640    {
2641        SYSLOCK();
2642
2643        replace = (IOFramebuffer *) gRunawayFramebuffers->getObject(0);
2644        gRunawayFramebuffers->removeObject(0);
2645
2646        SYSUNLOCK();
2647    }
2648
2649    return (replace ? replace : this);
2650}
2651
2652
2653__private_extern__ "C" kern_return_t IOGraphicsFamilyModuleStart(kmod_info_t *ki, void *data)
2654{
2655	gIOFBSystemWorkLoop = IOGraphicsWorkLoop::workLoop(0, NULL, NULL, NULL);
2656    if (!gIOFBSystemWorkLoop) panic("gIOFBSystemWorkLoop");
2657	gAllFramebuffers     = OSArray::withCapacity(1);
2658	gStartedFramebuffers = OSArray::withCapacity(1);
2659	gIOFramebufferKey    = OSSymbol::withCStringNoCopy("IOFramebuffer");
2660
2661	if (PE_parse_boot_argn("iog", &gIOGDebugFlags, sizeof(gIOGDebugFlags)))
2662	{
2663		DEBG1("IOGraphics", " flags 0x%x\n", gIOGDebugFlags);
2664		gIOFBLidOpenMode = (0 != (kIOGDbgLidOpen     & gIOGDebugFlags));
2665		gIOFBVBLThrottle = (0 != (kIOGDbgVBLThrottle & gIOGDebugFlags));
2666		gIOFBVBLDrift    = (0 != (kIOGDbgVBLDrift & gIOGDebugFlags));
2667	}
2668	else
2669	{
2670		gIOFBLidOpenMode = (version_major >= 11);
2671		gIOFBVBLThrottle = (version_major >= 11);
2672	}
2673	gIOGFades = (version_major >= 14);
2674	if (!PE_parse_boot_argn("iognotifyto", &gIOGNotifyTO, sizeof(gIOGNotifyTO))
2675		|| !gIOGNotifyTO)
2676	{
2677		gIOGNotifyTO = kSystemWillSleepTimeout;
2678	}
2679	DEBG1("IOGraphics", " notify timeout %ds\n", gIOGNotifyTO);
2680
2681	return (kIOReturnSuccess);
2682}
2683
2684static bool
2685IOFramebufferLockedSerialize(void * target, void * ref, OSSerialize * s)
2686{
2687    bool ok;
2688    SYSLOCK();
2689    ok = ((OSObject *) target)->serialize(s);
2690    SYSUNLOCK();
2691    return (ok);
2692}
2693
2694void IOFramebuffer::initialize()
2695{
2696	OSDictionary  *     matching;
2697	OSIterator    *     iter;
2698
2699	gIOFBServerInit = true;
2700	gIOFBBlackBoot  = (0 != (kBootArgsFlagBlack & ((boot_args *) PE_state.bootArgs)->flags));
2701	if (gIOFBBlackBoot) gIOFBGrayValue = 0;
2702
2703	gIOFBGetSensorValueKey = OSSymbol::withCStringNoCopy(kIOFBGetSensorValueKey);
2704	gIOFBRotateKey = OSSymbol::withCStringNoCopy(kIOFBRotatePrefsKey);
2705	gIOFBStartupModeTimingKey = OSSymbol::withCStringNoCopy(kIOFBStartupTimingPrefsKey);
2706	gIOFBPMSettingDisplaySleepUsesDimKey = OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey);
2707
2708	gIOFBConfigKey = OSSymbol::withCString(kIOFBConfigKey);
2709	gIOFBModesKey  = OSSymbol::withCString(kIOFBModesKey);
2710	gIOFBModeIDKey = OSSymbol::withCString(kIOFBModeIDKey);
2711	gIOFBModeDMKey = OSSymbol::withCString(kIOFBModeDMKey);
2712
2713	matching = serviceMatching("AppleGraphicsControl");
2714	if ((gIOGraphicsControl = copyMatchingService(matching)))
2715	{
2716		gIOFBGCNotifier = gIOGraphicsControl->registerInterest(
2717									gIOGeneralInterest, &agcMessage, 0, 0 );
2718	}
2719	if (matching) matching->release();
2720
2721	matching = serviceMatching("IOAccelerator");
2722	if ((iter = getMatchingServices(matching)))
2723	{
2724		IOService * accel;
2725		while ((accel = OSDynamicCast(IOService, iter->getNextObject())))
2726			accel->requestProbe(kIOFBUserRequestProbe);
2727
2728		iter->release();
2729	}
2730	if (matching) matching->release();
2731
2732	if (gIOFBPrefs)
2733		gIOFBPrefsSerializer = OSSerializer::forTarget(gIOFBPrefs,
2734														&IOFramebufferLockedSerialize, 0);
2735
2736	clock_interval_to_absolutetime_interval(20, kMillisecondScale, &gIOFBMaxVBLDelta);
2737
2738	gIOFBRootNotifier = getPMRootDomain()->registerInterest(
2739							gIOPriorityPowerStateInterest, &systemPowerChange, 0, 0 );
2740	gIOFBClamshellCallout = thread_call_allocate(&delayedEvent, (thread_call_param_t) 0);
2741	static uint32_t zero = 0;
2742	static uint32_t one = 1;
2743	gIOFBZero32Data = OSData::withBytesNoCopy(&zero, sizeof(zero));
2744	gIOFBOne32Data = OSData::withBytesNoCopy(&one, sizeof(one));
2745	gIOFBGray32Data = OSData::withBytesNoCopy(&gIOFBGrayValue, sizeof(gIOFBGrayValue));
2746
2747	gIOGraphicsPrefsVersionKey = OSSymbol::withCStringNoCopy(kIOGraphicsPrefsVersionKey);
2748	gIOGraphicsPrefsVersionValue = OSNumber::withNumber(kIOGraphicsPrefsCurrentVersion, 32);
2749
2750    matching  = nameMatching("IOHIDSystem");
2751	IOService * hidsystem = copyMatchingService(matching);
2752	if (hidsystem)
2753	{
2754		gIOFBHIDWorkLoop = hidsystem->getWorkLoop();
2755		if (gIOFBHIDWorkLoop) gIOFBHIDWorkLoop->retain();
2756		hidsystem->release();
2757	}
2758	if (matching) matching->release();
2759
2760	// system work
2761	gIOFBWorkES = IOInterruptEventSource::interruptEventSource(gIOFBSystemWorkLoop, &systemWork);
2762	if (gIOFBWorkES)
2763		gIOFBSystemWorkLoop->addEventSource(gIOFBWorkES);
2764
2765	gIOFBDelayedPrefsEvent = IOTimerEventSource::timerEventSource(
2766											gAllFramebuffers, &writePrefs);
2767	if (gIOFBDelayedPrefsEvent)
2768		gIOFBSystemWorkLoop->addEventSource(gIOFBDelayedPrefsEvent);
2769
2770	gIOFBServerAckTimer = IOTimerEventSource::timerEventSource(
2771											gAllFramebuffers, &serverAckTimeout);
2772	if (gIOFBServerAckTimer)
2773		gIOFBSystemWorkLoop->addEventSource(gIOFBServerAckTimer);
2774}
2775
2776bool IOFramebuffer::start( IOService * provider )
2777{
2778    bool runaway;
2779
2780    if (!super::start(provider)) return (false);
2781
2782    runaway = (__private != 0);
2783
2784    if (!__private)
2785    {
2786        __private = IONew( IOFramebufferPrivate, 1 );
2787        if (!__private)
2788            return (false);
2789        bzero( __private, sizeof(IOFramebufferPrivate) );
2790        __private->lastNotifyOnline = 0xdd;
2791        __private->regID = getRegistryEntryID();
2792
2793        userAccessRanges = OSArray::withCapacity( 1 );
2794        if (!userAccessRanges)
2795            return (false);
2796
2797        serverMsg = IOMalloc( sizeof (mach_msg_header_t) );
2798        if (!serverMsg)
2799            return (false);
2800        bzero( serverMsg, sizeof (mach_msg_header_t));
2801    }
2802    if (!thisName)
2803    	thisName = "IOFB?";
2804
2805    // initialize superclass power management variables
2806    PMinit();
2807    // attach into the power management hierarchy
2808    setProperty("IOPMStrictTreeOrder", kOSBooleanTrue);
2809    provider->joinPMtree(this);
2810
2811	SYSLOCK();
2812	if (!runaway && !gIOFBServerInit) do
2813	{
2814		IOFramebuffer * fb;
2815		char          * path;
2816		char          * pathThis;
2817		int             pathLen;
2818
2819		pathLen = 1024;
2820		path     = IONew(char, pathLen);
2821		pathThis = IONew(char, pathLen);
2822		if (!path || !pathThis) continue;
2823
2824		if (!getPath(pathThis, &pathLen, gIOServicePlane)) pathThis[0] = 0;
2825		for (thisIndex = 0; (fb = (IOFramebuffer *) gStartedFramebuffers->getObject(thisIndex)); thisIndex++)
2826		{
2827			pathLen = 1024;
2828			if (!fb->getPath(path, &pathLen, gIOServicePlane)) path[0] = 0;
2829			if (0 > strcmp(pathThis, path)) break;
2830		}
2831		gStartedFramebuffers->setObject(thisIndex, this);
2832
2833		IODelete(path, char, 1024);
2834		IODelete(pathThis, char, 1024);
2835	}
2836	while (false);
2837	SYSUNLOCK();
2838
2839    if (!runaway) registerService();
2840	else
2841    {
2842        IOReturn err;
2843
2844        SYSLOCK();
2845        err = enableController();
2846        if (kIOReturnSuccess == err)
2847        {
2848            opened = true;
2849            dead = false;
2850            isUsable = true;
2851            connectChangeInterrupt(this, 0);
2852        }
2853        SYSUNLOCK();
2854    }
2855
2856    return (true);
2857}
2858
2859/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2860
2861//
2862// BEGIN:       Implementation of the evScreen protocol
2863//
2864
2865void IOFramebuffer::deferredMoveCursor( IOFramebuffer * inst )
2866{
2867    StdFBShmem_t *      shmem = GetShmem(inst);
2868    IOReturn            err = kIOReturnSuccess;
2869
2870    if (shmem->hardwareCursorActive)
2871    {
2872        if (shmem->cursorObscured)
2873        {
2874            shmem->cursorObscured = 0;
2875            if (shmem->cursorShow)
2876                --shmem->cursorShow;
2877        }
2878        if (shmem->hardwareCursorShields && shmem->shieldFlag)
2879            CheckShield(inst);
2880        if (!shmem->cursorShow)
2881        {
2882            IOGPoint * hs;
2883            hs = &shmem->hotSpot[0 != shmem->frame];
2884            err = inst->_setCursorState(
2885                        shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx,
2886                        shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny, true );
2887#if 0
2888			// debug
2889			shmem->cursorRect.minx = shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx;
2890			shmem->cursorRect.miny = shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny;
2891			shmem->cursorRect.maxx = 0;
2892			shmem->cursorRect.maxy = 0;
2893#endif
2894        }
2895    }
2896    else
2897    {
2898        if (!shmem->cursorShow++)
2899            RemoveCursor(inst);
2900        if (shmem->cursorObscured)
2901        {
2902            shmem->cursorObscured = 0;
2903            if (shmem->cursorShow)
2904                --shmem->cursorShow;
2905        }
2906        if (shmem->shieldFlag)
2907            CheckShield(inst);
2908        if (shmem->cursorShow)
2909            if (!--shmem->cursorShow)
2910                DisplayCursor(inst);
2911
2912        inst->flushCursor();
2913
2914        if (inst->__private->cursorPanning)
2915        {
2916            IOGPoint * hs;
2917            hs = &shmem->hotSpot[0 != shmem->frame];
2918            err = inst->setCursorState(
2919                      shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx,
2920                      shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny, false );
2921        }
2922    }
2923}
2924
2925void IOFramebuffer::cursorWork( OSObject * p0, IOInterruptEventSource * evtSrc, int intCount )
2926{
2927    IOFramebuffer *             inst = (IOFramebuffer *) p0;
2928    StdFBShmem_t *              shmem = GetShmem(inst);
2929    struct IOFramebufferPrivate * __private = inst->__private;
2930    IOFBCursorControlAttribute  * cursorControl = &__private->cursorControl;
2931    IOReturn                    ret;
2932    IOHardwareCursorDescriptor  desc;
2933
2934    IOOptionBits todo = inst->__private->cursorToDo;
2935
2936    while (todo)
2937    {
2938        if (2 & todo)
2939        {
2940            desc.majorVersion   = kHardwareCursorDescriptorMajorVersion;
2941            desc.minorVersion   = kHardwareCursorDescriptorMinorVersion;
2942            desc.height         = shmem->cursorSize[0 != __private->framePending].height;
2943            desc.width          = shmem->cursorSize[0 != __private->framePending].width;
2944            desc.bitDepth       = inst->__private->cursorBytesPerPixel * 8;
2945            desc.maskBitDepth   = 0;
2946            desc.colorEncodings = 0;
2947            desc.flags          = 0;
2948            desc.supportedSpecialEncodings = kTransparentEncodedPixel;
2949
2950            ret = (*cursorControl->callouts->setCursorImage) (
2951                      cursorControl->self, cursorControl->ref,
2952                      &desc, (void *)(uintptr_t) __private->framePending );
2953        }
2954        if (1 & todo)
2955            ret = (*cursorControl->callouts->setCursorState) (
2956                      cursorControl->self, cursorControl->ref,
2957                      __private->xPending, __private->yPending, __private->visiblePending );
2958
2959        todo = __private->cursorToDo & ~todo;
2960        __private->cursorToDo = todo;
2961    }
2962}
2963
2964IOOptionBits IOFramebuffer::_setCursorImage( UInt32 frame )
2965{
2966    StdFBShmem_t * shmem = GetShmem(this);
2967    IOGPoint *     hs;
2968    IOOptionBits   flags;
2969    bool           animation = (((int) frame) != shmem->frame);
2970
2971    hs = &shmem->hotSpot[0 != frame];
2972    if (false && ((hs->x != __private->lastHotSpot.x) || (hs->y != __private->lastHotSpot.y)))
2973    {
2974        __private->lastHotSpot = *hs;
2975        if (GetShmem(this) && __private->deferredCLUTSetEvent && shmem->vblCount && !__private->cursorSlept && !suspended)
2976        {
2977            if (false)
2978            {
2979                __private->waitVBLEvent = hs;
2980                FBWL(this)->sleepGate(hs, THREAD_UNINT);
2981            }
2982            else if (CMP_ABSOLUTETIME(&shmem->vblDelta, &gIOFBMaxVBLDelta) < 0)
2983            {
2984                AbsoluteTime deadline = shmem->vblTime;
2985                ADD_ABSOLUTETIME(&deadline, &shmem->vblDelta);
2986                clock_delay_until(deadline);
2987            }
2988        }
2989    }
2990
2991    if (!animation && ((kIOFBHardwareCursorActive == shmem->hardwareCursorActive) || !shmem->cursorShow))
2992	{
2993        RemoveCursor(this);
2994    }
2995    flags = (kIOReturnSuccess == setCursorImage( (void *)(uintptr_t) frame ))
2996            ? kIOFBHardwareCursorActive : 0;
2997    if (!animation && !shmem->cursorShow)
2998	{
2999        DisplayCursor(this);
3000	}
3001    if (!flags && __private->cursorThread && (__private->cursorBytesPerPixel >= 2))
3002    {
3003        __private->framePending = frame;
3004        __private->cursorToDo |= 2;
3005        flags = kIOFBHardwareCursorActive | kIOFBHardwareCursorInVRAM;
3006    }
3007
3008    return (flags);
3009}
3010
3011IOReturn IOFramebuffer::_setCursorState( SInt32 x, SInt32 y, bool visible )
3012{
3013    StdFBShmem_t *shmem = GetShmem(this);
3014    IOReturn ret = kIOReturnUnsupported;
3015
3016    x -= __private->cursorHotSpotAdjust[0].x;
3017    y -= __private->cursorHotSpotAdjust[0].y;
3018
3019    if (kIOFBHardwareCursorActive == shmem->hardwareCursorActive)
3020    {
3021        ret = setCursorState( x, y, visible );
3022    }
3023    else if (__private->cursorThread)
3024    {
3025        __private->cursorToDo |= 1;
3026        __private->xPending = x;
3027        __private->yPending = y;
3028        __private->visiblePending = visible;
3029    }
3030
3031    return (ret);
3032}
3033
3034void IOFramebuffer::transformLocation(StdFBShmem_t * shmem,
3035                                        IOGPoint * cursorLoc, IOGPoint * transformLoc)
3036{
3037    SInt32 x, y;
3038
3039    x = cursorLoc->x - shmem->screenBounds.minx;
3040    y = cursorLoc->y - shmem->screenBounds.miny;
3041
3042    if (__private->transform & kIOFBSwapAxes)
3043    {
3044        SInt32 t = x;
3045        x = y;
3046        y = t;
3047    }
3048    if (__private->transform & kIOFBInvertX)
3049        x = __private->framebufferWidth - x - 1;
3050    if (__private->transform & kIOFBInvertY)
3051        y = __private->framebufferHeight - y - 1;
3052
3053    transformLoc->x = x + shmem->screenBounds.minx;
3054    transformLoc->y = y + shmem->screenBounds.miny;
3055}
3056
3057void IOFramebuffer::moveCursor( IOGPoint * cursorLoc, int frame )
3058{
3059    UInt32 hwCursorActive;
3060
3061	nextCursorLoc = *cursorLoc;
3062    nextCursorFrame = frame;
3063
3064	CURSORLOCK(this);
3065
3066    if (frame != shmem->frame)
3067    {
3068        if (__private->cursorFlags[frame] && pagingState)
3069        {
3070            hwCursorActive = _setCursorImage( frame );
3071            __private->cursorFlags[frame] = hwCursorActive ? kIOFBCursorHWCapable : 0;
3072        }
3073        else
3074            hwCursorActive = 0;
3075
3076        shmem->frame = frame;
3077        if (shmem->hardwareCursorActive != hwCursorActive)
3078        {
3079            SysHideCursor( this );
3080            shmem->hardwareCursorActive = hwCursorActive;
3081            if (shmem->shieldFlag
3082                    && ((0 == hwCursorActive) || (shmem->hardwareCursorShields)))
3083                CheckShield(this);
3084            SysShowCursor( this );
3085        }
3086    }
3087
3088	if (kIOFBRotateFlags & __private->transform)
3089		transformLocation(shmem, &nextCursorLoc, &shmem->cursorLoc);
3090	else
3091		shmem->cursorLoc = nextCursorLoc;
3092	shmem->frame = frame;
3093	deferredMoveCursor( this );
3094
3095	CURSORUNLOCK(this);
3096}
3097
3098void IOFramebuffer::hideCursor( void )
3099{
3100	CURSORLOCK(this);
3101
3102    SysHideCursor(this);
3103
3104	CURSORUNLOCK(this);
3105}
3106
3107void IOFramebuffer::showCursor( IOGPoint * cursorLoc, int frame )
3108{
3109    UInt32 hwCursorActive;
3110
3111	CURSORLOCK(this);
3112
3113    if (frame != shmem->frame)
3114    {
3115        if (__private->cursorFlags[frame])
3116        {
3117            hwCursorActive = _setCursorImage( frame );
3118            __private->cursorFlags[frame] = hwCursorActive ? kIOFBCursorHWCapable : 0;
3119        }
3120        else
3121            hwCursorActive = 0;
3122        shmem->frame = frame;
3123        shmem->hardwareCursorActive = hwCursorActive;
3124    }
3125
3126    shmem->cursorLoc = *cursorLoc;
3127    if (shmem->shieldFlag
3128            && ((0 == shmem->hardwareCursorActive) || (shmem->hardwareCursorShields)))
3129        CheckShield(this);
3130
3131    SysShowCursor(this);
3132
3133	CURSORUNLOCK(this);
3134}
3135
3136void IOFramebuffer::updateVBL(OSObject * owner, IOTimerEventSource * sender)
3137{
3138    IOFramebuffer * inst = (IOFramebuffer *) owner;
3139
3140	if (inst->__private->vblInterrupt
3141			&& inst->__private->vblThrottle
3142			&& inst->__private->displaysOnline
3143			&& inst->pagingState)
3144	{
3145		inst->setInterruptState(inst->__private->vblInterrupt, kEnabledInterruptState);
3146		inst->__private->vblEnabled = true;
3147	}
3148}
3149
3150void IOFramebuffer::deferredVBLDisable(OSObject * owner,
3151                                       IOInterruptEventSource * evtSrc, int intCount)
3152{
3153    IOFramebuffer * inst = (IOFramebuffer *) owner;
3154
3155	if (inst->__private->vblInterrupt && inst->__private->vblThrottle)
3156	{
3157		inst->setInterruptState(inst->__private->vblInterrupt, kDisabledInterruptState);
3158	}
3159}
3160
3161bool IOFramebuffer::getTimeOfVBL(AbsoluteTime * deadline, uint32_t frames)
3162{
3163	uint64_t last, now;
3164	uint64_t delta;
3165
3166    StdFBShmem_t * shmem = GetShmem(this);
3167    if (!shmem)
3168        return (false);
3169
3170	do
3171	{
3172		last = AbsoluteTime_to_scalar(&shmem->vblTime);
3173		now = mach_absolute_time();
3174	}
3175	while (last != AbsoluteTime_to_scalar(&shmem->vblTime));
3176
3177	delta = AbsoluteTime_to_scalar(&shmem->vblDelta);
3178	if (delta)
3179	{
3180		now += frames * delta - ((now - last) % delta);
3181	}
3182	AbsoluteTime_to_scalar(deadline) = now;
3183
3184	return (true);
3185}
3186
3187void IOFramebuffer::handleVBL(IOFramebuffer * inst, void * ref)
3188{
3189    StdFBShmem_t * shmem = GetShmem(inst);
3190    AbsoluteTime   now;
3191    uint64_t       _now, calculatedDelta, drift;
3192
3193    if (!shmem) return;
3194	inst->__private->actualVBLCount++;
3195	if (!inst->__private->vblEnabled) return;
3196
3197    _now = mach_absolute_time();
3198    AbsoluteTime_to_scalar(&now) = _now;
3199	AbsoluteTime delta = now;
3200	SUB_ABSOLUTETIME(&delta, &shmem->vblTime);
3201	calculatedDelta = AbsoluteTime_to_scalar(&shmem->vblDelta);
3202
3203	if (calculatedDelta && inst->__private->vblThrottle)
3204	{
3205		// round up to deal with scheduling noise.
3206		uint64_t timeCount = ((AbsoluteTime_to_scalar(&delta) * 2 / calculatedDelta) + 1) / 2;
3207		shmem->vblCount += timeCount;
3208		timeCount = (timeCount > inst->__private->actualVBLCount)
3209					? (timeCount - inst->__private->actualVBLCount)
3210					: (inst->__private->actualVBLCount - timeCount);
3211		if (gIOFBVBLDrift && (timeCount <= 1))
3212		{
3213			drift = (AbsoluteTime_to_scalar(&shmem->vblTime)
3214					 + inst->__private->actualVBLCount * calculatedDelta);
3215			drift = (drift < _now) ? (_now - drift) : (drift - _now);
3216			shmem->vblDrift = drift;
3217			shmem->vblDeltaMeasured = (AbsoluteTime_to_scalar(&delta) / inst->__private->actualVBLCount);
3218//   		shmem->vblDeltaMeasured = IOMappedRead32(0xb0070000);
3219		}
3220	}
3221	else
3222	{
3223		shmem->vblCount++;
3224		shmem->vblDelta = delta;
3225	}
3226    shmem->vblTime  = now;
3227	inst->__private->actualVBLCount = 0;
3228
3229    KERNEL_DEBUG(0xc000030 | DBG_FUNC_NONE,
3230                 (uint32_t)(AbsoluteTime_to_scalar(&shmem->vblDelta) >> 32),
3231                 (uint32_t)(AbsoluteTime_to_scalar(&shmem->vblDelta)), 0, 0, 0);
3232
3233    if (inst->vblSemaphore)
3234        semaphore_signal_all(inst->vblSemaphore);
3235
3236	if (inst->__private->vblThrottle)
3237	{
3238		inst->__private->vblEnabled = false;
3239        if (!gIOFBVBLDrift) inst->__private->deferredVBLDisableEvent->interruptOccurred(0, 0, 0);
3240		inst->__private->vblUpdateTimer->setTimeoutMS(kVBLThrottleTimeMS);
3241	}
3242	else if (inst->__private->deferredCLUTSetEvent
3243           && (inst->__private->gammaNeedSet || inst->__private->clutDataLen || inst->__private->waitVBLEvent))
3244	{
3245        inst->__private->deferredCLUTSetEvent->interruptOccurred(0, 0, 0);
3246	}
3247}
3248
3249void IOFramebuffer::resetCursor( void )
3250{
3251    StdFBShmem_t *      shmem;
3252    int                 frame;
3253
3254    shmem = GetShmem(this);
3255    //    hwCursorLoaded = false;
3256    if (!shmem)
3257        return;
3258
3259    shmem->hardwareCursorActive = 0;
3260    frame = shmem->frame;
3261    shmem->frame = frame ^ 1;
3262    showCursor( &shmem->cursorLoc, frame );
3263}
3264
3265void IOFramebuffer::getVBLTime( AbsoluteTime * time, AbsoluteTime * delta )
3266{
3267    StdFBShmem_t *shmem;
3268
3269    shmem = GetShmem(this);
3270    if (shmem)
3271    {
3272		getTimeOfVBL(time, 0);
3273        *delta = shmem->vblDelta;
3274    }
3275    else
3276    {
3277        AbsoluteTime_to_scalar(time) = 0;
3278        AbsoluteTime_to_scalar(delta) = 0;
3279    }
3280}
3281
3282void IOFramebuffer::getBoundingRect( IOGBounds ** bounds )
3283{
3284    StdFBShmem_t *shmem;
3285
3286    shmem = GetShmem(this);
3287    if (NULL == shmem)
3288        *bounds = NULL;
3289    else
3290        *bounds = &__private->screenBounds[0];
3291}
3292
3293//
3294// END:         Implementation of the evScreen protocol
3295//
3296
3297/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3298
3299IOReturn IOFramebuffer::getNotificationSemaphore(
3300    IOSelect interruptType, semaphore_t * semaphore )
3301{
3302    kern_return_t       kr;
3303    semaphore_t         sema;
3304
3305    if (interruptType != kIOFBVBLInterruptType)
3306        return (kIOReturnUnsupported);
3307
3308    if (!haveVBLService)
3309        return (kIOReturnNoResources);
3310
3311    if (MACH_PORT_NULL == vblSemaphore)
3312    {
3313        kr = semaphore_create(kernel_task, &sema, SYNC_POLICY_FIFO, 0);
3314        if (kr == KERN_SUCCESS)
3315            vblSemaphore = sema;
3316    }
3317    else
3318        kr = KERN_SUCCESS;
3319
3320    if (kr == KERN_SUCCESS)
3321        *semaphore = vblSemaphore;
3322
3323    return (kr);
3324}
3325
3326IOReturn IOFramebuffer::extSetCursorVisible(
3327        OSObject * target, void * reference, IOExternalMethodArguments * args)
3328{
3329    IOFramebuffer * inst    = (IOFramebuffer *) target;
3330    bool            visible = args->scalarInput[0];
3331
3332    IOReturn            err;
3333    IOGPoint *          hs;
3334    StdFBShmem_t *      shmem;
3335
3336    if ((err = inst->extEntry(true)))
3337        return (err);
3338
3339    shmem = GetShmem(inst);
3340    if (shmem->hardwareCursorActive && inst->__private->online)
3341    {
3342        hs = &shmem->hotSpot[0 != shmem->frame];
3343        err = inst->_setCursorState(
3344                  shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx,
3345                  shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny,
3346                  visible );
3347
3348        if (inst->__private->cursorToDo)
3349            KICK_CURSOR(inst->__private->cursorThread);
3350    }
3351    else
3352        err = kIOReturnBadArgument;
3353
3354    inst->extExit(err);
3355
3356    return (err);
3357}
3358
3359IOReturn IOFramebuffer::extSetCursorPosition(
3360        OSObject * target, void * reference, IOExternalMethodArguments * args)
3361{
3362//    IOFramebuffer * inst = (IOFramebuffer *) target;
3363//    SInt32          x    = args->scalarInput[0];
3364//    SInt32          y    = args->scalarInput[1];
3365
3366    return (kIOReturnUnsupported);
3367}
3368
3369void IOFramebuffer::transformCursor( StdFBShmem_t * shmem, IOIndex frame )
3370{
3371    void *                    buf;
3372    unsigned int * out;
3373    volatile unsigned int   * cursPtr32 = 0;
3374    volatile unsigned short * cursPtr16 = 0;
3375    SInt32 x, y, dw, dh, sx, sy, sw, sh;
3376
3377    if (__private->cursorBytesPerPixel == 4)
3378    {
3379        cursPtr32 = (volatile unsigned int *) __private->cursorImages[frame];
3380        cursPtr16 = 0;
3381    }
3382    else if (__private->cursorBytesPerPixel == 2)
3383    {
3384        cursPtr32 = 0;
3385        cursPtr16 = (volatile unsigned short *) __private->cursorImages[frame];
3386    }
3387
3388    sw = shmem->cursorSize[0 != frame].width;
3389    sh = shmem->cursorSize[0 != frame].height;
3390
3391    if (kIOFBSwapAxes & __private->transform)
3392    {
3393        dw = sh;
3394        dh = sw;
3395    }
3396    else
3397    {
3398        dw = sw;
3399        dh = sh;
3400    }
3401
3402    buf = IOMalloc(dw * dh * __private->cursorBytesPerPixel);
3403    out = (unsigned int *) buf;
3404
3405    for (y = 0; y < dh; y++)
3406    {
3407        for (x = 0; x < dw; x++)
3408        {
3409            if (kIOFBSwapAxes & __private->transform)
3410            {
3411                sx = y;
3412                sy = x;
3413            }
3414            else
3415            {
3416                sx = x;
3417                sy = y;
3418            }
3419            if (__private->transform & kIOFBInvertY)
3420                sx = sw - sx - 1;
3421            if (__private->transform & kIOFBInvertX)
3422                sy = sh - sy - 1;
3423
3424            if (cursPtr32)
3425                *out++ = cursPtr32[sx + sy * sw];
3426            else
3427                STOREINC(out, cursPtr16[sx + sy * sw], UInt16)
3428        }
3429    }
3430
3431    bcopy(buf, (void *) __private->cursorImages[frame], dw * dh * __private->cursorBytesPerPixel);
3432    IOFree(buf, dw * dh * __private->cursorBytesPerPixel);
3433
3434    shmem->cursorSize[0 != frame].width  = dw;
3435    shmem->cursorSize[0 != frame].height = dh;
3436
3437    if (kIOFBSwapAxes & __private->transform)
3438    {
3439        x = shmem->hotSpot[0 != frame].y;
3440        y = shmem->hotSpot[0 != frame].x;
3441    }
3442    else
3443    {
3444        x = shmem->hotSpot[0 != frame].x;
3445        y = shmem->hotSpot[0 != frame].y;
3446    }
3447    if (__private->transform & kIOFBInvertX)
3448        x = dw - x - 1;
3449    if (__private->transform & kIOFBInvertY)
3450        y = dh - y - 1;
3451    shmem->hotSpot[0 != frame].x = x;
3452    shmem->hotSpot[0 != frame].y = y;
3453}
3454
3455IOReturn IOFramebuffer::extSetNewCursor(
3456        OSObject * target, void * reference, IOExternalMethodArguments * args)
3457{
3458    IOFramebuffer * inst    = (IOFramebuffer *) target;
3459    IOIndex         cursor  = args->scalarInput[0];
3460    IOIndex         frame   = args->scalarInput[1];
3461    IOOptionBits    options = args->scalarInput[2];
3462
3463    StdFBShmem_t *      shmem;
3464    IOReturn            err;
3465    UInt32              hwCursorActive;
3466
3467    if ((err = inst->extEntry(false)))
3468        return (err);
3469
3470    shmem = GetShmem(inst);
3471    // assumes called with cursorSema held
3472    if (cursor || options || (((UInt32) frame) >= inst->__private->numCursorFrames))
3473        err = kIOReturnBadArgument;
3474    else
3475    {
3476        if (kIOFBRotateFlags & inst->__private->transform)
3477            inst->transformCursor(shmem, frame);
3478
3479        if ((shmem->cursorSize[0 != frame].width > inst->maxCursorSize.width)
3480                || (shmem->cursorSize[0 != frame].height > inst->maxCursorSize.height))
3481            err = kIOReturnBadArgument;
3482
3483        else if (inst->haveHWCursor)
3484        {
3485            if (frame == shmem->frame)
3486            {
3487                hwCursorActive = inst->_setCursorImage( frame );
3488                shmem->hardwareCursorActive = hwCursorActive;
3489                inst->__private->cursorFlags[frame] = hwCursorActive ? kIOFBCursorHWCapable : 0;
3490            }
3491            else
3492            {
3493                inst->__private->cursorFlags[frame] = kIOFBCursorImageNew;
3494            }
3495            err = kIOReturnSuccess;             // I guess
3496        }
3497        else
3498            err = kIOReturnUnsupported;
3499    }
3500    if (inst->__private->cursorToDo)
3501        KICK_CURSOR(inst->__private->cursorThread);
3502
3503    inst->extExit(err);
3504
3505    return (err);
3506}
3507
3508bool IOFramebuffer::convertCursorImage( void * cursorImage,
3509                                        IOHardwareCursorDescriptor * hwDesc,
3510                                        IOHardwareCursorInfo * hwCursorInfo )
3511{
3512    StdFBShmem_t *              shmem = GetShmem(this);
3513    UInt8 *                     dataOut = hwCursorInfo->hardwareCursorData;
3514    IOColorEntry *              clut = hwCursorInfo->colorMap;
3515    UInt32                      maxColors = hwDesc->numColors;
3516    int                         frame = (uintptr_t) cursorImage;
3517
3518    volatile unsigned short *   cursPtr16;
3519    volatile unsigned int *     cursPtr32;
3520    SInt32                      x, lastx, y, lasty;
3521    UInt32                      width, height, lineBytes = 0;
3522    UInt32                      index, numColors = 0;
3523    UInt32                      alpha, red, green, blue;
3524    UInt16                      s16;
3525    UInt32                      s32;
3526    UInt32                      pixel = 0;
3527    UInt32                      data = 0;
3528    UInt32                      bits = 0;
3529    bool                        ok = true;
3530    bool                        isDirect;
3531
3532    if (__private->testingCursor)
3533    {
3534        IOHardwareCursorDescriptor copy;
3535
3536        if ((hwDesc->numColors == 0) && (hwDesc->bitDepth > 8) && (hwDesc->bitDepth < 32))
3537        {
3538            copy = *hwDesc;
3539            hwDesc = &copy;
3540            copy.bitDepth = 32;
3541        }
3542
3543        OSData * data = OSData::withBytes( hwDesc, sizeof(IOHardwareCursorDescriptor) );
3544        if (data)
3545        {
3546            __private->cursorAttributes->setObject( data );
3547            data->release();
3548        }
3549
3550        return (false);
3551    }
3552    else if (!hwCursorInfo || !hwCursorInfo->hardwareCursorData)
3553        return (false);
3554
3555    assert( frame < __private->numCursorFrames );
3556
3557    if (__private->cursorBytesPerPixel == 4)
3558    {
3559        cursPtr32 = (volatile unsigned int *) __private->cursorImages[frame];
3560        cursPtr16 = 0;
3561    }
3562    else if (__private->cursorBytesPerPixel == 2)
3563    {
3564        cursPtr32 = 0;
3565        cursPtr16 = (volatile unsigned short *) __private->cursorImages[frame];
3566    }
3567    else
3568        return (false);
3569
3570	if (!cursPtr32 && !cursPtr16) return (false);
3571
3572    x = shmem->cursorSize[0 != frame].width;
3573    y = shmem->cursorSize[0 != frame].height;
3574    if ((x > (SInt32) hwDesc->width) || (y > (SInt32) hwDesc->height))
3575        return (false);
3576    isDirect = (hwDesc->bitDepth > 8);
3577    if (isDirect && (hwDesc->bitDepth != 32) && (hwDesc->bitDepth != 16))
3578        return (false);
3579
3580    width  = hwDesc->width;
3581    height = hwDesc->height;
3582
3583    // matrox workaround - 2979661
3584    if ((maxColors > 1) && (&clut[1] == (IOColorEntry *) hwCursorInfo))
3585        width = height = 16;
3586    // --
3587
3588    SInt32 adjX = 4 - shmem->hotSpot[0 != frame].x;
3589    SInt32 adjY = 4 - shmem->hotSpot[0 != frame].y;
3590    if ((adjX < 0) || ((UInt32)(x + adjX) > width))
3591        adjX = 0;
3592    else
3593        x += adjX;
3594    if ((adjY < 0) || ((UInt32)(y + adjY) > height))
3595        adjY = 0;
3596
3597    __private->cursorHotSpotAdjust[0 != frame].x = adjX;
3598    __private->cursorHotSpotAdjust[0 != frame].y = adjY;
3599
3600    while ((width >> 1) >= (UInt32) x)
3601        width >>= 1;
3602    while ((UInt32)(height >> 1) >= (UInt32)(y + adjY))
3603        height >>= 1;
3604
3605    hwCursorInfo->cursorWidth  = width;
3606    hwCursorInfo->cursorHeight = height;
3607    hwCursorInfo->cursorHotSpotX = shmem->hotSpot[0 != frame].x
3608                                 + __private->cursorHotSpotAdjust[0 != frame].x;
3609    hwCursorInfo->cursorHotSpotY = shmem->hotSpot[0 != frame].y
3610                                 + __private->cursorHotSpotAdjust[0 != frame].y;
3611    lastx = x - width - 1;
3612
3613    if (isDirect && adjY)
3614    {
3615        lineBytes = width * (hwDesc->bitDepth >> 3);
3616        // top lines
3617        bzero_nc( dataOut, adjY * lineBytes );
3618        dataOut += adjY * lineBytes;
3619        // bottom lines
3620        adjY    = height - shmem->cursorSize[0 != frame].height - adjY;
3621        lasty   = -1;
3622    }
3623    else
3624    {
3625        y += adjY;
3626        lasty = y - height - 1;
3627    }
3628
3629    while (ok && (--y != lasty))
3630    {
3631        x = shmem->cursorSize[0 != frame].width + adjX;
3632        while (ok && (--x != lastx))
3633        {
3634            if ((x < 0)
3635                    || (y < 0)
3636                    || (x >= shmem->cursorSize[0 != frame].width)
3637                    || (y >= shmem->cursorSize[0 != frame].height))
3638                alpha = red = green = blue = 0;
3639
3640            else if (cursPtr32)
3641            {
3642                s32 = *(cursPtr32++);
3643                alpha = (s32 >> 24) & 0xff;
3644                red = (s32 >> 16) & 0xff;
3645                green = (s32 >> 8) & 0xff;
3646                blue = (s32) & 0xff;
3647            }
3648            else
3649            {
3650#define RMASK16 0xF000
3651#define GMASK16 0x0F00
3652#define BMASK16 0x00F0
3653#define AMASK16 0x000F
3654                s16 = *(cursPtr16++);
3655                alpha = s16 & AMASK16;
3656                alpha |= (alpha << 4);
3657                red = (s16 & RMASK16) >> 8;
3658                red |= (red >> 4);
3659                green = (s16 & GMASK16) >> 4;
3660                green |= (green >> 4);
3661                blue = s16 & BMASK16;
3662                blue |= (blue >> 4);
3663            }
3664
3665            if (isDirect)
3666            {
3667                if (alpha == 0)
3668                {
3669                    if (0xff == (red & green & blue))
3670                    {
3671                        /* Transparent white area.  Invert dst. */
3672                        if (kInvertingEncodedPixel
3673                                & hwDesc->supportedSpecialEncodings)
3674                            pixel = hwDesc->specialEncodings[kInvertingEncoding];
3675                        else
3676                            ok = false;
3677                    }
3678                    else
3679                        pixel = 0;
3680
3681                    if (hwDesc->bitDepth == 32)
3682                        STOREINC(dataOut, pixel, UInt32)
3683                    else
3684                        STOREINC(dataOut, pixel, UInt16)
3685                }
3686                else
3687                {
3688                    if (0xff != alpha)
3689                    {
3690                        red   = 0xff * red   / alpha;
3691                        green = 0xff * green / alpha;
3692                        blue  = 0xff * blue  / alpha;
3693                    }
3694                    if (hwDesc->bitDepth == 32)
3695                    {
3696                        pixel =   (alpha << 24)
3697                                  | ((red   & 0xff) << 16)
3698                                  | ((green & 0xff) << 8)
3699                                  | (blue   & 0xff);
3700
3701                        STOREINC(dataOut, pixel, UInt32)
3702                    }
3703                    else
3704                    {
3705                        pixel =   ((alpha & 0xf0) << 8)
3706                                  | ((red   & 0xf0) << 4)
3707                                  | ((green & 0xf0) << 0)
3708                                  | ((blue  & 0xf0) >> 4);
3709
3710                        STOREINC(dataOut, pixel, UInt16)
3711                    }
3712                }
3713            }
3714            else
3715            {
3716                /* Indexed pixels */
3717
3718                if (alpha == 0)
3719                {
3720                    if (0 == (red | green | blue))
3721                    {
3722                        /* Transparent black area.  Leave dst as is. */
3723                        if (kTransparentEncodedPixel
3724                                & hwDesc->supportedSpecialEncodings)
3725                            pixel = hwDesc->specialEncodings[kTransparentEncoding];
3726                        else
3727                            ok = false;
3728                    }
3729                    else if (0xff == (red & green & blue))
3730                    {
3731                        /* Transparent white area.  Invert dst. */
3732                        if (kInvertingEncodedPixel
3733                                & hwDesc->supportedSpecialEncodings)
3734                            pixel = hwDesc->specialEncodings[kInvertingEncoding];
3735                        else
3736                            ok = false;
3737                    }
3738                    else
3739                        ok = false;
3740                }
3741                else if (alpha == 0xff)
3742                {
3743                    red   |= (red << 8);
3744                    green |= (green << 8);
3745                    blue  |= (blue << 8);
3746
3747                    /* Opaque cursor pixel.  Mark it. */
3748                    for (index = 0; index < numColors; index++)
3749                    {
3750                        if ((red   == clut[index].red)
3751                                && (green == clut[index].green)
3752                                && (blue  == clut[index].blue))
3753                        {
3754                            pixel = clut[index].index;
3755                            break;
3756                        }
3757                    }
3758                    if (index == numColors)
3759                    {
3760                        ok = (numColors < maxColors);
3761                        if (ok)
3762                        {
3763                            pixel = hwDesc->colorEncodings[numColors++];
3764                            clut[index].red   = red;
3765                            clut[index].green = green;
3766                            clut[index].blue  = blue;
3767                            clut[index].index = pixel;
3768                        }
3769                    }
3770                }
3771                else
3772                {
3773                    /* Alpha is not 0 or 1.0.  Sover the cursor. */
3774                    ok = false;
3775                    break;
3776                }
3777                data <<= hwDesc->bitDepth;
3778                data |= pixel;
3779                bits += hwDesc->bitDepth;
3780                if (0 == (bits & 31))
3781                {
3782                    OSWriteBigInt32(dataOut, 0, data);
3783                    dataOut += sizeof(UInt32);
3784                }
3785            }
3786        } /* x */
3787    } /* y */
3788
3789    if (ok && isDirect && adjY)
3790    {
3791        // bottom lines
3792        bzero_nc( dataOut, adjY * lineBytes );
3793        dataOut += adjY * lineBytes;
3794    }
3795
3796    __private->cursorClutDependent = (ok && !isDirect);
3797
3798#if 0
3799    if (ok)
3800    {
3801        static UInt32 lastWidth;
3802        static UInt32 lastHeight;
3803
3804        if ((width != lastWidth) || (height != lastHeight))
3805        {
3806            lastWidth = width;
3807            lastHeight = height;
3808            IOLog("[%d,%d]", width, height);
3809        }
3810
3811        if (((UInt32)(dataOut - hwCursorInfo->hardwareCursorData)
3812                != ((hwCursorInfo->cursorHeight * hwCursorInfo->cursorWidth * hwDesc->bitDepth) >> 3)))
3813            IOLog("dataOut %p, %p @ %d\n", dataOut, hwCursorInfo->hardwareCursorData, hwDesc->bitDepth );
3814    }
3815#endif
3816
3817    return (ok);
3818}
3819
3820/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3821
3822// Apple standard 8-bit CLUT
3823
3824#if 0
3825UInt8 appleClut8[256 * 3] =
3826{
3827    // 00
3828    0xFF,0xFF,0xFF, 0xFF,0xFF,0xCC,     0xFF,0xFF,0x99, 0xFF,0xFF,0x66,
3829    0xFF,0xFF,0x33, 0xFF,0xFF,0x00,     0xFF,0xCC,0xFF, 0xFF,0xCC,0xCC,
3830    0xFF,0xCC,0x99, 0xFF,0xCC,0x66,     0xFF,0xCC,0x33, 0xFF,0xCC,0x00,
3831    0xFF,0x99,0xFF, 0xFF,0x99,0xCC,     0xFF,0x99,0x99, 0xFF,0x99,0x66,
3832    // 10
3833    0xFF,0x99,0x33, 0xFF,0x99,0x00,     0xFF,0x66,0xFF, 0xFF,0x66,0xCC,
3834    0xFF,0x66,0x99, 0xFF,0x66,0x66,     0xFF,0x66,0x33, 0xFF,0x66,0x00,
3835    0xFF,0x33,0xFF, 0xFF,0x33,0xCC,     0xFF,0x33,0x99, 0xFF,0x33,0x66,
3836    0xFF,0x33,0x33, 0xFF,0x33,0x00,     0xFF,0x00,0xFF, 0xFF,0x00,0xCC,
3837    // 20
3838    0xFF,0x00,0x99, 0xFF,0x00,0x66,     0xFF,0x00,0x33, 0xFF,0x00,0x00,
3839    0xCC,0xFF,0xFF, 0xCC,0xFF,0xCC,     0xCC,0xFF,0x99, 0xCC,0xFF,0x66,
3840    0xCC,0xFF,0x33, 0xCC,0xFF,0x00,     0xCC,0xCC,0xFF, 0xCC,0xCC,0xCC,
3841    0xCC,0xCC,0x99, 0xCC,0xCC,0x66,     0xCC,0xCC,0x33, 0xCC,0xCC,0x00,
3842    // 30
3843    0xCC,0x99,0xFF, 0xCC,0x99,0xCC,     0xCC,0x99,0x99, 0xCC,0x99,0x66,
3844    0xCC,0x99,0x33, 0xCC,0x99,0x00,     0xCC,0x66,0xFF, 0xCC,0x66,0xCC,
3845    0xCC,0x66,0x99, 0xCC,0x66,0x66,     0xCC,0x66,0x33, 0xCC,0x66,0x00,
3846    0xCC,0x33,0xFF, 0xCC,0x33,0xCC,     0xCC,0x33,0x99, 0xCC,0x33,0x66,
3847    // 40
3848    0xCC,0x33,0x33, 0xCC,0x33,0x00,     0xCC,0x00,0xFF, 0xCC,0x00,0xCC,
3849    0xCC,0x00,0x99, 0xCC,0x00,0x66,     0xCC,0x00,0x33, 0xCC,0x00,0x00,
3850    0x99,0xFF,0xFF, 0x99,0xFF,0xCC,     0x99,0xFF,0x99, 0x99,0xFF,0x66,
3851    0x99,0xFF,0x33, 0x99,0xFF,0x00,     0x99,0xCC,0xFF, 0x99,0xCC,0xCC,
3852    // 50
3853    0x99,0xCC,0x99, 0x99,0xCC,0x66,     0x99,0xCC,0x33, 0x99,0xCC,0x00,
3854    0x99,0x99,0xFF, 0x99,0x99,0xCC,     0x99,0x99,0x99, 0x99,0x99,0x66,
3855    0x99,0x99,0x33, 0x99,0x99,0x00,     0x99,0x66,0xFF, 0x99,0x66,0xCC,
3856    0x99,0x66,0x99, 0x99,0x66,0x66,     0x99,0x66,0x33, 0x99,0x66,0x00,
3857    // 60
3858    0x99,0x33,0xFF, 0x99,0x33,0xCC,     0x99,0x33,0x99, 0x99,0x33,0x66,
3859    0x99,0x33,0x33, 0x99,0x33,0x00,     0x99,0x00,0xFF, 0x99,0x00,0xCC,
3860    0x99,0x00,0x99, 0x99,0x00,0x66,     0x99,0x00,0x33, 0x99,0x00,0x00,
3861    0x66,0xFF,0xFF, 0x66,0xFF,0xCC,     0x66,0xFF,0x99, 0x66,0xFF,0x66,
3862    // 70
3863    0x66,0xFF,0x33, 0x66,0xFF,0x00,     0x66,0xCC,0xFF, 0x66,0xCC,0xCC,
3864    0x66,0xCC,0x99, 0x66,0xCC,0x66,     0x66,0xCC,0x33, 0x66,0xCC,0x00,
3865    0x66,0x99,0xFF, 0x66,0x99,0xCC,     0x66,0x99,0x99, 0x66,0x99,0x66,
3866    0x66,0x99,0x33, 0x66,0x99,0x00,     0x66,0x66,0xFF, 0x66,0x66,0xCC,
3867    // 80
3868    0x66,0x66,0x99, 0x66,0x66,0x66,     0x66,0x66,0x33, 0x66,0x66,0x00,
3869    0x66,0x33,0xFF, 0x66,0x33,0xCC,     0x66,0x33,0x99, 0x66,0x33,0x66,
3870    0x66,0x33,0x33, 0x66,0x33,0x00,     0x66,0x00,0xFF, 0x66,0x00,0xCC,
3871    0x66,0x00,0x99, 0x66,0x00,0x66,     0x66,0x00,0x33, 0x66,0x00,0x00,
3872    // 90
3873    0x33,0xFF,0xFF, 0x33,0xFF,0xCC,     0x33,0xFF,0x99, 0x33,0xFF,0x66,
3874    0x33,0xFF,0x33, 0x33,0xFF,0x00,     0x33,0xCC,0xFF, 0x33,0xCC,0xCC,
3875    0x33,0xCC,0x99, 0x33,0xCC,0x66,     0x33,0xCC,0x33, 0x33,0xCC,0x00,
3876    0x33,0x99,0xFF, 0x33,0x99,0xCC,     0x33,0x99,0x99, 0x33,0x99,0x66,
3877    // a0
3878    0x33,0x99,0x33, 0x33,0x99,0x00,     0x33,0x66,0xFF, 0x33,0x66,0xCC,
3879    0x33,0x66,0x99, 0x33,0x66,0x66,     0x33,0x66,0x33, 0x33,0x66,0x00,
3880    0x33,0x33,0xFF, 0x33,0x33,0xCC,     0x33,0x33,0x99, 0x33,0x33,0x66,
3881    0x33,0x33,0x33, 0x33,0x33,0x00,     0x33,0x00,0xFF, 0x33,0x00,0xCC,
3882    // b0
3883    0x33,0x00,0x99, 0x33,0x00,0x66,     0x33,0x00,0x33, 0x33,0x00,0x00,
3884    0x00,0xFF,0xFF, 0x00,0xFF,0xCC,     0x00,0xFF,0x99, 0x00,0xFF,0x66,
3885    0x00,0xFF,0x33, 0x00,0xFF,0x00,     0x00,0xCC,0xFF, 0x00,0xCC,0xCC,
3886    0x00,0xCC,0x99, 0x00,0xCC,0x66,     0x00,0xCC,0x33, 0x00,0xCC,0x00,
3887    // c0
3888    0x00,0x99,0xFF, 0x00,0x99,0xCC,     0x00,0x99,0x99, 0x00,0x99,0x66,
3889    0x00,0x99,0x33, 0x00,0x99,0x00,     0x00,0x66,0xFF, 0x00,0x66,0xCC,
3890    0x00,0x66,0x99, 0x00,0x66,0x66,     0x00,0x66,0x33, 0x00,0x66,0x00,
3891    0x00,0x33,0xFF, 0x00,0x33,0xCC,     0x00,0x33,0x99, 0x00,0x33,0x66,
3892    // d0
3893    0x00,0x33,0x33, 0x00,0x33,0x00,     0x00,0x00,0xFF, 0x00,0x00,0xCC,
3894    0x00,0x00,0x99, 0x00,0x00,0x66,     0x00,0x00,0x33, 0xEE,0x00,0x00,
3895    0xDD,0x00,0x00, 0xBB,0x00,0x00,     0xAA,0x00,0x00, 0x88,0x00,0x00,
3896    0x77,0x00,0x00, 0x55,0x00,0x00,     0x44,0x00,0x00, 0x22,0x00,0x00,
3897    // e0
3898    0x11,0x00,0x00, 0x00,0xEE,0x00,     0x00,0xDD,0x00, 0x00,0xBB,0x00,
3899    0x00,0xAA,0x00, 0x00,0x88,0x00,     0x00,0x77,0x00, 0x00,0x55,0x00,
3900    0x00,0x44,0x00, 0x00,0x22,0x00,     0x00,0x11,0x00, 0x00,0x00,0xEE,
3901    0x00,0x00,0xDD, 0x00,0x00,0xBB,     0x00,0x00,0xAA, 0x00,0x00,0x88,
3902    // f0
3903    0x00,0x00,0x77, 0x00,0x00,0x55,     0x00,0x00,0x44, 0x00,0x00,0x22,
3904    0x00,0x00,0x11, 0xEE,0xEE,0xEE,     0xDD,0xDD,0xDD, 0xBB,0xBB,0xBB,
3905    0xAA,0xAA,0xAA, 0x88,0x88,0x88,     0x77,0x77,0x77, 0x55,0x55,0x55,
3906    0x44,0x44,0x44, 0x22,0x22,0x22,     0x11,0x11,0x11, 0x00,0x00,0x00
3907};
3908#endif
3909
3910/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3911
3912#ifdef __ppc__
3913extern
3914#endif
3915    int killprint;
3916extern "C"
3917{
3918    int kmputc( int c );
3919}
3920
3921#if DOANIO
3922
3923#warning ** DO AN IO **
3924
3925static unsigned long doaniobuf[256];
3926
3927static void doanio( void )
3928{
3929    struct uio uio;
3930    struct iovec iovec;
3931    int err;
3932    dev_t device = makedev( 14, 0 );
3933
3934    iovec.iov_base = (char *) &doaniobuf[0];
3935    iovec.iov_len  = 1024;
3936
3937    uio.uio_iov = &iovec;
3938    uio.uio_iovcnt = 1;
3939    uio.uio_rw = UIO_READ;
3940    uio.uio_segflg = UIO_SYSSPACE;
3941    uio.uio_offset = 0;
3942    uio.uio_resid = 1024;
3943
3944    DEBG("", "\n");
3945    err = ((*cdevsw[major(device)].d_read)(device, &uio, 0));
3946    DEBG("", " done(%08lx)\n", doaniobuf[0]);
3947}
3948
3949#endif
3950
3951IOReturn IOFramebuffer::deliverDisplayModeDidChangeNotification( void )
3952{
3953    IOReturn
3954    ret = deliverFramebufferNotification( kIOFBNotifyDisplayModeDidChange );
3955
3956    if (__private->lastNotifyOnline != __private->online)
3957    {
3958        __private->lastNotifyOnline = __private->online;
3959        deliverFramebufferNotification( kIOFBNotifyOnlineChange, (void *)(uintptr_t) __private->online);
3960    }
3961
3962    return (ret);
3963}
3964
3965void IOFramebuffer::saveFramebuffer(void)
3966{
3967#if VRAM_SAVE
3968	// vram content is being lost
3969	uintptr_t           value;
3970	if (true
3971			&& !dead
3972			&& !__private->saveLength
3973			&& __private->online
3974			&& __private->framebufferHeight
3975			&& __private->framebufferWidth
3976			&& rowBytes
3977			&& (kIOReturnSuccess == getAttribute(kIOVRAMSaveAttribute, &value))
3978			&& value)
3979	{
3980		vm_size_t sLen;
3981		sLen = __private->framebufferHeight * rowBytes;
3982
3983		/*
3984		* dLen should account for possible growth. (e.g. run-length encoding noise)
3985		*       Add 5 bytes for header,
3986		*       12% for RLE growth
3987		*       2 bytes per line for line spans,
3988		*       1 additional escape code byte for trailing pixel in each line
3989		*/
3990#if VRAM_COMPRESS
3991		vm_size_t dLen;
3992		uint32_t  idx;
3993
3994		dLen = 5 + sLen + ((sLen + 7) >> 3) + (__private->framebufferHeight * 3) + rowBytes;
3995
3996		for (idx = 0;
3997			 (idx < kIOPreviewImageCount) && __private->saveBitsMD[idx];
3998			 idx++)	{}
3999
4000		dLen *= (idx + 1);
4001		DEBG1(thisName, " dLen 0x%x\n", (int) dLen);
4002
4003		dLen = round_page(dLen);
4004		if (dLen >= 96*1024*1024) dLen = 95*1024*1024;
4005		__private->saveLength = dLen;
4006#else
4007		__private->saveLength = round_page(sLen);
4008#endif
4009		__private->saveFramebuffer = IOMallocPageable( __private->saveLength, page_size );
4010		if (!__private->saveFramebuffer)
4011			__private->saveLength = 0;
4012		else
4013		{
4014#if VRAM_COMPRESS
4015			UInt8 *       bits[kIOPreviewImageCount] = { 0 };
4016			IOByteCount   bitsLen = 0;
4017			IOMemoryMap * map[kIOPreviewImageCount] = { 0 };
4018
4019			for (idx = 0;
4020				 (idx < kIOPreviewImageCount) && __private->saveBitsMD[idx];
4021				 idx++)
4022			{
4023				map[idx] = __private->saveBitsMD[idx]->map(kIOMapReadOnly);
4024				if (map[idx])
4025				{
4026					bits[idx] = (UInt8 *) map[idx]->getVirtualAddress();
4027					if (!idx) bitsLen = map[idx]->getLength();
4028					else if (bitsLen != map[idx]->getLength())
4029					{
4030						bits[idx] = NULL;
4031						map[idx]->release();
4032						map[idx] = 0;
4033					}
4034				}
4035				__private->saveBitsMD[idx]->release();
4036				__private->saveBitsMD[idx] = 0;
4037			}
4038
4039			if (!bits[0])
4040			{
4041				IOLog("%s: no save bits\n", thisName);
4042				dLen = 0;
4043			}
4044			else if ((((__private->framebufferHeight - 1) * rowBytes)
4045				 + __private->framebufferWidth * bytesPerPixel) > bitsLen)
4046			{
4047				IOLog("%s: bad pixel parameters %d x %d x %d > 0x%x\n", thisName,
4048				 (int) __private->framebufferWidth, (int) __private->framebufferHeight, (int) rowBytes, (int) bitsLen);
4049				dLen = 0;
4050			}
4051			else
4052			{
4053				uint8_t * gammaData = __private->gammaData;
4054				if (gammaData) gammaData += __private->gammaHeaderSize;
4055				dLen = CompressData( bits, kIOPreviewImageCount, bytesPerPixel,
4056									 __private->framebufferWidth, __private->framebufferHeight, rowBytes,
4057									 (UInt8 *) __private->saveFramebuffer, __private->saveLength,
4058									 __private->gammaChannelCount, __private->gammaDataCount,
4059									__private->gammaDataWidth, gammaData);
4060			}
4061			DEBG1(thisName, " compressed to %d%%\n", (int) ((dLen * 100) / sLen));
4062
4063			for (idx = 0; (idx < kIOPreviewImageCount); idx++)
4064			{
4065				if (map[idx]) map[idx]->release();
4066			}
4067
4068			dLen = round_page( dLen );
4069			if (__private->saveLength > dLen)
4070			{
4071				IOFreePageable( (void *) (((uintptr_t) __private->saveFramebuffer) + dLen),
4072								__private->saveLength - dLen );
4073				__private->saveLength = dLen;
4074			}
4075#else
4076			if (frameBuffer) bcopy_nc( (void *) frameBuffer, __private->saveFramebuffer, sLen );
4077#endif
4078			if (__private->saveLength)
4079			{
4080#if RLOG
4081				kern_return_t kr =
4082#endif
4083				vm_map_wire( IOPageableMapForAddress( (vm_address_t) __private->saveFramebuffer ),
4084							 (vm_address_t) __private->saveFramebuffer,
4085							 ((vm_address_t) __private->saveFramebuffer) + __private->saveLength,
4086							 VM_PROT_READ | VM_PROT_WRITE, FALSE );
4087				DEBG(thisName, " vm_map_wire(%x)\n", kr);
4088
4089				if (this == gIOFBConsoleFramebuffer)
4090				{
4091					IOMemoryDescriptor *
4092					previewBuffer = IOMemoryDescriptor::withAddress(
4093										__private->saveFramebuffer,
4094										__private->saveLength,
4095										kIODirectionInOut);
4096					if (previewBuffer)
4097					{
4098						getPMRootDomain()->setProperty(kIOHibernatePreviewBufferKey, previewBuffer);
4099						previewBuffer->release();
4100
4101						OSNumber * num;
4102						if (false
4103						 && frameBuffer
4104						 && (num = OSDynamicCast(OSNumber, getPMRootDomain()->getProperty(kIOHibernateModeKey)))
4105						 && (kIOHibernateModeOn == ((kIOHibernateModeSleep | kIOHibernateModeOn) & num->unsigned32BitValue()))
4106						 && !gIOFBCurrentClamshellState)
4107						{
4108							// hibernate enabled, will power off, clamshell open - do preview
4109							UInt32 flags = 0;
4110							getProvider()->setProperty(kIOHibernatePreviewActiveKey, &flags, sizeof(flags));
4111							PreviewDecompressData(&__private->saveFramebuffer, 0, (void *)frameBuffer,
4112													__private->framebufferWidth, __private->framebufferHeight,
4113													bytesPerPixel, rowBytes);
4114						}
4115					}
4116				}
4117			}
4118		}
4119	}
4120#endif /* VRAM_SAVE */
4121}
4122
4123IOReturn IOFramebuffer::restoreFramebuffer(IOIndex event)
4124{
4125	IOReturn ret = kIOReturnNotReady;
4126	uint32_t restoreType;
4127
4128	if (2 == pendingPowerState)
4129	{
4130		restoreType =
4131			(kOSBooleanFalse == getPMRootDomain()->getProperty(kIOPMUserTriggeredFullWakeKey))
4132			? kIOScreenRestoreStateDark : kIOScreenRestoreStateNormal;
4133	}
4134	else restoreType = kIOScreenRestoreStateDark;
4135
4136	if (__private->hibernateGfxStatus) restoreType = kIOScreenRestoreStateDark;
4137
4138#if VRAM_SAVE
4139	// restore vram content
4140	if (restoreType != __private->restoreType)
4141	{
4142		thread_t saveThread = NULL;
4143
4144		if (kIOFBNotifyVRAMReady == event)
4145		{
4146			IOMemoryDescriptor * vram;
4147			if ((vram = getVRAMRange()))
4148			{
4149				vram->redirect( kernel_task, false );
4150				vram->release();
4151			}
4152		}
4153		else
4154		{
4155			saveThread = __private->controller->powerThread;
4156			__private->controller->powerThread = current_thread();
4157			setAttribute(kIOFBSpeedAttribute, kIOFBVRAMCompressSpeed);
4158		}
4159
4160		if (!__private->saveLength) restoreType = kIOScreenRestoreStateDark;
4161
4162		if (frameBuffer)
4163		{
4164			if (kIOScreenRestoreStateDark == restoreType)
4165			{
4166				volatile unsigned char * line = frameBuffer;
4167				for (uint32_t y = 0; y < __private->framebufferHeight; y++)
4168				{
4169					bzero((void *) line, __private->framebufferWidth * __private->cursorBytesPerPixel);
4170					line += rowBytes;
4171				}
4172			}
4173			else
4174			{
4175				KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_IOGRAPHICS, DBG_IOG_VRAM_RESTORE) | DBG_FUNC_START,
4176									  0, (uintptr_t) __private->regID, (uintptr_t) (__private->regID >> 32), 0, 0);
4177	#if VRAM_COMPRESS
4178				uint32_t image = (kOSBooleanTrue ==
4179					IORegistryEntry::getRegistryRoot()->getProperty(kIOConsoleLockedKey));
4180				if (image >= kIOPreviewImageCount) image = 0;
4181				DecompressData((UInt8 *) __private->saveFramebuffer, image, (UInt8 *) frameBuffer,
4182								0, 0, __private->framebufferWidth, __private->framebufferHeight, rowBytes);
4183	#else
4184				bcopy_nc( __private->saveFramebuffer, (void *) frameBuffer, __private->saveLength );
4185	#endif
4186				KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_IOGRAPHICS, DBG_IOG_VRAM_RESTORE) | DBG_FUNC_END,
4187									  0, (uintptr_t) __private->regID, (uintptr_t) (__private->regID >> 32), 0, 0);
4188				DEBG1(thisName, " screen drawn\n");
4189			}
4190		}
4191		DEBG1(thisName, " restoretype %d->%d\n", __private->restoreType, restoreType);
4192		__private->needGammaRestore = (0 == __private->restoreType);
4193		__private->restoreType      = restoreType;
4194
4195		if (kIOFBNotifyVRAMReady != event)
4196		{
4197			setAttribute(kIOFBSpeedAttribute, __private->reducedSpeed);
4198			__private->controller->powerThread = saveThread;
4199		}
4200
4201		ret = kIOReturnSuccess;
4202	}
4203
4204	if ((kIOFBNotifyVRAMReady != event) && __private->restoreType && __private->needGammaRestore)
4205	{
4206		if (__private->gammaDataLen && __private->gammaData && !__private->scaledMode)
4207		{
4208			DEBG1(thisName, " set gamma\n");
4209			setGammaTable( __private->gammaChannelCount, __private->gammaDataCount,
4210							__private->gammaDataWidth, __private->gammaData );
4211		}
4212		__private->needGammaRestore = false;
4213	}
4214#endif /* VRAM_SAVE */
4215
4216    return (ret);
4217}
4218
4219IOReturn IOFramebuffer::handleEvent( IOIndex event, void * info )
4220{
4221    IOReturn ret = kIOReturnSuccess;
4222	bool     sendEvent = true;
4223
4224    DEBG1(thisName, "(%d, %d)\n", (uint32_t) event,
4225    		current_thread() != __private->controller->powerThread);
4226
4227    if (current_thread() != __private->controller->powerThread)
4228    {
4229		sendEvent = false;
4230    }
4231    else switch (event)
4232    {
4233        case kIOFBNotifyWillSleep:
4234            if (!info)
4235				break;
4236
4237            if (this == gIOFBConsoleFramebuffer)
4238            {
4239//              getPlatform()->setConsoleInfo( 0, kPEDisableScreen);
4240                killprint = 1;
4241            }
4242			__private->restoreType = kIOScreenRestoreStateNone;
4243			// notification sent early at system sleep
4244			sendEvent = false;
4245			ret = kIOReturnSuccess;
4246            break;
4247
4248        case kIOFBNotifyDidWake:
4249            if (!info)
4250				break;
4251
4252			restoreFramebuffer(event);
4253
4254            if (this == gIOFBConsoleFramebuffer)
4255            {
4256//              getPlatform()->setConsoleInfo( 0, kPEEnableScreen);
4257                killprint = 0;
4258                kmputc( 033 );
4259                kmputc( 'c' );
4260            }
4261
4262            sleepConnectCheck = true;
4263
4264#if DOANIO
4265            doanio();
4266#endif
4267			pagingState = true;
4268		    __private->actualVBLCount = 0;
4269			updateVBL(this, NULL);
4270			ret = deliverFramebufferNotification(kIOFBNotifyDidWake, (void *) true);
4271			info = (void *) false;
4272			break;
4273
4274        case kIOFBNotifyDidPowerOn:
4275			pagingState = true;
4276			ret = kIOReturnSuccess;
4277            break;
4278
4279        case kIOFBNotifyVRAMReady:
4280			ret = restoreFramebuffer(event);
4281			sendEvent = false;
4282            break;
4283    }
4284
4285	if (sendEvent)
4286		ret = deliverFramebufferNotification(event, info);
4287
4288    return (ret);
4289}
4290
4291IOReturn IOFramebuffer::notifyServer( UInt8 state )
4292{
4293    mach_msg_header_t * msgh = (mach_msg_header_t *) serverMsg;
4294    IOReturn            err = kIOReturnSuccess;
4295
4296    if (serverNotified != state)
4297    {
4298		if (!gChosenEntry) gChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
4299		if (gChosenEntry && !state) gChosenEntry->removeProperty(kIOScreenLockStateKey);
4300		if (state)
4301		{
4302			if (this == gIOFBConsoleFramebuffer)
4303			{
4304				getPMRootDomain()->removeProperty(kIOHibernatePreviewBufferKey);
4305				getProvider()->removeProperty(kIOHibernatePreviewActiveKey);
4306			}
4307			if (__private->saveFramebuffer && __private->saveLength)
4308			{
4309				IOFreePageable( __private->saveFramebuffer, __private->saveLength );
4310			}
4311			__private->saveFramebuffer = 0;
4312			__private->saveLength      = 0;
4313			setProperty(kIOScreenRestoreStateKey,
4314						&__private->restoreType, sizeof(__private->restoreType));
4315			DEBG1(thisName, " kIOScreenRestoreStateKey %d\n", __private->restoreType);
4316			__private->restoreType      = kIOScreenRestoreStateNone;
4317			__private->needGammaRestore = false;
4318		}
4319
4320        serverNotified = state;
4321
4322        DEBG1(thisName, "(%p, wait %d, %d->%d)\n", msgh->msgh_remote_port,
4323             __private->controller->wsWait, serverState, serverNotified);
4324
4325		KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_IOGRAPHICS, DBG_IOG_NOTIFYSERVER) | DBG_FUNC_NONE,
4326							  state, (uintptr_t) __private->regID, (uintptr_t) (__private->regID >> 32), 0, 0);
4327
4328        msgh->msgh_id = state;
4329        if ((MACH_PORT_NULL == msgh->msgh_remote_port)
4330                || (KERN_SUCCESS != mach_msg_send_from_kernel(msgh, msgh->msgh_size)))
4331        {
4332			// failed to send
4333            serverState = serverNotified;
4334        }
4335        else
4336        {
4337			// start ack timeout
4338			gIOFBServerAckTimer->setTimeoutMS(kServerAckTimeout * 1000);
4339        }
4340    }
4341
4342    if (serverNotified)
4343	{
4344		// wakeup is not gate specific
4345    	FBWL(this)->wakeupGate(&serverConnect, true);
4346	}
4347
4348    return (err);
4349}
4350
4351bool IOFramebuffer::getIsUsable( void )
4352{
4353    return (dead || (0 != isUsable));
4354}
4355
4356IOReturn IOFramebuffer::postWake(void)
4357{
4358    IOReturn  ret;
4359    uintptr_t value;
4360    bool      probeDP;
4361
4362	DEBG1(thisName, " post wake from sleep %d\n", sleepConnectCheck);
4363
4364    probeDP = (__private->dpDongle && !sleepConnectCheck);
4365
4366    ret = getAttributeForConnection(0, kConnectionPostWake, &value);
4367
4368    if (captured)
4369		gIOFBProbeCaptured = true;
4370	else
4371    {
4372        getAttributeForConnection(0, kConnectionChanged, 0);
4373        if (probeDP)
4374        {
4375#if RLOG
4376            IOReturn probeErr =
4377#endif
4378            setAttributeForConnection(0, kConnectionProbe, kIOFBUserRequestProbe);
4379            DEBG(thisName, " dp probe wake result %x\n", probeErr);
4380        }
4381    }
4382
4383	__private->controller->postWakeChange = __private->controller->connectChange;
4384	if (sleepConnectCheck)
4385	{
4386		gIOFBLastReadClamshellState = gIOFBCurrentClamshellState;
4387		sleepConnectCheck = false;
4388    }
4389
4390	resetClamshell(kIOFBClamshellProbeDelayMS);
4391
4392    return (ret);
4393}
4394
4395/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4396
4397IOReturn IOFramebuffer::pmSettingsChange(OSObject * target, const OSSymbol * type,
4398                                         OSObject * val, uintptr_t refcon)
4399{
4400    if (type == gIOFBPMSettingDisplaySleepUsesDimKey)
4401    {
4402        OSBitOrAtomic(kIOFBEventDisplayDimsSetting, &gIOFBGlobalEvents);
4403		startThread(false);
4404    }
4405    return (kIOReturnSuccess);
4406}
4407
4408/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4409
4410void IOFramebuffer::startAsync(IOFBController * controller, uint32_t asyncWork)
4411{
4412	if (!gIOFBSystemWorkLoop->inGate()) panic("!sys");
4413	if (!controller->wl->inGate())      panic("!gate\n");
4414	if (controller->asyncWork) 			panic("asyncWork");
4415	if (controller->didWork) 			panic("didWork");
4416
4417	controller->asyncWork = asyncWork;
4418	controller->workES->interruptOccurred(0, 0, 0);
4419}
4420
4421// system WL
4422
4423enum
4424{
4425    kIOFBDidWork 			= 0x00000001,
4426    kIOFBWorking  			= 0x00000002,
4427    kIOFBPaging   			= 0x00000004,
4428    kIOFBWsWait   			= 0x00000008,
4429    kIOFBDimmed   			= 0x00000010,
4430    kIOFBServerSlept 		= 0x00000020,	// any fb ws notified asleep
4431    kIOFBServerUp           = 0x00000040,	// any fb ws state awake
4432    kIOFBServerDown			= 0x00000080,	// any fb ws state asleep
4433    kIOFBCaptured 			= 0x00000100,
4434    kIOFBDimDisable 		= 0x00000200,
4435    kIOFBDisplaysChanging 	= 0x00001000
4436};
4437
4438enum
4439{
4440	kWorkStateChange = 0x00000001,
4441	kWorkPower       = 0x00000002,
4442	kWorkSuspend     = 0x00000004,
4443};
4444
4445void IOFramebuffer::systemWork(OSObject * owner,
4446                               IOInterruptEventSource * evtSrc, int intCount)
4447{
4448    UInt32 events;
4449    uint32_t	        index;
4450    IOFBController *    controller;
4451    IOFramebuffer *     fb;
4452    uint32_t            allState;
4453
4454	allState = 0;
4455
4456	controller = gIOFBAllControllers;
4457	if (controller) do
4458	{
4459		allState |= controllerState(controller);
4460		controller = controller->nextController;
4461	}
4462	while (controller != gIOFBAllControllers);
4463
4464    DEBG1("S1", " state 0x%x\n", allState);
4465
4466	controller = gIOFBAllControllers;
4467	if (controller) do
4468	{
4469		if (controller->needsWork)
4470		{
4471			uint32_t state = allState;
4472			DEBG1(controller->name, " working %x\n", state);
4473
4474			FCLOCK(controller);
4475			if (!controller->didWork)
4476			{
4477				if (kIOFBEventSystemPowerOn & gIOFBGlobalEvents)
4478				{
4479					OSBitAndAtomic(~kIOFBEventSystemPowerOn, &gIOFBGlobalEvents);
4480					muxPowerMessage(kIOMessageDeviceWillPowerOn);
4481				}
4482
4483				state |= checkPowerWork(controller, state);
4484
4485				if (kIOFBServerSlept & state)
4486				{
4487					if ((controller->lastFinishedChange != controller->connectChange)
4488							 && !controller->fbs[0]->messaged
4489							 && gIOFBSwitching)
4490					{
4491						IODisplayWrangler::activityChange(controller->fbs[0]);
4492					}
4493				}
4494				else if (!(kIOFBServerDown & state))
4495				{
4496					state |= checkConnectionWork(controller, state);
4497					controller->needsWork = false;
4498				}
4499			}
4500			FCUNLOCK(controller);
4501		}
4502		controller = controller->nextController;
4503	}
4504	while (controller != gIOFBAllControllers);
4505
4506    DEBG1("S2", " state 0x%x\n", allState);
4507
4508	if (kIOFBWorking & allState)
4509		return;
4510
4511	if (!(kIOFBWsWait & allState))
4512	{
4513		bool wsState = ((gIOFBSystemPower || gIOFBSwitching) && !(kIOFBDimmed & allState));
4514		if (wsState != gIOFBWSState)
4515		{
4516			if (wsState && (kIOFBServerUp & allState))
4517			{
4518				DEBG1("S", " notifyServer wait ack\n");
4519			}
4520			else
4521			{
4522				DEBG1("S", " notifyServer(%d)\n", wsState);
4523				gIOFBWSState = wsState;
4524				if (wsState)
4525					gIOFBPostWakeNeeded = true;
4526				for (index = 0;
4527						(fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
4528						index++)
4529				{
4530					FBLOCK(fb);
4531					fb->notifyServer(wsState);
4532					FBUNLOCK(fb);
4533				}
4534			}
4535		}
4536	}
4537
4538	if (!(kIOFBServerUp & allState) && gIOFBSystemPowerAckTo
4539		&& !(kIOFBDisplaysChanging & allState)
4540		&& !gIOFBSwitching)
4541	{
4542		uintptr_t notiArg;
4543		// tell accelerators to disable, then protect HW
4544		for(notiArg = 0; notiArg < 2; notiArg++)
4545		{
4546			for (index = 0;
4547				 (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
4548				 index++)
4549			{
4550				FBLOCK(fb);
4551				fb->deliverFramebufferNotification(kIOFBNotifyWillSleep, (void *) notiArg);
4552				if (notiArg)
4553				{
4554					fb->saveFramebuffer();
4555					fb->pagingState = false;
4556				}
4557				FBUNLOCK(fb);
4558			}
4559		}
4560
4561		DEBG("S", " allowPowerChange(%p)\n", gIOFBSystemPowerAckRef);
4562
4563		IOService * ackTo  = gIOFBSystemPowerAckTo;
4564		void *      ackRef = gIOFBSystemPowerAckRef;
4565		gIOFBSystemPowerAckTo = 0;
4566
4567		ackTo->allowPowerChange( (uintptr_t) ackRef );
4568
4569		DEBG("S", " did allowPowerChange()\n");
4570	}
4571
4572	if (!(kIOFBServerDown & allState) && gIOFBPostWakeNeeded)
4573	{
4574		gIOFBPostWakeNeeded = false;
4575		for (index = 0;
4576			 (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
4577			 index++)
4578		{
4579			FBLOCK(fb);
4580			fb->postWake();
4581			FBUNLOCK(fb);
4582		}
4583	}
4584
4585	events = gIOFBGlobalEvents;
4586
4587	if (kIOFBEventCaptureSetting & events)
4588	{
4589		bool wasCaptured, wasDimDisable;
4590		bool newCaptured, newDimDisable;
4591
4592		OSBitAndAtomic(~kIOFBEventCaptureSetting, &gIOFBGlobalEvents);
4593
4594		wasCaptured   = (0 != (kIOFBCaptured & allState));
4595		wasDimDisable = (0 != (kIOFBDimDisable & allState));
4596		newCaptured   = (0 != (kIOCaptureDisableDisplayChange  & gIOFBCaptureState));
4597		newDimDisable = (0 != (kIOCaptureDisableDisplayDimming & gIOFBCaptureState));
4598
4599		for (index = 0;
4600			 (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
4601			 index++)
4602		{
4603			FBLOCK(fb);
4604			fb->setCaptured(newCaptured);
4605			fb->setDimDisable(newDimDisable);
4606			FBUNLOCK(fb);
4607		}
4608		if (wasCaptured != newCaptured) gIOFBGrayValue = newCaptured ? 0 : kIOFBGrayValue;
4609
4610		if (newDimDisable != wasDimDisable)
4611		{
4612			getPMRootDomain()->setAggressiveness(kIOFBCaptureAggressiveness, newDimDisable);
4613		}
4614
4615		if (gIOFBProbeCaptured && wasCaptured && !newCaptured)
4616		{
4617			gIOFBProbeCaptured = false;
4618			OSBitOrAtomic(kIOFBEventProbeAll, &gIOFBGlobalEvents);
4619			startThread(false);
4620			DEBG1("S", " capt probe all\n");
4621		}
4622	}
4623
4624	if (kIOFBEventDisplayDimsSetting & events)
4625	{
4626		OSNumber *  num;
4627		uintptr_t   value = true;
4628		OSObject *  obj;
4629
4630		OSBitAndAtomic(~kIOFBEventDisplayDimsSetting, &gIOFBGlobalEvents);
4631		obj = getPMRootDomain()->copyPMSetting(const_cast<OSSymbol *>
4632											   (gIOFBPMSettingDisplaySleepUsesDimKey));
4633		if ((num = OSDynamicCast(OSNumber, obj)))
4634			value = num->unsigned32BitValue();
4635		if (obj)
4636			obj->release();
4637
4638		if (num) for (uint32_t index = 0;
4639			 (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
4640			 index++)
4641		{
4642			FBLOCK(fb);
4643			fb->deliverFramebufferNotification(kIOFBNotifyDisplayDimsChange, (void *) value);
4644			FBUNLOCK(fb);
4645		}
4646	}
4647
4648	if ((kIOFBEventReadClamshell & events)
4649		&& !gIOFBSwitching
4650		&& !(kIOFBWsWait & allState))
4651	{
4652		OSObject * clamshellProperty;
4653
4654		OSBitAndAtomic(~kIOFBEventReadClamshell, &gIOFBGlobalEvents);
4655		clamshellProperty = gIOResourcesAppleClamshellState;
4656		if (clamshellProperty)
4657		{
4658			gIOFBLastClamshellState =
4659			gIOFBCurrentClamshellState = (kOSBooleanTrue == clamshellProperty);
4660			DEBG1("S", " clamshell read %d\n", (int) gIOFBCurrentClamshellState);
4661
4662			for (uint32_t index = 0;
4663					(fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
4664					index++)
4665			{
4666				FBLOCK(fb);
4667				fb->deliverFramebufferNotification(kIOFBNotifyClamshellChange, clamshellProperty);
4668				FBUNLOCK(fb);
4669			}
4670
4671			bool desktopMode;
4672			if (gIOFBLidOpenMode)
4673				desktopMode = gIOFBDesktopModeAllowed && (gIOFBDisplayCount > 0);
4674			else
4675				desktopMode = gIOFBDesktopModeAllowed && (gIOFBBacklightDisplayCount <= 0);
4676
4677			if (desktopMode)
4678			{
4679				// lid change, desktop mode
4680				DEBG1("S", " desktop will reprobe\n");
4681				resetClamshell(kIOFBClamshellProbeDelayMS);
4682			}
4683		}
4684	}
4685
4686	if ((kIOFBEventResetClamshell & events) && gIOFBSystemPower
4687		&& !(kIOFBWsWait & allState)
4688		&& !(kIOFBDisplaysChanging & allState))
4689	{
4690		OSBitAndAtomic(~kIOFBEventResetClamshell, &gIOFBGlobalEvents);
4691
4692		DEBG1("S", " kIOFBEventResetClamshell %d, %d\n", gIOFBCurrentClamshellState, gIOFBLastReadClamshellState);
4693
4694		if ((gIOFBLidOpenMode && (gIOFBCurrentClamshellState != gIOFBLastReadClamshellState))
4695			// clamshell changed since last probe
4696		 || (!gIOFBLidOpenMode && (gIOFBBacklightDisplayCount && gIOFBLastReadClamshellState && !gIOFBCurrentClamshellState)))
4697			// clamshell was closed during last probe, now open => reprobe
4698		{
4699			DEBG1("S", " clamshell caused reprobe\n");
4700			events |= kIOFBEventProbeAll;
4701			OSBitOrAtomic(kIOFBEventProbeAll, &gIOFBGlobalEvents);
4702		}
4703		else
4704		{
4705			AbsoluteTime deadline;
4706			clock_interval_to_deadline(kIOFBClamshellEnableDelayMS, kMillisecondScale, &deadline );
4707			thread_call_enter1_delayed(gIOFBClamshellCallout,
4708										(thread_call_param_t) kIOFBEventEnableClamshell, deadline );
4709		}
4710	}
4711
4712	if ((kIOFBEventEnableClamshell & events) && gIOFBSystemPower
4713		&& !(kIOFBWsWait & allState)
4714		&& !(kIOFBDisplaysChanging & allState))
4715	{
4716		UInt32      change;
4717		bool        desktopMode;
4718
4719		OSBitAndAtomic(~kIOFBEventEnableClamshell, &gIOFBGlobalEvents);
4720
4721		if (gIOFBLidOpenMode)
4722			desktopMode = gIOFBDesktopModeAllowed && (gIOFBDisplayCount > 0);
4723		else
4724			desktopMode = gIOFBDesktopModeAllowed && (gIOFBBacklightDisplayCount <= 0);
4725
4726		change = kIOPMEnableClamshell | kIOPMSetDesktopMode | (desktopMode ? kIOPMSetValue : 0);
4727		if (change != gIOFBClamshellState)
4728		{
4729			gIOFBClamshellState = change;
4730			DEBG1("S", " clamshell ena desktopMode %d\n", desktopMode);
4731			getPMRootDomain()->receivePowerNotification(change);
4732		}
4733	}
4734
4735	if (kIOFBEventDisplaysPowerState & events)
4736	{
4737		unsigned long state = IODisplayWrangler::getDisplaysPowerState();
4738
4739		if (gIOFBSwitching && (state < kIODisplayNumPowerStates))
4740		{
4741			state = kIODisplayNumPowerStates;
4742		}
4743		else
4744		{
4745			OSBitAndAtomic(~kIOFBEventDisplaysPowerState, &gIOFBGlobalEvents);
4746		}
4747		DEBG1("S", " displays pstate %ld\n", state);
4748
4749		for (uint32_t index = 0;
4750				(fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
4751				index++)
4752		{
4753			FBLOCK(fb);
4754			if (fb->__private->display)
4755				fb->__private->display->setDisplayPowerState(state);
4756			FBUNLOCK(fb);
4757		}
4758	}
4759
4760	if ((kIOFBEventProbeAll & events)
4761		&& gIOFBSystemPower
4762		&& (kIOMessageSystemHasPoweredOn == gIOFBLastMuxMessage)
4763		&& !(kIOFBWsWait & allState)
4764		&& !(kIOFBCaptured & allState)
4765		&& !(kIOFBDisplaysChanging & allState))
4766	{
4767		OSBitAndAtomic(~kIOFBEventProbeAll, &gIOFBGlobalEvents);
4768
4769		DEBG1("S", " probeAll clam %d -> %d\n",
4770				(int) gIOFBLastClamshellState, (int) gIOFBCurrentClamshellState);
4771
4772		gIOFBLastClamshellState = gIOFBCurrentClamshellState;
4773		gIOFBLastReadClamshellState = gIOFBCurrentClamshellState;
4774
4775		probeAll(kIOFBUserRequestProbe);
4776		for (uint32_t index = 0;
4777				(fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
4778				index++)
4779		{
4780			FBLOCK(fb);
4781			fb->deliverFramebufferNotification(kIOFBNotifyProbed, NULL);
4782			FBUNLOCK(fb);
4783		}
4784		resetClamshell(kIOFBClamshellProbeDelayMS);
4785	}
4786}
4787
4788void IOFramebuffer::serverAckTimeout(OSObject * null, IOTimerEventSource * sender)
4789{
4790    uint32_t	        index;
4791    IOFramebuffer *     fb;
4792
4793	for (index = 0;
4794			(fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
4795			index++)
4796	{
4797		FBLOCK(fb);
4798		if (fb->serverState != fb->serverNotified)
4799		{
4800			DEBG1(fb->thisName, " (%d->%d) server ack timeout\n",
4801				 fb->serverState, fb->serverNotified);
4802			fb->serverAcknowledgeNotification();
4803		}
4804		FBUNLOCK(fb);
4805	}
4806}
4807
4808IOFBController * IOFramebuffer::aliasController(IOFBController * controller)
4809{
4810	IOFBController * result = controller;
4811	do
4812	{
4813		result = result->nextController;
4814		if (result->aliasID == controller->aliasID)
4815			break;
4816	}
4817	while (result != controller);
4818
4819	if (result == controller)
4820		result = controller->nextController;
4821
4822	return (result);
4823}
4824
4825uint32_t IOFramebuffer::controllerState(IOFBController * controller)
4826{
4827	IOFramebuffer * fb;
4828    uint32_t idx;
4829    uint32_t state;
4830
4831	state = controller->state;
4832
4833	if (controller->didWork || controller->connectChange)
4834	{
4835		FCLOCK(controller);
4836
4837		if (controller->connectChange)
4838			controller->needsWork = true;
4839
4840		if (controller->didWork & ~kWorkStateChange)
4841		{
4842			controller->asyncWork = false;
4843
4844			for (idx = 0; (fb = controller->fbs[idx]); idx++)
4845			{
4846				if (kWorkPower & controller->didWork)
4847				{
4848					if (fb->pendingPowerState)
4849					{
4850						fb->deliverFramebufferNotification( kIOFBNotifyDidWake,    (void *) true);
4851						fb->deliverFramebufferNotification( kIOFBNotifyDidPowerOn, (void *) false);
4852//   					fb->deliverFramebufferNotification( kIOFBNotifyDidWake,    (void *) false);
4853					}
4854					else
4855						fb->deliverFramebufferNotification( kIOFBNotifyDidPowerOff, (void *) false);
4856				}
4857				if (kWorkSuspend & controller->didWork)
4858				{
4859					fb->suspend(false);
4860				}
4861			}
4862
4863			if (kWorkSuspend & controller->didWork)
4864			{
4865				if (controller->onlineMask) 				// bgOn
4866				{
4867					IOFBController * oldController;
4868
4869					oldController = aliasController(controller);
4870					FCLOCK(oldController);
4871					if (oldController->lastFinishedChange == oldController->connectChange)
4872					{
4873						DEBG1(controller->name, " mute exit\n");
4874					}
4875					FCUNLOCK(oldController);
4876					messageConnectionChange(controller);
4877				}
4878			}
4879		}
4880
4881		state = 0;
4882		if (controller->wsWait)
4883			state |= kIOFBWsWait;
4884
4885		for (idx = 0; (fb = controller->fbs[idx]); idx++)
4886		{
4887			if (fb->pagingState)
4888				state |= kIOFBPaging;
4889			if (fb->messaged)
4890				state |= kIOFBDisplaysChanging;
4891			if (!fb->getIsUsable())
4892				state |= kIOFBDimmed;
4893			if (!fb->serverNotified)
4894				state |= kIOFBServerSlept;
4895			if (fb->serverState)
4896				state |= kIOFBServerUp;
4897			else
4898				state |= kIOFBServerDown;
4899			if (fb->captured)
4900				state |= kIOFBCaptured;
4901			if (fb->getDimDisable())
4902				state |= kIOFBDimDisable;
4903		}
4904
4905		controller->state = state;
4906		controller->didWork = false;
4907		state |= kIOFBDidWork;
4908
4909		FCUNLOCK(controller);
4910	}
4911
4912	DEBG1(controller->name, " state %x\n", state);
4913
4914	return (state);
4915}
4916
4917void IOFramebuffer::startThread(bool highPri)
4918{
4919    gIOFBWorkES->interruptOccurred(0, 0, 0);
4920}
4921
4922// controller WL
4923
4924void IOFramebuffer::startControllerThread(IOFBController * controller)
4925{
4926	controller->needsWork = true;
4927
4928	controller->didWork |= kWorkStateChange;
4929
4930	startThread(false);
4931}
4932
4933void IOFramebuffer::controllerDidWork(IOFBController * controller, IOOptionBits work)
4934{
4935	if (controller->asyncWork && !work) OSReportWithBacktrace("asyncWork+did");
4936
4937	controller->didWork |= work;
4938
4939	startThread(false);
4940}
4941
4942void IOFramebuffer::controllerAsyncWork(OSObject * owner,
4943                                        IOInterruptEventSource * evtSrc, int intCount)
4944{
4945	IOFramebuffer * fb = (IOFramebuffer *) owner;
4946	IOFBController * controller = fb->__private->controller;
4947    uint32_t idx;
4948    uint32_t asyncWork;
4949
4950	asyncWork = controller->asyncWork;
4951	controller->asyncWork = true;
4952
4953	DEBG1(controller->name, " (%d)\n", asyncWork);
4954
4955	if (kWorkPower & asyncWork)
4956	{
4957		uint32_t newState = controller->fbs[0]->pendingPowerState;
4958		DEBG1(controller->name, " async kIODriverPowerAttribute(%d, %d)\n",
4959				newState, controller->fbs[0]->pendingPowerState);
4960		for (idx = 0; (fb = controller->fbs[idx]); idx++)
4961			fb->setAttribute(kIODriverPowerAttribute, newState);
4962		controllerDidWork(controller, kWorkPower);
4963	}
4964	else if (kWorkSuspend & asyncWork)
4965	{
4966		for (idx = 0; (fb = controller->fbs[idx]); idx++)
4967			fb->setAttributeForConnection(0, kConnectionPanelTimingDisable, false);
4968
4969		processConnectChange(controller, bg);
4970		if (controller->onlineMask)
4971			matchController(controller);
4972		else
4973		{
4974			DEBG1(controller->name, " bg offline\n");
4975			controller->lastFinishedChange = controller->connectChange;
4976		}
4977
4978		for (idx = 0; (fb = controller->fbs[idx]); idx++)
4979			fb->setAttributeForConnection(0, kConnectionPanelTimingDisable, true);
4980
4981		controllerDidWork(controller, kWorkSuspend);
4982	}
4983}
4984
4985IOOptionBits IOFramebuffer::checkPowerWork(IOFBController * controller, IOOptionBits state)
4986{
4987	IOFramebuffer *  fb;
4988    uint32_t idx;
4989
4990	if (controller->pendingMuxPowerChange)
4991	{
4992		uint32_t newState = controller->fbs[0]->pendingPowerState;
4993		DEBG1(controller->name, " async checkPowerWork(%d)\n", newState);
4994		if (!newState)
4995		{
4996			for (idx = 0; (fb = controller->fbs[idx]); idx++)
4997			{
4998//					fb->deliverFramebufferNotification(kIOFBNotifyWillSleep,    (void *) false);
4999				fb->deliverFramebufferNotification(kIOFBNotifyWillPowerOff, (void *) false);
5000				fb->deliverFramebufferNotification(kIOFBNotifyWillSleep,    (void *) true);
5001			}
5002		}
5003		controller->pendingMuxPowerChange = false;
5004		startAsync(controller, kWorkPower);
5005	}
5006	else for (idx = 0; (fb = controller->fbs[idx]); idx++)
5007	{
5008		state |= fb->checkPowerWork(state);
5009	}
5010
5011    return (state);
5012}
5013
5014IOOptionBits IOFramebuffer::checkPowerWork(IOOptionBits state)
5015{
5016    IOOptionBits ourState = kIOFBPaging;
5017	IOService *  device = 0;
5018    OSData *     stateData = 0;
5019
5020	if (pendingPowerChange)
5021	{
5022		uintptr_t newState = pendingPowerState;
5023
5024		DEBG1(thisName, " pendingPowerState(%ld)\n", newState);
5025
5026    	__private->controller->powerThread = current_thread();
5027		__private->hibernateGfxStatus = 0;
5028		if (!pagingState)
5029		{
5030			device = __private->controller->device;
5031			if (device
5032			  && (stateData = OSDynamicCast(OSData, getPMRootDomain()->getProperty(kIOHibernateStateKey))))
5033			{
5034				if (kIOHibernateStateWakingFromHibernate == ((uint32_t *) stateData->getBytesNoCopy())[0])
5035				{
5036					OSNumber *
5037					num = OSDynamicCast(OSNumber, getPMRootDomain()->getProperty(kIOHibernateOptionsKey));
5038					uint32_t options = 0;
5039					if (num) options = num->unsigned32BitValue();
5040					DEBG1(thisName, " kIOHibernateOptionsKey %p (0x%x)\n", num, options);
5041					if (kIOHibernateOptionDarkWake & options)
5042					{
5043						stateData = 0;
5044					}
5045					else
5046					{
5047						device->setProperty(kIOHibernateStateKey, stateData);
5048
5049
5050						OSData *
5051						data = OSDynamicCast(OSData, getPMRootDomain()->getProperty(kIOHibernateGfxStatusKey));
5052						if (data)
5053						{
5054							__private->hibernateGfxStatus = ((uint32_t *)data->getBytesNoCopy())[0];
5055							device->setProperty(kIOHibernateEFIGfxStatusKey, data);
5056						}
5057						if (newState == 1) newState = 2;
5058					}
5059				}
5060			}
5061		}
5062
5063		// online-online test
5064		// if (newState && __private->controllerIndex) connectChangeInterrupt(this, 0);
5065
5066		if ((newState == 1)
5067			&& (kIODisplayOptionDimDisable & __private->displayOptions)
5068// 9564372			&& __private->audioStreaming
5069			&& !gIOFBSystemDark)
5070		{
5071			newState = 2;
5072		}
5073
5074		setAttribute(kIOPowerStateAttribute, newState);
5075		DEBG1(thisName, " did kIOPowerStateAttribute(%ld)\n", newState);
5076		if (device && stateData)
5077		{
5078			device->setProperty(kIOHibernateStateKey, gIOFBZero32Data);
5079			device->removeProperty(kIOHibernateEFIGfxStatusKey);
5080		}
5081
5082    	__private->controller->powerThread = NULL;
5083
5084		OSObject * obj;
5085		if ((this == gIOFBConsoleFramebuffer)
5086			&& (obj = copyProperty(kIOHibernatePreviewActiveKey, gIOServicePlane)))
5087		{
5088			getPMRootDomain()->setProperty(kIOHibernatePreviewActiveKey, obj);
5089			obj->release();
5090		}
5091
5092		DEBG(thisName, " acknowledgeSetPowerState\n");
5093		pendingPowerChange = false;
5094		acknowledgeSetPowerState();
5095	}
5096
5097    if (__private->allowSpeedChanges && __private->pendingSpeedChange)
5098    {
5099        __private->pendingSpeedChange = false;
5100    	__private->controller->powerThread = current_thread();
5101        setAttribute(kIOFBSpeedAttribute, __private->reducedSpeed);
5102    	__private->controller->powerThread = NULL;
5103    }
5104
5105    return (ourState);
5106}
5107
5108IOOptionBits IOFramebuffer::checkConnectionWork( IOFBController * controller, IOOptionBits state )
5109{
5110    IOFramebuffer * fb;
5111    uint32_t idx;
5112
5113    DEBG1(controller->name, " count(%d, msg %d, fin %d, proc %d, wake %d), capt(%d) wsWait(%d)\n",
5114          controller->connectChange,
5115          controller->lastMessagedChange, controller->lastFinishedChange,
5116          controller->fbs[0]->__private->lastProcessedChange,
5117          controller->postWakeChange,
5118          (0 != (kIOFBCaptured & state)), controller->wsWait);
5119
5120	if (kIOFBCaptured & state)
5121	{
5122		if (controller->connectChange != controller->lastForceRetrain)
5123        {
5124            controller->lastForceRetrain = controller->connectChange;
5125            for (idx = 0; (fb = controller->fbs[idx]); idx++)
5126            {
5127                if (!fb->__private->dpSupported)
5128				{
5129                    IOReturn err;
5130					uintptr_t value[16];
5131                    err = fb->getAttributeForConnection(0, kConnectionHandleDisplayPortEvent, &value[0]);
5132					fb->__private->dpSupported = (kIOReturnSuccess == err) ? true : -1;
5133                    DEBG1(fb->thisName, " dpSupported(%d)\n", fb->__private->dpSupported);
5134				}
5135
5136                if (fb->__private->dpSupported > 0)
5137                {
5138                    IOReturn err;
5139                    uintptr_t sel = kIODPEventForceRetrain;
5140                    err = fb->setAttributeForConnection(0, kConnectionHandleDisplayPortEvent, (uintptr_t) &sel);
5141                    DEBG1(fb->thisName, " kIODPEventForceRetrain(0x%x)\n", err);
5142                }
5143            }
5144        }
5145		return (state);
5146	}
5147
5148	if (gIOGraphicsControl
5149	 && (controller->fbs[0]->__private->lastProcessedChange != controller->connectChange)
5150	 && !controller->asyncWork)
5151	{
5152		bool needAsync = false;
5153		if ((!controller->onlineMask)
5154			&& (controller->lastFinishedChange == controller->connectChange))
5155		{
5156			// bgOff
5157			needAsync = true;
5158		}
5159		else if ((!controller->onlineMask)
5160				&& (!controller->mute)
5161				&& (controller->connectChange != controller->postWakeChange))
5162		{
5163			// bgOn
5164			IOFBController * oldController;
5165			IOFramebuffer  * oldfb;
5166			oldController = aliasController(controller);
5167			FCLOCK(oldController);
5168
5169			DEBG1(controller->name, " copy from %s\n", oldController->name);
5170
5171			for (idx = 0; (fb = controller->fbs[idx]) && (oldfb = oldController->fbs[idx]); idx++)
5172			{
5173				DEBG1(oldfb->thisName, " copy %d x %d\n",
5174					(int) oldfb->__private->pixelInfo.activeWidth,
5175					(int) oldfb->__private->pixelInfo.activeHeight);
5176
5177				fb->__private->pixelInfo    = oldfb->__private->pixelInfo;
5178				fb->__private->timingInfo   = oldfb->__private->timingInfo;
5179				fb->__private->uiScale      = oldfb->__private->uiScale;
5180				fb->__private->matchedMode  = oldfb->__private->setupMode;
5181
5182				if (oldfb->__private->displayAttributes) oldfb->__private->displayAttributes->retain();
5183				if (fb->__private->displayAttributes) fb->__private->displayAttributes->release();
5184				fb->__private->displayAttributes =    oldfb->__private->displayAttributes;
5185
5186				if (oldfb->__private->rawGammaDataLen != fb->__private->rawGammaDataLen)
5187				{
5188					if (fb->__private->rawGammaDataLen)
5189						IODelete(fb->__private->rawGammaData, UInt8, fb->__private->rawGammaDataLen);
5190					fb->__private->rawGammaData = IONew(UInt8, oldfb->__private->rawGammaDataLen);
5191				}
5192				if (!fb->__private->rawGammaData)
5193				{
5194					fb->__private->rawGammaDataLen = 0;
5195					break;
5196				}
5197				fb->__private->rawGammaDataLen      = oldfb->__private->rawGammaDataLen;
5198				fb->__private->rawGammaChannelCount = oldfb->__private->rawGammaChannelCount;
5199				fb->__private->rawGammaDataCount    = oldfb->__private->rawGammaDataCount;
5200				fb->__private->rawGammaDataWidth    = oldfb->__private->rawGammaDataWidth;
5201
5202				bcopy(oldfb->__private->rawGammaData, fb->__private->rawGammaData,
5203						fb->__private->rawGammaDataLen);
5204
5205			}
5206			FCUNLOCK(oldController);
5207			needAsync = true;
5208		}
5209
5210		if (needAsync)
5211		{
5212			for (idx = 0; (fb = controller->fbs[idx]); idx++)
5213				fb->suspend(true);
5214			startAsync(controller, kWorkSuspend);
5215			state |= kIOFBDisplaysChanging;
5216		}
5217	}
5218
5219	if (!controller->asyncWork)
5220	{
5221		messageConnectionChange(controller);
5222	}
5223
5224	return (state);
5225}
5226
5227void IOFramebuffer::messageConnectionChange( IOFBController * controller )
5228{
5229	IOReturn 		err;
5230	bool     		discard = false;
5231    IOFramebuffer * fb;
5232    uint32_t 		idx;
5233
5234	if ((controller->lastMessagedChange != controller->connectChange)
5235		 && !controller->fbs[0]->messaged
5236		 && !controller->wsWait)
5237	{
5238		controller->lastMessagedChange = controller->connectChange;
5239		if (gIOGraphicsControl)
5240		{
5241			err = gIOGraphicsControl->message(kIOFBMessageConnectChange, controller->fbs[0], NULL);
5242			if (kIOReturnOffline == err)
5243			{
5244				DEBG1(controller->name, " AGC discard\n");
5245				discard = true;
5246			}
5247		}
5248		if (discard)
5249		{
5250			controller->lastFinishedChange  = controller->lastMessagedChange;
5251			for (idx = 0; (fb = controller->fbs[idx]); idx++)
5252				fb->__private->lastProcessedChange = controller->lastMessagedChange;
5253		}
5254		else
5255		{
5256			DEBG1(controller->name, " messaged\n");
5257			controller->fbs[0]->messaged = true;
5258			controller->fbs[0]->messageClients(kIOMessageServiceIsSuspended, (void *) true);
5259		}
5260    }
5261}
5262
5263
5264IOReturn IOFramebuffer::extEndConnectionChange(void)
5265{
5266    IOFBController * controller = __private->controller;
5267
5268	DEBG1(controller->name, " WS done msg %d, onl %x, count(%d, msg %d, fin %d, proc %d, wake %d)\n",
5269		  controller->fbs[0]->messaged, __private->controller->onlineMask,
5270          controller->connectChange,
5271          controller->lastMessagedChange, controller->lastFinishedChange,
5272          controller->fbs[0]->__private->lastProcessedChange,
5273          controller->postWakeChange);
5274
5275    if (!controller->fbs[0]->messaged)
5276        return (kIOReturnSuccess);
5277
5278	controller->fbs[0]->messaged = false;
5279	__private->controller->lastFinishedChange = __private->controller->lastMessagedChange;
5280
5281	if (gIOGraphicsControl)
5282	{
5283		IOReturn err;
5284		err = gIOGraphicsControl->message(kIOFBMessageEndConnectChange, controller->fbs[0], NULL);
5285	}
5286
5287	resetClamshell(kIOFBClamshellProbeDelayMS);
5288	startControllerThread(controller);
5289
5290	return (kIOReturnSuccess);
5291}
5292
5293IOReturn IOFramebuffer::processConnectChange(IOFBController * controller, IOOptionBits mode)
5294{
5295    IOFramebuffer * fb;
5296    uint32_t idx;
5297
5298    for (idx = 0; (fb = controller->fbs[idx]); idx++)
5299    {
5300        fb->processConnectChange(mode);
5301    }
5302    return (kIOReturnSuccess);
5303}
5304
5305IOReturn IOFramebuffer::extProcessConnectionChange(void)
5306{
5307    IOFBController * controller = __private->controller;
5308    IOReturn         err = kIOReturnSuccess;
5309	IOOptionBits     mode = 0;
5310
5311	TIMELOCK(gIOFBSystemWorkLoop, thisName, __FUNCTION__);
5312
5313	if ((err = extEntry(true)))
5314	{
5315		SYSUNLOCK();
5316		return (err);
5317	}
5318
5319    if (controller->fbs[0]->messaged)
5320	{
5321		if (controller->mute)
5322			mode = fgOff;
5323		else if (__private->lastProcessedChange != __private->controller->connectChange)
5324			mode = fg;
5325		else if (kIODisplayModeIDInvalid != __private->aliasMode)
5326		{
5327			IOFBController * oldController;
5328			IOFramebuffer  * oldfb;
5329			bool			 rematch = false;
5330
5331			oldController = aliasController(controller);
5332			FCLOCK(oldController);
5333			oldfb = oldController->fbs[__private->controllerIndex];
5334			if (oldfb)
5335			{
5336				DEBG1(thisName, " check copy from %s: 0x%x==0x%x?\n", oldfb->thisName,
5337						(int) __private->matchedMode, (int) oldfb->__private->setupMode);
5338				rematch = (__private->matchedMode != oldfb->__private->setupMode);
5339				if (rematch)
5340				{
5341					DEBG1(thisName, " rematch using %d x %d\n",
5342						(int) oldfb->__private->pixelInfo.activeWidth,
5343						(int) oldfb->__private->pixelInfo.activeHeight);
5344					__private->pixelInfo    = oldfb->__private->pixelInfo;
5345					__private->timingInfo   = oldfb->__private->timingInfo;
5346					__private->uiScale      = oldfb->__private->uiScale;
5347					__private->matchedMode  = oldfb->__private->setupMode;
5348				}
5349			}
5350			FCUNLOCK(oldController);
5351			if (rematch)
5352			{
5353				suspend(true);
5354				matchFramebuffer();
5355				suspend(false);
5356			}
5357		}
5358	}
5359	extExit(err);
5360
5361    if (mode)
5362    {
5363		temporaryPowerClampOn();
5364		IODisplayWrangler::destroyDisplayConnects(this);
5365
5366		err = extEntry(true);
5367		if (kIOReturnSuccess == err)
5368		{
5369			err = processConnectChange(mode);
5370			extExit(err);
5371		}
5372	}
5373
5374	SYSUNLOCK();
5375
5376    return (err);
5377}
5378
5379
5380IOReturn IOFramebuffer::processConnectChange(IOOptionBits mode)
5381{
5382    IOReturn  err;
5383    uintptr_t unused;
5384    bool      nowOnline;
5385
5386    DEBG1(thisName, " (%d==%s) curr %d\n",
5387    		(uint32_t) mode, processConnectChangeModeNames[mode], __private->lastProcessedChange);
5388
5389    if (fgOff == mode)
5390    {
5391		displaysOnline(false);
5392        __private->online = false;
5393        return (kIOReturnSuccess);
5394    }
5395    if (__private->lastProcessedChange == __private->controller->connectChange)
5396        return (kIOReturnSuccess);
5397
5398    if (fg == mode) suspend(true);
5399
5400	{
5401		// connect change vars here
5402		__private->enableScalerUnderscan = false;
5403		__private->audioStreaming        = false;
5404		__private->colorModesSupported   = 0;
5405	}
5406
5407    TIMESTART();
5408    err = getAttributeForConnection(0, kConnectionChanged, &unused);
5409    TIMEEND(thisName, "kConnectionChanged time: %qd ms\n");
5410
5411    __private->lastProcessedChange = __private->controller->connectChange;
5412    extSetMirrorOne(0, 0);
5413    if (fg == mode) suspend(true);
5414
5415    nowOnline = updateOnline();
5416    if (false && nowOnline)
5417    {
5418        DEBG1(thisName, " bgOff forced\n");
5419        nowOnline = false;
5420    }
5421
5422    displaysOnline(false);
5423    __private->online = nowOnline;
5424    __private->transform = __private->selectedTransform;
5425    setProperty(kIOFBTransformKey, __private->transform, 64);
5426    if (nowOnline)
5427        displaysOnline(true);
5428
5429    if (nowOnline)
5430    {
5431        if (__private->cursorAttributes && !__private->cursorAttributes->getCount())
5432        {
5433            __private->cursorAttributes->release();
5434            __private->cursorAttributes = 0;
5435        }
5436
5437        if (!__private->cursorAttributes)
5438        {
5439            if ((__private->cursorAttributes = OSArray::withCapacity(2)))
5440            {
5441                __private->testingCursor = true;
5442                setCursorImage( (void *) 0 );
5443                __private->testingCursor = false;
5444
5445                setProperty( kIOFBCursorInfoKey, __private->cursorAttributes );
5446            }
5447        }
5448    }
5449	else
5450	{
5451		if (kIODisplayModeIDInvalid != __private->offlineMode)
5452		{
5453			IOPixelInformation pixelInfo;
5454
5455			pixelInfo.bitsPerPixel     = 32;
5456			pixelInfo.pixelType        = kIORGBDirectPixels;
5457			pixelInfo.componentCount   = 3;
5458			pixelInfo.bitsPerComponent = 8;
5459			__private->currentDepth    = closestDepth(__private->offlineMode, &pixelInfo);
5460
5461			err = setDisplayMode(__private->offlineMode, __private->currentDepth);
5462			DEBG1(thisName, " offline setDisplayMode(0x%x, %d) err %x msg %d susp %d\n",
5463					(int32_t) __private->offlineMode, (int32_t) __private->currentDepth,
5464					err, messaged, suspended);
5465		}
5466		if (fg == mode) suspend(false);
5467	}
5468
5469    err = kIOReturnSuccess;
5470    return (err);
5471}
5472
5473bool IOFramebuffer::updateOnline(void)
5474{
5475    IOReturn                    err;
5476    uintptr_t					connectEnabled;
5477	bool						nowOnline;
5478    IOTimingInformation         info;
5479    IODisplayModeID *           modeIDs;
5480    IOItemCount                 modeCount, modeNum;
5481
5482    TIMESTART();
5483    err = getAttributeForConnection(0, kConnectionCheckEnable, &connectEnabled);
5484    TIMEEND(thisName, "kConnectionCheckEnable == %ld, time: %qd ms\n", connectEnabled);
5485
5486    nowOnline = (!dead && ((kIOReturnSuccess != err) || connectEnabled));
5487
5488    __private->gammaScale[0] = __private->gammaScale[1]
5489    	= __private->gammaScale[2] = __private->gammaScale[3] = (1 << 16);
5490	__private->aliasMode         = kIODisplayModeIDInvalid;
5491	__private->offlineMode       = kIODisplayModeIDInvalid;
5492
5493	if (!nowOnline) do
5494	{
5495		TIMESTART();
5496		modeCount = getDisplayModeCount();
5497		modeIDs = IONew(IODisplayModeID, modeCount);
5498		if (!modeIDs)
5499			break;
5500		err = getDisplayModes(modeIDs);
5501		if (kIOReturnSuccess == err)
5502		{
5503			for (modeNum = 0; modeNum < modeCount; modeNum++)
5504			{
5505				info.flags = 0;
5506				err = getTimingInfoForDisplayMode(modeIDs[modeNum], &info);
5507				if (kIOReturnSuccess != err)
5508					continue;
5509				if (kIOTimingIDApple_0x0_0hz_Offline != info.appleTimingID)
5510					continue;
5511				__private->offlineMode = modeIDs[modeNum];
5512				break;
5513			}
5514		}
5515		IODelete(modeIDs, IODisplayModeID, modeCount);
5516		TIMEEND(thisName, "offline mode %x time: %qd ms\n", (int32_t) __private->offlineMode);
5517	}
5518	while (false);
5519
5520    return (nowOnline);
5521}
5522
5523void IOFramebuffer::displaysOnline(bool nowOnline)
5524{
5525	if (nowOnline == __private->displaysOnline)
5526		return;
5527
5528	if (nowOnline)
5529    {
5530		TIMESTART();
5531        IODisplayWrangler::makeDisplayConnects(this);
5532		TIMEEND(thisName, "makeDisplayConnects time: %qd ms\n");
5533	}
5534	else
5535	{
5536		if (__private->displayPrefKey)
5537		{
5538			__private->displayPrefKey->release();
5539			__private->displayPrefKey = NULL;
5540		}
5541
5542		TIMESTART();
5543		if (__private->paramHandler)
5544			__private->paramHandler->setDisplay(0);
5545		TIMEEND(thisName, "setDisplay time: %qd ms\n");
5546
5547		TIMESTART();
5548		stopCursor();
5549//		temporaryPowerClampOn();
5550		//        FCUNLOCK(controller);
5551//		IODisplayWrangler::destroyDisplayConnects(this);
5552		//        FCLOCK(controller);
5553		TIMEEND(thisName, "destroyDisplayConnects time: %qd ms\n");
5554	}
5555	__private->displaysOnline = nowOnline;
5556
5557	__private->actualVBLCount = 0;
5558    StdFBShmem_t * shmem = GetShmem(this);
5559	if (shmem)
5560	{
5561		shmem->vblDrift         = 0;
5562		shmem->vblDeltaMeasured = 0;
5563	}
5564	if (nowOnline)
5565	{
5566		__private->controller->onlineMask |=  (1 << __private->controllerIndex);
5567		updateVBL(this, NULL);
5568	}
5569	else
5570	{
5571		__private->controller->onlineMask &= ~(1 << __private->controllerIndex);
5572	}
5573}
5574
5575IOReturn IOFramebuffer::matchFramebuffer(void)
5576{
5577	IOFBDisplayModeDescription  modeInfo;
5578	IOReturn		err;
5579	IODisplayModeID mode;
5580	IOIndex         depth = 0;
5581	OSData *		data;
5582	OSArray *		array;
5583
5584	modeInfo.timingInfo = __private->timingInfo;
5585	mode = kIODisplayModeIDInvalid;
5586	if (kIODetailedTimingValid & modeInfo.timingInfo.flags) do
5587	{
5588		modeInfo.timingInfo.detailedInfo.v2.detailedTimingModeID
5589				= (kIODisplayModeIDReservedBase | kIODisplayModeIDAliasBase);
5590		modeInfo.timingInfo.detailedInfo.v2.minPixelClock
5591				= modeInfo.timingInfo.detailedInfo.v2.pixelClock;
5592		modeInfo.timingInfo.detailedInfo.v2.maxPixelClock
5593				= modeInfo.timingInfo.detailedInfo.v2.pixelClock;
5594
5595		err = validateDetailedTiming(&modeInfo, sizeof(modeInfo));
5596		if (kIOReturnSuccess != err)
5597		{
5598			DEBG1(thisName, " validateDetailedTiming(%x)\n", err);
5599			break;
5600		}
5601		data = OSData::withBytes(&modeInfo.timingInfo.detailedInfo.v2,
5602										  sizeof(modeInfo.timingInfo.detailedInfo.v2));
5603		array = OSArray::withObjects((const OSObject**) &data, 1, 1);
5604		data->release();
5605		err = setDetailedTimings(array);
5606		array->release();
5607		if (kIOReturnSuccess != err)
5608		{
5609			DEBG1(thisName, " setDetailedTimings(%x)\n", err);
5610			break;
5611		}
5612		mode = kIODisplayModeIDReservedBase | kIODisplayModeIDAliasBase;
5613	}
5614	while (false);
5615	if (kIODisplayModeIDInvalid != mode)
5616	{
5617		setDisplayAttributes(__private->displayAttributes);
5618
5619		depth = closestDepth(mode, &__private->pixelInfo);
5620		TIMESTART();
5621		err = setDisplayMode(mode, depth);
5622		TIMEEND(thisName, "matching setDisplayMode(0x%x, %d) err %x time: %qd ms\n",
5623				(int32_t) mode, (int32_t) depth, err);
5624
5625		if (__private->rawGammaData)
5626		{
5627			TIMESTART();
5628			updateGammaTable(__private->rawGammaChannelCount,
5629									__private->rawGammaDataCount,
5630									__private->rawGammaDataWidth,
5631									__private->rawGammaData,
5632									true);
5633			TIMEEND(thisName, "match updateGammaTable time: %qd ms\n");
5634		}
5635	}
5636	__private->aliasMode    = mode;
5637	__private->currentDepth = depth;
5638    return (err);
5639}
5640
5641IOReturn IOFramebuffer::matchController(IOFBController * controller)
5642{
5643    IOFramebuffer * fb;
5644    uint32_t idx;
5645
5646    for (idx = 0; (fb = controller->fbs[idx]); idx++)
5647    {
5648	   	if (!fb->__private->online)
5649			continue;
5650		fb->matchFramebuffer();
5651	}
5652    return (kIOReturnSuccess);
5653}
5654
5655IOReturn IOFramebuffer::setPowerState( unsigned long powerStateOrdinal,
5656                                       IOService * whichDevice )
5657{
5658	IOReturn ret = kIOPMAckImplied;
5659
5660    DEBG1(thisName, " (%ld) mute %d, now %d\n",
5661    	 powerStateOrdinal, __private->controller->mute, (int)getPowerState());
5662
5663	if (gIOFBSystemPowerAckTo && !powerStateOrdinal)
5664		IOLog("graphics notify timeout (%d, %d)", serverState, serverNotified);
5665
5666    FBLOCK(this);
5667    if (!__private->closed)
5668	{
5669		pendingPowerState = powerStateOrdinal;
5670		pendingPowerChange = true;
5671
5672		startControllerThread(__private->controller);
5673		ret = kPowerStateTimeout * 1000 * 1000;
5674	}
5675    FBUNLOCK(this);
5676
5677    return (ret);
5678}
5679
5680IOReturn IOFramebuffer::powerStateWillChangeTo( IOPMPowerFlags flags,
5681        unsigned long state, IOService * whatDevice )
5682{
5683    DEBG1(thisName, " (%08lx)\n", flags);
5684
5685	FBLOCK(this);
5686    if (isUsable && !(IOPMDeviceUsable & flags))
5687    {
5688		isUsable = false;
5689		controllerDidWork(__private->controller, kWorkStateChange);
5690	}
5691	FBUNLOCK(this);
5692
5693    return (kIOReturnSuccess);
5694}
5695
5696IOReturn IOFramebuffer::powerStateDidChangeTo( IOPMPowerFlags flags,
5697        unsigned long, IOService* whatDevice )
5698{
5699    DEBG1(thisName, " (%08lx)\n", flags);
5700
5701	FBLOCK(this);
5702    if ((IOPMDeviceUsable & flags) && !isUsable)
5703    {
5704		isUsable = true;
5705		controllerDidWork(__private->controller, kWorkStateChange);
5706	}
5707	FBUNLOCK(this);
5708
5709    return (kIOReturnSuccess);
5710}
5711
5712void IOFramebuffer::updateDisplaysPowerState(void)
5713{
5714	OSBitOrAtomic(kIOFBEventDisplaysPowerState, &gIOFBGlobalEvents);
5715	startThread(false);
5716}
5717
5718void IOFramebuffer::delayedEvent(thread_call_param_t p0, thread_call_param_t p1)
5719{
5720	OSBitOrAtomic((uintptr_t) p1, &gIOFBGlobalEvents);
5721	startThread(false);
5722}
5723
5724void IOFramebuffer::resetClamshell(uint32_t delay)
5725{
5726	AbsoluteTime deadline;
5727	clock_interval_to_deadline(delay, kMillisecondScale, &deadline );
5728	thread_call_enter1_delayed(gIOFBClamshellCallout,
5729								(thread_call_param_t) kIOFBEventResetClamshell, deadline );
5730}
5731
5732void IOFramebuffer::displayOnline(IODisplay * display, SInt32 delta, uint32_t options)
5733{
5734	if (delta <= 0)
5735	{
5736		options = __private->displayOptions;
5737	}
5738	if (kIODisplayOptionBacklight & options)
5739		OSAddAtomic(delta, &gIOFBBacklightDisplayCount);
5740	else
5741		OSAddAtomic(delta, &gIOFBDisplayCount);
5742
5743	if (delta < 0)
5744	{
5745//		if (display != __private->display) panic("(display != __private->display)");
5746		__private->display        = NULL;
5747		__private->displayOptions = 0;
5748		if (kIODisplayOptionBacklight & options)
5749		{
5750			OSBitAndAtomic(~kIOFBEventEnableClamshell, &gIOFBGlobalEvents);
5751			gIOFBClamshellState = kIOPMDisableClamshell;
5752			getPMRootDomain()->receivePowerNotification(kIOPMDisableClamshell);
5753			DEBG1("S", " clamshell disable\n");
5754		}
5755	}
5756	else
5757	{
5758//		if (__private->display) panic("(__private->display)");
5759		__private->display        = display;
5760		__private->displayOptions = options;
5761	}
5762}
5763
5764IOOptionBits IOFramebuffer::clamshellState( void )
5765{
5766    return (gIOFBClamshellState);
5767}
5768
5769IOReturn IOFramebuffer::agcMessage( void * target, void * refCon,
5770        UInt32 messageType, IOService * service,
5771        void * messageArgument, vm_size_t argSize )
5772{
5773    IOReturn ret = kIOReturnSuccess;
5774	enum
5775	{
5776		gMux_Message      = 'gMUX',
5777		gMux_WillSwitch   = 0,
5778		gMux_DidSwitch    = 1,
5779		gMux_DidNotSwitch = 2,
5780	};
5781
5782	IOService * ackTo  = NULL;
5783	uint32_t    ackRef = NULL;
5784	uintptr_t   param  = (uintptr_t) messageArgument;
5785
5786    if (gMux_Message != messageType)
5787		return (ret);
5788
5789	DEBG1("AGC", " %p\n", messageArgument);
5790
5791	SYSLOCK();
5792	if (gMux_WillSwitch == param)
5793	{
5794		gIOFBSwitching = true;
5795	}
5796	else if (gIOFBSwitching && ((gMux_DidSwitch == param) || (gMux_DidNotSwitch == param)))
5797	{
5798		gIOFBSwitching = false;
5799
5800		ackTo  = gIOFBSystemPowerMuxAckTo;
5801		ackRef = gIOFBSystemPowerMuxAckRef;
5802		gIOFBSystemPowerMuxAckTo = 0;
5803
5804		startThread(false);
5805	}
5806
5807	SYSUNLOCK();
5808
5809	if (ackTo)
5810	{
5811		DEBG("S", " mux allowPowerChange()\n");
5812		ackTo->allowPowerChange(ackRef);
5813	}
5814
5815    return (ret);
5816}
5817
5818
5819IOReturn IOFramebuffer::muxPowerMessage(UInt32 messageType)
5820{
5821    IOReturn ret = kIOReturnSuccess;
5822
5823    DEBG1("PWR", " muxPowerMessage(%x->%x)\n", (int) gIOFBLastMuxMessage, (int) messageType);
5824
5825	if (messageType == gIOFBLastMuxMessage)
5826		return (kIOReturnSuccess);
5827
5828	if (kIOMessageSystemWillPowerOn == messageType)
5829	{
5830		OSBitOrAtomic(kIOFBEventSystemPowerOn, &gIOFBGlobalEvents);
5831		return (kIOReturnSuccess);
5832	}
5833	if (kIOMessageDeviceWillPowerOn == messageType) messageType = kIOMessageSystemWillPowerOn;
5834
5835	if ((kIOMessageSystemHasPoweredOn == messageType)
5836		&& (kIOMessageSystemWillPowerOn != gIOFBLastMuxMessage))
5837	{
5838		DEBG1("PWR", " muxPowerMessage(%x)\n", (int) kIOMessageSystemWillPowerOn);
5839		if (gIOGraphicsControl) (void) gIOGraphicsControl->message(kIOMessageSystemWillPowerOn, NULL, NULL);
5840	}
5841
5842	gIOFBLastMuxMessage = messageType;
5843	DEBG1("PWR", " muxPowerMessage(%x)\n", (int) messageType);
5844	if (gIOGraphicsControl) ret = gIOGraphicsControl->message(messageType, NULL, NULL);
5845
5846	return (ret);
5847}
5848
5849IOReturn IOFramebuffer::systemPowerChange( void * target, void * refCon,
5850        UInt32 messageType, IOService * service,
5851        void * messageArgument, vm_size_t argSize )
5852{
5853    IOReturn ret = kIOReturnSuccess;
5854
5855    DEBG1("PWR", "(%08x)\n", (uint32_t) messageType);
5856
5857	if (gIOGraphicsControl) switch (messageType)
5858	{
5859#if VERSION_MAJOR >= 11
5860        case kIOMessageSystemCapabilityChange:
5861#endif
5862        case kIOMessageSystemWillSleep:
5863        case kIOMessageSystemWillPowerOn:
5864        case kIOMessageSystemHasPoweredOn:
5865			break;
5866
5867		default:
5868			ret = gIOGraphicsControl->message(messageType, service, messageArgument);
5869			break;
5870	}
5871
5872    switch (messageType)
5873    {
5874        case kIOMessageSystemCapabilityChange:
5875		{
5876			IOPMSystemCapabilityChangeParameters * params = (typeof params) messageArgument;
5877
5878			// root domain won't overlap capability changes with pstate changes
5879
5880			DEBG1("DARK", " %s%s 0x%x->0x%x\n",
5881			params->changeFlags & kIOPMSystemCapabilityWillChange ? "will" : "",
5882			params->changeFlags & kIOPMSystemCapabilityDidChange ? "did" : "",
5883			params->fromCapabilities,
5884			params->toCapabilities);
5885
5886			if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
5887				(params->fromCapabilities & kIOPMSystemCapabilityGraphics) &&
5888				((params->toCapabilities & kIOPMSystemCapabilityGraphics) == 0))
5889			{
5890				ret = muxPowerMessage(kIOMessageSystemWillSleep);
5891				if (kIOReturnNotReady == ret)
5892				{
5893					SYSLOCK();
5894					gIOFBSwitching = true;
5895					gIOFBSystemPowerMuxAckRef = params->notifyRef;
5896					gIOFBSystemPowerMuxAckTo  = service;
5897					SYSUNLOCK();
5898					params->maxWaitForReply = gIOGNotifyTO * 1000 * 1000;
5899				}
5900			}
5901			else if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
5902				((params->fromCapabilities & kIOPMSystemCapabilityGraphics) == 0) &&
5903				(params->toCapabilities & kIOPMSystemCapabilityGraphics))
5904			{
5905		        if (kIOMessageSystemHasPoweredOn != gIOFBLastMuxMessage)
5906				    muxPowerMessage(kIOMessageSystemWillPowerOn);
5907			}
5908			else if ((params->changeFlags & kIOPMSystemCapabilityDidChange) &&
5909				((params->fromCapabilities & kIOPMSystemCapabilityGraphics) == 0) &&
5910				(params->toCapabilities & kIOPMSystemCapabilityGraphics))
5911			{
5912				muxPowerMessage(kIOMessageSystemHasPoweredOn);
5913			}
5914
5915			else if ((params->changeFlags & kIOPMSystemCapabilityDidChange) &&
5916				((params->fromCapabilities & kIOPMSystemCapabilityCPU) == 0) &&
5917				(params->toCapabilities & kIOPMSystemCapabilityCPU))
5918			{
5919				muxPowerMessage(kIOMessageSystemHasPoweredOn);
5920			}
5921			else if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
5922				((params->fromCapabilities & kIOPMSystemCapabilityCPU) == 0) &&
5923				(params->toCapabilities & kIOPMSystemCapabilityCPU))
5924			{
5925				muxPowerMessage(kIOMessageSystemWillPowerOn);
5926				SYSLOCK();
5927				gIOFBSystemPower       = true;
5928				gIOGraphicsSystemPower = true;
5929				gIOFBSystemDark        = true;
5930				SYSUNLOCK();
5931			}
5932			else if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
5933				(params->fromCapabilities & kIOPMSystemCapabilityCPU) &&
5934				((params->toCapabilities & kIOPMSystemCapabilityCPU) == 0))
5935			{
5936				if (gIOFBSystemPower)
5937				{
5938					ret = muxPowerMessage(kIOMessageSystemWillSleep);
5939
5940					SYSLOCK();
5941
5942//					gIOFBClamshellState = kIOPMDisableClamshell;
5943//					getPMRootDomain()->receivePowerNotification(kIOPMDisableClamshell);
5944
5945					gIOFBSystemPower       = false;
5946					gIOFBSystemPowerAckRef = (void *)(uintptr_t) params->notifyRef;
5947					gIOFBSystemPowerAckTo  = service;
5948					startThread(false);
5949					gIOGraphicsSystemPower = false;
5950
5951					SYSUNLOCK();
5952
5953					// We will ack within gIOGNotifyTO seconds
5954					params->maxWaitForReply = gIOGNotifyTO * 1000 * 1000;
5955					ret                    = kIOReturnSuccess;
5956				}
5957			}
5958			ret = kIOReturnSuccess;
5959			break;
5960		}
5961
5962        case kIOMessageSystemWillSleep:
5963		{
5964			IOPowerStateChangeNotification * params = (typeof params) messageArgument;
5965
5966			ret = muxPowerMessage(kIOMessageSystemWillSleep);
5967
5968			SYSLOCK();
5969 			gIOFBClamshellState = kIOPMDisableClamshell;
5970			getPMRootDomain()->receivePowerNotification(kIOPMDisableClamshell);
5971
5972			gIOFBSystemPower       = false;
5973			gIOFBSystemPowerAckRef = params->powerRef;
5974			gIOFBSystemPowerAckTo  = service;
5975			gIOFBSwitching = (kIOReturnNotReady == ret);
5976			if (gIOFBSwitching)
5977			{
5978				DEBG1("PWR", " agc not ready\n");
5979			}
5980			startThread(false);
5981			gIOGraphicsSystemPower = false;
5982			SYSUNLOCK();
5983
5984			// We will ack within gIOGNotifyTO seconds
5985			params->returnValue    = gIOGNotifyTO * 1000 * 1000;
5986            ret                    = kIOReturnSuccess;
5987            break;
5988		}
5989
5990        case kIOMessageSystemWillPowerOn:
5991		{
5992			IOPowerStateChangeNotification * params = (typeof params) messageArgument;
5993
5994			gIOFBSystemDark        = false;
5995
5996			if (!gIOFBSystemPower)
5997			{
5998				muxPowerMessage(kIOMessageSystemWillPowerOn);
5999
6000				SYSLOCK();
6001
6002				readClamshellState();
6003				OSBitAndAtomic(~(kIOFBEventResetClamshell | kIOFBEventEnableClamshell),
6004								&gIOFBGlobalEvents);
6005				gIOFBSystemPower       = true;
6006				gIOGraphicsSystemPower = true;
6007
6008				SYSUNLOCK();
6009			}
6010            params->returnValue    = 0;
6011            ret                    = kIOReturnSuccess;
6012            break;
6013		}
6014
6015        case kIOMessageSystemHasPoweredOn:
6016		{
6017			IOPowerStateChangeNotification * params = (typeof params) messageArgument;
6018
6019			muxPowerMessage(kIOMessageSystemHasPoweredOn);
6020
6021			SYSLOCK();
6022			startThread(false);
6023			SYSUNLOCK();
6024
6025            params->returnValue = 0;
6026            ret                 = kIOReturnSuccess;
6027            break;
6028		}
6029
6030        case kIOMessageSystemWillRestart:
6031        case kIOMessageSystemWillPowerOff:
6032        case kIOMessageSystemPagingOff:
6033		{
6034			IOPowerStateChangeNotification * params = (typeof params) messageArgument;
6035
6036            SYSLOCK();
6037            if (gAllFramebuffers)
6038            {
6039                IOFramebuffer * fb;
6040                for (UInt32 index = 0;
6041                        (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
6042                        index++)
6043                {
6044                    FBLOCK(fb);
6045                    fb->deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange );
6046					if (kIOMessageSystemPagingOff != messageType)
6047					{
6048						fb->setAttribute( kIOSystemPowerAttribute, messageType );
6049						fb->__private->closed = true;
6050					}
6051                    FBUNLOCK(fb);
6052                }
6053				if (kIOMessageSystemPagingOff == messageType) saveGammaTables();
6054            }
6055            SYSUNLOCK();
6056
6057            params->returnValue = 0;
6058            ret                 = kIOReturnSuccess;
6059            break;
6060		}
6061
6062        default:
6063            ret = kIOReturnUnsupported;
6064            break;
6065    }
6066
6067    return (ret);
6068}
6069
6070void IOFramebuffer::deferredSpeedChangeEvent( OSObject * owner,
6071                                              IOInterruptEventSource * evtSrc, int intCount )
6072{
6073    IOFramebuffer * self = (IOFramebuffer *) owner;
6074
6075    if (self->__private->pendingSpeedChange)
6076    {
6077        self->__private->pendingSpeedChange = false;
6078    	self->__private->controller->powerThread = current_thread();
6079        self->setAttribute(kIOFBSpeedAttribute, self->__private->reducedSpeed);
6080    	self->__private->controller->powerThread = NULL;
6081
6082    }
6083}
6084
6085IOReturn IOFramebuffer::setAggressiveness( unsigned long type, unsigned long newLevel )
6086{
6087    UInt32 reducedSpeed = newLevel;
6088
6089    if (__private
6090     && (type == (unsigned long) kIOFBLowPowerAggressiveness)
6091//     && (reducedSpeed != __private->reducedSpeed)
6092	)
6093    {
6094        __private->reducedSpeed       = reducedSpeed;
6095        __private->pendingSpeedChange = true;
6096        if (__private->allowSpeedChanges && __private->deferredSpeedChangeEvent)
6097		{
6098			FBLOCK(this);
6099			startControllerThread(__private->controller);
6100			FBUNLOCK(this);
6101//            __private->deferredSpeedChangeEvent->interruptOccurred(0, 0, 0);
6102		}
6103    }
6104
6105    super::setAggressiveness(type, newLevel);
6106
6107    return (kIOReturnSuccess);
6108}
6109
6110IOReturn
6111IOFramebuffer::getAggressiveness( unsigned long type, unsigned long * currentLevel )
6112{
6113    IOReturn ret;
6114
6115    if (gIOFBSystemWorkLoop && (type == (unsigned long) kIOFBLowPowerAggressiveness))
6116    {
6117        SYSLOCK();
6118        *currentLevel = __private->reducedSpeed;
6119        SYSUNLOCK();
6120        ret = kIOReturnSuccess;
6121    }
6122    else
6123        ret = super::getAggressiveness(type, currentLevel);
6124
6125    return (ret);
6126}
6127
6128void
6129IOFramebuffer::serverAcknowledgeNotification(void)
6130{
6131    bool  nowOn;
6132
6133    nowOn = (serverNotified && (serverState != serverNotified));
6134    serverState = serverNotified;
6135
6136    if (serverState && __private->cursorSlept)
6137    {
6138        resetCursor();
6139        __private->cursorSlept = false;
6140    }
6141    else if (!serverState && !__private->cursorSlept)
6142    {
6143        hideCursor();
6144        __private->cursorSlept = true;
6145    }
6146
6147    controllerDidWork(__private->controller, kWorkStateChange);
6148}
6149
6150IOReturn
6151IOFramebuffer::extAcknowledgeNotification(
6152            OSObject * target, void * reference, IOExternalMethodArguments * args)
6153{
6154    IOFramebuffer * inst = (IOFramebuffer *) target;
6155    IOReturn err;
6156	uint32_t idx;
6157	uint32_t countIn;
6158
6159    if ((err = inst->extEntry(true)))
6160        return (err);
6161
6162	countIn = args->scalarInputCount / 2;
6163	for (idx = 0; (idx < kIOPreviewImageCount); idx++)
6164	{
6165		mach_vm_address_t address;
6166		mach_vm_size_t    length;
6167		if (inst->__private->saveBitsMD[idx])
6168		{
6169			inst->__private->saveBitsMD[idx]->release();
6170			inst->__private->saveBitsMD[idx] = 0;
6171		}
6172		if ((idx < countIn)
6173			&& (address = args->scalarInput[idx])
6174			&& (length  = args->scalarInput[countIn + idx]))
6175		{
6176			inst->__private->saveBitsMD[idx] = IOMemoryDescriptor::withAddressRange(
6177												address, length,
6178												kIODirectionOut | kIOMemoryPersistent, current_task());
6179			DEBG1(inst->thisName, " (%d->%d) save bits [0x%llx, 0x%llx] md %p\n",
6180				 inst->serverState, inst->serverNotified,
6181				 address, length,
6182				 inst->__private->saveBitsMD[idx]);
6183		}
6184	}
6185
6186	inst->serverAcknowledgeNotification();
6187
6188    inst->extExit(err);
6189
6190    return (err);
6191}
6192
6193IOReturn IOFramebuffer::extRegisterNotificationPort(
6194    mach_port_t         port,
6195    UInt32              type,
6196    UInt32              refCon )
6197{
6198    mach_msg_header_t * msgh;
6199    UInt8               currentState;
6200
6201    FBLOCK(this);
6202
6203    msgh = (mach_msg_header_t *) serverMsg;
6204    bzero( msgh, sizeof(mach_msg_header_t) );
6205
6206    msgh->msgh_bits        = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
6207    msgh->msgh_size        = sizeof(mach_msg_header_t);
6208    msgh->msgh_remote_port = port;
6209
6210    msgh->msgh_id = 0x87654321;
6211    mach_msg_send_from_kernel( msgh, msgh->msgh_size );
6212
6213    currentState     = serverNotified;
6214    serverNotified   = true;                    // server assumes so at startup
6215    notifyServer( currentState );
6216
6217    FBUNLOCK(this);
6218
6219    return (kIOReturnSuccess);
6220}
6221
6222/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6223
6224#if IOFB_DISABLEFB
6225IODeviceMemory * IOFramebuffer::_getApertureRange(IOFramebuffer * fb, IOPixelAperture aperture)
6226{
6227	typedef IODeviceMemory * (*Proc)(IOFramebuffer * fb, IOPixelAperture aperture);
6228	Proc proc = (Proc) fb->__private->controller->saveGAR;
6229    IODeviceMemory * mem;
6230
6231	mem = (*proc)(fb, aperture);
6232//	kprintf("%s: zorch GAR(%d) %p\n", fb->thisName, aperture, mem);
6233	if (kIOFBSystemAperture == aperture) mem = 0;
6234
6235	return (mem);
6236}
6237#endif
6238
6239/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6240
6241void IOFramebuffer::writePrefs( OSObject * null, IOTimerEventSource * sender )
6242{
6243    IOFramebuffer * fb = (IOFramebuffer *) gAllFramebuffers->getObject(0);
6244	if (fb)
6245	{
6246		DEBG(fb->thisName, "\n");
6247		fb->messageClients( kIOMessageServicePropertyChange, (void *) 'pref' );
6248	}
6249}
6250
6251void IOFramebuffer::connectChangeInterrupt( IOFramebuffer * inst, void * delay )
6252{
6253    OSIncrementAtomic( &inst->__private->controller->connectChange);
6254
6255    DEBG1(inst->thisName, "(%d)\n", inst->__private->controller->connectChange);
6256
6257	startThread(false);
6258}
6259
6260IOReturn IOFramebuffer::open( void )
6261{
6262    IOReturn            err = kIOReturnSuccess;
6263    uintptr_t           value;
6264    IOFramebuffer *     next;
6265    OSNumber *          depIDProp;
6266    OSNumber *          depIDMatch;
6267    OSNumber *          num;
6268    OSData *            data;
6269    OSObject *          obj;
6270    bool                newController;
6271    bool                openAllDependents;
6272
6273    do
6274    {
6275		if (!gIOFBSystemWorkLoop) panic("gIOFBSystemWorkLoop");
6276		SYSLOCK();
6277
6278        if (opened) continue;
6279        if (dead)
6280        {
6281            err = kIOReturnNotOpen;
6282            continue;
6283        }
6284
6285        if (!gIOFBServerInit) IOFramebuffer::initialize();
6286        if (!gAllFramebuffers)  continue;
6287        if (!gIOFBRootNotifier) continue;
6288        if (!gIOFBHIDWorkLoop)  continue;
6289        if (!gIOFBWorkES)       continue;
6290
6291        if (!IODisplayWrangler::serverStart()) continue;
6292
6293        if (!gIOFBClamshellNotify)
6294            gIOFBClamshellNotify = addMatchingNotification( gIOPublishNotification,
6295                                                       resourceMatching(kAppleClamshellStateKey),
6296                                                       &clamshellHandler, NULL, 0, 10000 );
6297		readClamshellState();
6298
6299        if (-1 == gIOFBHaveBacklight) do
6300        {
6301            OSDictionary * matching      = nameMatching("backlight");
6302            OSIterator *   iter          = NULL;
6303            bool           haveBacklight = false;
6304            if (matching)
6305            {
6306                iter = getMatchingServices(matching);
6307                matching->release();
6308            }
6309            if (iter)
6310            {
6311                haveBacklight = (0 != iter->getNextObject());
6312                iter->release();
6313            }
6314            gIOFBHaveBacklight = haveBacklight;
6315
6316            if (!haveBacklight)
6317                continue;
6318
6319            const OSSymbol * settingsArray[2];
6320            getPMRootDomain()->publishFeature("DisplayDims");
6321            // Register to manage the "DisplaySleepUsesDim" setting
6322            settingsArray[0] = gIOFBPMSettingDisplaySleepUsesDimKey;
6323            settingsArray[1] = NULL;
6324            OSObject * pmSettingNotificationHandle;
6325            getPMRootDomain()->registerPMSettingController(settingsArray,
6326                                                            &pmSettingsChange,
6327                                                            NULL,
6328                                                            (uintptr_t) NULL,
6329                                                            &pmSettingNotificationHandle);
6330        }
6331        while (false);
6332
6333        serverNotified   = true;
6334        serverState      = true;
6335
6336        newController = (!__private->controller);
6337        if (newController)
6338        {
6339            __private->controller = IONew(IOFBController, 1);
6340            if (!__private->controller)
6341                panic("IOFBController");
6342            bzero(__private->controller, sizeof(IOFBController));
6343            IOService * service = this;
6344            while ((service = service->getProvider()) && !OSDynamicCast(IOPCIDevice, service))
6345            	{}
6346            if (service)
6347            {
6348            	__private->controller->device = service;
6349                __private->controller->name = service->getName();
6350				if ((data = OSDynamicCast(OSData, service->getProperty("vendor-id"))))
6351					__private->controller->vendorID = ((uint32_t *) data->getBytesNoCopy())[0];
6352				__private->controller->integrated =  (0 == ((IOPCIDevice *)service)->getBusNumber());
6353			}
6354            else
6355                __private->controller->name = "FB??";
6356#if SINGLE_THREAD
6357            __private->controller->wl = gIOFBSystemWorkLoop;
6358#else
6359            __private->controller->wl = IOGraphicsWorkLoop::workLoop(0,
6360												NULL, NULL, __private->controller);
6361#endif
6362            if (!__private->controller->wl)
6363                panic("controller->wl");
6364            __private->controller->workES = IOInterruptEventSource::interruptEventSource(
6365												this, &controllerAsyncWork);
6366            if (!__private->controller->workES)
6367                panic("controller->workES");
6368			__private->controller->wl->addEventSource(__private->controller->workES);
6369			__private->controller->didWork = true;
6370		}
6371		if (__private->controller->integrated) setProperty(kIOFBIntegratedKey, kOSBooleanTrue);
6372
6373		FBLOCK(this);
6374
6375		uint32_t depIdx;
6376        depIDProp = OSDynamicCast(OSNumber, getProperty(kIOFBDependentIDKey));
6377        openAllDependents = depIDProp && !nextDependent;
6378        num = OSDynamicCast(OSNumber, getProperty(kIOFBDependentIndexKey));
6379		depIdx = num ? num->unsigned32BitValue() : 0;
6380		if (depIdx >= kIOFBControllerMaxFBs)
6381			panic("%s: bad " kIOFBDependentIndexKey "\n", getName());
6382		else
6383		{
6384			__private->controller->fbs[depIdx] = this;
6385			if (depIdx >= __private->controller->maxFB)
6386				__private->controller->maxFB = depIdx;
6387			__private->controllerIndex = depIdx;
6388		}
6389
6390		__private->controller->wsWait  |= (1 << __private->controllerIndex);
6391		isUsable = true;
6392
6393		size_t len = strlen(__private->controller->name) + 3;
6394		char * logName = IONew(char, len);
6395		if (logName)
6396			snprintf(logName, len, "%s-%c", __private->controller->name, 'A' + depIdx);
6397		thisName = logName;
6398
6399        if (openAllDependents)
6400        {
6401            do
6402            {
6403				IOFramebuffer * first = 0;
6404				IOFramebuffer * last = 0;
6405				for (thisIndex = 0; (next = (IOFramebuffer *) gStartedFramebuffers->getObject(thisIndex)); thisIndex++)
6406				{
6407					depIDMatch = OSDynamicCast(OSNumber, next->getProperty(kIOFBDependentIDKey));
6408					if (!depIDMatch || !depIDMatch->isEqualTo(depIDProp)) continue;
6409					next->__private->controller = __private->controller;
6410					if (!first)
6411						first = next;
6412					else if (last)
6413						last->setNextDependent( next );
6414					last = next;
6415				}
6416				if (first && last && (first != last))
6417					last->setNextDependent( first );
6418            }
6419            while (false);
6420        }
6421
6422        // tell the console if it's on this display, it's going away
6423        if (isConsoleDevice() /*&& !gIOFBConsoleFramebuffer*/)
6424            gIOFBConsoleFramebuffer = this;
6425        if ((this == gIOFBConsoleFramebuffer) || !gIOFBConsoleFramebuffer)
6426            getPlatform()->setConsoleInfo( 0, kPEDisableScreen);
6427
6428        deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange );
6429
6430        IOService * provider = getProvider();
6431        provider->setProperty("AAPL,gray-value", gIOFBGray32Data);
6432        provider->setProperty("AAPL,gray-page", gIOFBOne32Data);
6433        data = OSData::withBytesNoCopy(&__private->uiScale, sizeof(__private->uiScale));
6434		if (data)
6435		{
6436			setProperty(kIOFBUIScaleKey, data);
6437			data->release();
6438		}
6439
6440		if (!AbsoluteTime_to_scalar(&__private->controller->initTime))
6441			AbsoluteTime_to_scalar(&__private->controller->initTime) = mach_absolute_time();
6442
6443        err = enableController();
6444
6445        if (kIOReturnSuccess != err)
6446        {
6447            dead = true;
6448            if (nextDependent)
6449            {
6450                nextDependent->setNextDependent( NULL );
6451                nextDependent = NULL;
6452            }
6453            deliverDisplayModeDidChangeNotification();
6454			FBUNLOCK(this);
6455            continue;
6456        }
6457
6458#if IOFB_DISABLEFB
6459        if (newController)
6460		{
6461			// getApertureRange 2472
6462			// getVRAMRange 2480
6463			uintptr_t * vt;
6464			addr64_t    v;
6465			ppnum_t     phys;
6466			vt = ((uintptr_t **)this)[0];
6467			__private->controller->saveGAR = vt[2472/sizeof(uintptr_t)];
6468			v = (addr64_t) &vt[2472/sizeof(uintptr_t)];
6469			phys = pmap_find_phys(kernel_pmap, v);
6470			ml_phys_write_double_64(ptoa_64(phys) | (v & page_mask), (uint64_t) &IOFramebuffer::_getApertureRange);
6471		}
6472#endif
6473
6474        if (newController)
6475        {
6476            if (gIOFBLastController)
6477                gIOFBLastController->nextController = __private->controller;
6478			else
6479                gIOFBAllControllers = __private->controller;
6480			__private->controller->nextController = gIOFBAllControllers;
6481			gIOFBLastController = __private->controller;
6482
6483			if ((obj = copyProperty("AAPL,display-alias", gIOServicePlane)))
6484			{
6485				if ((data = OSDynamicCast(OSData, obj)))
6486					__private->controller->aliasID = (0x80000000 | ((uint32_t *) data->getBytesNoCopy())[0]);
6487				obj->release();
6488			}
6489        }
6490
6491        thisIndex = gStartedFramebuffers->getNextIndexOfObject(this, 0);
6492		if (-1U == thisIndex)
6493		{
6494			thisIndex = gStartedFramebuffers->getCount();
6495			gStartedFramebuffers->setObject(this);
6496		}
6497        setProperty(kIOFramebufferOpenGLIndexKey, thisIndex, 64);
6498		gAllFramebuffers->setObject(this);
6499
6500        DEBG(thisName, " this %p \"%s\" \"%s\"\n", this, getName(), getProvider()->getName());
6501        DEBG1(thisName, " singleth %d, this %p controller %p\n",
6502              SINGLE_THREAD, this, __private->controller);
6503        DEBG1(thisName, " init time now %lld start %lld\n",
6504              mach_absolute_time(), AbsoluteTime_to_scalar(&__private->controller->initTime));
6505
6506        pagingState = true;
6507
6508		obj = copyProperty("graphic-options", gIOServicePlane);
6509		if (obj)
6510		{
6511			data = OSDynamicCast(OSData, obj);
6512			uint32_t gOpts = ((UInt32 *) data->getBytesNoCopy())[0];
6513			__private->colorModesAllowed = (data && (0 != (kIOGPlatformYCbCr & gOpts)));
6514			obj->release();
6515		}
6516
6517        if ((num = OSDynamicCast(OSNumber, getProperty(kIOFBTransformKey))))
6518            __private->selectedTransform = num->unsigned64BitValue();
6519        __private->selectedTransform |= kIOFBDefaultScalerUnderscan;
6520
6521        // vbl events
6522        err = registerForInterruptType( kIOFBVBLInterruptType,
6523                                        (IOFBInterruptProc) &handleVBL,
6524                                        this, priv, &__private->vblInterrupt );
6525        haveVBLService = (err == kIOReturnSuccess );
6526        __private->vblEnabled = haveVBLService;
6527        if (haveVBLService)
6528        {
6529            __private->deferredVBLDisableEvent = IOInterruptEventSource::interruptEventSource(
6530															this, &deferredVBLDisable);
6531			if (__private->deferredVBLDisableEvent)
6532				__private->controller->wl->addEventSource(__private->deferredVBLDisableEvent);
6533			__private->vblUpdateTimer = IOTimerEventSource::timerEventSource(this, &updateVBL);
6534			if (__private->vblUpdateTimer)
6535				__private->controller->wl->addEventSource(__private->vblUpdateTimer);
6536		}
6537
6538        if (haveVBLService
6539         && (kIOReturnSuccess == getAttribute( kIODeferCLUTSetAttribute, &value ))
6540         && value)
6541        {
6542            __private->deferredCLUTSetEvent = IOInterruptEventSource::interruptEventSource(
6543															this, &deferredCLUTSetInterrupt);
6544            if (__private->deferredCLUTSetEvent)
6545                __private->controller->wl->addEventSource(__private->deferredCLUTSetEvent);
6546
6547            __private->deferredCLUTSetTimerEvent = IOTimerEventSource::timerEventSource(
6548            												this, &deferredCLUTSetTimer);
6549            if (__private->deferredCLUTSetTimerEvent)
6550                __private->controller->wl->addEventSource(__private->deferredCLUTSetTimerEvent);
6551
6552            if (__private->deferredCLUTSetEvent || __private->deferredCLUTSetTimerEvent)
6553                setProperty(kIOFBCLUTDeferKey, kOSBooleanTrue);
6554        }
6555
6556        // connect events
6557		obj = copyProperty(kIOFBConnectInterruptDelayKey, gIOServicePlane);
6558        if (obj)
6559        {
6560            OSData * data;
6561            if ((data = OSDynamicCast(OSData, obj)))
6562                __private->delayedConnectTime = *((UInt32 *) data->getBytesNoCopy());
6563            obj->release();
6564        }
6565
6566        err = registerForInterruptType( kIOFBConnectInterruptType,
6567                                        (IOFBInterruptProc) &connectChangeInterrupt,
6568                                        this, (void *)(uintptr_t) __private->delayedConnectTime,
6569                                        &__private->connectInterrupt );
6570        // dp events
6571        __private->dpInterrupDelayTime = 2;
6572        __private->dpInterruptES = IOTimerEventSource::timerEventSource(this, &dpInterrupt);
6573        if (__private->dpInterruptES)
6574            __private->controller->wl->addEventSource(__private->dpInterruptES);
6575
6576        err = registerForInterruptType( kIOFBDisplayPortInterruptType,
6577                                       (IOFBInterruptProc) &dpInterruptProc,
6578                                       this, (void *)(uintptr_t) __private->dpInterrupDelayTime,
6579                                       &__private->dpInterruptRef );
6580        __private->dpInterrupts = (kIOReturnSuccess == err);
6581        __private->dpSupported  = __private->dpInterrupts;
6582        //
6583
6584        err = getAttribute( kIOHardwareCursorAttribute, &value );
6585        haveHWCursor = ((err == kIOReturnSuccess) && (0 != (kIOFBHWCursorSupported & value)));
6586
6587        clock_interval_to_deadline(40, kMicrosecondScale,
6588                                    &__private->defaultI2CTiming.bitTimeout);
6589        clock_interval_to_deadline(40, kMicrosecondScale,
6590                                    &__private->defaultI2CTiming.byteTimeout);
6591        clock_interval_to_deadline(40, kMicrosecondScale,
6592                                    &__private->defaultI2CTiming.acknowledgeTimeout);
6593        clock_interval_to_deadline(40, kMicrosecondScale,
6594                                    &__private->defaultI2CTiming.startTimeout);
6595
6596        __private->lli2c = (kIOReturnSuccess == getAttributeForConnection(
6597                                        0, kConnectionSupportsLLDDCSense,
6598                                        (uintptr_t *) &__private->defaultI2CTiming));
6599
6600        if ((num = OSDynamicCast(OSNumber, getProperty(kIOFBGammaWidthKey))))
6601            __private->desiredGammaDataWidth = num->unsigned32BitValue();
6602        if ((num = OSDynamicCast(OSNumber, getProperty(kIOFBGammaCountKey))))
6603            __private->desiredGammaDataCount = num->unsigned32BitValue();
6604        if ((num = OSDynamicCast(OSNumber, getProperty(kIOFBGammaHeaderSizeKey))))
6605            __private->gammaHeaderSize = num->unsigned32BitValue();
6606
6607        __private->deferredSpeedChangeEvent = IOInterruptEventSource::interruptEventSource(
6608                                                                    this, deferredSpeedChangeEvent);
6609        if (__private->deferredSpeedChangeEvent)
6610            __private->controller->wl->addEventSource(__private->deferredSpeedChangeEvent);
6611
6612        opened = true;
6613
6614        bool nowOnline;
6615        nowOnline = updateOnline();
6616		if (nowOnline)
6617		{
6618			if (!gIOFBConsoleFramebuffer)        gIOFBConsoleFramebuffer = this;
6619		}
6620		else
6621		{
6622			if (this == gIOFBConsoleFramebuffer) gIOFBConsoleFramebuffer = NULL;
6623		}
6624
6625        __private->paramHandler = IOFramebufferParameterHandler::withFramebuffer(this);
6626        if (__private->paramHandler)
6627            setProperty(gIODisplayParametersKey, __private->paramHandler);
6628
6629        IOFramebufferI2CInterface::create( this );
6630
6631        __private->online = nowOnline;
6632        if (nowOnline)
6633        	displaysOnline(nowOnline);
6634        else
6635            IODisplayUpdateNVRAM(this, 0);
6636
6637        __private->transform = __private->selectedTransform;
6638        setProperty(kIOFBTransformKey, __private->transform, 64);
6639
6640        if (openAllDependents)
6641        {
6642            next = this;
6643            while ((next = next->getNextDependent()) && (next != this))
6644            {
6645                next->open();
6646            }
6647        }
6648
6649        if (nowOnline)
6650        {
6651            deliverDisplayModeDidChangeNotification();
6652            err = kIOReturnSuccess;
6653        }
6654        else
6655        {
6656        	findConsole();
6657            deliverDisplayModeDidChangeNotification();
6658            dpUpdateConnect();
6659        }
6660
6661        if (openAllDependents)
6662        {
6663            next = this;
6664            do
6665            {
6666                next->postOpen();
6667            }
6668            while ((next = next->getNextDependent()) && (next != this));
6669        }
6670
6671		FBUNLOCK(this);
6672    }
6673    while (false);
6674
6675	if (__private->controller)
6676	{
6677		FBLOCK(this);
6678		__private->allowSpeedChanges = true;
6679		if (__private->pendingSpeedChange)
6680		{
6681			__private->pendingSpeedChange = false;
6682			__private->controller->powerThread = current_thread();
6683			setAttribute(kIOFBSpeedAttribute, __private->reducedSpeed);
6684			__private->controller->powerThread = NULL;
6685		}
6686		FBUNLOCK(this);
6687	}
6688
6689	SYSUNLOCK();
6690
6691    return (err);
6692}
6693
6694void IOFramebuffer::setTransform( UInt64 newTransform, bool generateChange )
6695{
6696    newTransform |= (kIOFBScalerUnderscan & __private->selectedTransform);
6697
6698    if (newTransform != __private->selectedTransform)
6699    {
6700        __private->userSetTransform = generateChange;
6701        __private->selectedTransform = newTransform;
6702        if (generateChange)
6703            connectChangeInterrupt(this, 0);
6704        else
6705        {
6706            __private->transform = newTransform;
6707            setProperty(kIOFBTransformKey, newTransform, 64);
6708        }
6709    }
6710}
6711
6712UInt64 IOFramebuffer::getTransform( void )
6713{
6714    return (__private->transform);
6715}
6716
6717IOReturn IOFramebuffer::selectTransform( UInt64 transform, bool generateChange )
6718{
6719    IOFramebuffer * next;
6720    next = this;
6721//    do
6722    {
6723        next->setTransform(transform, generateChange);
6724    }
6725//    while ((next = next->getNextDependent()) && (next != this));
6726
6727    return (kIOReturnSuccess);
6728}
6729
6730IOReturn IOFramebuffer::probeAll( IOOptionBits options )
6731{
6732    IOReturn err = kIOReturnSuccess;
6733
6734    do
6735    {
6736        unsigned int    index;
6737        IOFramebuffer * fb;
6738
6739        if (gIOGraphicsControl)
6740        {
6741            err = gIOGraphicsControl->requestProbe(options);
6742			break;
6743        }
6744        for (index = 0;
6745                (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
6746                index++)
6747        {
6748			FBLOCK(fb);
6749            if (!fb->captured)
6750			{
6751				IOReturn
6752				thisErr = fb->setAttributeForConnection(0, kConnectionProbe, options);
6753				if (kIOReturnSuccess == err)
6754					err = thisErr;
6755			}
6756			FBUNLOCK(fb);
6757        }
6758    }
6759    while (false);
6760
6761    return (err);
6762}
6763
6764IOReturn IOFramebuffer::requestProbe( IOOptionBits options )
6765{
6766    IOReturn err;
6767
6768    if (!gIOFBSystemWorkLoop || gIOFBSystemWorkLoop->inGate())
6769        return (kIOReturnNotReady);
6770
6771    if ((err = extEntry(true)))
6772        return (err);
6773
6774#if 0
6775    if (!__private->online)
6776    {
6777		inst->extExit(err);
6778        return (kIOReturnSuccess);
6779    }
6780#endif
6781    if (kIOFBSetTransform & options)
6782    {
6783        options >>= 16;
6784        selectTransform(options, true);
6785    }
6786    else
6787    {
6788        if (captured)
6789        {
6790            err = kIOReturnBusy;
6791        }
6792        else
6793        {
6794            AbsoluteTime now;
6795            AbsoluteTime_to_scalar(&now) = mach_absolute_time();
6796            if (CMP_ABSOLUTETIME(&now, &gIOFBNextProbeAllTime) >= 0)
6797            {
6798				OSBitOrAtomic(kIOFBEventProbeAll, &gIOFBGlobalEvents);
6799				startThread(false);
6800                clock_interval_to_deadline(10, kSecondScale, &gIOFBNextProbeAllTime);
6801            }
6802        }
6803    }
6804
6805    extExit(err);
6806
6807    return (kIOReturnSuccess);
6808}
6809
6810void IOFramebuffer::initFB(void)
6811{
6812	AbsoluteTime now;
6813    uint64_t nsec;
6814
6815	if (!__private->online)
6816	{
6817		__private->needsInit = false;
6818		return;
6819	}
6820	if (!frameBuffer) return;
6821
6822	do
6823	{
6824		IOReturn             err;
6825		IODisplayModeID      mode;
6826		IOIndex              depth;
6827		IOPixelInformation	 pixelInfo;
6828		IOMemoryDescriptor * fbRange;
6829		uint32_t 			 totalWidth, consoleDepth;
6830		uint8_t				 logo;
6831		bool				 timeout = false;
6832
6833		err = getCurrentDisplayMode(&mode, &depth);
6834		if (kIOReturnSuccess != err)
6835			break;
6836		err = getPixelInformation(mode, depth, kIOFBSystemAperture, &pixelInfo);
6837		if (kIOReturnSuccess != err)
6838			break;
6839		if (pixelInfo.activeWidth < 128)
6840			break;
6841
6842		if (!vramMap)
6843		{
6844			fbRange = getApertureRange(kIOFBSystemAperture);
6845			if (!fbRange)
6846				break;
6847			vramMap = fbRange->map(kIOFBMapCacheMode);
6848			fbRange->release();
6849			if (!vramMap)
6850				break;
6851		}
6852		if (pixelInfo.bitsPerComponent > 8)
6853			consoleDepth = pixelInfo.componentCount * pixelInfo.bitsPerComponent;
6854		else
6855			consoleDepth = pixelInfo.bitsPerPixel;
6856		totalWidth = (pixelInfo.bytesPerRow * 8) / pixelInfo.bitsPerPixel;
6857
6858		if (false && __private->needsInit == 1)
6859		{
6860			AbsoluteTime_to_scalar(&now) = mach_absolute_time();
6861			SUB_ABSOLUTETIME(&now, &__private->controller->initTime);
6862			absolutetime_to_nanoseconds(now, &nsec);
6863			timeout = (nsec > kInitFBTimeoutNS);
6864			if (timeout) DEBG1(thisName, " init timeout\n");
6865		}
6866		// timeout = false;
6867		logo = ((!timeout)
6868			&& (NULL != getProperty("AAPL,boot-display", gIOServicePlane))
6869			&& (__private->needsInit != 3));
6870		// logo = 1;
6871		if (logo)
6872		{
6873			PE_Video consoleInfo;
6874            IOService::getPlatform()->getConsoleInfo(&consoleInfo);
6875			if ((consoleInfo.v_width == pixelInfo.activeWidth)
6876				&& (consoleInfo.v_height == pixelInfo.activeHeight))
6877			{
6878				if (2 == consoleInfo.v_scale) logo = 2;
6879			}
6880			else logo = 0;
6881		}
6882		DEBG1(thisName, " initFB: needsInit %d logo %d\n",
6883				__private->needsInit, logo);
6884		IOFramebufferBootInitFB(
6885			vramMap->getVirtualAddress(),
6886			pixelInfo.activeWidth, pixelInfo.activeHeight,
6887			totalWidth, consoleDepth,
6888			logo);
6889		DEBG1(thisName, " initFB: done\n");
6890		if (logo && !getProperty(kIOFBBootGammaRestoredKey, gIOServicePlane)) updateGammaTable(3, 256, 16, NULL, false);
6891		__private->needsInit = false;
6892		setProperty(kIOFBNeedsRefreshKey, (0 == logo));
6893	}
6894	while (false);
6895}
6896
6897IOReturn IOFramebuffer::postOpen( void )
6898{
6899	__private->needsInit = true;
6900	__private->needsInit += (kOSBooleanFalse == getProperty(kIOFBNeedsRefreshKey));
6901	setProperty(kIOFBNeedsRefreshKey, true);
6902	initFB();
6903
6904    if (__private->cursorAttributes)
6905    {
6906        __private->cursorAttributes->release();
6907        __private->cursorAttributes = 0;
6908    }
6909
6910    __private->cursorAttributes = OSArray::withCapacity(2);
6911    if (!__private->cursorAttributes)
6912        return (kIOReturnNoMemory);
6913
6914    __private->testingCursor = true;
6915
6916    setCursorImage( (void *) 0 );
6917
6918    if (__private->cursorThread)
6919    {
6920        IOHardwareCursorDescriptor desc;
6921
6922        desc.majorVersion       = kHardwareCursorDescriptorMajorVersion;
6923        desc.minorVersion       = kHardwareCursorDescriptorMinorVersion;
6924        desc.height             = 256;
6925        desc.width              = 256;
6926        desc.bitDepth           = 32;
6927        desc.maskBitDepth       = 0;
6928        desc.colorEncodings     = 0;
6929        desc.flags              = 0;
6930        desc.supportedSpecialEncodings = kTransparentEncodedPixel;
6931
6932        (*__private->cursorControl.callouts->setCursorImage) (
6933            __private->cursorControl.self, __private->cursorControl.ref,
6934            &desc, (void *) 0 );
6935
6936        if (__private->controller->wl)
6937            __private->controller->wl->addEventSource(__private->cursorThread);
6938    }
6939
6940    __private->testingCursor = false;
6941
6942    setProperty( kIOFBCursorInfoKey, __private->cursorAttributes );
6943
6944    IOService * sensor = 0;
6945    uintptr_t value[16];
6946
6947//#define kTempAttribute        kConnectionWSSB
6948#define kTempAttribute  'thrm'
6949
6950    if (!__private->temperatureSensor
6951     && (kIOReturnSuccess == getAttributeForConnection(0, kTempAttribute, &value[0])))
6952    do
6953    {
6954        UInt32     data;
6955        OSNumber * num;
6956
6957        num = OSDynamicCast(OSNumber, getProperty(kIOFBDependentIDKey));
6958        if (num && num->unsigned32BitValue())
6959            continue;
6960
6961        sensor = new IOService;
6962        if (!sensor)
6963            continue;
6964        if (!sensor->init())
6965            continue;
6966
6967#define kTempSensorName         "temp-sensor"
6968        sensor->setName(kTempSensorName);
6969        sensor->setProperty("name", (void *) kTempSensorName, strlen(kTempSensorName) + 1);
6970        sensor->setProperty("compatible", (void *) kTempSensorName, strlen(kTempSensorName) + 1);
6971        sensor->setProperty("device_type", (void *) kTempSensorName, strlen(kTempSensorName) + 1);
6972        sensor->setProperty("type", "temperature");
6973        sensor->setProperty("location", "GPU");
6974        data = 0xff000002;
6975        sensor->setProperty("zone", &data, sizeof(data));
6976        data = 0x00000001;
6977        sensor->setProperty("version", &data, sizeof(data));
6978
6979        OSData * prop;
6980        IOService * device;
6981        data = 0x12345678;
6982        if ((device = getProvider())
6983         && (prop = OSDynamicCast(OSData, device->getProperty("AAPL,phandle"))))
6984            data = (*((UInt32 *) prop->getBytesNoCopy())) << 8;
6985        sensor->setProperty("sensor-id", &data, sizeof(data));
6986
6987        if (!sensor->attach(this))
6988            continue;
6989
6990        sensor->registerService();
6991        __private->temperatureSensor = sensor;
6992    }
6993    while (false);
6994
6995    if (sensor)
6996        sensor->release();
6997
6998    return (kIOReturnSuccess);
6999}
7000
7001IOReturn IOFramebuffer::callPlatformFunction( const OSSymbol * functionName,
7002                                                    bool waitForFunction,
7003                                                    void *p1, void *p2,
7004                                                    void *p3, void *p4 )
7005{
7006    uintptr_t   value[16];
7007    IOReturn ret;
7008
7009    if (functionName != gIOFBGetSensorValueKey)
7010        return (super::callPlatformFunction(functionName, waitForFunction, p1, p2, p3, p4));
7011
7012    FBLOCK(this);
7013    ret = getAttributeForConnection(0, kTempAttribute, &value[0]);
7014    FBUNLOCK(this);
7015
7016    if (kIOReturnSuccess == ret)
7017        *((UInt32 *)p2) = ((value[0] & 0xffff) << 16);
7018
7019    return (ret);
7020}
7021
7022IOWorkLoop * IOFramebuffer::getControllerWorkLoop() const
7023{
7024	return (__private->controller->wl);
7025}
7026
7027IOWorkLoop * IOFramebuffer::getGraphicsSystemWorkLoop() const
7028{
7029    return (gIOFBSystemWorkLoop);
7030}
7031
7032IOWorkLoop * IOFramebuffer::getWorkLoop() const
7033{
7034	if (__private && __private->controller)
7035	return (__private->controller->wl);
7036	else
7037		return (NULL);
7038}
7039
7040void IOFramebuffer::setCaptured( bool isCaptured )
7041{
7042    bool wasCaptured = captured;
7043
7044    captured = isCaptured;
7045
7046	DEBG1(thisName, " captured %d -> %d\n", wasCaptured, captured);
7047
7048    if (wasCaptured != isCaptured)
7049    {
7050        if (isCaptured)
7051            setProperty(kIOFBCapturedKey, kOSBooleanTrue);
7052        else
7053            removeProperty(kIOFBCapturedKey);
7054		deliverFramebufferNotification(kIOFBNotifyCaptureChange, (void *) isCaptured);
7055
7056		startControllerThread(__private->controller);
7057    }
7058}
7059
7060void IOFramebuffer::setDimDisable( bool dimDisable )
7061{
7062    __private->dimDisable = dimDisable;
7063}
7064
7065bool IOFramebuffer::getDimDisable( void )
7066{
7067    return (__private->dimDisable);
7068}
7069
7070void IOFramebuffer::setNextDependent( IOFramebuffer * dependent )
7071{
7072    nextDependent = dependent;
7073}
7074
7075IOFramebuffer * IOFramebuffer::getNextDependent( void )
7076{
7077    return (nextDependent);
7078}
7079
7080void IOFramebuffer::close( void )       // called by the user client when
7081{                                       // the window server exits
7082    IOReturn            err;
7083    unsigned int        idx;
7084    mach_msg_header_t * msgh;
7085
7086    if ((err = extEntrySys(true)))
7087        return;
7088
7089    if ((this == gIOFBConsoleFramebuffer) && getPowerState())
7090        getPlatform()->setConsoleInfo( 0, kPEAcquireScreen);
7091
7092    msgh = (mach_msg_header_t *) serverMsg;
7093    if (msgh)
7094        msgh->msgh_remote_port = MACH_PORT_NULL;
7095
7096	__private->controller->wsWait |= (1 << __private->controllerIndex);
7097    serverConnect = 0;
7098    captured = false;
7099	setProperty(kIOFBNeedsRefreshKey, true);
7100
7101	for (idx = 0;
7102		 (idx < kIOPreviewImageCount) && __private->saveBitsMD[idx];
7103		 idx++)
7104	{
7105		__private->saveBitsMD[idx]->release();
7106		__private->saveBitsMD[idx] = 0;
7107	}
7108
7109    if (gRunawayFramebuffers)
7110    {
7111        idx = gAllFramebuffers->getNextIndexOfObject( this, 0 );
7112        if (idx != (unsigned int) -1)
7113            gAllFramebuffers->removeObject(idx);
7114
7115        idx = gRunawayFramebuffers->getNextIndexOfObject( this, 0 );
7116        if (idx != (unsigned int) -1)
7117            gRunawayFramebuffers->removeObject(idx);
7118
7119        if (idx != (unsigned int) -1)
7120        {
7121            terminate();
7122        }
7123    }
7124
7125	extExitSys(err);
7126}
7127
7128IODeviceMemory * IOFramebuffer::getVRAMRange( void )
7129{
7130    return (getApertureRange(kIOFBSystemAperture));
7131}
7132
7133IOReturn IOFramebuffer::setUserRanges( void )
7134{
7135#if RLOG
7136    // print ranges
7137    uint32_t              i, numRanges;
7138    IOMemoryDescriptor *    mem;
7139    numRanges = userAccessRanges->getCount();
7140    DEBG(thisName, " ranges num:%d\n", numRanges);
7141    for (i = 0; i < numRanges; i++)
7142    {
7143        mem = (IOMemoryDescriptor *) userAccessRanges->getObject( i );
7144        if (0 == mem)
7145            continue;
7146        DEBG(thisName, " start:%llx size:%lx\n",
7147             mem->getPhysicalSegment(0, 0, kIOMemoryMapperNone), (long) mem->getLength() );
7148    }
7149#endif
7150
7151    return (kIOReturnSuccess);
7152}
7153
7154IOReturn IOFramebuffer::setBackingFramebuffer(const IOPixelInformation * info,
7155					      uint32_t bufferCount,
7156					      void * mappedAddress[])
7157{
7158    return (kIOReturnSuccess);
7159}
7160
7161IOReturn IOFramebuffer::switchBackingFramebuffer(uint32_t bufferIndex)
7162{
7163    return (kIOReturnSuccess);
7164}
7165
7166void IOFramebuffer::findConsole(void)
7167{
7168    PE_Video newConsole;
7169    IOFramebuffer * look;
7170    IOFramebuffer * fb = NULL;
7171    uintptr_t       value;
7172
7173    for (uint32_t index = 0;
7174            (look = (IOFramebuffer *) gAllFramebuffers->getObject(index));
7175            index++)
7176    {
7177        if (!look->__private
7178            || !look->frameBuffer
7179            || !look->__private->framebufferWidth
7180            || !look->__private->framebufferHeight
7181            || !look->__private->online
7182            || !look->__private->controller
7183            || !look->__private->controller->device
7184            || !look->__private->consoleDepth
7185            || (look->__private->consoleDepth > 32))
7186            continue;
7187
7188		if ((kIOReturnSuccess == look->getAttribute(kIOVRAMSaveAttribute, &value))
7189			&& !value)
7190			continue;
7191
7192		if (kIODisplayOptionBacklight & look->__private->displayOptions)
7193		{
7194			fb = look;
7195			break;
7196		}
7197		if (!fb || (look == gIOFBConsoleFramebuffer))
7198		{
7199			fb = look;
7200		}
7201    }
7202
7203    if (fb)
7204    {
7205		DEBG1(fb->thisName, " console set 0x%x000 %d x %d\n",
7206							pmap_find_phys(kernel_pmap, (addr64_t) fb->frameBuffer),
7207							fb->__private->framebufferWidth,
7208							fb->__private->framebufferHeight);
7209        bzero(&newConsole, sizeof(newConsole));
7210        newConsole.v_baseAddr   = (unsigned long) fb->frameBuffer;
7211        newConsole.v_rowBytes   = fb->rowBytes;
7212        newConsole.v_width      = fb->__private->framebufferWidth;
7213        newConsole.v_height     = fb->__private->framebufferHeight;
7214        newConsole.v_depth      = fb->__private->consoleDepth;
7215        newConsole.v_scale      = fb->__private->uiScale;
7216        newConsole.v_display    = 1;  // graphics mode for i386
7217        //      strcpy( consoleInfo->v_pixelFormat, "PPPPPPPP");
7218        getPlatform()->setConsoleInfo( &newConsole, kPEReleaseScreen );
7219        getPlatform()->setConsoleInfo( &newConsole, kPEEnableScreen );
7220        gIOFBConsoleFramebuffer = fb;
7221        DEBG1(fb->thisName, " now console\n");
7222    }
7223}
7224
7225IOReturn IOFramebuffer::setupForCurrentConfig( void )
7226{
7227	TIMESTART();
7228	if (__private->paramHandler)
7229		__private->paramHandler->displayModeChange();
7230	TIMEEND(thisName, "paramHandler->displayModeChange time: %qd ms\n");
7231
7232    return (doSetup(true));
7233}
7234
7235OSData * IOFramebuffer::getConfigMode(IODisplayModeID mode, const OSSymbol * sym)
7236{
7237	OSDictionary * dict;
7238	OSArray * array;
7239	OSNumber * num;
7240	unsigned int idx;
7241
7242	dict = OSDynamicCast(OSDictionary, getProperty(gIOFBConfigKey));
7243	if (!dict) return (0);
7244	array = OSDynamicCast(OSArray, dict->getObject(gIOFBModesKey));
7245	if (!array) return (0);
7246	for (idx = 0; (dict = OSDynamicCast(OSDictionary, array->getObject(idx))); idx++)
7247	{
7248		if (!(num = OSDynamicCast(OSNumber, dict->getObject(gIOFBModeIDKey)))) continue;
7249		if (num->unsigned32BitValue() == (UInt32) mode) break;
7250	}
7251	if (!dict) return (0);
7252	return (OSDynamicCast(OSData, dict->getObject(sym)));
7253}
7254
7255IOReturn IOFramebuffer::doSetup( bool full )
7256{
7257    StdFBShmem_t *      		shmem = GetShmem(this);
7258    IOReturn                    err;
7259    IODisplayModeID             mode;
7260    IOIndex                     depth;
7261    IOMemoryDescriptor *        mem;
7262    IOMemoryDescriptor *        fbRange;
7263	OSData *				    data;
7264    IOPhysicalAddress64         base;
7265    uintptr_t                   value;
7266    bool                        haveFB = __private->online;
7267
7268	bzero(&__private->pixelInfo, sizeof(__private->pixelInfo));
7269	if (haveFB)
7270	{
7271		err = getAttribute( kIOHardwareCursorAttribute, &value );
7272		__private->cursorPanning = ((err == kIOReturnSuccess) && (0 != (kIOFBCursorPans & value)));
7273
7274		err = getCurrentDisplayMode( &mode, &depth );
7275		if (kIOReturnSuccess == err)
7276			err = getPixelInformation( mode, depth, kIOFBSystemAperture, &__private->pixelInfo );
7277		if (kIOReturnSuccess != err)
7278			bzero(&__private->pixelInfo, sizeof(__private->pixelInfo));
7279		if (__private->pixelInfo.activeWidth < 128)
7280			haveFB = false;
7281		else if ((data = getConfigMode(mode, gIOFBModeDMKey)))
7282		{
7283			IODisplayModeInformation * info = (typeof(info)) data->getBytesNoCopy();
7284			if (info->imageWidth)
7285			{
7286				if ((__private->pixelInfo.activeWidth >= 2048)
7287				 && (__private->pixelInfo.activeHeight >= 1280)
7288				 && (((254 * __private->pixelInfo.activeWidth) / info->imageWidth) > k2xDPI))
7289					 __private->uiScale  = 2;
7290				else __private->uiScale  = 1;
7291			}
7292			else __private->uiScale      = 0;
7293		}
7294	}
7295
7296    __private->timingInfo.flags = kIODetailedTimingValid;
7297    if (haveFB
7298     && (kIOReturnSuccess == getTimingInfoForDisplayMode(mode, &__private->timingInfo)))
7299    {
7300        if (kIODetailedTimingValid & __private->timingInfo.flags)
7301        {
7302        	uint64_t count = ((uint64_t)(__private->timingInfo.detailedInfo.v2.horizontalActive
7303									+ __private->timingInfo.detailedInfo.v2.horizontalBlanking));
7304			count *= ((uint64_t)(__private->timingInfo.detailedInfo.v2.verticalActive
7305								   + __private->timingInfo.detailedInfo.v2.verticalBlanking));
7306			if (kIOInterlacedCEATiming & __private->timingInfo.detailedInfo.v2.signalConfig)
7307				count >>= 1;
7308
7309			uint64_t clock  = __private->timingInfo.detailedInfo.v2.pixelClock;
7310			uint64_t actual = __private->timingInfo.detailedInfo.v2.minPixelClock;
7311
7312			DEBG1(thisName, " minPixelClock %qd maxPixelClock %qd\n",
7313							__private->timingInfo.detailedInfo.v2.maxPixelClock,
7314							__private->timingInfo.detailedInfo.v2.minPixelClock);
7315
7316			if (actual != __private->timingInfo.detailedInfo.v2.maxPixelClock)
7317				actual = 0;
7318			bool throttleEnable = (gIOFBVBLThrottle && clock && actual && shmem);
7319			DEBG1(thisName, " vblthrottle(%d) clk %qd act %qd\n", throttleEnable, clock, actual);
7320			if (throttleEnable)
7321				clock = actual;
7322            setProperty(kIOFBCurrentPixelClockKey, clock, 64);
7323            setProperty(kIOFBCurrentPixelCountKey, count, 64);
7324            if (shmem && throttleEnable)
7325            {
7326				mach_timebase_info_data_t timebaseInfo;
7327				clock_timebase_info(&timebaseInfo);
7328				AbsoluteTime_to_scalar(&shmem->vblDelta)
7329						= (count * kSecondScale * timebaseInfo.numer / clock / timebaseInfo.denom);
7330			}
7331			__private->vblThrottle = throttleEnable;
7332			__private->setupMode = mode;
7333        }
7334        else
7335        {
7336            removeProperty(kIOFBCurrentPixelClockKey);
7337            removeProperty(kIOFBCurrentPixelCountKey);
7338			if (shmem && __private->vblThrottle)
7339				AbsoluteTime_to_scalar(&shmem->vblDelta) = 0;
7340        }
7341
7342        __private->scaledMode = false;
7343        if (kIOScalingInfoValid & __private->timingInfo.flags)
7344        {
7345            __private->scaledMode =
7346            (__private->timingInfo.detailedInfo.v2.scalerFlags
7347             || __private->timingInfo.detailedInfo.v2.horizontalScaledInset
7348             || __private->timingInfo.detailedInfo.v2.verticalScaledInset
7349             || (__private->timingInfo.detailedInfo.v2.horizontalScaled
7350                    && (__private->timingInfo.detailedInfo.v2.horizontalScaled != __private->timingInfo.detailedInfo.v2.horizontalActive))
7351             || (__private->timingInfo.detailedInfo.v2.verticalScaled
7352                    && (__private->timingInfo.detailedInfo.v2.verticalScaled != __private->timingInfo.detailedInfo.v2.verticalActive)));
7353        }
7354    }
7355    else
7356		__private->timingInfo.flags = 0;
7357
7358    if (full)
7359    {
7360    	frameBuffer = NULL;
7361    	if ((fbRange = getApertureRange(kIOFBSystemAperture)))
7362		{
7363			userAccessRanges->removeObject( kIOFBSystemAperture );
7364			userAccessRanges->setObject( kIOFBSystemAperture, fbRange );
7365			err = setUserRanges();
7366
7367			base = fbRange->getPhysicalSegment(0, 0, kIOMemoryMapperNone);
7368			if ((mem = getVRAMRange()))
7369			{
7370				vramMapOffset = base - mem->getPhysicalSegment(0, 0, kIOMemoryMapperNone);
7371				if (vramMapOffset > mem->getLength())
7372					vramMapOffset &= (mem->getLength() - 1);
7373				setProperty( kIOFBMemorySizeKey, mem->getLength(), 32 );
7374				mem->release();
7375			}
7376
7377			IOMemoryMap * oldMap = vramMap;
7378			vramMap = fbRange->map( kIOFBMapCacheMode );
7379			if (oldMap)
7380				oldMap->release();
7381			assert( vramMap );
7382			if (vramMap)
7383			{
7384				base = vramMap->getVirtualAddress();
7385				frameBuffer = (volatile unsigned char *) base;
7386			}
7387
7388			DEBG1(thisName, " using (%dx%d,%d bpp)\n",
7389				 (uint32_t) __private->pixelInfo.activeWidth, (uint32_t) __private->pixelInfo.activeHeight,
7390				 (uint32_t) __private->pixelInfo.bitsPerPixel );
7391
7392			if (fbRange)
7393				fbRange->release();
7394		}
7395	}
7396
7397    if (full)
7398    {
7399        deliverDisplayModeDidChangeNotification();
7400
7401        dpUpdateConnect();
7402    }
7403
7404DEBG1(thisName, " doSetup vram %d, fb %d\n", vramMap != NULL, haveFB);
7405    if (haveFB)
7406    {
7407		if (__private->needsInit) initFB();
7408        setupCursor();
7409    }
7410    else
7411    {
7412        cursorBlitProc   = (CursorBlitProc)   NULL;
7413        cursorRemoveProc = (CursorRemoveProc) NULL;
7414        __private->framebufferWidth  = 0;
7415        __private->framebufferHeight = 0;
7416    }
7417
7418    // reset console
7419    if (full && (haveFB || !gIOFBConsoleFramebuffer))
7420        findConsole();
7421
7422    return (kIOReturnSuccess);
7423}
7424
7425bool IOFramebuffer::suspend(bool now)
7426{
7427    if (now == suspended)
7428        return (true);
7429
7430    if (now)
7431    {
7432		stopCursor();
7433		checkDeferredCLUTSet();
7434		if (this == gIOFBConsoleFramebuffer)
7435		{
7436			getPlatform()->setConsoleInfo( 0, kPEDisableScreen);
7437			gIOFBConsoleFramebuffer = 0;
7438		}
7439		deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange );
7440        suspended = true;
7441    }
7442    else
7443    {
7444		TIMESTART();
7445		setupForCurrentConfig();
7446		TIMEEND(thisName, "exit suspend setupForCurrentConfig time: %qd ms\n");
7447
7448        suspended = false;
7449        __private->modeUpdate = false;
7450    }
7451
7452    return (false);
7453}
7454
7455IOReturn IOFramebuffer::extSetDisplayMode(
7456        OSObject * target, void * reference, IOExternalMethodArguments * args)
7457{
7458    IOFramebuffer * inst        = (IOFramebuffer *) target;
7459    IODisplayModeID displayMode = args->scalarInput[0];
7460    IOIndex         depth       = args->scalarInput[1];
7461    IOReturn        err;
7462
7463	err = inst->doSetDisplayMode(displayMode, depth);
7464
7465	return (err);
7466}
7467
7468IOReturn IOFramebuffer::doSetDisplayMode(
7469		IODisplayModeID displayMode, IOIndex depth)
7470{
7471    IOReturn        err;
7472
7473    DEBG1(thisName, " extSetDisplayMode(0x%x, %d) susp %d online %d\n",
7474    		(int32_t) displayMode, (uint32_t) depth, suspended,
7475            __private->online);
7476
7477    if (kIODisplayModeIDAliasBase & displayMode)
7478    {
7479    	// && (depth == __private->currentDepth))
7480
7481		if ((err = extEntry(false)))
7482			return (err);
7483
7484        DEBG(thisName, " nop set mode\n");
7485		__private->aliasMode = displayMode & ~kIODisplayModeIDAliasBase;
7486		__private->modeUpdate = false;
7487		extExit(err);
7488
7489        return (kIOReturnSuccess);
7490    }
7491
7492    if ((err = extEntrySys(false)))
7493        return (err);
7494
7495   	if ((kIODisplayModeIDCurrent == displayMode)
7496   		&& __private->modeUpdate)
7497	{
7498        getCurrentDisplayMode(&displayMode, &depth);
7499	}
7500
7501	suspend(true);
7502
7503   	if (kIODisplayModeIDCurrent != displayMode)
7504	{
7505		TIMESTART();
7506		err = setDisplayMode( displayMode, depth );
7507		TIMEEND(thisName, "setDisplayMode time: %qd ms\n");
7508		__private->aliasMode    = kIODisplayModeIDInvalid;
7509		__private->currentDepth = depth;
7510	}
7511
7512    suspend(false);
7513
7514	extExitSys(err);
7515
7516    return (err);
7517}
7518
7519IOReturn IOFramebuffer::checkMirrorSafe( UInt32 value, IOFramebuffer * other )
7520{
7521    IOReturn        err = kIOReturnSuccess;
7522    IOFramebuffer * next = this;
7523
7524    while ((next = next->getNextDependent()) && (next != this))
7525    {
7526		DEBG1(next->thisName, " transform 0x%llx \n", __private->transform);
7527        if (~kIOFBScalerUnderscan & (__private->transform ^ next->getTransform()))
7528        {
7529            err = kIOReturnUnsupported;
7530            break;
7531        }
7532    }
7533
7534    return (err);
7535}
7536
7537IOReturn IOFramebuffer::extSetMirrorOne(uint32_t value, IOFramebuffer * other)
7538{
7539    IOReturn    err;
7540    IOFramebuffer * next;
7541    uintptr_t   data[2];
7542    bool        was;
7543
7544	if (value && __private->nextMirror)   return (kIOReturnBusy);
7545	if (value && !other)                  return (kIOReturnBadArgument);
7546	if (!value && !__private->nextMirror) return (kIOReturnSuccess);
7547	if (!value && __private->nextMirror)
7548	{
7549		next = this;
7550		do
7551		{
7552			next->suspend(true);
7553			data[0] = value;
7554			data[1] = (uintptr_t) next->__private->nextMirror;
7555			DEBG1(next->thisName, " kIOMirrorAttribute(0)\n");
7556			err = next->setAttribute(kIOMirrorAttribute, (uintptr_t) &data);
7557			DEBG1(next->thisName, " kIOMirrorAttribute(%d) ret 0x%x\n", value, err);
7558		}
7559		while ((next = next->__private->nextMirror) && (next != this));
7560
7561		next = this;
7562		do
7563		{
7564			IOFramebuffer * prev;
7565			prev = next;
7566			next = next->__private->nextMirror;
7567			prev->__private->nextMirror = 0;
7568			prev->suspend(false);
7569		}
7570		while (next && (next != this));
7571
7572		return (kIOReturnSuccess);
7573	}
7574
7575	was = suspend(true);
7576	data[0] = value;
7577	data[1] = (uintptr_t) other;
7578	err = setAttribute(kIOMirrorAttribute, (uintptr_t) &data);
7579	DEBG1(thisName, " kIOMirrorAttribute(%d) ret 0x%x\n", value, err);
7580	if (kIOReturnSuccess != err)
7581	{
7582		if (!was) suspend(false);
7583	}
7584	else
7585	{
7586		__private->nextMirror = other;
7587		if (other->__private->nextMirror)
7588		{
7589			next = other;
7590			do next->suspend(false);
7591			while ((next = next->__private->nextMirror) && (next != other));
7592		}
7593	}
7594	return (err);
7595}
7596
7597IOReturn IOFramebuffer::extSetAttribute(
7598        OSObject * target, void * reference, IOExternalMethodArguments * args)
7599{
7600    IOFramebuffer * inst      = (IOFramebuffer *) target;
7601    IOSelect        attribute = args->scalarInput[0];
7602    uint32_t        value     = args->scalarInput[1];
7603    IOFramebuffer * other     = (IOFramebuffer *) reference;
7604
7605    IOReturn    err;
7606
7607    if ((err = inst->extEntry(false)))
7608        return (err);
7609
7610    switch (attribute)
7611    {
7612        case kIOMirrorAttribute:
7613
7614            DEBG1(inst->thisName, " kIOMirrorAttribute(%d) susp(%d), curr(%d)\n",
7615                    value, inst->suspended, (inst->__private->nextMirror != 0));
7616            value = (value != 0);
7617            if (value)
7618            {
7619                err = inst->checkMirrorSafe(value, other);
7620                if (kIOReturnSuccess != err)
7621                    break;
7622            }
7623			err = inst->extSetMirrorOne(value, other);
7624            break;
7625
7626        default:
7627            err = inst->setAttribute( attribute, value );
7628            break;
7629    }
7630
7631	inst->extExit(err);
7632
7633    return (err);
7634}
7635
7636IOReturn IOFramebuffer::extGetAttribute(
7637        OSObject * target, void * reference, IOExternalMethodArguments * args)
7638{
7639    IOFramebuffer * inst      = (IOFramebuffer *) target;
7640    IOSelect        attribute = args->scalarInput[0];
7641    uint64_t *      value     = &args->scalarOutput[0];
7642    IOFramebuffer * other     = (IOFramebuffer *) reference;
7643
7644    IOReturn    err = kIOReturnSuccess;
7645
7646	*value = 0;
7647
7648    switch (attribute)
7649    {
7650        case kIOFBProcessConnectChangeAttribute:
7651            err = inst->extProcessConnectionChange();
7652            break;
7653
7654        case kIOFBEndConnectChangeAttribute:
7655			if ((err = inst->extEntrySys(true)))
7656				return (err);
7657            err = inst->extEndConnectionChange();
7658			inst->extExitSys(err);
7659            break;
7660
7661        case kIOFBWSStartAttribute:
7662			if ((err = inst->extEntrySys(true)))
7663				return (err);
7664        	if (inst->__private->controller->wsWait)
7665        	{
7666				DEBG1(inst->thisName, " kIOFBWSStartAttribute wsWait %d\n", inst->__private->controller->wsWait);
7667				inst->__private->controller->wsWait &= ~(1 << inst->__private->controllerIndex);
7668				if (!inst->__private->controller->wsWait)
7669				{
7670				DEBG1(inst->thisName, " wsWait done remsg %d\n", inst->messaged);
7671				if (inst->messaged)
7672				{
7673					inst->messageClients(kIOMessageServiceIsSuspended, (void *) true);
7674				}
7675				resetClamshell(kIOFBClamshellProbeDelayMS);
7676				startControllerThread(inst->__private->controller);
7677			}
7678			}
7679			inst->extExitSys(err);
7680            break;
7681
7682        default:
7683
7684			if ((err = inst->extEntry(false)))
7685				return (err);
7686
7687			uintptr_t result = (uintptr_t) other;
7688			err = inst->getAttribute( attribute, &result );
7689			*value = (UInt32) result;
7690
7691			inst->extExit(err);
7692            break;
7693    }
7694
7695
7696    return (err);
7697}
7698
7699IOReturn IOFramebuffer::extGetInformationForDisplayMode(
7700        OSObject * target, void * reference, IOExternalMethodArguments * args)
7701{
7702    IOFramebuffer * inst   = (IOFramebuffer *) target;
7703    IODisplayModeID mode   = args->scalarInput[0];
7704    void *          info   = args->structureOutput;
7705    IOByteCount     length = args->structureOutputSize;
7706
7707    UInt32                       flags = 0;
7708    IOReturn                     err;
7709    bool                         getTiming;
7710    IOFBDisplayModeDescription * out = (IOFBDisplayModeDescription *) info;
7711
7712    if (length < sizeof(IODisplayModeInformation))
7713        return (kIOReturnBadArgument);
7714
7715    if ((err = inst->extEntry(false)))
7716        return (err);
7717
7718    err = inst->getInformationForDisplayMode( mode, &out->info );
7719    if (kIOReturnSuccess == err)
7720    {
7721        err = IODisplayWrangler::getFlagsForDisplayMode( inst, mode, &flags);
7722        if (kIOReturnSuccess == err)
7723        {
7724            out->info.flags &= ~kDisplayModeSafetyFlags;
7725            out->info.flags |= flags;
7726        }
7727        getTiming = (length >= sizeof(IOFBDisplayModeDescription));
7728        out->timingInfo.flags = getTiming ? kIODetailedTimingValid : 0;
7729        if (kIOReturnSuccess != inst->getTimingInfoForDisplayMode(mode, &out->timingInfo))
7730        {
7731            out->timingInfo.flags &= ~kIODetailedTimingValid;
7732            out->timingInfo.appleTimingID = 0;
7733        }
7734    }
7735
7736	inst->extExit(err);
7737
7738    return (err);
7739}
7740
7741IOReturn IOFramebuffer::setDisplayAttributes(OSObject * obj)
7742{
7743    IOReturn       r, ret = kIOReturnSuccess;
7744    OSData *       data;
7745    OSDictionary * dict;
7746	uint32_t *     attributes;
7747	uint32_t       idx, max;
7748	uint32_t       attr, attrValue, value, mask;
7749	uint32_t       controllerDepths, ditherMask = 0;
7750	uintptr_t      lvalue[16];
7751	bool           found = false;
7752	bool           skip = false;
7753	bool           updatesMode = false;
7754
7755	if (!obj) return (kIOReturnSuccess);
7756
7757	obj->retain();
7758	if (__private->displayAttributes) __private->displayAttributes->release();
7759	__private->displayAttributes = obj;
7760
7761	if (__private->display) __private->display->setProperty(kIODisplayAttributesKey, obj);
7762
7763	dict = OSDynamicCast(OSDictionary, obj);
7764	data = dict ? OSDynamicCast(OSData, dict->getObject(kIODisplayAttributesKey))
7765			    : OSDynamicCast(OSData, obj);
7766
7767	if (!data) return (kIOReturnSuccess);
7768
7769	attributes = (uint32_t *) data->getBytesNoCopy();
7770	max        = data->getLength() / sizeof(attributes[0]);
7771
7772	for (idx = 0; idx < max; idx += 2)
7773	{
7774		attr      = attributes[idx];
7775		attrValue = attributes[idx + 1];
7776
7777		if (kConnectionVendorTag == attr)
7778		{
7779			if (found)
7780				break;
7781			skip = (attrValue && (attrValue != __private->controller->vendorID));
7782			found = !skip;
7783			continue;
7784		}
7785		if (skip)
7786			continue;
7787
7788		DEBG1(thisName, " (0x%08x '%c%c%c%c')(%x)\n", attr, FEAT(attr), attrValue);
7789
7790		updatesMode = false;
7791		switch (attr)
7792		{
7793		  case kConnectionColorModesSupported:
7794			attrValue |= kIODisplayColorModeAuto;
7795			attrValue |= kIODisplayColorModeRGBLimited;
7796			__private->colorModesSupported = attrValue;
7797			break;
7798
7799		  case kConnectionColorDepthsSupported:
7800
7801			r = getAttributeForConnection(0, kConnectionControllerDepthsSupported, &lvalue[0]);
7802			if (kIOReturnSuccess != r)
7803			{
7804				lvalue[0] =  kIODisplayRGBColorComponentBits6
7805						| kIODisplayRGBColorComponentBits8;
7806				if (10 == __private->desiredGammaDataWidth)
7807					lvalue[0] |= kIODisplayRGBColorComponentBits10;
7808			}
7809
7810			controllerDepths = lvalue[0];
7811
7812#define COLRMASK(n)   ((n ## 16) | (n ## 14) | (n ## 12) | (n ## 10) | (n ## 8) | (n ## 6))
7813#define HIGHBIT(v)    (1 << (31 - __builtin_clz(v)))
7814
7815			value = controllerDepths & attrValue;
7816			if (!value)
7817				value = kIODisplayRGBColorComponentBits8;
7818
7819			mask = COLRMASK(kIODisplayRGBColorComponentBits);
7820			if (value & mask)
7821			{
7822				value = (value & ~mask) | HIGHBIT(value & mask);
7823				if (!(value & HIGHBIT(controllerDepths & mask)))
7824					ditherMask |= (kIODisplayDitherAll << kIODisplayDitherRGBShift);
7825			}
7826
7827			mask = COLRMASK(kIODisplayYCbCr444ColorComponentBits);
7828			if (value & mask)
7829			{
7830				value = (value & ~mask) | HIGHBIT(value & mask);
7831				if (!(value & HIGHBIT(controllerDepths & mask)))
7832					ditherMask |= (kIODisplayDitherAll << kIODisplayDitherYCbCr444Shift);
7833			}
7834
7835			mask = COLRMASK(kIODisplayYCbCr422ColorComponentBits);
7836			if (value & mask)
7837			{
7838				value = (value & ~mask) | HIGHBIT(value & mask);
7839				if (!(value & HIGHBIT(controllerDepths & mask)))
7840					ditherMask |= (kIODisplayDitherAll << kIODisplayDitherYCbCr422Shift);
7841			}
7842
7843			// pass thru kConnectionColorDepthsSupported
7844			DEBG1(thisName, " (0x%08x '%c%c%c%c')(%x)\n", attr, FEAT(attr), attrValue);
7845			r = setAttributeForConnection(0, attr, attrValue);
7846			if (kIOReturnSuccess != r)
7847				ret = r;
7848
7849			attr = kConnectionControllerColorDepth;
7850			attrValue = value;
7851			updatesMode = true;
7852			break;
7853
7854		  case kConnectionControllerDitherControl:
7855
7856			attrValue &= ditherMask;
7857			updatesMode = true;
7858			break;
7859		}
7860
7861		DEBG1(thisName, " (0x%08x '%c%c%c%c')(%x)\n", attr, FEAT(attr), attrValue);
7862
7863		if (updatesMode)
7864		{
7865			r = getAttributeForConnection(0, attr, &lvalue[0]);
7866			if (kIOReturnSuccess != r)
7867				continue;
7868			if (lvalue[0] == attrValue)
7869				continue;
7870		}
7871		r = setAttributeForConnection(0, attr, attrValue);
7872		if (kIOReturnSuccess == r)
7873			__private->modeUpdate |= updatesMode;
7874		else
7875			ret = r;
7876	}
7877
7878	return (ret);
7879}
7880
7881IOReturn IOFramebuffer::extSetProperties( OSDictionary * props )
7882{
7883    OSDictionary * dict;
7884    OSArray *      array;
7885    IOReturn       err = kIOReturnUnsupported;
7886
7887    if ((err = extEntry(true)))
7888        return (err);
7889
7890    err = kIOReturnUnsupported;
7891    if ((dict = OSDynamicCast(OSDictionary, props->getObject(gIOFBConfigKey)))) do
7892    {
7893        setProperty( gIOFBConfigKey, dict );
7894        if (!__private->online)
7895        {
7896            err = kIOReturnSuccess;
7897            break;
7898        }
7899        if (dict->getObject("IOFBScalerUnderscan"))
7900        {
7901            __private->enableScalerUnderscan = true;
7902        }
7903        if ((array = OSDynamicCast(OSArray,
7904                                   dict->getObject(kIOFBDetailedTimingsKey))))
7905            err = setDetailedTimings( array );
7906        else
7907            err = kIOReturnSuccess;
7908    }
7909    while (false);
7910
7911	setDisplayAttributes(props->getObject(kIODisplayAttributesKey));
7912
7913	extExit(err);
7914
7915    return (err);
7916}
7917
7918//// Controller attributes
7919
7920IOReturn IOFramebuffer::setAttribute( IOSelect attribute, uintptr_t value )
7921{
7922    IOReturn        ret;
7923
7924    switch (attribute)
7925    {
7926        case kIOCapturedAttribute:
7927        {
7928            DEBG(thisName, " kIOCapturedAttribute(%ld)\n", value);
7929			if (value != gIOFBCaptureState)
7930			{
7931				gIOFBCaptureState = value;
7932				OSBitOrAtomic(kIOFBEventCaptureSetting, &gIOFBGlobalEvents);
7933				controllerDidWork(__private->controller, kWorkStateChange);
7934			}
7935            ret = kIOReturnSuccess;
7936            break;
7937        }
7938
7939        case kIOCursorControlAttribute:
7940            {
7941                IOFBCursorControlAttribute * crsrControl;
7942
7943                crsrControl = (IOFBCursorControlAttribute *) value;
7944
7945                if (__private->cursorThread)
7946                {
7947                    __private->cursorThread->release();
7948                    __private->cursorThread = 0;
7949                }
7950
7951                if (crsrControl && crsrControl->callouts)
7952                {
7953                    __private->cursorControl = *((IOFBCursorControlAttribute *) value);
7954                    __private->cursorThread = IOInterruptEventSource::interruptEventSource(this, &cursorWork);
7955                    if (__private->controller->wl && __private->cursorThread)
7956                        __private->controller->wl->addEventSource(__private->cursorThread);
7957                }
7958                ret = kIOReturnSuccess;
7959                break;
7960            }
7961
7962		case kIOPowerStateAttribute:
7963            ret = setAttribute(kIOPowerAttribute, value);
7964            break;
7965
7966        case kIOPowerAttribute:
7967            ret = setAttributeExt(attribute, value);
7968            break;
7969
7970        default:
7971            ret = kIOReturnUnsupported;
7972            break;
7973    }
7974
7975    return (ret);
7976}
7977
7978/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7979
7980#if __ppc__
7981static IOReturn
7982ApplePMUSendMiscCommand( UInt32 command,
7983                            IOByteCount sendLength, UInt8 * sendBuffer,
7984                            IOByteCount * readLength, UInt8 * readBuffer )
7985{
7986    struct SendMiscCommandParameterBlock
7987    {
7988        int command;
7989        IOByteCount sLength;
7990        UInt8 *sBuffer;
7991        IOByteCount *rLength;
7992        UInt8 *rBuffer;
7993    };
7994    IOReturn ret = kIOReturnError;
7995    static IOService * pmu;
7996
7997    // See if ApplePMU exists
7998    if (!pmu)
7999    {
8000        OSIterator * iter;
8001        iter = IOService::getMatchingServices(IOService::serviceMatching("ApplePMU"));
8002        if (iter)
8003        {
8004            pmu = (IOService *) iter->getNextObject();
8005            iter->release();
8006        }
8007    }
8008
8009    SendMiscCommandParameterBlock params = { command, sendLength, sendBuffer,
8010                                            readLength, readBuffer };
8011    if (pmu)
8012        ret = pmu->callPlatformFunction( "sendMiscCommand", true,
8013                                            (void*)&params, NULL, NULL, NULL );
8014    return (ret);
8015}
8016#endif
8017
8018/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8019
8020void IOFramebuffer::readClamshellState()
8021{
8022    // zero -> lid open
8023
8024#if __ppc__
8025
8026#define readExtSwitches 0xDC
8027
8028    UInt8 bootEnvIntData[32];
8029    IOByteCount iLen = sizeof(UInt8);
8030
8031    ret = ApplePMUSendMiscCommand(readExtSwitches, 0, NULL, &iLen, &bootEnvIntData[0]);
8032    if (kIOReturnSuccess == ret)
8033    {
8034		gIOFBLastClamshellState = bootEnvIntData[0];
8035    }
8036
8037#elif defined(__i386__) || defined(__x86_64__)
8038    static IOACPIPlatformDevice * lidDevice;
8039    UInt32 lidState;
8040
8041    if (!lidDevice)
8042    {
8043        OSIterator *   iter;
8044        IOService *    service;
8045        OSDictionary * matching;
8046
8047		matching = IOService::nameMatching("PNP0C0D");
8048        iter = IOService::getMatchingServices(matching);
8049        if (matching) matching->release();
8050        if (iter)
8051        {
8052            service = (IOService *)iter->getNextObject();
8053            if (service->metaCast("IOACPIPlatformDevice"))
8054            {
8055                lidDevice = (IOACPIPlatformDevice *) service;
8056                lidDevice->retain();
8057            }
8058            iter->release();
8059        }
8060    }
8061
8062    if (lidDevice)
8063    {
8064    	IOReturn ret;
8065        ret = lidDevice->evaluateInteger("_LID", &lidState);
8066        if (kIOReturnSuccess == ret)
8067            gIOFBLastClamshellState = (lidState == 0);
8068    }
8069#endif
8070
8071    DEBG1("S", " %d\n", (int) gIOFBLastClamshellState);
8072}
8073
8074extern "C" IOReturn
8075IOGetHardwareClamshellState( IOOptionBits * result )
8076{
8077    // zero -> lid open
8078	if (gIOFBDesktopModeAllowed)
8079		*result = gIOFBLastClamshellState;
8080	else
8081		*result = 0;
8082
8083//	gIOFBLastReadClamshellState = gIOFBLastClamshellState;
8084
8085    DEBG1("S", " %d\n", (int) *result);
8086
8087    return (kIOReturnSuccess);
8088}
8089
8090/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8091
8092bool IOFramebuffer::clamshellHandler(void * target, void * ref,
8093                                       IOService * resourceService, IONotifier * notifier)
8094{
8095    gIOResourcesAppleClamshellState = resourceService->getProperty(kAppleClamshellStateKey);
8096    resourceService->removeProperty(kAppleClamshellStateKey);
8097	OSBitOrAtomic(kIOFBEventReadClamshell, &gIOFBGlobalEvents);
8098	startThread(false);
8099	return (true);
8100}
8101
8102/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8103
8104IOReturn IOFramebuffer::getAttribute( IOSelect attribute, uintptr_t * value )
8105{
8106    IOReturn ret = kIOReturnUnsupported;
8107
8108    switch (attribute)
8109    {
8110      case kIOClamshellStateAttribute:
8111        IOOptionBits result;
8112        ret = IOGetHardwareClamshellState( &result );
8113        *value = result;
8114        break;
8115
8116      default:
8117        break;
8118    }
8119
8120    return (ret);
8121}
8122
8123/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8124
8125bool IOFramebuffer::setNumber( OSDictionary * dict, const char * key,
8126                               UInt32 value )
8127{
8128    OSNumber *  num;
8129    bool        ok;
8130
8131    num = OSNumber::withNumber( value, 32 );
8132    if (!num)
8133        return (false);
8134
8135    ok = dict->setObject( key, num );
8136    num->release();
8137
8138    return (ok);
8139}
8140
8141bool IOFramebuffer::serializeInfo( OSSerialize * s )
8142{
8143    IOReturn                    err;
8144    IODisplayModeInformation    info;
8145    IOPixelInformation          pixelInfo;
8146    IODisplayModeID *           modeIDs;
8147    IOItemCount                 modeCount, modeNum, aperture;
8148    IOIndex                     depthNum;
8149    OSDictionary *              infoDict;
8150    OSDictionary *              modeDict;
8151    OSDictionary *              pixelDict;
8152    char                        keyBuf[12];
8153    bool                        ok = true;
8154
8155    modeCount = getDisplayModeCount();
8156    modeIDs = IONew( IODisplayModeID, modeCount );
8157    if (!modeIDs)
8158        return (false);
8159
8160    err = getDisplayModes( modeIDs );
8161    if (err)
8162        return (false);
8163
8164    infoDict = OSDictionary::withCapacity( 10 );
8165    if (!infoDict)
8166        return (false);
8167
8168    for (modeNum = 0; modeNum < modeCount; modeNum++)
8169    {
8170        err = getInformationForDisplayMode( modeIDs[modeNum], &info );
8171        if (err)
8172            continue;
8173
8174        modeDict = OSDictionary::withCapacity( 10 );
8175        if (!modeDict)
8176            break;
8177
8178        ok = setNumber( modeDict, kIOFBWidthKey,
8179                        info.nominalWidth )
8180             && setNumber( modeDict, kIOFBHeightKey,
8181                           info.nominalHeight )
8182             && setNumber( modeDict, kIOFBRefreshRateKey,
8183                           info.refreshRate )
8184             && setNumber( modeDict, kIOFBFlagsKey,
8185                           info.flags );
8186        if (!ok)
8187            break;
8188
8189        for (depthNum = 0; depthNum < info.maxDepthIndex; depthNum++)
8190        {
8191            for (aperture = 0; ; aperture++)
8192            {
8193                err = getPixelInformation( modeIDs[modeNum], depthNum,
8194                                           aperture, &pixelInfo );
8195                if (err)
8196                    break;
8197
8198                pixelDict = OSDictionary::withCapacity( 10 );
8199                if (!pixelDict)
8200                    continue;
8201
8202                ok = setNumber( pixelDict, kIOFBBytesPerRowKey,
8203                                pixelInfo.bytesPerRow )
8204                     && setNumber( pixelDict, kIOFBBytesPerPlaneKey,
8205                                   pixelInfo.bytesPerPlane )
8206                     && setNumber( pixelDict, kIOFBBitsPerPixelKey,
8207                                   pixelInfo.bitsPerPixel )
8208                     && setNumber( pixelDict, kIOFBComponentCountKey,
8209                                   pixelInfo.componentCount )
8210                     && setNumber( pixelDict, kIOFBBitsPerComponentKey,
8211                                   pixelInfo.bitsPerComponent )
8212                     && setNumber( pixelDict, kIOFBFlagsKey,
8213                                   pixelInfo.flags )
8214                     && setNumber( pixelDict, kIOFBWidthKey,
8215                                   pixelInfo.activeWidth )
8216                     && setNumber( pixelDict, kIOFBHeightKey,
8217                                   pixelInfo.activeHeight );
8218                if (!ok)
8219                    break;
8220
8221                snprintf(keyBuf, sizeof(keyBuf), "%x", (int) (depthNum + (aperture << 16)));
8222                modeDict->setObject( keyBuf, pixelDict );
8223                pixelDict->release();
8224            }
8225        }
8226
8227        snprintf(keyBuf, sizeof(keyBuf), "%x", (int) modeIDs[modeNum]);
8228        infoDict->setObject( keyBuf, modeDict );
8229        modeDict->release();
8230    }
8231
8232    IODelete( modeIDs, IODisplayModeID, modeCount );
8233
8234    ok &= infoDict->serialize( s );
8235    infoDict->release();
8236
8237    return (ok);
8238}
8239
8240/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8241
8242OSDefineMetaClassAndStructors(_IOFramebufferNotifier, IONotifier)
8243#define LOCKNOTIFY()
8244#define UNLOCKNOTIFY()
8245
8246void _IOFramebufferNotifier::remove()
8247{
8248    LOCKNOTIFY();
8249
8250    if (whence)
8251    {
8252        whence->removeObject( (OSObject *) this );
8253        whence = 0;
8254    }
8255
8256    fEnable = false;
8257
8258    UNLOCKNOTIFY();
8259
8260    release();
8261}
8262
8263bool _IOFramebufferNotifier::disable()
8264{
8265    bool        ret;
8266
8267    LOCKNOTIFY();
8268    ret = fEnable;
8269    fEnable = false;
8270    UNLOCKNOTIFY();
8271
8272    return (ret);
8273}
8274
8275void _IOFramebufferNotifier::enable( bool was )
8276{
8277    LOCKNOTIFY();
8278    fEnable = was;
8279    UNLOCKNOTIFY();
8280}
8281
8282IONotifier * IOFramebuffer::addFramebufferNotification(
8283    IOFramebufferNotificationHandler handler,
8284    OSObject * self, void * ref)
8285{
8286    _IOFramebufferNotifier *    notify = 0;
8287
8288    notify = new _IOFramebufferNotifier;
8289    if (notify && !notify->init())
8290    {
8291        notify->release();
8292        notify = 0;
8293    }
8294
8295    if (notify)
8296    {
8297        notify->handler = handler;
8298        notify->self = self;
8299        notify->ref = ref;
8300        notify->fEnable = true;
8301
8302		if (__private && __private->controller)
8303			FBLOCK(this);
8304		else
8305			SYSLOCK();
8306        if (0 == fbNotifications)
8307            fbNotifications = OSSet::withCapacity(1);
8308
8309        notify->whence = fbNotifications;
8310        if (fbNotifications)
8311            fbNotifications->setObject( notify );
8312		if (__private && __private->controller)
8313			FBUNLOCK(this);
8314		else
8315			SYSUNLOCK();
8316    }
8317
8318    return (notify);
8319}
8320
8321IOReturn IOFramebuffer::deliverFramebufferNotification(
8322    IOIndex event, void * info )
8323{
8324    OSIterator *                iter;
8325    _IOFramebufferNotifier *    notify;
8326    IOReturn                    ret = kIOReturnSuccess;
8327    IOReturn                    r;
8328
8329#if RLOG1
8330    const char * name = NULL;
8331    switch (event)
8332    {
8333        case kIOFBNotifyDisplayModeWillChange:
8334            name = "kIOFBNotifyDisplayModeWillChange";
8335            break;
8336        case kIOFBNotifyDisplayModeDidChange:
8337            name = "kIOFBNotifyDisplayModeDidChange";
8338            break;
8339        case kIOFBNotifyWillSleep:
8340            name = "kIOFBNotifyWillSleep";
8341            break;
8342        case kIOFBNotifyDidWake:
8343            name = "kIOFBNotifyDidWake";
8344            break;
8345        case kIOFBNotifyDidPowerOff:
8346            name = "kIOFBNotifyDidPowerOff";
8347            break;
8348        case kIOFBNotifyWillPowerOn:
8349            name = "kIOFBNotifyWillPowerOn";
8350            break;
8351        case kIOFBNotifyWillPowerOff:
8352            name = "kIOFBNotifyWillPowerOff";
8353            break;
8354        case kIOFBNotifyDidPowerOn:
8355            name = "kIOFBNotifyDidPowerOn";
8356            break;
8357#if 0
8358        case kIOFBNotifyWillChangeSpeed:
8359            name = "kIOFBNotifyWillChangeSpeed";
8360            break;
8361        case kIOFBNotifyDidChangeSpeed:
8362            name = "kIOFBNotifyDidChangeSpeed";
8363            break;
8364        case kIOFBNotifyDisplayDimsChange:
8365            name = "kIOFBNotifyDisplayDimsChange";
8366            break;
8367#endif
8368        case kIOFBNotifyClamshellChange:
8369            name = "kIOFBNotifyClamshellChange";
8370            break;
8371        case kIOFBNotifyCaptureChange:
8372            name = "kIOFBNotifyCaptureChange";
8373            break;
8374        case kIOFBNotifyOnlineChange:
8375            name = "kIOFBNotifyOnlineChange";
8376            break;
8377    }
8378#endif
8379
8380    LOCKNOTIFY();
8381
8382#if RLOG1
8383    AbsoluteTime startTime, endTime;
8384    uint64_t nsec;
8385	AbsoluteTime_to_scalar(&startTime) = mach_absolute_time();
8386#endif
8387
8388    iter = OSCollectionIterator::withCollection( fbNotifications );
8389
8390    if (iter)
8391    {
8392        while ((notify = (_IOFramebufferNotifier *) iter->getNextObject()))
8393        {
8394            if (notify->fEnable)
8395            {
8396                r = (*notify->handler)( notify->self, notify->ref, this,
8397                                        event, info );
8398                if (kIOReturnSuccess != r)
8399                    ret = r;
8400            }
8401        }
8402        iter->release();
8403    }
8404
8405#if RLOG1
8406	AbsoluteTime_to_scalar(&endTime) = mach_absolute_time();
8407    SUB_ABSOLUTETIME(&endTime, &startTime);
8408    absolutetime_to_nanoseconds(endTime, &nsec);
8409
8410	bool notGated = (!gIOFBSystemWorkLoop->inGate() || !FBWL(this)->inGate());
8411
8412	if (name || notGated)
8413	{
8414    	DEBG1(thisName, " %s(%s(%d), %p) %qd ms\n",
8415                    notGated ? "not gated " : "",
8416                    name ? name : "", (uint32_t) event, info,
8417                    nsec / 1000000ULL);
8418	}
8419#endif
8420
8421    UNLOCKNOTIFY();
8422
8423    return (ret);
8424}
8425
8426/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8427
8428// Some stubs
8429
8430IOReturn IOFramebuffer::enableController ( void )
8431{
8432    return (kIOReturnSuccess);
8433}
8434
8435bool IOFramebuffer::isConsoleDevice( void )
8436{
8437    return (false);
8438}
8439
8440// Set display mode and depth
8441IOReturn IOFramebuffer::setDisplayMode( IODisplayModeID /* displayMode */,
8442                                        IOIndex /* depth */ )
8443{
8444    return (kIOReturnUnsupported);
8445}
8446
8447// For pages
8448IOReturn IOFramebuffer::setApertureEnable(
8449    IOPixelAperture /* aperture */, IOOptionBits /* enable */ )
8450{
8451    return (kIOReturnUnsupported);
8452}
8453
8454// Display mode and depth for startup
8455IOReturn IOFramebuffer::setStartupDisplayMode(
8456    IODisplayModeID /* displayMode */, IOIndex /* depth */ )
8457{
8458    return (kIOReturnUnsupported);
8459}
8460
8461IOReturn IOFramebuffer::getStartupDisplayMode(
8462    IODisplayModeID * /* displayMode */, IOIndex * /* depth */ )
8463{
8464    return (kIOReturnUnsupported);
8465}
8466
8467//// CLUTs
8468
8469IOReturn IOFramebuffer::setCLUTWithEntries(
8470    IOColorEntry * /* colors */, UInt32 /* index */,
8471    UInt32 /* numEntries */, IOOptionBits /* options */ )
8472{
8473    return (kIOReturnUnsupported);
8474}
8475
8476//// Gamma
8477
8478IOReturn IOFramebuffer::setGammaTable( UInt32 /* channelCount */,
8479                                       UInt32 /* dataCount */, UInt32 /* dataWidth */, void * /* data */ )
8480{
8481    return (kIOReturnUnsupported);
8482}
8483
8484
8485//// Display mode timing information
8486
8487IOReturn IOFramebuffer::getTimingInfoForDisplayMode(
8488    IODisplayModeID /* displayMode */,
8489    IOTimingInformation * /* info */ )
8490{
8491    return (kIOReturnUnsupported);
8492}
8493
8494IOReturn IOFramebuffer::validateDetailedTiming(
8495    void * description, IOByteCount descripSize )
8496{
8497    return (kIOReturnUnsupported);
8498}
8499
8500IOReturn IOFramebuffer::setDetailedTimings( OSArray * array )
8501{
8502    return (kIOReturnUnsupported);
8503}
8504
8505//// Connections
8506
8507IOItemCount IOFramebuffer::getConnectionCount( void )
8508{
8509    return (1);
8510}
8511
8512/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8513
8514IOReturn IOFramebuffer::setAttributeExt( IOSelect attribute, uintptr_t value )
8515{
8516	IOReturn err;
8517
8518	FBLOCK(this);
8519
8520	switch (attribute)
8521	{
8522        case kIOPowerAttribute:
8523
8524            DEBG1(thisName, " mux power change %d->%ld, gated %d, thread %d\n",
8525            	pendingPowerState, value,
8526                gIOFBSystemWorkLoop->inGate(), gIOFBSystemWorkLoop->onThread());
8527
8528            if (value != pendingPowerState)
8529            {
8530                pendingPowerState = value;
8531				if (!__private->controllerIndex)
8532				{
8533					__private->controller->pendingMuxPowerChange = true;
8534					startControllerThread(__private->controller);
8535				}
8536            }
8537            err = kIOReturnSuccess;
8538			break;
8539
8540		default:
8541			err = setAttribute(attribute, value);
8542			break;
8543	}
8544
8545	FBUNLOCK(this);
8546	return (err);
8547}
8548
8549IOReturn IOFramebuffer::getAttributeExt( IOSelect attribute, uintptr_t * value )
8550{
8551	IOReturn err;
8552
8553	FBLOCK(this);
8554	err = getAttribute(attribute, value);
8555	switch (attribute)
8556	{
8557		case kIOMirrorAttribute:
8558			if (kIOReturnSuccess != err) *value = 0;
8559			if (__private->nextMirror) *value |= kIOMirrorIsMirrored;
8560			err = kIOReturnSuccess;
8561			break;
8562
8563		default:
8564			break;
8565	}
8566	FBUNLOCK(this);
8567	return (err);
8568}
8569
8570IOReturn IOFramebuffer::setAttributeForConnectionExt( IOIndex connectIndex,
8571           IOSelect attribute, uintptr_t value )
8572{
8573	IOReturn err;
8574
8575	if (opened)
8576		FBLOCK(this);
8577	else
8578		return (kIOReturnNotReady);
8579
8580	if ('\0igr' == attribute)
8581	{
8582		DEBG1(thisName, " 0igr ->0x%lx, gated %d, thread %d\n", value,
8583                gIOFBSystemWorkLoop->inGate(), gIOFBSystemWorkLoop->onThread());
8584		__private->controller->mute = (0 != (value & (1 << 31)));
8585	}
8586
8587	err = setAttributeForConnection(connectIndex, attribute, value);
8588
8589	if (opened)
8590		FBUNLOCK(this);
8591
8592	return (err);
8593}
8594
8595IOReturn IOFramebuffer::getAttributeForConnectionExt( IOIndex connectIndex,
8596        IOSelect attribute, uintptr_t * value )
8597{
8598	IOReturn err;
8599
8600	FBLOCK(this);
8601	err = getAttributeForConnection(connectIndex, attribute, value);
8602	FBUNLOCK(this);
8603
8604	return (err);
8605}
8606
8607/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8608
8609IOReturn IOFramebuffer::getAttributeForConnectionParam( IOIndex connectIndex,
8610        IOSelect attribute, uintptr_t * value )
8611{
8612	IOReturn err;
8613
8614	if (!__private->colorModesAllowed)
8615	{
8616		if (kConnectionColorMode == attribute)
8617			return (kIOReturnUnsupported);
8618		if (kConnectionColorModesSupported == attribute)
8619			return (kIOReturnUnsupported);
8620	}
8621
8622	err = getAttributeForConnection(connectIndex, attribute, value);
8623
8624	return (err);
8625}
8626
8627IOReturn IOFramebuffer::setAttributeForConnectionParam( IOIndex connectIndex,
8628           IOSelect attribute, uintptr_t value )
8629{
8630	IOReturn err;
8631
8632	err = setAttributeForConnection(connectIndex, attribute, value);
8633
8634	return (err);
8635}
8636
8637/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8638
8639IOReturn IOFramebuffer::setAttributeForConnection( IOIndex connectIndex,
8640        IOSelect attribute, uintptr_t info )
8641{
8642    IOReturn err;
8643
8644    switch( attribute )
8645    {
8646        case kConnectionRedGammaScale:
8647            if (info != __private->gammaScale[0])
8648            {
8649                __private->gammaScale[0] = info;
8650                __private->gammaScaleChange = true;
8651            }
8652            err = kIOReturnSuccess;
8653            break;
8654
8655        case kConnectionGreenGammaScale:
8656            if (info != __private->gammaScale[1])
8657            {
8658                __private->gammaScale[1] = info;
8659                __private->gammaScaleChange = true;
8660            }
8661            err = kIOReturnSuccess;
8662            break;
8663
8664        case kConnectionBlueGammaScale:
8665            if (info != __private->gammaScale[2])
8666            {
8667                __private->gammaScale[2] = info;
8668                __private->gammaScaleChange = true;
8669            }
8670            err = kIOReturnSuccess;
8671            break;
8672
8673        case kConnectionGammaScale:
8674            if (info != __private->gammaScale[3])
8675            {
8676                __private->gammaScale[3] = info;
8677                __private->gammaScaleChange = true;
8678            }
8679            err = kIOReturnSuccess;
8680            break;
8681
8682        case kConnectionFlushParameters:
8683			if (__private->gammaScaleChange)
8684			{
8685				__private->gammaScaleChange = false;
8686				updateGammaTable(__private->rawGammaChannelCount, __private->rawGammaDataCount,
8687								 __private->rawGammaDataWidth, __private->rawGammaData);
8688			}
8689            err = kIOReturnSuccess;
8690            break;
8691
8692        case kConnectionAudioStreaming:
8693			__private->audioStreaming = info;
8694			pendingPowerChange = true;
8695			startControllerThread(__private->controller);
8696            err = kIOReturnSuccess;
8697            break;
8698
8699        case kConnectionOverscan:
8700
8701            UInt64 newTransform;
8702            DEBG(thisName, " set oscn %ld, ena %d\n", info, __private->enableScalerUnderscan);
8703            if (info)
8704                newTransform = __private->selectedTransform & ~kIOFBScalerUnderscan;
8705            else
8706                newTransform = __private->selectedTransform | kIOFBScalerUnderscan;
8707            if (__private->enableScalerUnderscan)
8708            {
8709                if (newTransform != __private->selectedTransform)
8710                {
8711                    __private->selectedTransform = newTransform;
8712                    if (!suspended)
8713                        connectChangeInterrupt(this, 0);
8714                    else
8715                    {
8716                        __private->transform = newTransform;
8717                        setProperty(kIOFBTransformKey, newTransform, 64);
8718                    }
8719                }
8720                err = kIOReturnSuccess;
8721                break;
8722            }
8723
8724            /* fall thru */
8725
8726        default:
8727            err = kIOReturnUnsupported;
8728            break;
8729    }
8730
8731    return( err );
8732}
8733
8734IOReturn IOFramebuffer::getAttributeForConnection( IOIndex connectIndex,
8735        IOSelect attribute, uintptr_t * value )
8736{
8737    IOReturn err;
8738    uintptr_t result;
8739
8740    switch( attribute )
8741    {
8742        case kConnectionDisplayParameterCount:
8743            result = 3;		         // 3 gamma rgb scales
8744			if (gIOGFades) result++; // 1 gamma scale
8745            if (__private->enableScalerUnderscan)
8746                result++;
8747            *value = result;
8748            err = kIOReturnSuccess;
8749            break;
8750
8751        case kConnectionDisplayParameters:
8752			result = 0;
8753            value[result++] = kConnectionRedGammaScale;
8754            value[result++] = kConnectionGreenGammaScale;
8755            value[result++] = kConnectionBlueGammaScale;
8756            if (gIOGFades) value[result++] = kConnectionGammaScale;
8757            if (__private->enableScalerUnderscan)
8758                value[result++] = kConnectionOverscan;
8759            err = kIOReturnSuccess;
8760            break;
8761
8762        case kConnectionOverscan:
8763            if (__private->enableScalerUnderscan)
8764            {
8765                value[0] = (0 == (kIOFBScalerUnderscan & __private->selectedTransform));
8766                DEBG(thisName, " oscn %ld (%qx)\n", value[0], __private->selectedTransform);
8767                value[1] = 0;
8768                value[2] = 1;
8769                err = kIOReturnSuccess;
8770            }
8771            else
8772                err = kIOReturnUnsupported;
8773            break;
8774
8775        case kConnectionRedGammaScale:
8776            value[0] = __private->gammaScale[0];
8777            value[1] = 0;
8778            value[2] = (1 << 16);
8779            err = kIOReturnSuccess;
8780            break;
8781
8782        case kConnectionGreenGammaScale:
8783            value[0] = __private->gammaScale[1];
8784            value[1] = 0;
8785            value[2] = (1 << 16);
8786            err = kIOReturnSuccess;
8787            break;
8788
8789        case kConnectionBlueGammaScale:
8790            value[0] = __private->gammaScale[2];
8791            value[1] = 0;
8792            value[2] = (1 << 16);
8793            err = kIOReturnSuccess;
8794            break;
8795
8796        case kConnectionGammaScale:
8797            value[0] = __private->gammaScale[3];
8798            value[1] = 0;
8799            value[2] = (1 << 16);
8800            err = kIOReturnSuccess;
8801            break;
8802
8803        case kConnectionCheckEnable:
8804            err = getAttributeForConnection(connectIndex, kConnectionEnable, value);
8805            break;
8806
8807        case kConnectionSupportsHLDDCSense:
8808            if (__private->lli2c)
8809            {
8810                err = kIOReturnSuccess;
8811                break;
8812            }
8813            // fall thru
8814        default:
8815            err = kIOReturnUnsupported;
8816            break;
8817    }
8818
8819    return( err );
8820}
8821
8822//// HW Cursors
8823
8824IOReturn IOFramebuffer::setCursorImage( void * cursorImage )
8825{
8826    return (kIOReturnUnsupported);
8827}
8828
8829IOReturn IOFramebuffer::setCursorState( SInt32 x, SInt32 y, bool visible )
8830{
8831    return (kIOReturnUnsupported);
8832}
8833
8834void IOFramebuffer::flushCursor( void )
8835{}
8836
8837//// Interrupts
8838
8839IOReturn IOFramebuffer::registerForInterruptType( IOSelect interruptType,
8840        IOFBInterruptProc proc, OSObject * target, void * ref,
8841        void ** interruptRef )
8842{
8843    if ((interruptType != kIOFBMCCSInterruptType) || !__private->dpInterrupts)
8844		return (kIOReturnNoResources);
8845
8846	interruptType = kIOFBMCCSInterruptRegister;
8847	__private->interruptRegisters[interruptType].handler = proc;
8848	__private->interruptRegisters[interruptType].target  = target;
8849	__private->interruptRegisters[interruptType].ref     = ref;
8850	__private->interruptRegisters[interruptType].state   = true;
8851	*interruptRef = &__private->interruptRegisters[interruptType];
8852
8853    return (kIOReturnSuccess);
8854}
8855
8856IOReturn IOFramebuffer::unregisterInterrupt(void * interruptRef)
8857{
8858	uintptr_t index;
8859    IOReturn  err;
8860
8861	index = ((IOFBInterruptRegister *) interruptRef) - &__private->interruptRegisters[0];
8862    if (interruptRef == &__private->interruptRegisters[index])
8863    {
8864        __private->interruptRegisters[index].handler = 0;
8865        err = kIOReturnSuccess;
8866    }
8867    else
8868    {
8869        err = kIOReturnUnsupported;
8870    }
8871
8872    return (err);
8873}
8874
8875IOReturn IOFramebuffer::setInterruptState(void * interruptRef, UInt32 state)
8876{
8877	uintptr_t index;
8878    IOReturn  err;
8879
8880	index = ((IOFBInterruptRegister *) interruptRef) - &__private->interruptRegisters[0];
8881    if (interruptRef == &__private->interruptRegisters[index])
8882    {
8883        __private->interruptRegisters[index].state = state;
8884        err = kIOReturnSuccess;
8885    }
8886    else
8887    {
8888        err = kIOReturnUnsupported;
8889    }
8890
8891    return (err);
8892}
8893
8894// Apple sensing
8895
8896IOReturn IOFramebuffer::getAppleSense(
8897    IOIndex  /* connectIndex */,
8898    UInt32 * /* senseType */,
8899    UInt32 * /* primary */,
8900    UInt32 * /* extended */,
8901    UInt32 * /* displayType */ )
8902{
8903    return (kIOReturnUnsupported);
8904}
8905
8906IOReturn IOFramebuffer::connectFlags( IOIndex /* connectIndex */,
8907                                      IODisplayModeID /* displayMode */, IOOptionBits * /* flags */ )
8908{
8909    return (kIOReturnUnsupported);
8910}
8911
8912//// IOLowLevelDDCSense
8913
8914void IOFramebuffer::setDDCClock( IOIndex /* connectIndex */, UInt32 /* value */ )
8915{}
8916
8917void IOFramebuffer::setDDCData( IOIndex /* connectIndex */, UInt32 /* value */ )
8918{}
8919
8920bool IOFramebuffer::readDDCClock( IOIndex /* connectIndex */ )
8921{
8922    return (false);
8923}
8924
8925bool IOFramebuffer::readDDCData( IOIndex /* connectIndex */ )
8926{
8927    return (false);
8928}
8929
8930IOReturn IOFramebuffer::enableDDCRaster( bool /* enable */ )
8931{
8932    return (kIOReturnUnsupported);
8933}
8934
8935/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8936
8937//// IOHighLevelDDCSense
8938
8939enum { kDDCBlockSize = 128 };
8940
8941bool IOFramebuffer::hasDDCConnect( IOIndex connectIndex )
8942{
8943    return (__private->lli2c);
8944}
8945
8946IOReturn IOFramebuffer::getDDCBlock( IOIndex bus, UInt32 blockNumber,
8947                                        IOSelect blockType, IOOptionBits options,
8948                                        UInt8 * data, IOByteCount * length )
8949{
8950    UInt8               startAddress;
8951    IOReturn            err;
8952    UInt32              badsums, timeouts;
8953    IOI2CBusTiming *    timing = &__private->defaultI2CTiming;
8954
8955    if (!__private->lli2c)
8956        return (kIOReturnUnsupported);
8957
8958    // Assume that we have already attempted to stop DDC1
8959
8960    // Read the requested block (Block 1 is at 0x0, each additional block is at 0x80 offset)
8961    startAddress = kDDCBlockSize * (blockNumber - 1);
8962    if (length)
8963        *length = kDDCBlockSize;
8964
8965    // Attempt to read the DDC data
8966    //  1.      If the error is a timeout, then it will attempt one more time.  If it gets another timeout, then
8967    //          it will return a timeout error to the caller.
8968    //
8969    //  2.  If the error is a bad checksum error, it will attempt to read the block up to 2 more times.
8970    //          If it still gets an error, then it will return a bad checksum error to the caller.
8971    i2cSend9Stops(bus, timing);
8972    badsums = timeouts = 0;
8973    do
8974    {
8975        err = readDDCBlock(bus, timing, 0xa0, startAddress, data);
8976        if (kIOReturnSuccess == err)
8977            break;
8978        IOLog("readDDCBlock returned error\n");
8979        i2cSend9Stops(bus, timing);
8980
8981        // We got an error.   Determine what kind
8982        if (kIOReturnNotResponding == err)
8983        {
8984            IOLog("timeout\n");
8985            timeouts++;
8986        }
8987        else if (kIOReturnUnformattedMedia == err)
8988        {
8989            IOLog("bad sum\n");
8990            badsums++;
8991        }
8992        else
8993            break;
8994    }
8995    while ((timeouts < 2) && (badsums < 4));
8996
8997    return (err);
8998}
8999
9000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9001//
9002//      doI2CRequest(),
9003//
9004
9005IOReturn IOFramebuffer::doI2CRequest( UInt32 bus, IOI2CBusTiming * timing, IOI2CRequest * request )
9006{
9007    IOReturn err = kIOReturnError;      // Assume failure
9008
9009    if (!__private->lli2c)
9010        return (kIOReturnUnsupported);
9011
9012    if (!timing)
9013        timing = &__private->defaultI2CTiming;
9014
9015    if (request->sendTransactionType == kIOI2CSimpleTransactionType)
9016    {
9017        if ( request->sendAddress & 0x01 )
9018        {
9019            // Read Transaction
9020            //
9021            err = i2cReadData(bus, timing, request->sendAddress, request->sendBytes, (UInt8 *) request->sendBuffer);
9022        }
9023        else
9024        {
9025            // Read Transaction
9026            //
9027            err = i2cWriteData(bus, timing, request->sendAddress, request->sendBytes, (UInt8 *) request->sendBuffer);
9028        }
9029    }
9030
9031    // Now, let's check to see if there is a csReplyType
9032    //
9033    if (request->replyTransactionType == kIOI2CDDCciReplyTransactionType )
9034    {
9035        err = i2cReadDDCciData(bus, timing, request->replyAddress, request->replyBytes, (UInt8 *) request->replyBuffer);
9036    }
9037    else if (request->replyTransactionType == kIOI2CSimpleTransactionType )
9038    {
9039        err = i2cReadData(bus, timing, request->replyAddress, request->replyBytes, (UInt8 *) request->replyBuffer);
9040    }
9041
9042    request->result = err;
9043    if (request->completion)
9044        (*request->completion)(request);
9045
9046    err = kIOReturnSuccess;
9047
9048    return (err);
9049}
9050
9051/*
9052    with thanks to:
9053    File:       GraphicsCoreUtils.c
9054    Written by: Sean Williams, Kevin Williams, Fernando Urbina
9055*/
9056
9057/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9058//
9059//      stopDDC1SendCommand(),
9060//
9061//      The VESA spec for DDC says a display in DDC1 will transition from DDC1 to DDC2 when a valid DDC2
9062//      command is received.
9063//      DDC1 constantly spews data on the data line if syncs are active...bad for macintosh sensing
9064//      DDC2 only sends data when requested.
9065//      The VESA spec illustrates the manner to do this.
9066//      Read the first byte of data, send a Nack and a Stop.
9067//      This routine does that.
9068//
9069//      There is a delay of two vertical clock periods where the clock line is forced low. The
9070//      NEC XE15 monitor has a controller that sometimes pulls the clockline low and never releases it.
9071//      This is bad, DDC will fail, and the monitor sensing algorithim will think a mono 1152x870 display
9072//      is attached. This isn't part of the spec but it fixes the NEC XE15.
9073//
9074
9075IOReturn IOFramebuffer::stopDDC1SendCommand(IOIndex bus, IOI2CBusTiming * timing)
9076{
9077    UInt8       data;
9078    IOReturn    err = kIOReturnSuccess;
9079    UInt8       address;
9080
9081    // keep clock line low for 2 vclocks....keeps NEC XE15 from locking clock line low
9082    // 640x480@67hz has a veritcal frequency of 15 ms
9083    // 640x480@60hz has a vertical frequency of 16.7 ms
9084    // Lower the clock line for 34 milliseconds
9085
9086    setDDCClock(bus, kIODDCLow);
9087    IOSleep( 34 );
9088
9089    address = 0;
9090    err = i2cWrite(bus, timing, 0xa0, 1, &address);
9091
9092    if (kIOReturnSuccess == err)
9093    {
9094        i2cStart(bus, timing);
9095
9096        i2cSendByte(bus, timing, 0xa1 );
9097
9098        err = i2cWaitForAck(bus, timing);
9099        if (kIOReturnSuccess == err)
9100            err = i2cReadByte(bus, timing, &data);
9101    }
9102
9103    i2cSendNack(bus, timing);
9104    i2cStop(bus, timing);
9105
9106    return (err);
9107}
9108
9109/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9110//
9111//      i2cReadData()
9112//
9113//      The parameters are described as follows:
9114//
9115//                      -> deviceAddress        device's I2C address
9116//                      -> count                # of bytes to read
9117//                      <- buffer               buffer for the data
9118
9119IOReturn IOFramebuffer::i2cReadData(IOIndex bus, IOI2CBusTiming * timing,
9120                                    UInt8 deviceAddress, UInt8 count, UInt8 * buffer)
9121{
9122    IOReturn    err = kIOReturnError;
9123    UInt32      attempts = 10;
9124
9125    while ((kIOReturnSuccess != err) && (attempts-- > 0))
9126    {
9127        // Attempt to read the I2C data
9128        i2cSend9Stops(bus, timing);
9129        err = i2cRead(bus, timing, deviceAddress, count, buffer);
9130    }
9131
9132    return (err);
9133}
9134
9135/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9136//
9137//      i2cWriteData()
9138//
9139//      The parameters are described as follows:
9140//
9141//                      -> deviceAddress        device's I2C address
9142//                      -> count                # of bytes to read
9143//                      -> buffer               buffer for the data
9144
9145IOReturn IOFramebuffer::i2cWriteData(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 count, UInt8 * buffer)
9146{
9147    IOReturn    err = kIOReturnError;
9148    UInt32      attempts = 10;
9149
9150    while ((kIOReturnSuccess != err) && (attempts-- > 0))
9151    {
9152        // Attempt to write the I2C data
9153        i2cSend9Stops(bus, timing);
9154        err = i2cWrite(bus, timing, deviceAddress, count, buffer);
9155    }
9156
9157    return (err);
9158}
9159
9160/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9161//
9162//      WaitForDDCDataLine()
9163//
9164//      Watch the DDC data line and see if it is toggling. If the data line is toggling, it means
9165//      1) DDC display is connected
9166//      2) DDC controller in the display is ready to receive commands.
9167//
9168//                      -> waitTime             max duration that the DDC data line should be watched
9169
9170void IOFramebuffer::waitForDDCDataLine(IOIndex bus, IOI2CBusTiming * timing, UInt32 waitTime)
9171{
9172    AbsoluteTime        now, expirationTime;
9173    UInt32              dataLine;
9174
9175    setDDCData(bus, kIODDCTristate);            // make sure data line is tristated
9176
9177    // Set up the timeout timer...watch DDC data line for waitTime, see if it changes
9178    clock_interval_to_deadline(waitTime, kMillisecondScale, &expirationTime);
9179
9180    dataLine = readDDCData(bus);                // read present state of dataline
9181
9182    while (true)
9183    {
9184        if (dataLine != readDDCData(bus))
9185            break;
9186
9187        AbsoluteTime_to_scalar(&now) = mach_absolute_time();
9188        if (CMP_ABSOLUTETIME(&now, &expirationTime) > 0)
9189            break;
9190    }
9191}
9192
9193/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9194//
9195//      readDDCBlock()
9196//      Read one block of DDC data
9197//
9198//      The parameters are described as follows:
9199//
9200//                      -> deviceAddress        device's I2C address
9201//                      -> startAddress         start address to get data from
9202//                      <- data                 a block of EDID data
9203
9204IOReturn IOFramebuffer::readDDCBlock(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 startAddress, UInt8 * data)
9205{
9206    IOReturn    err;
9207    UInt32      i;
9208    UInt8       sum = 0;
9209
9210    // First, send the address/data as a write
9211    err = i2cWrite(bus, timing, deviceAddress, 1, &startAddress);
9212    if (kIOReturnSuccess != err)
9213        goto ErrorExit;
9214
9215    // Now, read the I2C data
9216    err = i2cRead(bus, timing, deviceAddress, kDDCBlockSize, data);
9217    if (kIOReturnSuccess != err)
9218        goto ErrorExit;
9219
9220    for (i = 0; i < kDDCBlockSize; i++)
9221        sum += data[i];
9222
9223    if (sum)
9224        err = kIOReturnUnformattedMedia;
9225
9226ErrorExit:
9227
9228    return (err);
9229}
9230
9231/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9232//
9233//      i2cStart()
9234//      Start a I2C transaction
9235
9236void IOFramebuffer::i2cStart(IOIndex bus, IOI2CBusTiming * timing)
9237{
9238    // Generates a Start condition:
9239
9240    // Set DATA and CLK high and enabled
9241    setDDCData(bus, kIODDCHigh);
9242    setDDCClock(bus, kIODDCHigh);
9243
9244    IODelay( 100 );
9245
9246    // Bring DATA low
9247    setDDCData(bus, kIODDCLow);
9248    IODelay( 100 );
9249
9250    // Bring CLK low
9251    setDDCClock(bus, kIODDCLow);
9252    IODelay( 100 );
9253}
9254
9255/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9256//
9257//      i2cStop()
9258
9259void IOFramebuffer::i2cStop(IOIndex bus, IOI2CBusTiming * timing)
9260{
9261    // Generate a low to high transition on DATA
9262    // while SCL is high
9263
9264    // Bring DATA and CLK low
9265    IODelay( 200 );
9266    setDDCData(bus, kIODDCLow);
9267    setDDCClock(bus, kIODDCLow);
9268
9269    IODelay( 100 );
9270
9271    // Bring CLK High
9272    setDDCClock(bus, kIODDCHigh);
9273    IODelay( 200 );
9274
9275    // Bring DATA High
9276    setDDCData(bus, kIODDCHigh);
9277    IODelay( 100 );
9278
9279    // Release Bus
9280
9281    setDDCData(bus, kIODDCTristate);
9282    setDDCClock(bus, kIODDCTristate);
9283}
9284
9285/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9286//
9287//      i2cSendAck()
9288//      Send an ACK to acknowledge we received the data
9289
9290void IOFramebuffer::i2cSendAck(IOIndex bus, IOI2CBusTiming * timing)
9291{
9292    // Here, we have to make sure that the CLK is low while
9293    // we bring DATA low and pulse CLK
9294    setDDCClock(bus, kIODDCLow);
9295
9296    // This routine will release the bus by
9297    // tristating the CLK and DATA lines
9298    IODelay(20);
9299
9300    // should we wait for the SDA to be high before going on???
9301
9302    IODelay( 40 );
9303
9304    // Bring SDA low
9305    setDDCData(bus, kIODDCLow);
9306    IODelay( 100 );
9307
9308    // pulse the CLK
9309    setDDCClock(bus, kIODDCHigh);
9310    IODelay( 200 );
9311    setDDCClock(bus, kIODDCLow);
9312    IODelay( 40 );
9313
9314    // Release SDA,
9315    setDDCData(bus, kIODDCTristate);
9316}
9317
9318/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9319//
9320//      i2cSendNack()
9321//      Send an ACK to acknowledge we received the data
9322
9323void IOFramebuffer::i2cSendNack(IOIndex bus, IOI2CBusTiming * timing)
9324{
9325    // Here, we have to make sure that the CLK is low while
9326    // we bring DATA high and pulse CLK
9327    setDDCClock(bus, kIODDCLow);
9328
9329    // This routine will release the bus by
9330    // tristating the CLK and DATA lines
9331    IODelay( 20 );
9332    // should we wait for the SDA to be high before going on???
9333
9334    IODelay( 40 );
9335
9336    // Bring SDA high
9337    setDDCData(bus, kIODDCHigh);
9338    IODelay( 100 );
9339
9340    // pulse the CLK
9341    setDDCClock(bus, kIODDCHigh);
9342    IODelay( 200 );
9343    setDDCClock(bus, kIODDCLow);
9344    IODelay( 40 );
9345
9346    // Release SDA,
9347    setDDCData(bus, kIODDCTristate);
9348    IODelay( 100 );
9349    IODelay( 100 );
9350}
9351
9352/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9353//
9354//      i2cWaitForAck()
9355//      This routine will poll the SDA line looking for a LOW value and when it finds it, it will pulse
9356//      the CLK.
9357
9358IOReturn IOFramebuffer::i2cWaitForAck(IOIndex bus, IOI2CBusTiming * timing)
9359{
9360    AbsoluteTime        now, expirationTime;
9361    IOReturn            err = kIOReturnSuccess;
9362
9363    IODelay( 40 );
9364
9365    // Set up a watchdog timer that will time us out, in case we never see the SDA LOW.
9366    clock_interval_to_deadline(1, kMillisecondScale, &expirationTime);
9367
9368    while ((0 != readDDCData(bus)) && (kIOReturnSuccess == err))
9369    {
9370        AbsoluteTime_to_scalar(&now) = mach_absolute_time();
9371        if (CMP_ABSOLUTETIME(&now, &expirationTime) > 0)
9372            err = kIOReturnNotResponding;                               // Timed Out
9373    }
9374
9375    // OK, now pulse the clock (SDA is not enabled), the CLK
9376    // should be low here.
9377    IODelay( 40 );
9378    setDDCClock(bus, kIODDCHigh);
9379    IODelay( 200 );
9380    setDDCClock(bus, kIODDCLow);
9381    IODelay( 40 );
9382
9383    return (err);
9384}
9385
9386/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9387//
9388//      i2cSendByte()
9389//      Send a byte of data
9390//
9391
9392void IOFramebuffer::i2cSendByte(IOIndex bus, IOI2CBusTiming * timing, UInt8 data)
9393{
9394    UInt8       valueToSend;
9395    int         i;
9396
9397    // CLK should be low when entering this routine
9398    // and will be low when exiting
9399
9400    for ( i = 0 ; i < 8; i++ )
9401    {
9402        // Wait a bit
9403        IODelay( 100 );
9404
9405        // Get the bit
9406        valueToSend = ( data >> (7 - i)) & 0x01;
9407
9408        // Send it out
9409        setDDCData(bus, valueToSend);
9410
9411        // Wait for 40 us and then pulse the clock
9412
9413        IODelay( 40 );
9414        // Raise the CLK line
9415        setDDCClock(bus, kIODDCHigh);
9416
9417        IODelay( 200 );
9418        // Lower the clock line
9419        setDDCClock(bus, kIODDCLow);
9420
9421        // Wait a bit
9422        IODelay( 40 );
9423    }
9424
9425    // Tristate the DATA while keeping CLK low
9426    setDDCData(bus, kIODDCTristate);
9427}
9428
9429/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9430//
9431//      i2cReadByte()
9432//      Read a byte of data
9433
9434IOReturn IOFramebuffer::i2cReadByte(IOIndex bus, IOI2CBusTiming * timing, UInt8 *data)
9435{
9436    AbsoluteTime        now, expirationTime;
9437    IOReturn            err = kIOReturnSuccess;
9438    UInt32              i;
9439    UInt32              value;
9440
9441    // Make sure that DATA is Tristated and that Clock is low
9442    setDDCClock(bus, kIODDCLow);
9443    setDDCData(bus, kIODDCTristate);
9444
9445    for (i = 0 ; (kIOReturnSuccess == err) && (i < 8); i++)
9446    {
9447        // Wait for 1 msec and then pulse the clock
9448        IODelay( 100 );
9449        // Release the CLK line
9450        setDDCClock(bus, kIODDCTristate);
9451
9452        // Wait for a slow device by reading the SCL line until it is high
9453        // (A slow device will keep it low).  The DDC spec suggests a timeout
9454        // of 2ms here.
9455        // Setup for a timeout
9456        clock_interval_to_deadline(2, kMillisecondScale, &expirationTime);
9457
9458        while ((0 == readDDCClock(bus)) && (kIOReturnSuccess == err))
9459        {
9460            AbsoluteTime_to_scalar(&now) = mach_absolute_time();
9461            if (CMP_ABSOLUTETIME(&now, &expirationTime) > 0)
9462                err = kIOReturnNotResponding;                   // Timed Out
9463        }
9464
9465        // Read the data
9466        value = readDDCData(bus);
9467        *data |= (value << (7-i));
9468
9469        //we keep clock high for when sending bits....so do same here. Ensures display sees clock.
9470        // reach 100% success rate with NEC XE15
9471
9472        IODelay( 200 );
9473        // Lower the clock line
9474        setDDCClock(bus, kIODDCLow);
9475        IODelay( 40 );
9476    }
9477
9478    return (err);
9479}
9480
9481/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9482//
9483//      i2cWaitForBus()
9484//      Tristate DDC Clk and DDC Data lines
9485
9486IOReturn IOFramebuffer::i2cWaitForBus(IOIndex bus, IOI2CBusTiming * timing)
9487{
9488    // should we wait for the bus here?
9489
9490    setDDCClock(bus, kIODDCTristate);
9491    setDDCData(bus, kIODDCTristate);
9492    IODelay( 200 );
9493
9494    return kIOReturnSuccess;
9495}
9496
9497/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9498//
9499//      i2cReadDDCciData()
9500//
9501//      The parameters are described as follows:
9502//
9503//                      -> deviceAddress                                device's I2C address
9504//                      -> count                                                # of bytes to read
9505//                      <- buffer                                               buffer for the data
9506//
9507
9508IOReturn IOFramebuffer::i2cReadDDCciData(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 count, UInt8 *buffer)
9509{
9510    // This is a funky call that encodes the length of the transaction in the response.
9511    // According to the VESA DDC/ci spec, the low 7 bits of second byte returned by the display
9512    // will contain the length of the message less the checksum.  The card should then attempt to read
9513    // that length plus the checksum but should not exceed "count" bytes.
9514    // If the size exceeds "count", then the buffer should be filled with "count" bytes and the
9515    // transaction should be completed without copying more bytes into the buffer.
9516
9517    IOReturn    err = kIOReturnSuccess;
9518    UInt32      i;
9519    UInt8       readLength;
9520    UInt32      bufferSize;
9521    Boolean     reportShortRead = false;
9522
9523    // Assume that the bufferSize == count
9524    bufferSize = count;
9525
9526    err = i2cWaitForBus(bus, timing);
9527    if( kIOReturnSuccess != err ) goto ErrorExit;
9528
9529    i2cStart(bus, timing);
9530
9531    i2cSendByte(bus, timing, deviceAddress | 0x01 );
9532
9533    err = i2cWaitForAck(bus, timing);
9534    if( kIOReturnSuccess != err ) goto ErrorExit;
9535
9536    for ( i = 0; i < bufferSize; i++ )
9537    {
9538        err = i2cReadByte(bus, timing, &buffer[i] );
9539        if( kIOReturnSuccess != err ) goto ErrorExit;
9540
9541        i2cSendAck(bus, timing);
9542
9543        if ( i == 1 )
9544        {
9545            // We have read the 2nd byte, so adjust the
9546            // bufferSize accordingly
9547            //
9548            readLength = buffer[i] & 0x07;
9549            if ( (readLength + 1) <= count )
9550            {
9551                // The read amount is less than our bufferSize, so
9552                // adjust that size
9553                //
9554                bufferSize = (readLength + 1);
9555            }
9556            else
9557            {
9558                // The amount to read  > than our bufferSize
9559                // so only read up to our buffer size and remember to
9560                // report that we didn't read all the data
9561                //
9562                reportShortRead = true;
9563            }
9564        }
9565    }
9566
9567
9568ErrorExit:
9569    i2cSendNack(bus, timing);
9570    i2cStop(bus, timing);
9571
9572    if ( reportShortRead )
9573            err = kIOReturnOverrun;
9574
9575    return (err);
9576
9577}
9578
9579/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9580//
9581//      i2cRead()
9582//      Read a bunch of data via I2C
9583//
9584//      The parameters are described as follows:
9585//
9586//                      -> deviceAddress                device's I2C address
9587//                      -> numberOfBytes                number of bytes to read
9588//                      <- data                         the requested number of bytes of data
9589
9590IOReturn IOFramebuffer::i2cRead(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 numberOfBytes, UInt8 * data)
9591{
9592    IOReturn    err = kIOReturnSuccess;
9593    int         i;
9594
9595    err = i2cWaitForBus(bus, timing);
9596    if (kIOReturnSuccess != err)
9597        goto ErrorExit;
9598
9599    i2cStart(bus, timing);
9600
9601    i2cSendByte(bus, timing, deviceAddress | 0x01 );
9602
9603    err = i2cWaitForAck(bus, timing);
9604    if (kIOReturnSuccess != err)
9605        goto ErrorExit;
9606
9607    for (i = 0; i < numberOfBytes; i++)
9608    {
9609        data[i] = 0;
9610        err = i2cReadByte(bus, timing, &data[i] );
9611        if (kIOReturnSuccess != err)
9612            break;
9613        if (i != (numberOfBytes - 1))
9614            i2cSendAck(bus, timing);
9615    }
9616
9617ErrorExit:
9618    i2cSendNack(bus, timing);
9619    i2cStop(bus, timing);
9620
9621    return (err);
9622}
9623
9624
9625/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9626//
9627//      i2cWrite()
9628//      Write a bunch of data via I2C
9629//
9630//      The parameters are described as follows:
9631//
9632//                      -> deviceAddress                device's I2C address
9633//                      -> numberOfBytes                number of bytes to write
9634//                      -> data                         the number of bytes of data
9635
9636IOReturn IOFramebuffer::i2cWrite(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 numberOfBytes, UInt8 * data)
9637{
9638    IOReturn    err = kIOReturnSuccess;
9639    UInt32      i;
9640
9641    err = i2cWaitForBus(bus, timing);
9642    if (kIOReturnSuccess != err)
9643        goto ErrorExit;
9644
9645    i2cStart(bus, timing);
9646
9647    i2cSendByte(bus, timing, deviceAddress);
9648
9649    err = i2cWaitForAck(bus, timing);
9650    if (kIOReturnSuccess != err)
9651        goto ErrorExit;
9652
9653    for (i = 0; i < numberOfBytes; i++)
9654    {
9655        i2cSendByte(bus, timing, data[i] );
9656        err = i2cWaitForAck(bus, timing);
9657        if (kIOReturnSuccess != err)
9658            break;
9659    }
9660
9661
9662ErrorExit:
9663
9664    if (kIOReturnSuccess != err)
9665        i2cStop(bus, timing);
9666
9667    return (err);
9668}
9669
9670/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9671
9672//
9673//      i2cSend9Stops()
9674//
9675//      Assume we are reading the DDC data, and display misses a few clocks, we send ack, display misses ack
9676//      The display might still be holding down the data line. Whenever we get an error, send nine stops.
9677//      If the display is waiting for a clock before going to the next bit, the stop will be interpreted
9678//      as a clock. It will go onto the next bit. Whenever it has finished writing the eigth bit, the
9679//      next stop will look like a stop....the display will release the bus.
9680//      8 bits, 9 stops. The display should see at least one stop....
9681
9682void IOFramebuffer::i2cSend9Stops(IOIndex bus, IOI2CBusTiming * timing)
9683{
9684    for (UInt32 i = 0; i < 9; i++)
9685        i2cStop(bus, timing);
9686}
9687
9688/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9689/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9690
9691IOReturn IOFramebuffer::setPreferences( IOService * props, OSDictionary * prefs )
9692{
9693    if (!gIOFBPrefs)
9694    {
9695        prefs->retain();
9696        gIOFBPrefs = prefs;
9697        gIOFBPrefsParameters = OSDynamicCast(OSDictionary,
9698                                        props->getProperty(kIOGraphicsPrefsParametersKey));
9699        gIOFBIgnoreParameters = OSDynamicCast(OSDictionary,
9700                                        props->getProperty(kIOGraphicsIgnoreParametersKey));
9701
9702    }
9703    return (kIOReturnSuccess);
9704}
9705
9706OSObject * IOFramebuffer::copyPreferences( void )
9707{
9708    if (gIOFBPrefsSerializer)
9709        gIOFBPrefsSerializer->retain();
9710    return (gIOFBPrefsSerializer);
9711}
9712
9713OSObject * IOFramebuffer::copyPreference( IODisplay * display, const OSSymbol * key )
9714{
9715    OSDictionary *   dict;
9716    OSObject *       value = 0;
9717
9718    if (!gIOFBPrefs)
9719        return (value);
9720
9721	if (!__private->displayPrefKey && display)
9722		__private->displayPrefKey = (const OSSymbol *) display->copyProperty(kIODisplayPrefKeyKey);
9723    if (!__private->displayPrefKey)
9724        return (value);
9725
9726    if ((dict = OSDynamicCast(OSDictionary, gIOFBPrefs->getObject(__private->displayPrefKey))))
9727    {
9728        value = dict->getObject(key);
9729        if (value)
9730            value->retain();
9731    }
9732
9733    return (value);
9734}
9735
9736bool IOFramebuffer::getIntegerPreference( IODisplay * display, const OSSymbol * key, UInt32 * value )
9737{
9738    bool found = false;
9739    OSObject *
9740    pref = copyPreference(display, key);
9741    if (pref)
9742    {
9743        OSNumber * num;
9744        if ((num = OSDynamicCast(OSNumber, pref)))
9745        {
9746            value[0] = num->unsigned32BitValue();
9747            DEBG1(thisName, " found(%s) %s = %d\n", __private->displayPrefKey->getCStringNoCopy(),
9748            										key->getCStringNoCopy(), (uint32_t) value[0]);
9749            found = true;
9750        }
9751        pref->release();
9752    }
9753    return (found);
9754}
9755
9756bool IOFramebuffer::setPreference( IODisplay * display, const OSSymbol * key, OSObject * value )
9757{
9758    OSDictionary *   dict;
9759    OSObject *       oldValue = 0;
9760    bool             madeChanges = false;
9761
9762    if (!gIOFBPrefs)
9763        return (false);
9764
9765	if (!__private->displayPrefKey && display)
9766		__private->displayPrefKey = (const OSSymbol *) display->copyProperty(kIODisplayPrefKeyKey);
9767
9768	if (!__private->displayPrefKey)
9769		return (false);
9770
9771    dict = OSDynamicCast(OSDictionary, gIOFBPrefs->getObject(__private->displayPrefKey));
9772    if (!dict)
9773    {
9774        dict = OSDictionary::withCapacity(4);
9775        if (dict)
9776        {
9777            gIOFBPrefs->setObject(__private->displayPrefKey, dict);
9778            dict->release();
9779            madeChanges = true;
9780        }
9781    }
9782    else if (key)
9783        oldValue = dict->getObject(key);
9784
9785	if (dict
9786	 && !gIOGraphicsPrefsVersionValue->isEqualTo(dict->getObject(gIOGraphicsPrefsVersionKey)))
9787	{
9788		dict->setObject(gIOGraphicsPrefsVersionKey, gIOGraphicsPrefsVersionValue);
9789		madeChanges = true;
9790	}
9791
9792    if (key && dict)
9793    {
9794        if (!oldValue || (!oldValue->isEqualTo(value)))
9795        {
9796            dict->setObject(key, value);
9797            madeChanges = true;
9798        }
9799    }
9800
9801    if (madeChanges)
9802    {
9803        DEBG(thisName, " sched prefs\n");
9804        gIOFBDelayedPrefsEvent->setTimeoutMS((UInt32) 2000);
9805    }
9806
9807    return (true);
9808}
9809
9810bool IOFramebuffer::setIntegerPreference( IODisplay * display, const OSSymbol * key, UInt32 value )
9811{
9812    bool ok = false;
9813    OSNumber *
9814    num = OSNumber::withNumber(value, 32);
9815    if (num)
9816    {
9817        ok = setPreference(display, key, num);
9818        num->release();
9819    }
9820    DEBG("", " %s = %d\n", key->getCStringNoCopy(), (uint32_t) value);
9821    return (ok);
9822}
9823
9824void IOFramebuffer::getTransformPrefs( IODisplay * display )
9825{
9826	OSObject * obj;
9827    UInt32     value;
9828
9829	if ((obj = copyPreference(display, gIOFBStartupModeTimingKey)))
9830		setProperty(gIOFBStartupModeTimingKey, obj);
9831
9832    if (getIntegerPreference(display, gIODisplayOverscanKey, &value))
9833    {
9834        if (value)
9835             __private->selectedTransform  = __private->selectedTransform & ~kIOFBScalerUnderscan;
9836        else
9837            __private->selectedTransform = __private->selectedTransform | kIOFBScalerUnderscan;
9838    }
9839
9840    if (__private->userSetTransform)
9841    {
9842        __private->userSetTransform = false;
9843        setIntegerPreference(display, gIOFBRotateKey, __private->selectedTransform & ~kIOFBScalerUnderscan);
9844    }
9845    else if (getIntegerPreference(display, gIOFBRotateKey, &value))
9846        selectTransform(value, false);
9847    else if (__private->transform & ~kIOFBScalerUnderscan)
9848        selectTransform(0, false);
9849}
9850
9851/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9852/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9853
9854#undef super
9855#define super IODisplayParameterHandler
9856
9857OSDefineMetaClassAndStructors(IOFramebufferParameterHandler, IODisplayParameterHandler)
9858
9859/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9860
9861IOFramebufferParameterHandler * IOFramebufferParameterHandler::withFramebuffer( IOFramebuffer * framebuffer )
9862{
9863    IOFramebufferParameterHandler * handler;
9864    uintptr_t                       count = 0;
9865
9866    if ((kIOReturnSuccess != framebuffer->getAttributeForConnection(
9867                                    0, kConnectionDisplayParameterCount, &count)))
9868        return (0);
9869
9870    handler = new IOFramebufferParameterHandler;
9871    if (handler && !handler->init())
9872    {
9873        handler->release();
9874        handler = 0;
9875    }
9876    if (handler)
9877        handler->fFramebuffer = framebuffer;
9878
9879    return (handler);
9880}
9881
9882void IOFramebufferParameterHandler::free()
9883{
9884    if (fDisplayParams)
9885        fDisplayParams->release();
9886
9887    super::free();
9888}
9889
9890bool IOFramebufferParameterHandler::setDisplay( IODisplay * display )
9891{
9892    fDisplay = display;
9893
9894    fFramebuffer->setPreference(display, 0, 0);         // register display
9895
9896    if (!display)
9897        return (false);
9898
9899    fFramebuffer->getTransformPrefs(display);
9900
9901    return (true);
9902}
9903
9904void IOFramebufferParameterHandler::displayModeChange( void )
9905{
9906    IODisplay *      display = fDisplay;
9907    IOReturn         ret;
9908    uintptr_t        count = 0;
9909    UInt32           str[2];
9910    const OSSymbol * sym;
9911    uintptr_t        value[16];
9912    uintptr_t *      attributes;
9913    OSDictionary *   allParams;
9914    OSDictionary *   newDict = 0;
9915    OSDictionary *   oldParams;
9916    const OSSymbol * key;
9917    OSIterator *     iter;
9918
9919    if (!display)
9920        return;
9921
9922    allParams = OSDynamicCast(OSDictionary, display->copyProperty(gIODisplayParametersKey));
9923    if (allParams)
9924    {
9925        newDict = OSDictionary::withDictionary(allParams);
9926        allParams->release();
9927    }
9928
9929    ret = fFramebuffer->getAttributeForConnectionParam(
9930                            0, kConnectionDisplayParameterCount, &count);
9931    if (kIOReturnSuccess != ret)
9932        count = 0;
9933
9934    DEBG(fFramebuffer->thisName, " (%x) count %ld\n", ret, count);
9935
9936    oldParams = fDisplayParams;
9937    do
9938    {
9939        if (count)
9940            fDisplayParams = OSDictionary::withCapacity(count);
9941        else
9942            fDisplayParams = 0;
9943        if (!fDisplayParams)
9944            continue;
9945
9946        attributes = IONew(uintptr_t, count);
9947        if (!attributes)
9948            continue;
9949
9950        if (kIOReturnSuccess != fFramebuffer->getAttributeForConnection(
9951                                        0, kConnectionDisplayParameters, attributes))
9952            continue;
9953
9954        str[1] = 0;
9955        for (uint32_t i = 0; i < count; i++)
9956        {
9957            DEBG1(fFramebuffer->thisName, " [%d] 0x%08lx '%c%c%c%c'\n", i, attributes[i], FEAT(attributes[i]));
9958
9959            if (attributes[i] < 0x00ffffff)
9960                continue;
9961
9962            OSWriteBigInt32(str, 0, attributes[i]);
9963            sym = OSSymbol::withCString((const char *) str);
9964            if (!sym)
9965                continue;
9966
9967			if ((!gIOFBIgnoreParameters || !gIOFBIgnoreParameters->getObject(sym))
9968			 && (kIOReturnSuccess == fFramebuffer->getAttributeForConnectionParam(0, attributes[i], &value[0])))
9969            {
9970            	OSObject * obj;
9971
9972				DEBG1(fFramebuffer->thisName, " [%d] drvr  %s = %ld, (%ld - %ld)\n", i, (const char *) str, value[0], value[1], value[2]);
9973
9974                if (gIOFBPrefsParameters && (obj = gIOFBPrefsParameters->getObject(sym)))
9975                {
9976					OSNumber * prefDefault = NULL;
9977                    UInt32     pref;
9978
9979                    if ((fFramebuffer->getIntegerPreference(display, sym, &pref))
9980					 || (prefDefault = OSDynamicCast(OSNumber, obj)))
9981					{
9982						if (prefDefault)
9983							pref = prefDefault->unsigned32BitValue();
9984						if (pref < value[1])
9985							pref = value[1];
9986						if (pref > value[2])
9987							pref = value[2];
9988						value[0] = pref;
9989					}
9990                }
9991				if (kConnectionColorMode == attributes[i])
9992				{
9993					IODisplay::addParameter(fDisplayParams, gIODisplaySelectedColorModeKey, 0, kIODisplayColorModeRGBLimited);
9994					IODisplay::setParameter(fDisplayParams, gIODisplaySelectedColorModeKey, kIODisplayColorModeRGB);
9995				}
9996                IODisplay::addParameter(fDisplayParams, sym, value[1], value[2]);
9997				IODisplay::setParameter(fDisplayParams, sym, value[0]);
9998            }
9999            DEBG1(fFramebuffer->thisName, " [%d] added %s = %ld, (%ld - %ld)\n", i, (const char *) str, value[0], value[1], value[2]);
10000            sym->release();
10001        }
10002
10003        IODelete(attributes, uintptr_t, count);
10004    }
10005    while (false);
10006
10007    if (oldParams)
10008    {
10009        if (newDict)
10010        {
10011            iter = OSCollectionIterator::withCollection(oldParams);
10012            if (iter)
10013            {
10014                while ((key = (const OSSymbol *) iter->getNextObject()))
10015                {
10016                    if (!fDisplayParams || !fDisplayParams->getObject(key))
10017                        newDict->removeObject(key);
10018                }
10019                iter->release();
10020            }
10021        }
10022        oldParams->release();
10023    }
10024
10025    if (newDict)
10026    {
10027        if (fDisplayParams)
10028            newDict->merge(fDisplayParams);
10029        display->setProperty(gIODisplayParametersKey, newDict);
10030        newDict->release();
10031    }
10032    else if (fDisplayParams)
10033        display->setProperty(gIODisplayParametersKey, fDisplayParams);
10034}
10035
10036bool IOFramebufferParameterHandler::doIntegerSet( OSDictionary * params,
10037                               const OSSymbol * paramName, UInt32 value )
10038{
10039    UInt32      attribute;
10040    bool        ok;
10041    SInt32      min, max;
10042
10043    fFramebuffer->fbLock();
10044
10045    if (fDisplayParams && fDisplayParams->getObject(paramName))
10046    {
10047        if (fDisplay
10048        	&& gIOFBPrefsParameters
10049        	&& gIOFBPrefsParameters->getObject(paramName)
10050			&& (params = IODisplay::getIntegerRange(fDisplayParams, paramName, 0, &min, &max))
10051        	&& (min != max))
10052		{
10053            fFramebuffer->setIntegerPreference(fDisplay, paramName, value);
10054		}
10055
10056        attribute = OSReadBigInt32(paramName->getCStringNoCopy(), 0);
10057
10058		if (kConnectionColorMode == attribute)
10059		{
10060			if ((kIODisplayColorModeAuto == value)
10061				&& (AUTO_COLOR_MODE != kIODisplayColorModeRGB)
10062				&& fFramebuffer->__private->colorModesAllowed
10063				&& (AUTO_COLOR_MODE & fFramebuffer->__private->colorModesSupported))
10064			{
10065				value = AUTO_COLOR_MODE;
10066			}
10067			else
10068			{
10069				value = kIODisplayColorModeRGB;
10070			}
10071			IODisplay::setParameter(fDisplayParams, gIODisplaySelectedColorModeKey, value);
10072		}
10073
10074        ok = (kIOReturnSuccess == fFramebuffer->setAttributeForConnectionParam(
10075                                        0, attribute, value));
10076
10077		DEBG1(fFramebuffer->thisName, "(%d) %s = %d\n", ok, paramName->getCStringNoCopy(), (int) value);
10078    }
10079    else
10080        ok = false;
10081
10082    if (gIODisplayParametersFlushKey == paramName)
10083    {
10084	    fFramebuffer->setAttributeForConnectionParam(0, kConnectionFlushParameters, true);
10085	}
10086
10087    fFramebuffer->fbUnlock();
10088
10089    return (ok);
10090}
10091
10092bool IOFramebufferParameterHandler::doDataSet( const OSSymbol * paramName, OSData * value )
10093{
10094    return (false);
10095}
10096
10097bool IOFramebufferParameterHandler::doUpdate( void )
10098{
10099    bool ok = true;
10100
10101    return (ok);
10102}
10103
10104/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10105
10106void IOFramebuffer::dpInterruptProc(OSObject * target, void * ref)
10107{
10108    IOFramebuffer * self = (IOFramebuffer *) target;
10109    uintptr_t       delay = (uintptr_t) ref;
10110
10111    if (delay && self->__private->dpInterruptES)
10112        self->__private->dpInterruptES->setTimeoutMS(delay);
10113}
10114
10115void IOFramebuffer::dpInterrupt(OSObject * owner, IOTimerEventSource * sender)
10116{
10117    IOFramebuffer * self = (IOFramebuffer *) owner;
10118    self->dpProcessInterrupt();
10119}
10120
10121void IOFramebuffer::dpProcessInterrupt(void)
10122{
10123    IOReturn     err;
10124    IOI2CRequest request;
10125    UInt8        data[6];
10126    uintptr_t    bits, sel;
10127
10128    if (__private->closed || !pagingState)
10129        return;
10130
10131    sel = kIODPEventStart;
10132    err = setAttributeForConnection(0, kConnectionHandleDisplayPortEvent, (uintptr_t) &sel);
10133
10134    bzero(&data[0], sizeof(data));
10135    do
10136    {
10137        bzero( &request, sizeof(request) );
10138
10139        request.commFlags               = 0;
10140        request.sendAddress             = 0;
10141        request.sendTransactionType     = kIOI2CNoTransactionType;
10142        request.sendBuffer              = NULL;
10143        request.sendBytes               = 0;
10144
10145        request.replyAddress            = kDPRegisterLinkStatus;
10146        request.replyTransactionType    = kIOI2CDisplayPortNativeTransactionType;
10147        request.replyBuffer             = (vm_address_t) &data[0];
10148        request.replyBytes              = sizeof(data);
10149
10150        err = doI2CRequest(__private->dpBusID, 0, &request);
10151        if( (kIOReturnSuccess != err) || (kIOReturnSuccess != request.result))
10152            break;
10153
10154        bits = data[1];
10155        if (!bits)
10156          break;
10157        DEBG1(thisName, "dp events: 0x%02lx\n", bits);
10158
10159        if (kDPIRQRemoteControlCommandPending & bits)
10160        {
10161            sel = kIODPEventRemoteControlCommandPending;
10162            err = setAttributeForConnection(0, kConnectionHandleDisplayPortEvent, (uintptr_t) &sel);
10163        }
10164        if (kDPIRQAutomatedTestRequest & bits)
10165        {
10166            sel = kIODPEventAutomatedTestRequest;
10167            err = setAttributeForConnection(0, kConnectionHandleDisplayPortEvent, (uintptr_t) &sel);
10168        }
10169        if (kDPIRQContentProtection & bits)
10170        {
10171            sel = kIODPEventContentProtection;
10172            err = setAttributeForConnection(0, kConnectionHandleDisplayPortEvent, (uintptr_t) &sel);
10173        }
10174        if (kDPIRQMCCS & bits)
10175        {
10176            sel = kIODPEventMCCS;
10177            err = setAttributeForConnection(0, kConnectionHandleDisplayPortEvent, (uintptr_t) &sel);
10178
10179			IOFBInterruptProc proc;
10180			if ((proc = __private->interruptRegisters[kIOFBMCCSInterruptRegister].handler)
10181				&& __private->interruptRegisters[kIOFBMCCSInterruptRegister].state)
10182			{
10183				(*proc)(__private->interruptRegisters[kIOFBMCCSInterruptRegister].target,
10184						__private->interruptRegisters[kIOFBMCCSInterruptRegister].ref);
10185			}
10186        }
10187        if (kDPIRQSinkSpecific & bits)
10188        {
10189            sel = kIODPEventSinkSpecific;
10190            err = setAttributeForConnection(0, kConnectionHandleDisplayPortEvent, (uintptr_t) &sel);
10191        }
10192
10193        request.sendAddress             = kDPRegisterServiceIRQ;
10194        request.sendTransactionType     = kIOI2CDisplayPortNativeTransactionType;
10195        request.sendBuffer              = (vm_address_t) &data[1];
10196        request.sendBytes               = sizeof(data[1]);
10197
10198        request.replyAddress            = kDPRegisterLinkStatus;
10199        request.replyTransactionType    = kIOI2CDisplayPortNativeTransactionType;
10200        request.replyBuffer             = (vm_address_t) &data[0];
10201        request.replyBytes              = sizeof(data);
10202
10203        err = doI2CRequest(__private->dpBusID, 0, &request);
10204        if( (kIOReturnSuccess != err) || (kIOReturnSuccess != request.result))
10205            break;
10206
10207        if (data[1] == bits)
10208        {
10209            DEBG("dp events not cleared: 0x%02x\n", thisName, data[1]);
10210            break;
10211        }
10212    }
10213    while (false);
10214
10215    sel = kIODPEventIdle;
10216    err = setAttributeForConnection(0, kConnectionHandleDisplayPortEvent, (uintptr_t) &sel);
10217
10218    DEBG(thisName, "dp sinkCount %d\n", (kDPLinkStatusSinkCountMask & data[0]));
10219
10220    if (__private->dpDongle)
10221    {
10222        UInt8 sinkCount = (kDPLinkStatusSinkCountMask & data[0]);
10223        if (sinkCount != __private->dpDongleSinkCount) do
10224        {
10225            __private->dpDongleSinkCount = sinkCount;
10226            if (captured)
10227                continue;
10228			OSBitOrAtomic(kIOFBEventProbeAll, &gIOFBGlobalEvents);
10229			startThread(false);
10230            DEBG(thisName, "dp dongle hpd probeDP\n");
10231        }
10232        while (false);
10233    }
10234
10235    return;
10236}
10237
10238void IOFramebuffer::dpUpdateConnect(void)
10239{
10240    OSObject * obj;
10241    OSData *   data;
10242
10243    __private->dpDongle          = false;
10244    if (getProvider()->getProperty(kIOFBDPDeviceIDKey)
10245     && (obj = getProvider()->copyProperty(kIOFBDPDeviceTypeKey)))
10246    {
10247        data = OSDynamicCast(OSData, obj);
10248        __private->dpDongle =
10249            (data && data->isEqualTo(kIOFBDPDeviceTypeDongleKey, strlen(kIOFBDPDeviceTypeDongleKey)));
10250        obj->release();
10251
10252        if (__private->dpDongle)
10253        {
10254            IOReturn     err;
10255            IOI2CRequest request;
10256            UInt8        data[6];
10257
10258            bzero(&data[0], sizeof(data));
10259            do
10260            {
10261                bzero( &request, sizeof(request) );
10262
10263                request.commFlags               = 0;
10264                request.sendAddress             = 0;
10265                request.sendTransactionType     = kIOI2CNoTransactionType;
10266                request.sendBuffer              = NULL;
10267                request.sendBytes               = 0;
10268
10269                request.replyAddress            = kDPRegisterLinkStatus;
10270                request.replyTransactionType    = kIOI2CDisplayPortNativeTransactionType;
10271                request.replyBuffer             = (vm_address_t) &data[0];
10272                request.replyBytes              = sizeof(data);
10273
10274                err = doI2CRequest(__private->dpBusID, 0, &request);
10275                if( (kIOReturnSuccess != err) || (kIOReturnSuccess != request.result))
10276                    break;
10277
10278                __private->dpDongleSinkCount = (kDPLinkStatusSinkCountMask & data[0]);
10279            }
10280            while (false);
10281        }
10282    }
10283    DEBG(thisName, "dp dongle %d, sinks %d\n", __private->dpDongle, __private->dpDongleSinkCount);
10284}
10285
10286/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10287/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10288
10289#undef super
10290#define super IOI2CInterface
10291
10292OSDefineMetaClassAndStructors(IOFramebufferI2CInterface, IOI2CInterface)
10293
10294/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10295
10296IOFramebufferI2CInterface * IOFramebufferI2CInterface::withFramebuffer(
10297    IOFramebuffer * framebuffer, OSDictionary * info )
10298{
10299    IOFramebufferI2CInterface * interface;
10300
10301    interface = new IOFramebufferI2CInterface;
10302    info = OSDictionary::withDictionary(info);
10303
10304    if (interface && info)
10305    {
10306        interface->fFramebuffer = framebuffer;
10307        if (!interface->init(info)
10308                || !interface->attach(framebuffer)
10309                || !interface->start(framebuffer)
10310           )
10311        {
10312            interface->detach( framebuffer );
10313            interface->release();
10314            interface = 0;
10315        }
10316    }
10317    if (info)
10318        info->release();
10319
10320    return (interface);
10321}
10322
10323bool IOFramebufferI2CInterface::start( IOService * provider )
10324{
10325    bool       ok = false;
10326    OSNumber * num;
10327
10328    if (!super::start(provider))
10329        return (false);
10330
10331    do
10332    {
10333        num = OSDynamicCast(OSNumber, getProperty(kIOI2CInterfaceIDKey));
10334        if (!num)
10335            break;
10336        fBusID = num->unsigned32BitValue();
10337
10338        num = OSDynamicCast(OSNumber, getProperty(kIOI2CBusTypeKey));
10339        if (!num)
10340            setProperty(kIOI2CBusTypeKey, (UInt64) kIOI2CBusTypeI2C, 32);
10341
10342        num = OSDynamicCast(OSNumber, getProperty(kIOI2CTransactionTypesKey));
10343        if (num)
10344            fSupportedTypes = num->unsigned32BitValue();
10345        else
10346        {
10347            fSupportedTypes = ((1 << kIOI2CNoTransactionType)
10348                             | (1 << kIOI2CSimpleTransactionType)
10349                             | (1 << kIOI2CDDCciReplyTransactionType)
10350                             | (1 << kIOI2CCombinedTransactionType));
10351            setProperty(kIOI2CTransactionTypesKey, (UInt64) fSupportedTypes, 32);
10352        }
10353
10354        num = OSDynamicCast(OSNumber, getProperty(kIOI2CSupportedCommFlagsKey));
10355        if (num)
10356            fSupportedCommFlags = num->unsigned32BitValue();
10357        else
10358        {
10359            fSupportedCommFlags = kIOI2CUseSubAddressCommFlag;
10360            setProperty(kIOI2CSupportedCommFlagsKey, (UInt64) fSupportedCommFlags, 32);
10361        }
10362
10363        UInt64 id = (((UInt64) (uintptr_t) fFramebuffer) << 32) | fBusID;
10364        registerI2C(id);
10365
10366        ok = true;
10367    }
10368    while (false);
10369
10370    return (ok);
10371}
10372
10373IOReturn IOFramebufferI2CInterface::startIO( IOI2CRequest * request )
10374{
10375    IOReturn            err;
10376
10377    fFramebuffer->fbLock();
10378
10379    do
10380    {
10381        if (0 == ((1 << request->sendTransactionType) & fSupportedTypes))
10382        {
10383            err = kIOReturnUnsupportedMode;
10384            continue;
10385        }
10386        if (0 == ((1 << request->replyTransactionType) & fSupportedTypes))
10387        {
10388            err = kIOReturnUnsupportedMode;
10389            continue;
10390        }
10391        if (request->commFlags != (request->commFlags & fSupportedCommFlags))
10392        {
10393            err = kIOReturnUnsupportedMode;
10394            continue;
10395        }
10396
10397        err = fFramebuffer->doI2CRequest( fBusID, 0, request );
10398    }
10399    while (false);
10400
10401    if (kIOReturnSuccess != err)
10402    {
10403        request->result = err;
10404        if (request->completion)
10405            (*request->completion)(request);
10406
10407        err = kIOReturnSuccess;
10408    }
10409
10410    fFramebuffer->fbUnlock();
10411
10412    return (err);
10413}
10414
10415/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10416
10417#if defined(__ppc__) && !defined(OSTYPES_K64_REV)
10418
10419class AppleOnboardI2CInterface : public IOI2CInterface
10420{
10421    OSDeclareDefaultStructors(AppleOnboardI2CInterface)
10422
10423    class PPCI2CInterface * fInterface;
10424    SInt32                  fPort;
10425
10426public:
10427    virtual bool start( IOService * provider );
10428    virtual IOReturn startIO( IOI2CRequest * request );
10429
10430    static AppleOnboardI2CInterface * withInterface( PPCI2CInterface * interface, SInt32 port );
10431};
10432
10433#undef super
10434#define super IOI2CInterface
10435
10436OSDefineMetaClassAndStructors(AppleOnboardI2CInterface, IOI2CInterface)
10437
10438/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10439
10440AppleOnboardI2CInterface * AppleOnboardI2CInterface::withInterface(
10441    PPCI2CInterface * onboardInterface, SInt32 port )
10442{
10443    AppleOnboardI2CInterface * interface;
10444    UInt64 id = (((UInt64) (UInt32) onboardInterface) << 32) | port;
10445
10446    interface = new AppleOnboardI2CInterface;
10447    if (interface)
10448    {
10449        interface->fInterface = onboardInterface;
10450        interface->fPort = port;
10451        if (!interface->init()
10452                || !interface->attach(onboardInterface)
10453                || !interface->start(onboardInterface)
10454           )
10455        {
10456            interface->detach( onboardInterface );
10457            interface->release();
10458            interface = 0;
10459        }
10460        else
10461            interface->registerI2C(id);
10462    }
10463    return (interface);
10464}
10465
10466bool AppleOnboardI2CInterface::start( IOService * provider )
10467{
10468    if (!super::start(provider))
10469        return (false);
10470
10471    setProperty(kIOI2CBusTypeKey,
10472                (UInt64) kIOI2CBusTypeI2C, 32);
10473    setProperty(kIOI2CTransactionTypesKey,
10474                (UInt64) ((1 << kIOI2CNoTransactionType)
10475                          | (1 << kIOI2CSimpleTransactionType)
10476                          | (1 << kIOI2CDDCciReplyTransactionType)
10477                          | (1 << kIOI2CCombinedTransactionType)), 32);
10478    setProperty(kIOI2CSupportedCommFlagsKey,
10479                (UInt64) kIOI2CUseSubAddressCommFlag, 32);
10480
10481    return (true);
10482}
10483
10484IOReturn AppleOnboardI2CInterface::startIO( IOI2CRequest * request )
10485{
10486    IOReturn err = kIOReturnSuccess;
10487
10488    do
10489    {
10490        // Open the interface and sets it in the wanted mode:
10491
10492        fInterface->openI2CBus(fPort);
10493
10494        // the i2c driver does not support well read in interrupt mode
10495        // so it is better to "go polling" (read does not timeout on errors
10496        // in interrupt mode).
10497        fInterface->setPollingMode(true);
10498
10499        if (request->sendBytes && (kIOI2CNoTransactionType != request->sendTransactionType))
10500        {
10501            if (kIOI2CCombinedTransactionType == request->sendTransactionType)
10502                fInterface->setCombinedMode();
10503            else if (kIOI2CUseSubAddressCommFlag & request->commFlags)
10504                fInterface->setStandardSubMode();
10505            else
10506                fInterface->setStandardMode();
10507
10508            if (!fInterface->writeI2CBus(request->sendAddress >> 1, request->sendSubAddress,
10509                                         (UInt8 *) request->sendBuffer, request->sendBytes))
10510                err = kIOReturnNotWritable;
10511        }
10512
10513        if (request->replyBytes && (kIOI2CNoTransactionType != request->replyTransactionType))
10514        {
10515            if (kIOI2CCombinedTransactionType == request->replyTransactionType)
10516                fInterface->setCombinedMode();
10517            else if (kIOI2CUseSubAddressCommFlag & request->commFlags)
10518                fInterface->setStandardSubMode();
10519            else
10520                fInterface->setStandardMode();
10521
10522            if (!fInterface->readI2CBus(request->replyAddress >> 1, request->replySubAddress,
10523                                        (UInt8 *) request->replyBuffer, request->replyBytes))
10524                err = kIOReturnNotReadable;
10525        }
10526
10527        fInterface->closeI2CBus();
10528    }
10529    while (false);
10530
10531    request->result = err;
10532
10533    err = kIOReturnSuccess;
10534
10535    return (err);
10536}
10537
10538#endif  /* __ppc__ && !defined(OSTYPES_K64_REV) */
10539
10540/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10541
10542IOReturn IOFramebufferI2CInterface::create( IOFramebuffer * framebuffer )
10543{
10544    IOReturn                    err = kIOReturnSuccess;
10545    IOI2CInterface *            interface;
10546    UInt32                      idx;
10547    OSArray *                   busArray;
10548    OSArray *                   interfaceIDArray;
10549    OSDictionary *              dict;
10550    OSObject *                  num;
10551    bool                        ok = true;
10552
10553    interfaceIDArray = OSArray::withCapacity(1);
10554    if (!interfaceIDArray)
10555        return (kIOReturnNoMemory);
10556
10557    busArray = OSDynamicCast(OSArray, framebuffer->getProperty(kIOFBI2CInterfaceInfoKey));
10558    do
10559    {
10560        if (!busArray)
10561            continue;
10562        for (idx = 0; (dict = OSDynamicCast(OSDictionary, busArray->getObject(idx))); idx++)
10563        {
10564            interface = IOFramebufferI2CInterface::withFramebuffer(framebuffer, dict);
10565            if (!interface)
10566                break;
10567            num = interface->getProperty(kIOI2CInterfaceIDKey);
10568            if (num)
10569                interfaceIDArray->setObject(num);
10570            else
10571                break;
10572        }
10573
10574        ok = (idx == busArray->getCount());
10575    }
10576    while (false);
10577
10578#if defined(__ppc__) && !defined(OSTYPES_K64_REV)
10579
10580    OSData * data = OSDynamicCast( OSData, framebuffer->getProvider()->getProperty("iic-address"));
10581    if (data && (!framebuffer->getProperty(kIOFBDependentIDKey))
10582            && (0x8c == *((UInt32 *) data->getBytesNoCopy())) /*iMac*/)
10583    {
10584        do
10585        {
10586            PPCI2CInterface * onboardInterface =
10587                (PPCI2CInterface*) getResourceService()->getProperty("PPCI2CInterface.i2c-uni-n");
10588            if (!onboardInterface)
10589                continue;
10590
10591            interface = AppleOnboardI2CInterface::withInterface( onboardInterface, 1 );
10592            if (!interface)
10593                break;
10594            num = interface->getProperty(kIOI2CInterfaceIDKey);
10595            if (num)
10596                interfaceIDArray->setObject(num);
10597            else
10598                break;
10599        }
10600        while (false);
10601    }
10602#endif /* defined(__ppc__) && !defined(OSTYPES_K64_REV) */
10603
10604    if (ok && interfaceIDArray->getCount())
10605        framebuffer->setProperty(kIOFBI2CInterfaceIDsKey, interfaceIDArray);
10606
10607    interfaceIDArray->release();
10608
10609    return (err);
10610}
10611
10612/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10613
10614OSMetaClassDefineReservedUsed(IOFramebuffer, 0);
10615
10616OSMetaClassDefineReservedUnused(IOFramebuffer, 1);
10617OSMetaClassDefineReservedUnused(IOFramebuffer, 2);
10618OSMetaClassDefineReservedUnused(IOFramebuffer, 3);
10619OSMetaClassDefineReservedUnused(IOFramebuffer, 4);
10620OSMetaClassDefineReservedUnused(IOFramebuffer, 5);
10621OSMetaClassDefineReservedUnused(IOFramebuffer, 6);
10622OSMetaClassDefineReservedUnused(IOFramebuffer, 7);
10623OSMetaClassDefineReservedUnused(IOFramebuffer, 8);
10624OSMetaClassDefineReservedUnused(IOFramebuffer, 9);
10625OSMetaClassDefineReservedUnused(IOFramebuffer, 10);
10626OSMetaClassDefineReservedUnused(IOFramebuffer, 11);
10627OSMetaClassDefineReservedUnused(IOFramebuffer, 12);
10628OSMetaClassDefineReservedUnused(IOFramebuffer, 13);
10629OSMetaClassDefineReservedUnused(IOFramebuffer, 14);
10630OSMetaClassDefineReservedUnused(IOFramebuffer, 15);
10631OSMetaClassDefineReservedUnused(IOFramebuffer, 16);
10632OSMetaClassDefineReservedUnused(IOFramebuffer, 17);
10633OSMetaClassDefineReservedUnused(IOFramebuffer, 18);
10634OSMetaClassDefineReservedUnused(IOFramebuffer, 19);
10635OSMetaClassDefineReservedUnused(IOFramebuffer, 20);
10636OSMetaClassDefineReservedUnused(IOFramebuffer, 21);
10637OSMetaClassDefineReservedUnused(IOFramebuffer, 22);
10638OSMetaClassDefineReservedUnused(IOFramebuffer, 23);
10639OSMetaClassDefineReservedUnused(IOFramebuffer, 24);
10640OSMetaClassDefineReservedUnused(IOFramebuffer, 25);
10641OSMetaClassDefineReservedUnused(IOFramebuffer, 26);
10642OSMetaClassDefineReservedUnused(IOFramebuffer, 27);
10643OSMetaClassDefineReservedUnused(IOFramebuffer, 28);
10644OSMetaClassDefineReservedUnused(IOFramebuffer, 29);
10645OSMetaClassDefineReservedUnused(IOFramebuffer, 30);
10646OSMetaClassDefineReservedUnused(IOFramebuffer, 31);
10647
10648
10649