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