#include <IOKit/IOLib.h>
#include <libkern/c++/OSContainers.h>
#include <libkern/OSByteOrder.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/IOCommandGate.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#define IOFRAMEBUFFER_PRIVATE
#include <IOKit/graphics/IOGraphicsPrivate.h>
#include <IOKit/graphics/IOFramebuffer.h>
#include <IOKit/graphics/IODisplay.h>
#include <IOKit/i2c/IOI2CInterface.h>
#include <IOKit/i2c/PPCI2CInterface.h>
#include "IOFramebufferUserClient.h"
#include "IODisplayWrangler.h"
#include "IOFramebufferReallyPrivate.h"
#include <IOKit/pwr_mgt/RootDomain.h>
#include <IOKit/pwr_mgt/IOPMPrivate.h>
#include <IOKit/IOHibernatePrivate.h>
#include <string.h>
#include <IOKit/assert.h>
#include <sys/kdebug.h>
#define ACCEL_OFF_ON_DIM false
#define DOANIO 0
#define VRAM_SAVE 1
#define VRAM_COMPRESS 1
#ifdef __i386__
enum { kIOFBMapCacheMode = kIOMapWriteCombineCache };
#else
enum { kIOFBMapCacheMode = kIOMapInhibitCache };
#endif
#if VRAM_COMPRESS
#include "bmcompress.h"
#endif
#if DOANIO
#include <sys/uio.h>
#include <sys/conf.h>
#endif
static OSArray * gAllFramebuffers;
static OSArray * gRunawayFramebuffers;
static class IOFBGate * gIOFBGate;
static thread_call_t gIOFBSleepCallout;
static IOWorkLoop * gIOFBWorkLoop;
static IOTimerEventSource * gIOFBDelayedPrefsEvent;
static IONotifier * gIOFBRootNotifier;
static IOService * gIOFBSystemPowerAckTo;
static UInt32 gIOFBSystemPowerAckRef;
bool gIOFBSystemPower = true;
static bool gIOFBSleepThread;
static thread_call_t gIOFBClamshellCallout;
static SInt32 gIOFBClamshellEnable;
static IOOptionBits gIOFBClamshellState;
static SInt32 gIOFBSuspendCount;
static IOFramebuffer * gIOFBConsoleFramebuffer;
bool gIOFBDesktopModeAllowed = true;
IOOptionBits gIOFBLastClamshellState;
const OSSymbol * gIOFBGetSensorValueKey;
const OSSymbol * gIOFramebufferKey;
const OSSymbol * gIOFBRotateKey;
static bool gIOFBDimDisable;
OSDictionary * gIOFBPrefs;
OSDictionary * gIOFBPrefsParameters;
OSSerializer * gIOFBPrefsSerializer;
#define kIOFBGetSensorValueKey "getSensorValue"
enum { kIOFBDefaultScalerUnderscan = 0*kIOFBScalerUnderscan };
extern UInt8 appleClut8[256 * 3];
struct IOFramebufferPrivate
{
IOGSize maxWaitCursorSize;
UInt32 numCursorFrames;
UInt8 * cursorFlags;
volatile unsigned char ** cursorImages;
volatile unsigned char ** cursorMasks;
class IOFramebufferParameterHandler * paramHandler;
OSArray * cursorAttributes;
IOFBCursorControlAttribute cursorControl;
IOInterruptEventSource * cursorThread;
IOOptionBits cursorToDo;
UInt32 framePending;
SInt32 xPending;
SInt32 yPending;
IOGPoint cursorHotSpotAdjust[2];
IOByteCount gammaHeaderSize;
UInt32 desiredGammaDataWidth;
UInt32 desiredGammaDataCount;
IOInterruptEventSource * deferredCLUTSetEvent;
IOInterruptEventSource * deferredSpeedChangeEvent;
IOTimerEventSource * delayedConnectInterrupt;
UInt32 delayedConnectTime;
SInt32 connectChangeAtSleep;
IOByteCount gammaDataLen;
UInt8 * gammaData;
UInt32 gammaChannelCount;
UInt32 gammaDataCount;
UInt32 gammaDataWidth;
IOByteCount clutDataLen;
UInt8 * clutData;
UInt32 clutIndex;
UInt32 clutOptions;
UInt32 framebufferWidth;
UInt32 framebufferHeight;
UInt32 saveLength;
void * saveFramebuffer;
UInt8 visiblePending;
UInt8 testingCursor;
UInt8 disabledForConnectChange;
UInt8 index;
UInt8 cursorSlept;
UInt8 cursorPanning;
UInt8 mirrorState;
UInt8 pendingSpeedChange;
UInt8 lli2c;
UInt8 cursorClutDependent;
UInt8 allowSpeedChanges;
UInt8 dimDisable;
UInt8 enableScalerUnderscan;
UInt8 userSetTransform;
UInt8 pad[2];
UInt64 transform;
UInt64 selectedTransform;
UInt32 reducedSpeed;
IOService * temperatureSensor;
IOI2CBusTiming defaultI2CTiming;
};
#define GetShmem(instance) ((StdFBShmem_t *)(instance->priv))
#define KICK_CURSOR(thread) \
thread->interruptOccurred(0, 0, 0);
#define CLEARSEMA(shmem, inst) \
if( inst->__private->cursorToDo ) { \
KICK_CURSOR(inst->__private->cursorThread); \
} \
ev_unlock(&shmem->cursorSema)
#define SETSEMA(shmem) \
if (!ev_try_lock(&shmem->cursorSema)) return;
#define TOUCHBOUNDS(one, two) \
(((one.minx < two.maxx) && (two.minx < one.maxx)) && \
((one.miny < two.maxy) && (two.miny < one.maxy)))
class IOFBGate : public IOCommandGate
{
OSDeclareDefaultStructors(IOFBGate)
public:
static IOFBGate *gate(IOService *owner);
inline void closeGate()
{
IOCommandGate::closeGate();
};
inline void openGate()
{
IOCommandGate::openGate();
};
inline bool tryCloseGate()
{
return IOCommandGate::tryCloseGate();
}
inline int sleepGate(void *event, UInt32 interuptibleType)
{
return IOCommandGate::sleepGate(event, interuptibleType);
}
inline void wakeupGate(void *event, bool oneThread)
{
return IOCommandGate::wakeupGate(event, oneThread);
}
};
#define super IOCommandGate
OSDefineMetaClassAndStructors(IOFBGate, IOCommandGate)
IOFBGate * IOFBGate::gate(IOService *inOwner)
{
IOFBGate *me = new IOFBGate;
if (me && !me->init(inOwner, 0))
{
me->free();
return (0);
}
return (me);
}
#define FBLOCK() \
gIOFBGate->closeGate();
#define FBUNLOCK() \
gIOFBGate->openGate();
class IOFramebufferParameterHandler : public IODisplayParameterHandler
{
OSDeclareDefaultStructors(IOFramebufferParameterHandler)
OSDictionary * fDisplayParams;
IOFramebuffer * fFramebuffer;
IODisplay * fDisplay;
public:
static IOFramebufferParameterHandler * withFramebuffer( IOFramebuffer * framebuffer );
virtual void free();
virtual bool setDisplay( IODisplay * display );
virtual bool doIntegerSet( OSDictionary * params,
const OSSymbol * paramName, UInt32 value );
virtual bool doDataSet( const OSSymbol * paramName, OSData * value );
virtual bool doUpdate( void );
void displayModeChange( void );
};
class IOFramebufferSensor : public IOService
{
OSDeclareDefaultStructors(IOFramebufferSensor)
IOFramebuffer * fFramebuffer;
public:
static IOFramebufferSensor * withFramebuffer( IOFramebuffer * framebuffer );
virtual void free();
virtual IOReturn callPlatformFunction( const OSSymbol * functionName,
bool waitForFunction,
void *param1, void *param2,
void *param3, void *param4 );
virtual IOReturn callPlatformFunction( const char * functionName,
bool waitForFunction,
void *param1, void *param2,
void *param3, void *param4 );
};
class IOFramebufferI2CInterface : public IOI2CInterface
{
OSDeclareDefaultStructors(IOFramebufferI2CInterface)
IOFramebuffer * fFramebuffer;
SInt32 fBusID;
UInt32 fSupportedTypes;
UInt32 fSupportedCommFlags;
public:
virtual bool start( IOService * provider );
virtual IOReturn startIO( IOI2CRequest * request );
static IOFramebufferI2CInterface * withFramebuffer( IOFramebuffer * framebuffer,
OSDictionary * info );
static IOReturn create( IOFramebuffer * framebuffer );
};
#undef super
#define super IOGraphicsDevice
OSDefineMetaClass( IOFramebuffer, IOGraphicsDevice )
OSDefineAbstractStructors( IOFramebuffer, IOGraphicsDevice )
#include "IOCursorBlits.h"
inline void IOFramebuffer::StdFBDisplayCursor( IOFramebuffer * inst )
{
StdFBShmem_t *shmem;
Bounds saveRect;
volatile unsigned char *vramPtr;
unsigned int cursStart;
unsigned int cursorWidth;
int width;
int height;
shmem = GetShmem(inst);
saveRect = shmem->cursorRect;
if (saveRect.miny < shmem->screenBounds.miny)
saveRect.miny = shmem->screenBounds.miny;
if (saveRect.maxy > shmem->screenBounds.maxy)
saveRect.maxy = shmem->screenBounds.maxy;
if (saveRect.minx < shmem->screenBounds.minx)
saveRect.minx = shmem->screenBounds.minx;
if (saveRect.maxx > shmem->screenBounds.maxx)
saveRect.maxx = shmem->screenBounds.maxx;
shmem->saveRect = saveRect;
vramPtr = inst->frameBuffer +
(inst->rowBytes * (saveRect.miny - shmem->screenBounds.miny)) +
(inst->bytesPerPixel * (saveRect.minx - shmem->screenBounds.minx));
width = saveRect.maxx - saveRect.minx;
height = saveRect.maxy - saveRect.miny;
cursorWidth = shmem->cursorSize[0 != shmem->frame].width;
cursStart = (saveRect.miny - shmem->cursorRect.miny) * cursorWidth +
(saveRect.minx - shmem->cursorRect.minx);
if (inst->cursorBlitProc)
inst->cursorBlitProc( inst,
(void *) shmem,
vramPtr,
cursStart,
inst->totalWidth - width,
cursorWidth - width,
width,
height);
}
inline void IOFramebuffer::StdFBRemoveCursor( IOFramebuffer * inst )
{
StdFBShmem_t *shmem;
volatile unsigned char *vramPtr;
unsigned int vramRow;
int width;
int height;
shmem = GetShmem(inst);
vramRow = inst->totalWidth;
vramPtr = inst->frameBuffer +
(inst->rowBytes * (shmem->saveRect.miny - shmem->screenBounds.miny))
+ (inst->bytesPerPixel *
(shmem->saveRect.minx - shmem->screenBounds.minx));
width = shmem->saveRect.maxx - shmem->saveRect.minx;
height = shmem->saveRect.maxy - shmem->saveRect.miny;
vramRow -= width;
if (inst->cursorRemoveProc)
inst->cursorRemoveProc( inst, (void *)shmem,
vramPtr, vramRow, width, height);
}
inline void IOFramebuffer::RemoveCursor( IOFramebuffer * inst )
{
StdFBShmem_t * shmem = GetShmem(inst);
if (shmem->hardwareCursorActive)
{
Point * hs;
hs = &shmem->hotSpot[0 != shmem->frame];
inst->_setCursorState(
shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx,
shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny, false );
}
else
StdFBRemoveCursor(inst);
}
inline void IOFramebuffer::DisplayCursor( IOFramebuffer * inst )
{
Point * hs;
StdFBShmem_t * shmem = GetShmem(inst);
SInt32 x, y;
hs = &shmem->hotSpot[0 != shmem->frame];
x = shmem->cursorLoc.x - hs->x;
y = shmem->cursorLoc.y - hs->y;
if (shmem->hardwareCursorActive)
inst->_setCursorState( x - shmem->screenBounds.minx,
y - shmem->screenBounds.miny, true );
else
{
shmem->cursorRect.maxx = (shmem->cursorRect.minx = x)
+ shmem->cursorSize[0 != shmem->frame].width;
shmem->cursorRect.maxy = (shmem->cursorRect.miny = y)
+ shmem->cursorSize[0 != shmem->frame].height;
StdFBDisplayCursor(inst);
shmem->oldCursorRect = shmem->cursorRect;
}
}
inline void IOFramebuffer::SysHideCursor( IOFramebuffer * inst )
{
if (!GetShmem(inst)->cursorShow++)
RemoveCursor(inst);
}
inline void IOFramebuffer::SysShowCursor( IOFramebuffer * inst )
{
StdFBShmem_t *shmem;
shmem = GetShmem(inst);
if (shmem->cursorShow)
if (!--(shmem->cursorShow))
DisplayCursor(inst);
}
inline void IOFramebuffer::CheckShield( IOFramebuffer * inst )
{
Point * hs;
int intersect;
Bounds tempRect;
StdFBShmem_t * shmem = GetShmem(inst);
hs = &shmem->hotSpot[0 != shmem->frame];
tempRect.maxx = (tempRect.minx = (shmem->cursorLoc).x - hs->x)
+ shmem->cursorSize[0 != shmem->frame].width;
tempRect.maxy = (tempRect.miny = (shmem->cursorLoc).y - hs->y)
+ shmem->cursorSize[0 != shmem->frame].height;
intersect = TOUCHBOUNDS(tempRect, shmem->shieldRect);
if (intersect != shmem->shielded)
(shmem->shielded = intersect) ?
SysHideCursor(inst) : SysShowCursor(inst);
}
void IOFramebuffer::setupCursor( IOPixelInformation * info )
{
StdFBShmem_t * shmem = GetShmem(this);
volatile unsigned char * bits;
IOByteCount cursorImageBytes, waitCursorImageBytes;
rowBytes = info->bytesPerRow;
totalWidth = (rowBytes * 8) / info->bitsPerPixel;
bytesPerPixel = info->bitsPerPixel / 8;
frameBuffer = (volatile unsigned char *) vramMap->getVirtualAddress();
__private->framebufferWidth = info->activeWidth;
__private->framebufferHeight = info->activeHeight;
if (shmem)
{
if ((shmem->screenBounds.maxx == shmem->screenBounds.minx)
|| (shmem->screenBounds.maxy == shmem->screenBounds.miny))
{
shmem->screenBounds.minx = 0;
shmem->screenBounds.miny = 0;
shmem->screenBounds.maxx = info->activeWidth;
shmem->screenBounds.maxy = info->activeHeight;
}
shmem->cursorSize[0] = maxCursorSize;
shmem->cursorSize[1] = __private->maxWaitCursorSize;
shmem->cursorSize[2] = __private->maxWaitCursorSize;
shmem->cursorSize[3] = __private->maxWaitCursorSize;
cursorImageBytes = maxCursorSize.width * maxCursorSize.height
* bytesPerPixel;
waitCursorImageBytes = __private->maxWaitCursorSize.width * __private->maxWaitCursorSize.height
* bytesPerPixel;
bits = shmem->cursor;
for (UInt32 i = 0; i < __private->numCursorFrames; i++)
{
__private->cursorFlags[i] = kIOFBCursorImageNew;
__private->cursorImages[i] = bits;
bits += i ? waitCursorImageBytes : cursorImageBytes;
}
if (info->bitsPerPixel <= 8)
{
for (UInt32 i = 0; i < __private->numCursorFrames; i++)
{
__private->cursorMasks[i] = bits;
bits += i ? waitCursorImageBytes : cursorImageBytes;
}
}
cursorSave = bits;
}
switch (info->bitsPerPixel)
{
case 8:
if (colorConvert.t._bm256To38SampleTable
&& colorConvert.t._bm38To256SampleTable)
{
cursorBlitProc = (CursorBlitProc) StdFBDisplayCursor8P;
cursorRemoveProc = (CursorRemoveProc) StdFBRemoveCursor8;
}
break;
case 16:
if (colorConvert.t._bm34To35SampleTable
&& colorConvert.t._bm35To34SampleTable)
{
cursorBlitProc = (CursorBlitProc) StdFBDisplayCursor555;
cursorRemoveProc = (CursorRemoveProc) StdFBRemoveCursor16;
}
break;
case 32:
if (colorConvert.t._bm256To38SampleTable
&& colorConvert.t._bm38To256SampleTable)
{
cursorBlitProc = (CursorBlitProc) StdFBDisplayCursor32Axxx;
cursorRemoveProc = (CursorRemoveProc) StdFBRemoveCursor32;
}
break;
default:
IOLog("%s: can't do cursor at depth %ld\n",
getName(), info->bitsPerPixel);
cursorBlitProc = (CursorBlitProc) NULL;
cursorRemoveProc = (CursorRemoveProc) NULL;
break;
}
}
void IOFramebuffer::stopCursor( void )
{
cursorBlitProc = (CursorBlitProc) NULL;
cursorRemoveProc = (CursorRemoveProc) NULL;
}
IOReturn IOFramebuffer::extCreateSharedCursor(
int version, int maxWidth, int maxWaitWidth )
{
IOReturn err;
if ((err = extEntry()))
return (err);
err = createSharedCursor( version, maxWidth, maxWidth );
FBUNLOCK();
return (err);
}
IOReturn IOFramebuffer::extGetPixelInformation(
IODisplayModeID displayMode, IOIndex depth,
IOPixelAperture aperture, IOPixelInformation * pixelInfo )
{
IOReturn err;
if ((err = extEntry()))
return (err);
err = getPixelInformation( displayMode, depth, aperture, pixelInfo );
FBUNLOCK();
return (err);
}
IOReturn IOFramebuffer::extGetCurrentDisplayMode(
IODisplayModeID * displayMode, IOIndex * depth )
{
IOReturn err;
if ((err = extEntry()))
return (err);
err = getCurrentDisplayMode( displayMode, depth );
FBUNLOCK();
return (err);
}
IOReturn IOFramebuffer::extSetStartupDisplayMode(
IODisplayModeID displayMode, IOIndex depth )
{
IOReturn err;
if ((err = extEntry()))
return (err);
err = setStartupDisplayMode( displayMode, depth );
FBUNLOCK();
return (err);
}
IOReturn IOFramebuffer::extSetGammaTable(
UInt32 channelCount, UInt32 dataCount,
UInt32 dataWidth, void * data )
{
IOReturn err = kIOReturnBadArgument;
UInt32 expandCount = 0;
IOByteCount dataLen;
UInt32 tryWidth;
UInt8 * table = 0;
bool needAlloc;
if ((err = extEntry()))
return (err);
do
{
if (!__private->desiredGammaDataWidth)
{
__private->desiredGammaDataWidth = dataWidth;
__private->desiredGammaDataCount = dataCount;
}
if (dataWidth < __private->desiredGammaDataWidth)
continue;
if (dataCount < __private->desiredGammaDataCount)
{
expandCount = __private->desiredGammaDataCount / dataCount;
if ((expandCount * dataCount) == __private->desiredGammaDataCount)
{
dataCount = __private->desiredGammaDataCount;
expandCount--;
}
else
expandCount = 0;
}
dataLen = (dataWidth + 7) / 8;
dataLen *= dataCount * channelCount;
dataLen += __private->gammaHeaderSize;
needAlloc = (0 == __private->gammaDataLen);
if (!needAlloc)
{
table = __private->gammaData;
if (__private->gammaDataLen != dataLen)
{
IODelete(table, UInt8, __private->gammaDataLen);
needAlloc = true;
}
__private->gammaDataLen = 0;
}
if (needAlloc)
{
table = IONew(UInt8, dataLen);
if (!table)
{
err = kIOReturnNoMemory;
continue;
}
__private->gammaData = table;
}
__private->gammaChannelCount = channelCount;
__private->gammaDataCount = dataCount;
table += __private->gammaHeaderSize;
tryWidth = __private->desiredGammaDataWidth;
if (!expandCount && (tryWidth == dataWidth))
bcopy(data, table, dataLen - __private->gammaHeaderSize);
else
{
UInt32 pin, pt5, value;
pin = (1 << tryWidth) - 1;
pt5 = (1 << (dataWidth - tryWidth - 1));
for (UInt32 in = 0, out = 0; out < (dataCount * channelCount);)
{
value = (((UInt16 *) data)[in++] + pt5) >> (dataWidth - tryWidth);
if (value > pin)
value = pin;
for (UInt32 i = 0; i <= expandCount; i++)
{
if (tryWidth <= 8)
((UInt8 *) table)[out++] = (value & 0xff);
else
((UInt16 *) table)[out++] = value;
}
}
}
__private->gammaDataWidth = tryWidth;
if (__private->deferredCLUTSetEvent)
{
__private->gammaDataLen = dataLen;
err = kIOReturnSuccess;
}
else
{
err = setGammaTable( __private->gammaChannelCount, __private->gammaDataCount,
__private->gammaDataWidth, __private->gammaData );
updateCursorForCLUTSet();
IODelete(__private->gammaData, UInt8, dataLen);
}
}
while (false);
FBUNLOCK();
return (err);
}
IOReturn IOFramebuffer::extSetCLUTWithEntries( UInt32 index, IOOptionBits options,
IOColorEntry * colors, IOByteCount dataLen )
{
IOReturn err;
UInt8 * table;
bool needAlloc;
if ((err = extEntry()))
return (err);
err = kIOReturnBadArgument;
if (__private->deferredCLUTSetEvent)
{
do
{
needAlloc = (0 == __private->clutDataLen);
if (!needAlloc)
{
if (index || (__private->clutDataLen != dataLen))
{
checkDeferredCLUTSet();
needAlloc = true;
}
__private->clutDataLen = 0;
}
if (needAlloc)
{
table = IONew(UInt8, dataLen);
if (!table)
{
err = kIOReturnNoMemory;
continue;
}
__private->clutData = table;
}
else
table = __private->clutData;
__private->clutIndex = index;
__private->clutOptions = options;
__private->clutDataLen = dataLen;
bcopy(colors, table, dataLen);
err = kIOReturnSuccess;
}
while (false);
}
else
{
err = setCLUTWithEntries( colors, index,
dataLen / sizeof( IOColorEntry), options );
updateCursorForCLUTSet();
}
if (this == gIOFBConsoleFramebuffer)
{
UInt32 count = index + dataLen / sizeof(IOColorEntry);
if (count > 256)
count = 256;
for (; index < count; index++)
{
appleClut8[index * 3 + 0] = colors[index].red >> 8;
appleClut8[index * 3 + 1] = colors[index].green >> 8;
appleClut8[index * 3 + 2] = colors[index].blue >> 8;
}
}
FBUNLOCK();
return (err);
}
void IOFramebuffer::updateCursorForCLUTSet( void )
{
if (__private->cursorClutDependent)
{
StdFBShmem_t *shmem = GetShmem(this);
SETSEMA(shmem);
if ((kIOFBHardwareCursorActive == shmem->hardwareCursorActive)
&& !shmem->cursorShow)
{
setCursorImage( (void *) shmem->frame );
DisplayCursor(this);
}
CLEARSEMA(shmem, this);
}
}
void IOFramebuffer::deferredCLUTSetInterrupt( OSObject * owner,
IOInterruptEventSource * evtSrc, int intCount )
{
IOFramebuffer * self = (IOFramebuffer *) owner;
self->checkDeferredCLUTSet();
}
void IOFramebuffer::checkDeferredCLUTSet( void )
{
IOReturn ret;
IOByteCount gammaLen = __private->gammaDataLen;
IOByteCount clutLen = __private->clutDataLen;
if( !gammaLen && !clutLen)
return;
__private->gammaDataLen = 0;
__private->clutDataLen = 0;
if (gammaLen)
{
ret = setGammaTable( __private->gammaChannelCount, __private->gammaDataCount,
__private->gammaDataWidth, __private->gammaData );
IODelete(__private->gammaData, UInt8, gammaLen);
}
if (clutLen)
{
ret = setCLUTWithEntries( (IOColorEntry *) __private->clutData, __private->clutIndex,
clutLen / sizeof( IOColorEntry), __private->clutOptions );
IODelete(__private->clutData, UInt8, clutLen);
}
updateCursorForCLUTSet();
}
IOReturn IOFramebuffer::createSharedCursor(
int version, int maxWidth, int maxWaitWidth )
{
StdFBShmem_t * shmem;
UInt32 shmemVersion;
IOByteCount size, maxImageSize, maxWaitImageSize;
UInt32 numCursorFrames;
DEBG(thisIndex, " vers = %08x, %d x %d\n",
version, maxWidth, maxWaitWidth);
shmemVersion = version & kIOFBShmemVersionMask;
if (shmemVersion == kIOFBTenPtTwoShmemVersion)
{
numCursorFrames = (kIOFBShmemCursorNumFramesMask & version) >> kIOFBShmemCursorNumFramesShift;
setProperty(kIOFBWaitCursorFramesKey, (numCursorFrames - 1), 32);
setProperty(kIOFBWaitCursorPeriodKey, 33333333, 32);
}
else if (shmemVersion == kIOFBTenPtOneShmemVersion)
{
numCursorFrames = 4;
}
else
return (kIOReturnUnsupported);
shmemClientVersion = shmemVersion;
if (__private->cursorFlags)
{
IODelete( __private->cursorFlags, UInt8, __private->numCursorFrames );
__private->cursorFlags = 0;
}
if (__private->cursorImages)
{
IODelete( __private->cursorImages, volatile unsigned char *, __private->numCursorFrames );
__private->cursorImages = 0;
}
if (__private->cursorMasks)
{
IODelete( __private->cursorMasks, volatile unsigned char *, __private->numCursorFrames );
__private->cursorMasks = 0;
}
__private->numCursorFrames = numCursorFrames;
__private->cursorFlags = IONew( UInt8, numCursorFrames );
__private->cursorImages = IONew( volatile unsigned char *, numCursorFrames );
__private->cursorMasks = IONew( volatile unsigned char *, numCursorFrames );
if (!__private->cursorFlags || !__private->cursorImages || !__private->cursorMasks)
return (kIOReturnNoMemory);
maxImageSize = (maxWidth * maxWidth * kIOFBMaxCursorDepth) / 8;
maxWaitImageSize = (maxWaitWidth * maxWaitWidth * kIOFBMaxCursorDepth) / 8;
size = sizeof( StdFBShmem_t)
+ maxImageSize
+ max(maxImageSize, maxWaitImageSize)
+ ((numCursorFrames - 1) * maxWaitImageSize);
if (!sharedCursor || (size != sharedCursor->getLength()))
{
IOBufferMemoryDescriptor * newDesc;
priv = 0;
newDesc = IOBufferMemoryDescriptor::withOptions(
kIODirectionNone | kIOMemoryKernelUserShared, size );
if (!newDesc)
return (kIOReturnNoMemory);
if (sharedCursor)
sharedCursor->release();
sharedCursor = newDesc;
}
shmem = (StdFBShmem_t *) sharedCursor->getBytesNoCopy();
priv = shmem;
bzero( shmem, size );
shmem->version = shmemClientVersion;
shmem->structSize = size;
shmem->cursorShow = 1;
shmem->hardwareCursorCapable = haveHWCursor;
for (UInt32 i = 0; i < numCursorFrames; i++)
__private->cursorFlags[i] = kIOFBCursorImageNew;
maxCursorSize.width = maxWidth;
maxCursorSize.height = maxWidth;
__private->maxWaitCursorSize.width = maxWaitWidth;
__private->maxWaitCursorSize.height = maxWaitWidth;
doSetup( false );
return (kIOReturnSuccess);
}
IOReturn IOFramebuffer::setBoundingRect( Bounds * bounds )
{
StdFBShmem_t *shmem;
shmem = GetShmem(this);
if (NULL == shmem)
return (kIOReturnUnsupported);
shmem->screenBounds = *bounds;
return (kIOReturnSuccess);
}
IOReturn IOFramebuffer::newUserClient( task_t owningTask,
void * security_id,
UInt32 type,
IOUserClient ** handler )
{
IOReturn err = kIOReturnSuccess;
IOUserClient * newConnect = 0;
IOUserClient * theConnect = 0;
switch (type)
{
case kIOFBServerConnectType:
if (serverConnect)
err = kIOReturnExclusiveAccess;
else
{
if (this == gIOFBConsoleFramebuffer)
getPlatform()->setConsoleInfo( 0, kPEReleaseScreen);
err = open();
if (kIOReturnSuccess == err)
newConnect = IOFramebufferUserClient::withTask(owningTask);
}
break;
case kIOFBSharedConnectType:
if (sharedConnect)
{
theConnect = sharedConnect;
theConnect->retain();
}
else if (serverConnect)
{
newConnect = IOFramebufferSharedUserClient::withTask(owningTask);
if (newConnect)
newConnect->retain();
}
else
err = kIOReturnNotOpen;
break;
default:
err = kIOReturnBadArgument;
}
if (newConnect)
{
if ((false == newConnect->attach(this))
|| (false == newConnect->start(this)))
{
newConnect->detach( this );
newConnect->release();
}
else
theConnect = newConnect;
}
*handler = theConnect;
return (err);
}
IOReturn IOFramebuffer::extGetDisplayModeCount( IOItemCount * count )
{
IOReturn err;
if ((err = extEntry()))
return (err);
*count = dead ? 0 : getDisplayModeCount();
FBUNLOCK();
return (kIOReturnSuccess);
}
IOReturn IOFramebuffer::extGetDisplayModes( IODisplayModeID * allModes, IOByteCount * size )
{
IOReturn err;
IOByteCount outSize;
if ((err = extEntry()))
return (err);
outSize = getDisplayModeCount() * sizeof( IODisplayModeID);
if (*size >= outSize)
{
*size = outSize;
err = getDisplayModes( allModes );
}
else
err = kIOReturnBadArgument;
FBUNLOCK();
return (err);
}
IOReturn IOFramebuffer::extGetVRAMMapOffset( IOPixelAperture ,
IOByteCount * offset )
{
IOReturn err;
if ((err = extEntry()))
return (err);
*offset = vramMapOffset;
FBUNLOCK();
return (kIOReturnSuccess);
}
void IOFramebuffer::wakeServerState(UInt8 state)
{
if (state)
gIOFBGate->wakeupGate(&serverConnect, true);
}
IOReturn IOFramebuffer::extEntry(void)
{
IOReturn err = kIOReturnSuccess;
FBLOCK();
while (!pagingState)
{
err = gIOFBGate->sleepGate(&serverConnect, false);
if (kIOReturnSuccess != err)
{
FBUNLOCK();
break;
}
}
return (err);
}
IOReturn IOFramebuffer::extSetBounds( Bounds * bounds )
{
IOReturn err;
StdFBShmem_t * shmem;
if ((err = extEntry()))
return (err);
shmem = GetShmem(this);
if (shmem)
{
if (kIOFBHardwareCursorActive == shmem->hardwareCursorActive)
{
IOReturn err;
Point * hs;
hs = &shmem->hotSpot[0 != shmem->frame];
err = _setCursorState(
shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx,
shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny, false );
}
shmem->screenBounds = *bounds;
}
FBUNLOCK();
return (kIOReturnSuccess);
}
IOReturn IOFramebuffer::extValidateDetailedTiming(
void * description, void * outDescription,
IOByteCount inSize, IOByteCount * outSize )
{
IOReturn err;
if (*outSize != inSize)
return (kIOReturnBadArgument);
if ((err = extEntry()))
return (err);
err = validateDetailedTiming( description, inSize );
if (kIOReturnSuccess == err)
bcopy( description, outDescription, inSize );
FBUNLOCK();
return (err);
}
IOReturn IOFramebuffer::extSetColorConvertTable( UInt32 select,
UInt8 * data, IOByteCount length )
{
static const IOByteCount checkLength[] = {
16 * sizeof( UInt8),
32 * sizeof( UInt8),
256 * sizeof( UInt32),
5 * 256 * sizeof( UInt8) };
IOReturn err;
UInt8 * table;
IODisplayModeID mode;
IOIndex depth;
IOPixelInformation info;
if (select > 3)
return (kIOReturnBadArgument);
if (length != checkLength[select])
return (kIOReturnBadArgument);
if ((err = extEntry()))
return (err);
do
{
err = kIOReturnNoMemory;
table = colorConvert.tables[select];
if (0 == table)
{
table = (UInt8 *) IOMalloc( length );
colorConvert.tables[select] = table;
}
if (!table)
continue;
bcopy( data, table, length );
if (select == 3)
white = data[data[255] + data[511] + data[767] + 1024];
if ((NULL == cursorBlitProc)
&& colorConvert.tables[0] && colorConvert.tables[1]
&& colorConvert.tables[2] && colorConvert.tables[3]
&& vramMap
&& (kIOReturnSuccess == getCurrentDisplayMode(&mode, &depth))
&& (kIOReturnSuccess == getPixelInformation(mode, depth, kIOFBSystemAperture, &info)))
setupCursor( &info );
err = kIOReturnSuccess;
}
while (false);
FBUNLOCK();
return (err);
}
bool IOFramebuffer::requestTerminate( IOService * provider, IOOptionBits options )
{
FBLOCK();
if (opened)
{
if (!gRunawayFramebuffers)
gRunawayFramebuffers = OSArray::withCapacity(4);
if (gRunawayFramebuffers)
gRunawayFramebuffers->setObject(this);
}
FBUNLOCK();
return (false);
}
void IOFramebuffer::stop( IOService * provider )
{
if (opened)
{
FBLOCK();
dead = true;
for (UInt32 i = 0; i < pm_vars->theNumberOfPowerStates; i++)
pm_vars->thePowerStates[i].capabilityFlags &= ~kIOPMPreventSystemSleep;
setAttribute( kIOSystemPowerAttribute, kIOMessageSystemWillPowerOff );
FBUNLOCK();
temporaryPowerClampOn(); PMstop();
initialized = false;
connectChangeInterrupt(this, 0);
}
return (super::stop(provider));
}
void IOFramebuffer::free()
{
if (vblSemaphore)
semaphore_destroy(kernel_task, vblSemaphore);
if (__private)
{
IODelete( __private, IOFramebufferPrivate, 1 );
__private = 0;
}
super::free();
}
IOService * IOFramebuffer::probe( IOService * provider, SInt32 * score )
{
IOFramebuffer * replace = 0;
if (gRunawayFramebuffers)
{
FBLOCK();
replace = (IOFramebuffer *) gRunawayFramebuffers->getObject(0);
gRunawayFramebuffers->removeObject(0);
FBUNLOCK();
}
return (replace ? replace : this);
}
void IOFramebuffer::initialize()
{
}
bool IOFramebuffer::start( IOService * provider )
{
bool runaway;
if (!super::start(provider))
return (false);
runaway = (__private != 0);
if (!__private)
{
__private = IONew( IOFramebufferPrivate, 1 );
if (!__private)
return (false);
bzero( __private, sizeof(IOFramebufferPrivate) );
userAccessRanges = OSArray::withCapacity( 1 );
if (!userAccessRanges)
return (false);
serverMsg = IOMalloc( sizeof (mach_msg_header_t) );
if (!serverMsg)
return (false);
bzero( serverMsg, sizeof (mach_msg_header_t));
}
PMinit();
provider->joinPMtree(this);
if (runaway)
{
IOReturn err;
FBLOCK();
err = enableController();
if (kIOReturnSuccess == err)
{
opened = true;
dead = false;
isUsable = true;
configPending = serverState ? 0 : 1;
connectChangeInterrupt(this, 0);
}
FBUNLOCK();
}
else
registerService();
return (true);
}
void IOFramebuffer::hideCursor( void )
{
StdFBShmem_t *shmem = GetShmem(this);
SETSEMA(shmem);
SysHideCursor(this);
CLEARSEMA(shmem, this);
}
void IOFramebuffer::deferredMoveCursor( IOFramebuffer * inst )
{
StdFBShmem_t * shmem = GetShmem(inst);
IOReturn err = kIOReturnSuccess;
if (shmem->hardwareCursorActive)
{
if (shmem->cursorObscured)
{
shmem->cursorObscured = 0;
if (shmem->cursorShow)
--shmem->cursorShow;
}
if (shmem->hardwareCursorShields && shmem->shieldFlag)
CheckShield(inst);
if (!shmem->cursorShow)
{
Point * hs;
hs = &shmem->hotSpot[0 != shmem->frame];
err = inst->_setCursorState(
shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx,
shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny, true );
}
}
else
{
if (!shmem->cursorShow++)
RemoveCursor(inst);
if (shmem->cursorObscured)
{
shmem->cursorObscured = 0;
if (shmem->cursorShow)
--shmem->cursorShow;
}
if (shmem->shieldFlag)
CheckShield(inst);
if (shmem->cursorShow)
if (!--shmem->cursorShow)
DisplayCursor(inst);
inst->flushCursor();
if (inst->__private->cursorPanning)
{
Point * hs;
hs = &shmem->hotSpot[0 != shmem->frame];
err = inst->setCursorState(
shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx,
shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny, false );
}
}
inst->needCursorService = (kIOReturnBusy == err);
}
void IOFramebuffer::cursorWork( OSObject * p0, IOInterruptEventSource * evtSrc, int intCount )
{
IOFramebuffer * inst = (IOFramebuffer *) p0;
StdFBShmem_t * shmem = GetShmem(inst);
struct IOFramebufferPrivate * __private = inst->__private;
IOFBCursorControlAttribute * cursorControl = &__private->cursorControl;
IOReturn ret;
IOHardwareCursorDescriptor desc;
IOOptionBits todo = inst->__private->cursorToDo;
while (todo)
{
if (2 & todo)
{
desc.majorVersion = kHardwareCursorDescriptorMajorVersion;
desc.minorVersion = kHardwareCursorDescriptorMinorVersion;
desc.height = shmem->cursorSize[0 != __private->framePending].height;
desc.width = shmem->cursorSize[0 != __private->framePending].width;
desc.bitDepth = inst->bytesPerPixel * 8;
desc.maskBitDepth = 0;
desc.colorEncodings = 0;
desc.flags = 0;
desc.supportedSpecialEncodings = kTransparentEncodedPixel;
ret = (*cursorControl->callouts->setCursorImage) (
cursorControl->self, cursorControl->ref,
&desc, (void *) __private->framePending );
}
if (1 & todo)
ret = (*cursorControl->callouts->setCursorState) (
cursorControl->self, cursorControl->ref,
__private->xPending, __private->yPending, __private->visiblePending );
todo = __private->cursorToDo & ~todo;
__private->cursorToDo = todo;
}
}
IOOptionBits IOFramebuffer::_setCursorImage( UInt32 frame )
{
IOOptionBits flags;
flags = (kIOReturnSuccess == setCursorImage( (void *) frame ))
? kIOFBHardwareCursorActive : 0;
if (!flags && __private->cursorThread && (bytesPerPixel >= 2))
{
__private->framePending = frame;
__private->cursorToDo |= 2;
flags = kIOFBHardwareCursorActive | kIOFBHardwareCursorInVRAM;
}
return (flags);
}
IOReturn IOFramebuffer::_setCursorState( SInt32 x, SInt32 y, bool visible )
{
StdFBShmem_t *shmem = GetShmem(this);
IOReturn ret = kIOReturnUnsupported;
x -= __private->cursorHotSpotAdjust[0].x;
y -= __private->cursorHotSpotAdjust[0].y;
if (kIOFBHardwareCursorActive == shmem->hardwareCursorActive)
ret = setCursorState( x, y, visible );
else if (__private->cursorThread)
{
__private->cursorToDo |= 1;
__private->xPending = x;
__private->yPending = y;
__private->visiblePending = visible;
}
return (ret);
}
void IOFramebuffer::transformLocation(StdFBShmem_t * shmem,
IOGPoint * cursorLoc, IOGPoint * transformLoc)
{
SInt32 x, y;
x = cursorLoc->x - shmem->screenBounds.minx;
y = cursorLoc->y - shmem->screenBounds.miny;
if (__private->transform & kIOFBSwapAxes)
{
SInt32 t = x;
x = y;
y = t;
}
if (__private->transform & kIOFBInvertX)
x = __private->framebufferWidth - x - 1;
if (__private->transform & kIOFBInvertY)
y = __private->framebufferHeight - y - 1;
transformLoc->x = x + shmem->screenBounds.minx;
transformLoc->y = y + shmem->screenBounds.miny;
}
void IOFramebuffer::moveCursor( Point * cursorLoc, int frame )
{
nextCursorLoc = *cursorLoc;
nextCursorFrame = frame;
needCursorService = true;
UInt32 hwCursorActive;
StdFBShmem_t *shmem = GetShmem(this);
SETSEMA(shmem);
if (frame != shmem->frame)
{
if (__private->cursorFlags[frame] && pagingState)
{
hwCursorActive = _setCursorImage( frame );
__private->cursorFlags[frame] = hwCursorActive ? kIOFBCursorHWCapable : 0;
}
else
hwCursorActive = 0;
shmem->frame = frame;
if (shmem->hardwareCursorActive != hwCursorActive)
{
SysHideCursor( this );
shmem->hardwareCursorActive = hwCursorActive;
if (shmem->shieldFlag
&& ((0 == hwCursorActive) || (shmem->hardwareCursorShields)))
CheckShield(this);
SysShowCursor( this );
}
}
if ((kIOFBHardwareCursorActive ==
(shmem->hardwareCursorActive & (kIOFBHardwareCursorActive | kIOFBHardwareCursorInVRAM)))
|| !haveVBLService)
{
if (kIOFBRotateFlags & __private->transform)
transformLocation(shmem, &nextCursorLoc, &shmem->cursorLoc);
else
shmem->cursorLoc = nextCursorLoc;
shmem->frame = frame;
deferredMoveCursor( this );
}
CLEARSEMA(shmem, this);
}
void IOFramebuffer::handleVBL( IOFramebuffer * inst, void * ref )
{
StdFBShmem_t * shmem = GetShmem(inst);
AbsoluteTime now;
AbsoluteTime delta;
if (!shmem)
return ;
shmem->vblCount++;
clock_get_uptime( &now );
delta = now;
SUB_ABSOLUTETIME( &delta, &shmem->vblTime );
shmem->vblDelta = delta;
shmem->vblTime = now;
KERNEL_DEBUG(0xc000030 | DBG_FUNC_NONE,
(uint32_t)(AbsoluteTime_to_scalar(&shmem->vblDelta) >> 32),
(uint32_t)(AbsoluteTime_to_scalar(&shmem->vblDelta)), 0, 0, 0);
if (inst->vblSemaphore)
semaphore_signal_all(inst->vblSemaphore);
SETSEMA(shmem);
if (inst->needCursorService)
{
if (kIOFBRotateFlags & inst->__private->transform)
inst->transformLocation(shmem, &inst->nextCursorLoc, &shmem->cursorLoc);
else
shmem->cursorLoc = inst->nextCursorLoc;
shmem->frame = inst->nextCursorFrame;
deferredMoveCursor( inst );
}
CLEARSEMA(shmem, inst);
if (inst->__private->deferredCLUTSetEvent
&& (inst->__private->gammaDataLen || inst->__private->clutDataLen))
inst->__private->deferredCLUTSetEvent->interruptOccurred(0, 0, 0);
}
void IOFramebuffer::showCursor( Point * cursorLoc, int frame )
{
StdFBShmem_t *shmem;
UInt32 hwCursorActive;
shmem = GetShmem(this);
SETSEMA(shmem);
if (frame != shmem->frame)
{
if (__private->cursorFlags[frame])
{
hwCursorActive = _setCursorImage( frame );
__private->cursorFlags[frame] = hwCursorActive ? kIOFBCursorHWCapable : 0;
}
else
hwCursorActive = 0;
shmem->frame = frame;
shmem->hardwareCursorActive = hwCursorActive;
}
shmem->cursorLoc = *cursorLoc;
if (shmem->shieldFlag
&& ((0 == shmem->hardwareCursorActive) || (shmem->hardwareCursorShields)))
CheckShield(this);
SysShowCursor(this);
CLEARSEMA(shmem, this);
}
void IOFramebuffer::resetCursor( void )
{
StdFBShmem_t * shmem;
int frame;
shmem = GetShmem(this);
if (!shmem)
return;
shmem->hardwareCursorActive = 0;
frame = shmem->frame;
shmem->frame = frame ^ 1;
showCursor( &shmem->cursorLoc, frame );
}
void IOFramebuffer::getVBLTime( AbsoluteTime * time, AbsoluteTime * delta )
{
StdFBShmem_t *shmem;
shmem = GetShmem(this);
if (shmem)
{
*time = shmem->vblTime;
*delta = shmem->vblDelta;
}
else
AbsoluteTime_to_scalar(&time) = 0;
}
void IOFramebuffer::getBoundingRect( Bounds ** bounds )
{
StdFBShmem_t *shmem;
shmem = GetShmem(this);
if (NULL == shmem)
*bounds = NULL;
else
*bounds = &shmem->screenBounds;
}
IOReturn IOFramebuffer::getNotificationSemaphore(
IOSelect interruptType, semaphore_t * semaphore )
{
kern_return_t kr;
semaphore_t sema;
if (interruptType != kIOFBVBLInterruptType)
return (kIOReturnUnsupported);
if (!haveVBLService)
return (kIOReturnNoResources);
if (MACH_PORT_NULL == vblSemaphore)
{
kr = semaphore_create(kernel_task, &sema, SYNC_POLICY_FIFO, 0);
if (kr == KERN_SUCCESS)
vblSemaphore = sema;
}
else
kr = KERN_SUCCESS;
if (kr == KERN_SUCCESS)
*semaphore = vblSemaphore;
return (kr);
}
IOReturn IOFramebuffer::extSetCursorVisible( bool visible )
{
IOReturn err;
Point * hs;
StdFBShmem_t * shmem;
if ((err = extEntry()))
return (err);
shmem = GetShmem(this);
if (shmem->hardwareCursorActive)
{
hs = &shmem->hotSpot[0 != shmem->frame];
err = _setCursorState(
shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx,
shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny,
visible );
if (__private->cursorToDo)
KICK_CURSOR(__private->cursorThread);
}
else
err = kIOReturnBadArgument;
FBUNLOCK();
return (err);
}
IOReturn IOFramebuffer::extSetCursorPosition( SInt32 x, SInt32 y )
{
return (kIOReturnUnsupported);
}
void IOFramebuffer::transformCursor( StdFBShmem_t * shmem, IOIndex frame )
{
void * buf;
unsigned int * out;
volatile unsigned int * cursPtr32 = 0;
volatile unsigned short * cursPtr16 = 0;
SInt32 x, y, dw, dh, sx, sy, sw, sh;
if (bytesPerPixel == 4)
{
cursPtr32 = (volatile unsigned int *) __private->cursorImages[frame];
cursPtr16 = 0;
}
else if (bytesPerPixel == 2)
{
cursPtr32 = 0;
cursPtr16 = (volatile unsigned short *) __private->cursorImages[frame];
}
sw = shmem->cursorSize[0 != frame].width;
sh = shmem->cursorSize[0 != frame].height;
if (kIOFBSwapAxes & __private->transform)
{
dw = sh;
dh = sw;
}
else
{
dw = sw;
dh = sh;
}
buf = IOMalloc(dw * dh * bytesPerPixel);
out = (unsigned int *) buf;
for (y = 0; y < dh; y++)
{
for (x = 0; x < dw; x++)
{
if (kIOFBSwapAxes & __private->transform)
{
sx = y;
sy = x;
}
else
{
sx = x;
sy = y;
}
if (__private->transform & kIOFBInvertY)
sx = sw - sx - 1;
if (__private->transform & kIOFBInvertX)
sy = sh - sy - 1;
if (cursPtr32)
*out++ = cursPtr32[sx + sy * sw];
else
*((UInt16 *)out)++ = cursPtr16[sx + sy * sw];
}
}
bcopy(buf, (void *) __private->cursorImages[frame], dw * dh * bytesPerPixel);
IOFree(buf, dw * dh * bytesPerPixel);
shmem->cursorSize[0 != frame].width = dw;
shmem->cursorSize[0 != frame].height = dh;
if (kIOFBSwapAxes & __private->transform)
{
x = shmem->hotSpot[0 != frame].y;
y = shmem->hotSpot[0 != frame].x;
}
else
{
x = shmem->hotSpot[0 != frame].x;
y = shmem->hotSpot[0 != frame].y;
}
if (__private->transform & kIOFBInvertX)
x = dw - x - 1;
if (__private->transform & kIOFBInvertY)
y = dh - y - 1;
shmem->hotSpot[0 != frame].x = x;
shmem->hotSpot[0 != frame].y = y;
}
IOReturn IOFramebuffer::extSetNewCursor( void * cursor, IOIndex frame,
IOOptionBits options )
{
StdFBShmem_t * shmem;
IOReturn err;
UInt32 hwCursorActive;
if ((err = extEntry()))
return (err);
shmem = GetShmem(this);
if (cursor || options || (((UInt32) frame) >= __private->numCursorFrames))
err = kIOReturnBadArgument;
else
{
if (kIOFBRotateFlags & __private->transform)
transformCursor(shmem, frame);
if ((shmem->cursorSize[0 != frame].width > maxCursorSize.width)
|| (shmem->cursorSize[0 != frame].height > maxCursorSize.height))
err = kIOReturnBadArgument;
else if (haveHWCursor)
{
if (frame == shmem->frame)
{
hwCursorActive = _setCursorImage( frame );
shmem->hardwareCursorActive = hwCursorActive;
__private->cursorFlags[frame] = hwCursorActive ? kIOFBCursorHWCapable : 0;
}
else
{
__private->cursorFlags[frame] = kIOFBCursorImageNew;
}
err = kIOReturnSuccess; }
else
err = kIOReturnUnsupported;
}
if (__private->cursorToDo)
KICK_CURSOR(__private->cursorThread);
FBUNLOCK();
return (err);
}
bool IOFramebuffer::convertCursorImage( void * cursorImage,
IOHardwareCursorDescriptor * hwDesc,
IOHardwareCursorInfo * hwCursorInfo )
{
StdFBShmem_t * shmem = GetShmem(this);
UInt8 * dataOut = hwCursorInfo->hardwareCursorData;
IOColorEntry * clut = hwCursorInfo->colorMap;
UInt32 maxColors = hwDesc->numColors;
int frame = (int) cursorImage;
volatile unsigned short * cursPtr16;
volatile unsigned int * cursPtr32;
SInt32 x, lastx, y, lasty;
UInt32 width, height, lineBytes = 0;
UInt32 index, numColors = 0;
UInt32 alpha, red, green, blue;
UInt16 s16;
UInt32 s32;
UInt32 pixel = 0;
UInt32 data = 0;
UInt32 bits = 0;
bool ok = true;
bool isDirect;
if (__private->testingCursor)
{
IOHardwareCursorDescriptor copy;
if ((hwDesc->numColors == 0) && (hwDesc->bitDepth > 8) && (hwDesc->bitDepth < 32))
{
copy = *hwDesc;
hwDesc = ©
copy.bitDepth = 32;
}
OSData * data = OSData::withBytes( hwDesc, sizeof(IOHardwareCursorDescriptor) );
if (data)
{
__private->cursorAttributes->setObject( data );
data->release();
}
return (false);
}
else if (!hwCursorInfo || !hwCursorInfo->hardwareCursorData)
return (false);
assert( frame < __private->numCursorFrames );
if (bytesPerPixel == 4)
{
cursPtr32 = (volatile unsigned int *) __private->cursorImages[frame];
cursPtr16 = 0;
}
else if (bytesPerPixel == 2)
{
cursPtr32 = 0;
cursPtr16 = (volatile unsigned short *) __private->cursorImages[frame];
}
else
return (false);
x = shmem->cursorSize[0 != frame].width;
y = shmem->cursorSize[0 != frame].height;
if ((x > (SInt32) hwDesc->width) || (y > (SInt32) hwDesc->height))
return (false);
isDirect = (hwDesc->bitDepth > 8);
if (isDirect && (hwDesc->bitDepth != 32) && (hwDesc->bitDepth != 16))
return (false);
width = hwDesc->width;
height = hwDesc->height;
if ((maxColors > 1) && (&clut[1] == (IOColorEntry *) hwCursorInfo))
width = height = 16;
SInt32 adjX = 4 - shmem->hotSpot[0 != frame].x;
SInt32 adjY = 4 - shmem->hotSpot[0 != frame].y;
if ((adjX < 0) || ((UInt32)(x + adjX) > width))
adjX = 0;
else
x += adjX;
if ((adjY < 0) || ((UInt32)(y + adjY) > height))
adjY = 0;
__private->cursorHotSpotAdjust[0 != frame].x = adjX;
__private->cursorHotSpotAdjust[0 != frame].y = adjY;
while ((width >> 1) >= (UInt32) x)
width >>= 1;
while ((UInt32)(height >> 1) >= (UInt32)(y + adjY))
height >>= 1;
hwCursorInfo->cursorWidth = width;
hwCursorInfo->cursorHeight = height;
lastx = x - width - 1;
if (isDirect && adjY)
{
lineBytes = width * (hwDesc->bitDepth >> 3);
bzero_nc( dataOut, adjY * lineBytes );
dataOut += adjY * lineBytes;
adjY = height - shmem->cursorSize[0 != frame].height - adjY;
lasty = -1;
}
else
{
y += adjY;
lasty = y - height - 1;
}
while (ok && (--y != lasty))
{
x = shmem->cursorSize[0 != frame].width + adjX;
while (ok && (--x != lastx))
{
if ((x < 0)
|| (y < 0)
|| (x >= shmem->cursorSize[0 != frame].width)
|| (y >= shmem->cursorSize[0 != frame].height))
alpha = red = green = blue = 0;
else if (cursPtr32)
{
s32 = *(cursPtr32++);
alpha = (s32 >> 24) & 0xff;
red = (s32 >> 16) & 0xff;
green = (s32 >> 8) & 0xff;
blue = (s32) & 0xff;
}
else
{
#define RMASK16 0xF000
#define GMASK16 0x0F00
#define BMASK16 0x00F0
#define AMASK16 0x000F
s16 = *(cursPtr16++);
alpha = s16 & AMASK16;
alpha |= (alpha << 4);
red = (s16 & RMASK16) >> 8;
red |= (red >> 4);
green = (s16 & GMASK16) >> 4;
green |= (green >> 4);
blue = s16 & BMASK16;
blue |= (blue >> 4);
}
if (isDirect)
{
if (alpha == 0)
{
if (0xff == (red & green & blue))
{
if (kInvertingEncodedPixel
& hwDesc->supportedSpecialEncodings)
pixel = hwDesc->specialEncodings[kInvertingEncoding];
else
ok = false;
}
else
pixel = 0;
if (hwDesc->bitDepth == 32)
*((UInt32 *)dataOut)++ = pixel;
else
*((UInt16 *)dataOut)++ = pixel;
}
else
{
if (0xff != alpha)
{
red = 0xff * red / alpha;
green = 0xff * green / alpha;
blue = 0xff * blue / alpha;
}
if (hwDesc->bitDepth == 32)
{
pixel = (alpha << 24)
| ((red & 0xff) << 16)
| ((green & 0xff) << 8)
| (blue & 0xff);
*((UInt32 *)dataOut)++ = pixel;
}
else
{
pixel = ((alpha & 0xf0) << 8)
| ((red & 0xf0) << 4)
| ((green & 0xf0) << 0)
| ((blue & 0xf0) >> 4);
*((UInt16 *)dataOut)++ = pixel;
}
}
}
else
{
if (alpha == 0)
{
if (0 == (red | green | blue))
{
if (kTransparentEncodedPixel
& hwDesc->supportedSpecialEncodings)
pixel = hwDesc->specialEncodings[kTransparentEncoding];
else
ok = false;
}
else if (0xff == (red & green & blue))
{
if (kInvertingEncodedPixel
& hwDesc->supportedSpecialEncodings)
pixel = hwDesc->specialEncodings[kInvertingEncoding];
else
ok = false;
}
else
ok = false;
}
else if (alpha == 0xff)
{
red |= (red << 8);
green |= (green << 8);
blue |= (blue << 8);
for (index = 0; index < numColors; index++)
{
if ((red == clut[index].red)
&& (green == clut[index].green)
&& (blue == clut[index].blue))
{
pixel = clut[index].index;
break;
}
}
if (index == numColors)
{
ok = (numColors < maxColors);
if (ok)
{
pixel = hwDesc->colorEncodings[numColors++];
clut[index].red = red;
clut[index].green = green;
clut[index].blue = blue;
clut[index].index = pixel;
}
}
}
else
{
ok = false;
break;
}
data <<= hwDesc->bitDepth;
data |= pixel;
bits += hwDesc->bitDepth;
if (0 == (bits & 31))
{
OSWriteBigInt32(dataOut, 0, data);
dataOut += sizeof(UInt32);
}
}
}
}
if (ok && isDirect && adjY)
{
bzero_nc( dataOut, adjY * lineBytes );
dataOut += adjY * lineBytes;
}
__private->cursorClutDependent = (ok && !isDirect);
#if 0
if (ok)
{
static UInt32 lastWidth;
static UInt32 lastHeight;
if ((width != lastWidth) || (height != lastHeight))
{
lastWidth = width;
lastHeight = height;
IOLog("[%d,%d]", width, height);
}
if (((UInt32)(dataOut - hwCursorInfo->hardwareCursorData)
!= ((hwCursorInfo->cursorHeight * hwCursorInfo->cursorWidth * hwDesc->bitDepth) >> 3)))
IOLog("dataOut %p, %p @ %d\n", dataOut, hwCursorInfo->hardwareCursorData, hwDesc->bitDepth );
}
#endif
return (ok);
}
#if 0
UInt8 appleClut8[256 * 3] =
{
0xFF,0xFF,0xFF, 0xFF,0xFF,0xCC, 0xFF,0xFF,0x99, 0xFF,0xFF,0x66,
0xFF,0xFF,0x33, 0xFF,0xFF,0x00, 0xFF,0xCC,0xFF, 0xFF,0xCC,0xCC,
0xFF,0xCC,0x99, 0xFF,0xCC,0x66, 0xFF,0xCC,0x33, 0xFF,0xCC,0x00,
0xFF,0x99,0xFF, 0xFF,0x99,0xCC, 0xFF,0x99,0x99, 0xFF,0x99,0x66,
0xFF,0x99,0x33, 0xFF,0x99,0x00, 0xFF,0x66,0xFF, 0xFF,0x66,0xCC,
0xFF,0x66,0x99, 0xFF,0x66,0x66, 0xFF,0x66,0x33, 0xFF,0x66,0x00,
0xFF,0x33,0xFF, 0xFF,0x33,0xCC, 0xFF,0x33,0x99, 0xFF,0x33,0x66,
0xFF,0x33,0x33, 0xFF,0x33,0x00, 0xFF,0x00,0xFF, 0xFF,0x00,0xCC,
0xFF,0x00,0x99, 0xFF,0x00,0x66, 0xFF,0x00,0x33, 0xFF,0x00,0x00,
0xCC,0xFF,0xFF, 0xCC,0xFF,0xCC, 0xCC,0xFF,0x99, 0xCC,0xFF,0x66,
0xCC,0xFF,0x33, 0xCC,0xFF,0x00, 0xCC,0xCC,0xFF, 0xCC,0xCC,0xCC,
0xCC,0xCC,0x99, 0xCC,0xCC,0x66, 0xCC,0xCC,0x33, 0xCC,0xCC,0x00,
0xCC,0x99,0xFF, 0xCC,0x99,0xCC, 0xCC,0x99,0x99, 0xCC,0x99,0x66,
0xCC,0x99,0x33, 0xCC,0x99,0x00, 0xCC,0x66,0xFF, 0xCC,0x66,0xCC,
0xCC,0x66,0x99, 0xCC,0x66,0x66, 0xCC,0x66,0x33, 0xCC,0x66,0x00,
0xCC,0x33,0xFF, 0xCC,0x33,0xCC, 0xCC,0x33,0x99, 0xCC,0x33,0x66,
0xCC,0x33,0x33, 0xCC,0x33,0x00, 0xCC,0x00,0xFF, 0xCC,0x00,0xCC,
0xCC,0x00,0x99, 0xCC,0x00,0x66, 0xCC,0x00,0x33, 0xCC,0x00,0x00,
0x99,0xFF,0xFF, 0x99,0xFF,0xCC, 0x99,0xFF,0x99, 0x99,0xFF,0x66,
0x99,0xFF,0x33, 0x99,0xFF,0x00, 0x99,0xCC,0xFF, 0x99,0xCC,0xCC,
0x99,0xCC,0x99, 0x99,0xCC,0x66, 0x99,0xCC,0x33, 0x99,0xCC,0x00,
0x99,0x99,0xFF, 0x99,0x99,0xCC, 0x99,0x99,0x99, 0x99,0x99,0x66,
0x99,0x99,0x33, 0x99,0x99,0x00, 0x99,0x66,0xFF, 0x99,0x66,0xCC,
0x99,0x66,0x99, 0x99,0x66,0x66, 0x99,0x66,0x33, 0x99,0x66,0x00,
0x99,0x33,0xFF, 0x99,0x33,0xCC, 0x99,0x33,0x99, 0x99,0x33,0x66,
0x99,0x33,0x33, 0x99,0x33,0x00, 0x99,0x00,0xFF, 0x99,0x00,0xCC,
0x99,0x00,0x99, 0x99,0x00,0x66, 0x99,0x00,0x33, 0x99,0x00,0x00,
0x66,0xFF,0xFF, 0x66,0xFF,0xCC, 0x66,0xFF,0x99, 0x66,0xFF,0x66,
0x66,0xFF,0x33, 0x66,0xFF,0x00, 0x66,0xCC,0xFF, 0x66,0xCC,0xCC,
0x66,0xCC,0x99, 0x66,0xCC,0x66, 0x66,0xCC,0x33, 0x66,0xCC,0x00,
0x66,0x99,0xFF, 0x66,0x99,0xCC, 0x66,0x99,0x99, 0x66,0x99,0x66,
0x66,0x99,0x33, 0x66,0x99,0x00, 0x66,0x66,0xFF, 0x66,0x66,0xCC,
0x66,0x66,0x99, 0x66,0x66,0x66, 0x66,0x66,0x33, 0x66,0x66,0x00,
0x66,0x33,0xFF, 0x66,0x33,0xCC, 0x66,0x33,0x99, 0x66,0x33,0x66,
0x66,0x33,0x33, 0x66,0x33,0x00, 0x66,0x00,0xFF, 0x66,0x00,0xCC,
0x66,0x00,0x99, 0x66,0x00,0x66, 0x66,0x00,0x33, 0x66,0x00,0x00,
0x33,0xFF,0xFF, 0x33,0xFF,0xCC, 0x33,0xFF,0x99, 0x33,0xFF,0x66,
0x33,0xFF,0x33, 0x33,0xFF,0x00, 0x33,0xCC,0xFF, 0x33,0xCC,0xCC,
0x33,0xCC,0x99, 0x33,0xCC,0x66, 0x33,0xCC,0x33, 0x33,0xCC,0x00,
0x33,0x99,0xFF, 0x33,0x99,0xCC, 0x33,0x99,0x99, 0x33,0x99,0x66,
0x33,0x99,0x33, 0x33,0x99,0x00, 0x33,0x66,0xFF, 0x33,0x66,0xCC,
0x33,0x66,0x99, 0x33,0x66,0x66, 0x33,0x66,0x33, 0x33,0x66,0x00,
0x33,0x33,0xFF, 0x33,0x33,0xCC, 0x33,0x33,0x99, 0x33,0x33,0x66,
0x33,0x33,0x33, 0x33,0x33,0x00, 0x33,0x00,0xFF, 0x33,0x00,0xCC,
0x33,0x00,0x99, 0x33,0x00,0x66, 0x33,0x00,0x33, 0x33,0x00,0x00,
0x00,0xFF,0xFF, 0x00,0xFF,0xCC, 0x00,0xFF,0x99, 0x00,0xFF,0x66,
0x00,0xFF,0x33, 0x00,0xFF,0x00, 0x00,0xCC,0xFF, 0x00,0xCC,0xCC,
0x00,0xCC,0x99, 0x00,0xCC,0x66, 0x00,0xCC,0x33, 0x00,0xCC,0x00,
0x00,0x99,0xFF, 0x00,0x99,0xCC, 0x00,0x99,0x99, 0x00,0x99,0x66,
0x00,0x99,0x33, 0x00,0x99,0x00, 0x00,0x66,0xFF, 0x00,0x66,0xCC,
0x00,0x66,0x99, 0x00,0x66,0x66, 0x00,0x66,0x33, 0x00,0x66,0x00,
0x00,0x33,0xFF, 0x00,0x33,0xCC, 0x00,0x33,0x99, 0x00,0x33,0x66,
0x00,0x33,0x33, 0x00,0x33,0x00, 0x00,0x00,0xFF, 0x00,0x00,0xCC,
0x00,0x00,0x99, 0x00,0x00,0x66, 0x00,0x00,0x33, 0xEE,0x00,0x00,
0xDD,0x00,0x00, 0xBB,0x00,0x00, 0xAA,0x00,0x00, 0x88,0x00,0x00,
0x77,0x00,0x00, 0x55,0x00,0x00, 0x44,0x00,0x00, 0x22,0x00,0x00,
0x11,0x00,0x00, 0x00,0xEE,0x00, 0x00,0xDD,0x00, 0x00,0xBB,0x00,
0x00,0xAA,0x00, 0x00,0x88,0x00, 0x00,0x77,0x00, 0x00,0x55,0x00,
0x00,0x44,0x00, 0x00,0x22,0x00, 0x00,0x11,0x00, 0x00,0x00,0xEE,
0x00,0x00,0xDD, 0x00,0x00,0xBB, 0x00,0x00,0xAA, 0x00,0x00,0x88,
0x00,0x00,0x77, 0x00,0x00,0x55, 0x00,0x00,0x44, 0x00,0x00,0x22,
0x00,0x00,0x11, 0xEE,0xEE,0xEE, 0xDD,0xDD,0xDD, 0xBB,0xBB,0xBB,
0xAA,0xAA,0xAA, 0x88,0x88,0x88, 0x77,0x77,0x77, 0x55,0x55,0x55,
0x44,0x44,0x44, 0x22,0x22,0x22, 0x11,0x11,0x11, 0x00,0x00,0x00
};
#endif
#ifdef __ppc__
extern
#endif
int killprint;
extern "C"
{
int kmputc( int c );
}
#if DOANIO
#warning ** DO AN IO **
static unsigned long doaniobuf[256];
static void doanio( void )
{
struct uio uio;
struct iovec iovec;
int err;
dev_t device = makedev( 14, 0 );
iovec.iov_base = (char *) &doaniobuf[0];
iovec.iov_len = 1024;
uio.uio_iov = &iovec;
uio.uio_iovcnt = 1;
uio.uio_rw = UIO_READ;
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_offset = 0;
uio.uio_resid = 1024;
DEBG(0, "\n");
err = ((*cdevsw[major(device)].d_read)(device, &uio, 0));
DEBG(0, " done(%08lx)\n", doaniobuf[0]);
}
#endif
IOReturn IOFramebuffer::handleEvent( IOIndex event, void * info )
{
IOReturn ret;
DEBG(thisIndex, "(%ld, %d)\n", event, pagingState);
switch (event)
{
case kIOFBNotifyWillPowerOff:
if (this == gIOFBConsoleFramebuffer)
{
killprint = 1;
}
if (ACCEL_OFF_ON_DIM && pagingState)
{
pagingState = false;
deliverFramebufferNotification( kIOFBNotifyWillSleep, info );
}
ret = deliverFramebufferNotification( event, info );
configPending = true;
break;
case kIOFBNotifyDidPowerOff:
__private->connectChangeAtSleep = connectChange;
ret = kIOReturnSuccess;
break;
case kIOFBNotifyDidPowerOn:
if (this == gIOFBConsoleFramebuffer)
{
killprint = 0;
kmputc( 033 );
kmputc( 'c' );
}
ret = deliverFramebufferNotification( event, info );
if (!pagingState && gIOFBSystemPower)
{
pagingState = true;
if (__private->connectChangeAtSleep != connectChange)
{
if (!__private->disabledForConnectChange)
{
__private->disabledForConnectChange = true;
deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange );
}
}
deliverFramebufferNotification( kIOFBNotifyDidWake, info );
}
#if DOANIO
doanio();
#endif
configPending = false;
break;
#if DOANIO
case kIOFBNotifyWillSleep:
if (!info)
{
doanio();
}
ret = deliverFramebufferNotification( event, info );
break;
#endif
#if VRAM_SAVE
case kIOFBNotifyDidWake:
if (info)
{
if (__private->saveLength)
{
if (!suspended
&& ((this != gIOFBConsoleFramebuffer)
|| (kOSBooleanTrue != getPMRootDomain()->getProperty(kIOHibernatePreviewBufferKey))))
{
#if VRAM_COMPRESS
DecompressData( (UInt8 *) __private->saveFramebuffer, (UInt8 *) frameBuffer,
0, 0, __private->framebufferWidth, __private->framebufferHeight, rowBytes);
#else
bcopy_nc( __private->saveFramebuffer, (void *) frameBuffer, __private->saveLength );
#endif
DEBG(thisIndex, " screen drawn\n");
}
if (this == gIOFBConsoleFramebuffer)
getPMRootDomain()->removeProperty(kIOHibernatePreviewBufferKey);
IOFreePageable( __private->saveFramebuffer, __private->saveLength );
__private->saveFramebuffer = 0;
__private->saveLength = 0;
}
}
ret = deliverFramebufferNotification( event, info );
break;
#endif
default:
ret = deliverFramebufferNotification( event, info );
break;
}
return (ret);
}
IOReturn IOFramebuffer::notifyServer( UInt8 state )
{
mach_msg_header_t * msgh = (mach_msg_header_t *) serverMsg;
IOReturn err = kIOReturnSuccess;
if (serverNotified != state)
{
serverNotified = state;
DEBG(thisIndex, "(%p, %d->%d, %d)\n", msgh->msgh_remote_port,
serverState, serverNotified, serverPendingAck);
msgh->msgh_id = state;
if ((MACH_PORT_NULL == msgh->msgh_remote_port)
|| (KERN_SUCCESS != mach_msg_send_from_kernel(msgh, msgh->msgh_size)))
{
serverState = serverNotified;
}
}
wakeServerState(serverNotified);
return (err);
}
bool IOFramebuffer::getIsUsable( void )
{
return (dead || (0 != isUsable));
}
IOReturn IOFramebuffer::postWake( IOOptionBits state )
{
IOReturn ret;
UInt32 value;
sleepConnectCheck = false;
configPending = false;
ret = getAttributeForConnection(0, kConnectionPostWake, &value);
if (!captured)
getAttributeForConnection(0, kConnectionChanged, 0);
return (ret);
}
void IOFramebuffer::notifyServerAll( UInt8 state )
{
unsigned int index;
IOFramebuffer * fb;
bool doNotify = true;
FBLOCK();
if (state)
{
doNotify = gIOFBSystemPower;
for (index = 0;
doNotify && (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
index++)
{
doNotify = fb->getIsUsable();
}
if (doNotify)
IOSleep(20);
}
if (doNotify)
{
if (state)
{
for (index = 0;
(fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
index++)
{
fb->postWake( state );
}
}
for (index = 0;
(fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
index++)
{
fb->notifyServer( state );
}
}
FBUNLOCK();
}
enum {
kIOFBDidWork = 0x00000001,
kIOFBPaging = 0x00000002,
};
void IOFramebuffer::sleepWork( void * arg )
{
unsigned int index;
IOFramebuffer * fb;
IOOptionBits allState;
DEBG(0, "\n");
FBLOCK();
do
{
for (index = 0, allState = 0;
(fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
index++)
{
allState |= fb->checkPowerWork();
}
if ((0 == (kIOFBPaging & allState)) && gIOFBSystemPowerAckTo)
{
DEBG(0, " allowPowerChange(%ld)\n", gIOFBSystemPowerAckRef);
IOService * ackTo = gIOFBSystemPowerAckTo;
UInt32 ackRef = gIOFBSystemPowerAckRef;
gIOFBSystemPowerAckTo = 0;
FBUNLOCK();
ackTo->allowPowerChange( ackRef );
DEBG(0, " did allowPowerChange()\n");
FBLOCK();
allState |= kIOFBDidWork;
}
}
while (kIOFBDidWork & allState);
gIOFBSleepThread = false;
FBUNLOCK();
}
IOOptionBits IOFramebuffer::checkPowerWork( void )
{
UInt32 newState;
IOOptionBits ourState = kIOFBPaging;
DEBG(thisIndex, "(%d, %d)\n",
gIOFBSystemPower, pendingPowerChange);
if (!gIOFBSystemPower)
{
notifyServer( false );
if (!serverState)
{
bool doSave = (0 != gIOFBSystemPowerAckTo);
if (pagingState)
{
pagingState = false;
FBUNLOCK();
handleEvent( kIOFBNotifyWillSleep );
FBLOCK();
ourState |= kIOFBDidWork;
}
#if VRAM_SAVE
UInt32 value;
if (doSave
&& !dead
&& !__private->saveLength
&& (kIOReturnSuccess == getAttribute(kIOVRAMSaveAttribute, &value)) && value)
{
vm_size_t sLen;
sLen = __private->framebufferHeight * rowBytes;
#if VRAM_COMPRESS
vm_size_t dLen;
dLen = 5 + sLen + ((sLen + 7) >> 3) + (__private->framebufferHeight * 3);
dLen = round_page_32(dLen);
__private->saveLength = dLen;
#else
__private->saveLength = round_page_32(sLen);
#endif
__private->saveFramebuffer = IOMallocPageable( __private->saveLength, page_size );
if (__private->saveFramebuffer)
{
#if VRAM_COMPRESS
DEBG(thisIndex, " compressing\n");
dLen = CompressData( (UInt8 *) frameBuffer, bytesPerPixel,
__private->framebufferWidth, __private->framebufferHeight, rowBytes,
(UInt8 *) __private->saveFramebuffer, __private->saveLength );
DEBG(thisIndex, " compressed to %d%%\n", (dLen * 100) / sLen);
dLen = round_page_32( dLen );
if (__private->saveLength > dLen)
{
IOFreePageable( (void *) (((UInt32) __private->saveFramebuffer) + dLen),
__private->saveLength - dLen );
__private->saveLength = dLen;
}
#else
bcopy_nc( (void *) frameBuffer, __private->saveFramebuffer, sLen );
#endif
if (__private->saveLength)
{
#if RLOG
kern_return_t kr =
#endif
vm_map_wire( IOPageableMapForAddress( (vm_address_t) __private->saveFramebuffer ),
(vm_address_t) __private->saveFramebuffer,
((vm_address_t) __private->saveFramebuffer) + __private->saveLength,
VM_PROT_READ | VM_PROT_WRITE, FALSE );
DEBG(thisIndex, " vm_map_wire(%x)\n", kr);
if (this == gIOFBConsoleFramebuffer)
{
OSData * previewBuffer = OSData::withBytesNoCopy(
__private->saveFramebuffer, __private->saveLength);
if (previewBuffer)
{
getPMRootDomain()->setProperty(kIOHibernatePreviewBufferKey, previewBuffer);
previewBuffer->release();
}
}
}
}
else
__private->saveLength = 0;
}
#endif
ourState &= ~kIOFBPaging;
}
}
if (pendingPowerChange)
{
pendingPowerChange = false;
newState = pendingPowerState;
DEBG(thisIndex, " kIOPowerAttribute(%ld)\n", newState);
setAttribute( kIOPowerAttribute, newState );
FBUNLOCK();
DEBG(thisIndex, " acknowledgeSetPowerState\n");
acknowledgeSetPowerState();
FBLOCK();
ourState |= kIOFBDidWork;
}
if (__private->pendingSpeedChange)
{
__private->pendingSpeedChange = false;
setAttribute(kIOFBSpeedAttribute, __private->reducedSpeed);
}
return (ourState);
}
void IOFramebuffer::startThread(bool highPri)
{
if (!gIOFBSleepThread)
{
gIOFBSleepThread = true;
if (highPri)
thread_call_enter1(gIOFBSleepCallout, (thread_call_param_t) 0);
else
IOCreateThread(&sleepWork, 0);
}
}
IOReturn IOFramebuffer::setPowerState( unsigned long powerStateOrdinal,
IOService * whichDevice )
{
bool now;
DEBG(thisIndex, " (%ld)\n", powerStateOrdinal);
FBLOCK();
pendingPowerState = powerStateOrdinal;
now = (0xffffffff == gAllFramebuffers->getNextIndexOfObject( this, 0 ));
if (!now)
{
pendingPowerChange = true;
startThread(!gIOFBSystemPower || sleepConnectCheck);
}
if (now)
setAttribute( kIOPowerAttribute, powerStateOrdinal );
FBUNLOCK();
return (now ? 0 : 45 * 1000 * 1000);
}
IOReturn IOFramebuffer::powerStateWillChangeTo( IOPMPowerFlags flags,
unsigned long state, IOService * whatDevice )
{
IOReturn ret;
DEBG(thisIndex, " (%08lx)\n", flags);
FBLOCK();
if (state && !pm_vars->myCurrentState)
{
gIOFBSystemPower = true;
sleepConnectCheck = true;
gIOFBLastClamshellState = 0;
}
if (IOPMDeviceUsable & flags)
ret = IOPMAckImplied;
else
{
notifyServerAll( false );
if (serverState != serverNotified)
{
serverPendingAck = true;
ret = 10 * 1000 * 1000;
}
else
ret = IOPMAckImplied;
}
FBUNLOCK();
return (ret);
}
IOReturn IOFramebuffer::powerStateDidChangeTo( IOPMPowerFlags flags,
unsigned long, IOService* whatDevice )
{
DEBG(thisIndex, " (%08lx)\n", flags);
FBLOCK();
isUsable = (0 != (IOPMDeviceUsable & flags));
serverState = serverNotified;
if (isUsable)
notifyServerAll( true );
FBUNLOCK();
return (kIOReturnSuccess);
}
void IOFramebuffer::clamshellWork( thread_call_param_t p0, thread_call_param_t p1 )
{
clamshellEnable( (SInt32) p1 );
}
void IOFramebuffer::clamshellEnable( SInt32 delta )
{
UInt32 change;
bool desktopMode;
bool notSuspended;
OSObject * state;
FBLOCK();
gIOFBClamshellEnable += delta;
notSuspended = gIOFBSystemPower && (0 == gIOFBSuspendCount);
desktopMode = notSuspended && gIOFBDesktopModeAllowed && (gIOFBClamshellEnable <= 0);
FBUNLOCK();
if (delta < 0)
change = kIOPMDisableClamshell;
else if (notSuspended)
change = kIOPMEnableClamshell | kIOPMSetDesktopMode | (desktopMode ? kIOPMSetValue : 0);
else
return ;
gIOFBClamshellState = change;
getPMRootDomain()->receivePowerNotification( change );
if ((kIOPMEnableClamshell & change)
&& (state = getPMRootDomain()->getProperty(kAppleClamshellStateKey)))
{
publishResource(kAppleClamshellStateKey, gIOFBLastClamshellState ? kOSBooleanTrue : kOSBooleanFalse );
}
}
IOOptionBits IOFramebuffer::clamshellState( void )
{
return (gIOFBClamshellState);
}
IOReturn IOFramebuffer::systemPowerChange( void * target, void * refCon,
UInt32 messageType, IOService * service,
void * messageArgument, vm_size_t argSize )
{
IOReturn ret;
IOPowerStateChangeNotification * params = (IOPowerStateChangeNotification *) messageArgument;
DEBG(0, "(%08lx, %ld)\n",
messageType, (UInt32) params->powerRef);
switch (messageType)
{
case kIOMessageSystemWillSleep:
gIOFBClamshellState = kIOPMDisableClamshell;
getPMRootDomain()->receivePowerNotification( kIOPMDisableClamshell );
FBLOCK();
gIOFBSystemPower = false;
gIOFBSystemPowerAckRef = (UInt32) params->powerRef;
gIOFBSystemPowerAckTo = service;
startThread(true);
FBUNLOCK();
params->returnValue = 20 * 1000 * 1000;
ret = kIOReturnSuccess;
break;
case kIOMessageSystemHasPoweredOn:
params->returnValue = 0;
ret = kIOReturnSuccess;
break;
case kIOMessageSystemWillRestart:
case kIOMessageSystemWillPowerOff:
FBLOCK();
if (gAllFramebuffers)
{
IOFramebuffer * fb;
for (UInt32 index = 0;
(fb = (IOFramebuffer *) gAllFramebuffers->getObject(index));
index++)
fb->setAttribute( kIOSystemPowerAttribute, messageType );
}
FBUNLOCK();
params->returnValue = 0;
ret = kIOReturnSuccess;
break;
default:
ret = kIOReturnUnsupported;
break;
}
return (ret);
}
void IOFramebuffer::deferredSpeedChangeEvent( OSObject * owner,
IOInterruptEventSource * evtSrc, int intCount )
{
IOFramebuffer * self = (IOFramebuffer *) owner;
if (self->__private->pendingSpeedChange && !gIOFBSleepThread)
{
self->__private->pendingSpeedChange = false;
self->setAttribute(kIOFBSpeedAttribute, self->__private->reducedSpeed);
}
}
IOReturn IOFramebuffer::setAggressiveness( unsigned long type, unsigned long newLevel )
{
UInt32 reducedSpeed = newLevel;
if (__private
&& (type == (unsigned long) kIOFBLowPowerAggressiveness))
{
__private->reducedSpeed = reducedSpeed;
__private->pendingSpeedChange = true;
if (__private->allowSpeedChanges && __private->deferredSpeedChangeEvent)
__private->deferredSpeedChangeEvent->interruptOccurred(0, 0, 0);
}
super::setAggressiveness(type, newLevel);
return (kIOReturnSuccess);
}
IOReturn IOFramebuffer::getAggressiveness( unsigned long type, unsigned long * currentLevel )
{
IOReturn ret;
if (gIOFBGate && (type == (unsigned long) kIOFBLowPowerAggressiveness))
{
FBLOCK();
*currentLevel = __private->reducedSpeed;
FBUNLOCK();
ret = kIOReturnSuccess;
}
else
ret = super::getAggressiveness(type, currentLevel);
return (ret);
}
IOReturn
IOFramebuffer::extAcknowledgeNotification( void )
{
IOReturn err;
bool needConnectCheck, needAck;
if ((err = extEntry()))
return (err);
DEBG(thisIndex, " (%d->%d, %d)\n",
serverState, serverNotified, serverPendingAck);
needConnectCheck = (serverState != serverNotified);
serverState = serverNotified;
needAck = serverPendingAck;
serverPendingAck = false;
if (serverState && __private->cursorSlept)
{
resetCursor();
__private->cursorSlept = false;
}
else if (!serverState && !__private->cursorSlept)
{
hideCursor();
__private->cursorSlept = true;
}
checkDeferredCLUTSet();
if (needConnectCheck)
checkConnectionChange();
startThread(!gIOFBSystemPower || sleepConnectCheck);
FBUNLOCK();
if (needAck)
acknowledgePowerChange(this);
return (kIOReturnSuccess);
}
IOReturn IOFramebuffer::extRegisterNotificationPort(
mach_port_t port,
UInt32 type,
UInt32 refCon )
{
mach_msg_header_t * msgh;
UInt8 currentState;
FBLOCK();
msgh = (mach_msg_header_t *) serverMsg;
bzero( msgh, sizeof(mach_msg_header_t) );
msgh->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
msgh->msgh_size = sizeof(mach_msg_header_t);
msgh->msgh_remote_port = port;
currentState = serverNotified;
serverNotified = true; wakeServerState(serverNotified);
serverPendingAck = false;
notifyServer( currentState );
msgh->msgh_id = 0x87654321;
mach_msg_send_from_kernel( msgh, msgh->msgh_size );
FBUNLOCK();
return (kIOReturnSuccess);
}
void IOFramebuffer::writePrefs( OSObject * owner, IOTimerEventSource * sender )
{
IOFramebuffer * self = (IOFramebuffer *) owner;
DEBG(self->thisIndex, "\n");
self->messageClients( kIOMessageServicePropertyChange, (void *) 'pref' );
}
void IOFramebuffer::connectChangeInterrupt( IOFramebuffer * inst, void * delay )
{
OSIncrementAtomic( &inst->connectChange);
DEBG(inst->thisIndex, "(%ld)\n", inst->connectChange);
if (0 == inst->configPending)
{
if (delay && inst->__private->delayedConnectInterrupt)
inst->__private->delayedConnectInterrupt->setTimeoutMS((UInt32) delay);
else
inst->deferredEvents->interruptOccurred(0, 0, 0);
}
}
void IOFramebuffer::connectChangeDelayedInterrupt( OSObject * owner, IOTimerEventSource * sender )
{
IOFramebuffer * self = (IOFramebuffer *) owner;
if (0 == self->configPending)
self->deferredEvents->interruptOccurred(0, 0, 0);
}
void IOFramebuffer::deferredInterrupt( OSObject * owner,
IOInterruptEventSource * evtSrc, int intCount )
{
IOFramebuffer * self = (IOFramebuffer *) owner;
self->checkConnectionChange();
}
void IOFramebuffer::checkConnectionChange( bool message )
{
bool nowSuspended;
bool connectChangeOverSleep = (__private->disabledForConnectChange);
DEBG(thisIndex, " count(%ld), susp(%d), sleep(%d), capt(%d)\n",
connectChange, suspended, connectChangeOverSleep, captured);
if ((gIOFBDesktopModeAllowed || !gIOFBLastClamshellState)
&& (connectChange && (connectChangeOverSleep || !captured)))
{
FBLOCK();
nowSuspended = !suspended;
if (nowSuspended)
{
suspended = true;
messaged = false;
connectChange = 0;
gIOFBSuspendCount++;
}
FBUNLOCK();
if (message)
{
IOFramebuffer * next = this;
while ((next = next->getNextDependent()) && (next != this))
{
next->checkConnectionChange(false);
}
}
if (nowSuspended)
{
if (message)
messageClients( kIOMessageServiceIsSuspended, (void *) true );
}
else
DEBG(thisIndex, " spurious\n");
}
sleepConnectCheck = false;
clamshellEnable(0);
}
static bool
IOFramebufferLockedSerialize(void * target, void * ref, OSSerialize * s)
{
bool ok;
FBLOCK();
ok = ((OSObject *) target)->serialize(s);
FBUNLOCK();
return (ok);
}
IOReturn IOFramebuffer::open( void )
{
IOReturn err = kIOReturnSuccess;
UInt32 value;
void * vblInterrupt;
void * connectInterrupt;
IOFramebuffer * next;
OSNumber * num;
bool firstOpen;
do
{
if (gIOFBGate)
FBLOCK();
if (opened)
continue;
if (dead)
{
err = kIOReturnNotOpen;
continue;
}
if (!gAllFramebuffers)
{
gAllFramebuffers = OSArray::withCapacity(1);
IORegistryEntry * root;
OSData * data = 0;
if ((root = IORegistryEntry::fromPath("/", gIOServicePlane)))
{
data = OSDynamicCast(OSData, root->getProperty("graphic-options"));
root->release();
}
gIOFBDesktopModeAllowed = !data || (0 != (8 & *((UInt32 *) data->getBytesNoCopy())));
OSIterator * iter = getMatchingServices(serviceMatching("IOAccelerator"));
if (iter)
{
IOService * accel;
while ((accel = OSDynamicCast(IOService, iter->getNextObject())))
accel->requestProbe(kIOFBUserRequestProbe);
iter->release();
}
if (gIOFBPrefs)
gIOFBPrefsSerializer = OSSerializer::forTarget(gIOFBPrefs,
&IOFramebufferLockedSerialize, 0);
}
if (!gIOFramebufferKey)
gIOFramebufferKey = OSSymbol::withCStringNoCopy("IOFramebuffer");
if (!gIOFBGetSensorValueKey)
gIOFBGetSensorValueKey = OSSymbol::withCStringNoCopy(kIOFBGetSensorValueKey);
if (!gIOFBRotateKey)
gIOFBRotateKey = OSSymbol::withCStringNoCopy(kIOFBRotatePrefsKey);
if (!gIOFramebufferKey || !gIOFBGetSensorValueKey || !gIOFBRotateKey)
continue;
if (!gAllFramebuffers)
continue;
if (!gIOFBRootNotifier)
gIOFBRootNotifier = getPMRootDomain()->registerInterest(
gIOPriorityPowerStateInterest, &systemPowerChange, 0, 0 );
if (!gIOFBRootNotifier)
continue;
if (!gIOFBSleepCallout)
gIOFBSleepCallout = thread_call_allocate( (thread_call_func_t)&sleepWork,
(thread_call_param_t) 0);
if (!gIOFBSleepCallout)
continue;
if (!gIOFBClamshellCallout)
gIOFBClamshellCallout = thread_call_allocate( &clamshellWork,
(thread_call_param_t) 0);
if (!gIOFBClamshellCallout)
continue;
if (!gIOFBWorkLoop)
{
OSIterator * iter = getMatchingServices( nameMatching("IOHIDSystem") );
if (iter)
{
IOService * hidsystem;
if ((hidsystem = OSDynamicCast(IOService, iter->getNextObject())))
{
gIOFBWorkLoop = hidsystem->getWorkLoop();
if (gIOFBWorkLoop)
gIOFBWorkLoop->retain();
}
iter->release();
}
}
if (!gIOFBWorkLoop)
gIOFBWorkLoop = IOWorkLoop::workLoop();
if (!gIOFBWorkLoop)
continue;
if (!gIOFBDelayedPrefsEvent)
{
gIOFBDelayedPrefsEvent = IOTimerEventSource::timerEventSource(
this, &writePrefs);
if (gIOFBDelayedPrefsEvent)
getWorkLoop()->addEventSource(gIOFBDelayedPrefsEvent);
}
if (!gIOFBGate)
{
gIOFBGate = IOFBGate::gate( this );
if (!gIOFBGate)
continue;
gIOFBWorkLoop->addEventSource( gIOFBGate );
FBLOCK();
}
serverNotified = true;
serverState = true;
if (isConsoleDevice())
{
gIOFBConsoleFramebuffer = this;
getPlatform()->setConsoleInfo( 0, kPEDisableScreen);
}
deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange );
err = enableController();
if (kIOReturnSuccess != err)
{
dead = true;
if (nextDependent)
{
nextDependent->setNextDependent( NULL );
nextDependent = NULL;
}
deliverFramebufferNotification( kIOFBNotifyDisplayModeDidChange );
continue;
}
pagingState = true;
thisIndex = gAllFramebuffers->getCount();
gAllFramebuffers->setObject(this);
DEBG(thisIndex, " this %p \"%s\" \"%s\"\n", this, getName(), getProvider()->getName());
setProperty(kIOFramebufferOpenGLIndexKey, thisIndex, 64);
if ((num = OSDynamicCast(OSNumber, getProperty(kIOFBTransformKey))))
__private->selectedTransform = num->unsigned64BitValue();
__private->selectedTransform |= kIOFBDefaultScalerUnderscan;
err = registerForInterruptType( kIOFBVBLInterruptType,
(IOFBInterruptProc) &handleVBL,
this, priv, &vblInterrupt );
haveVBLService = (err == kIOReturnSuccess );
deferredEvents = IOInterruptEventSource::interruptEventSource(this, deferredInterrupt);
if (deferredEvents)
getWorkLoop()->addEventSource(deferredEvents);
OSObject * obj = copyProperty(kIOFBConnectInterruptDelayKey, gIOServicePlane);
if (obj)
{
OSData * data;
if ((data = OSDynamicCast(OSData, obj)))
__private->delayedConnectTime = *((UInt32 *) data->getBytesNoCopy());
obj->release();
}
if (__private->delayedConnectTime)
{
__private->delayedConnectInterrupt = IOTimerEventSource::timerEventSource(
this, &connectChangeDelayedInterrupt);
if (__private->delayedConnectInterrupt)
getWorkLoop()->addEventSource(__private->delayedConnectInterrupt);
}
err = registerForInterruptType( kIOFBConnectInterruptType,
(IOFBInterruptProc) &connectChangeInterrupt,
this, (void *) __private->delayedConnectTime,
&connectInterrupt );
err = getAttribute( kIOHardwareCursorAttribute, &value );
haveHWCursor = ((err == kIOReturnSuccess) && (0 != (kIOFBHWCursorSupported & value)));
clock_interval_to_deadline(40, kMicrosecondScale,
&__private->defaultI2CTiming.bitTimeout);
clock_interval_to_deadline(40, kMicrosecondScale,
&__private->defaultI2CTiming.byteTimeout);
clock_interval_to_deadline(40, kMicrosecondScale,
&__private->defaultI2CTiming.acknowledgeTimeout);
clock_interval_to_deadline(40, kMicrosecondScale,
&__private->defaultI2CTiming.startTimeout);
__private->lli2c = (kIOReturnSuccess == getAttributeForConnection(
0, kConnectionSupportsLLDDCSense,
(UInt32 *) &__private->defaultI2CTiming));
if ((num = OSDynamicCast(OSNumber, getProperty(kIOFBGammaWidthKey))))
__private->desiredGammaDataWidth = num->unsigned32BitValue();
if ((num = OSDynamicCast(OSNumber, getProperty(kIOFBGammaCountKey))))
__private->desiredGammaDataCount = num->unsigned32BitValue();
if ((num = OSDynamicCast(OSNumber, getProperty(kIOFBGammaHeaderSizeKey))))
__private->gammaHeaderSize = num->unsigned32BitValue();
if (haveVBLService
&& (kIOReturnSuccess == getAttribute( kIODeferCLUTSetAttribute, &value ))
&& value)
{
__private->deferredCLUTSetEvent = IOInterruptEventSource::interruptEventSource(
this, deferredCLUTSetInterrupt);
if (__private->deferredCLUTSetEvent)
{
getWorkLoop()->addEventSource(__private->deferredCLUTSetEvent);
setProperty(kIOFBCLUTDeferKey, kOSBooleanTrue);
}
}
__private->deferredSpeedChangeEvent = IOInterruptEventSource::interruptEventSource(
this, deferredSpeedChangeEvent);
if (__private->deferredSpeedChangeEvent)
getWorkLoop()->addEventSource(__private->deferredSpeedChangeEvent);
num = OSDynamicCast( OSNumber, getProperty(kIOFBDependentIDKey) );
firstOpen = num && !nextDependent;
if (firstOpen)
{
do
{
OSDictionary * matching;
OSDictionary * propMatch;
OSIterator * iter;
matching = serviceMatching(gIOFramebufferKey);
if (!matching)
continue;
propMatch = OSDictionary::withCapacity(1);
if (!propMatch)
continue;
propMatch->setObject( kIOFBDependentIDKey, num );
matching->setObject( gIOPropertyMatchKey, propMatch );
propMatch->release();
iter = getMatchingServices( matching );
matching->release();
if (iter)
{
IOFramebuffer * first = 0;
IOFramebuffer * last = 0;
while ((next = (IOFramebuffer *) iter->getNextObject()))
{
if (!first)
first = next;
else if (last)
last->setNextDependent( next );
last = next;
}
if (first && last && (first != last))
last->setNextDependent( first );
iter->release();
}
}
while (false);
}
opened = true;
UInt32 connectEnabled;
err = getAttributeForConnection( 0, kConnectionEnable, &connectEnabled );
if (kIOReturnSuccess != err)
connectEnabled = true;
__private->paramHandler = IOFramebufferParameterHandler::withFramebuffer(this);
if (__private->paramHandler)
setProperty(gIODisplayParametersKey, __private->paramHandler);
IOFramebufferI2CInterface::create( this );
if (connectEnabled)
IODisplayWrangler::makeDisplayConnects(this);
else
IODisplayUpdateNVRAM(this, 0);
__private->transform = __private->selectedTransform;
setProperty(kIOFBTransformKey, __private->transform, 64);
if (firstOpen)
{
next = this;
while ((next = next->getNextDependent()) && (next != this))
{
next->open();
}
}
if (connectEnabled)
{
setupForCurrentConfig();
err = kIOReturnSuccess;
}
else
deliverFramebufferNotification( kIOFBNotifyDisplayModeDidChange, 0 );
{
next = this;
do
{
next->postOpen();
}
while ((next = next->getNextDependent()) && (next != this));
}
}
while (false);
if (opened)
checkConnectionChange();
__private->allowSpeedChanges = true;
if (__private->pendingSpeedChange)
{
__private->pendingSpeedChange = false;
setAttribute(kIOFBSpeedAttribute, __private->reducedSpeed);
}
if (gIOFBGate)
FBUNLOCK();
return (err);
}
void IOFramebuffer::setTransform( UInt64 newTransform, bool generateChange )
{
newTransform |= (kIOFBScalerUnderscan & __private->selectedTransform);
if (newTransform != __private->selectedTransform)
{
__private->userSetTransform = true;
__private->selectedTransform = newTransform;
if (generateChange)
connectChangeInterrupt(this, 0);
else
{
__private->transform = newTransform;
setProperty(kIOFBTransformKey, newTransform, 64);
}
}
}
UInt64 IOFramebuffer::getTransform( void )
{
return (__private->transform);
}
IOReturn IOFramebuffer::selectTransform( UInt64 transform, bool generateChange )
{
IOFramebuffer * next;
next = this;
{
next->setTransform(transform, generateChange);
}
return (kIOReturnSuccess);
}
IOReturn IOFramebuffer::checkMirrorSafe( UInt32 value, IOFramebuffer * other )
{
IOReturn err = kIOReturnSuccess;
IOFramebuffer * next = this;
while ((next = next->getNextDependent()) && (next != this))
{
if (~kIOFBScalerUnderscan & (__private->transform ^ next->getTransform()))
{
err = kIOReturnUnsupported;
break;
}
}
return (err);
}
IOReturn IOFramebuffer::requestProbe( IOOptionBits options )
{
IOReturn err;
if (kIOFBSetTransform & options)
{
if ((err = extEntry()))
return (err);
options >>= 16;
selectTransform(options, true);
FBUNLOCK();
}
return (kIOReturnSuccess);
}
IOReturn IOFramebuffer::postOpen( void )
{
IOService * sensor = 0;
if (__private->cursorAttributes)
{
__private->cursorAttributes->release();
__private->cursorAttributes = 0;
}
__private->cursorAttributes = OSArray::withCapacity(2);
if (!__private->cursorAttributes)
return (kIOReturnNoMemory);
__private->testingCursor = true;
setCursorImage( (void *) 0 );
if (__private->cursorThread)
{
IOHardwareCursorDescriptor desc;
desc.majorVersion = kHardwareCursorDescriptorMajorVersion;
desc.minorVersion = kHardwareCursorDescriptorMinorVersion;
desc.height = 256;
desc.width = 256;
desc.bitDepth = 32;
desc.maskBitDepth = 0;
desc.colorEncodings = 0;
desc.flags = 0;
desc.supportedSpecialEncodings = kTransparentEncodedPixel;
(*__private->cursorControl.callouts->setCursorImage) (
__private->cursorControl.self, __private->cursorControl.ref,
&desc, (void *) 0 );
if (gIOFBWorkLoop)
gIOFBWorkLoop->addEventSource(__private->cursorThread);
}
__private->testingCursor = false;
setProperty( kIOFBCursorInfoKey, __private->cursorAttributes );
UInt32 value[16];
#define kTempAttribute 'thrm'
if (!__private->temperatureSensor
&& (kIOReturnSuccess == getAttributeForConnection(0, kTempAttribute, &value[0])))
do
{
UInt32 data;
OSNumber * num;
num = OSDynamicCast(OSNumber, getProperty(kIOFBDependentIDKey));
if (num && num->unsigned32BitValue())
continue;
sensor = new IOService;
if (!sensor)
continue;
if (!sensor->init())
continue;
#define kTempSensorName "temp-sensor"
sensor->setName(kTempSensorName);
sensor->setProperty("name", (void *) kTempSensorName, strlen(kTempSensorName) + 1);
sensor->setProperty("compatible", (void *) kTempSensorName, strlen(kTempSensorName) + 1);
sensor->setProperty("device_type", (void *) kTempSensorName, strlen(kTempSensorName) + 1);
sensor->setProperty("type", "temperature");
sensor->setProperty("location", "GPU");
data = 0xff000002;
sensor->setProperty("zone", &data, sizeof(data));
data = 0x00000001;
sensor->setProperty("version", &data, sizeof(data));
OSData * prop;
IOService * device;
data = 0x12345678;
if ((device = getProvider())
&& (prop = OSDynamicCast(OSData, device->getProperty("AAPL,phandle"))))
data = (*((UInt32 *) prop->getBytesNoCopy())) << 8;
sensor->setProperty("sensor-id", &data, sizeof(data));
if (!sensor->attach(this))
continue;
sensor->registerService();
__private->temperatureSensor = sensor;
}
while (false);
if (sensor)
sensor->release();
return (kIOReturnSuccess);
}
IOReturn IOFramebuffer::callPlatformFunction( const OSSymbol * functionName,
bool waitForFunction,
void *p1, void *p2,
void *p3, void *p4 )
{
UInt32 value[16];
IOReturn ret;
if (functionName != gIOFBGetSensorValueKey)
return (super::callPlatformFunction(functionName, waitForFunction, p1, p2, p3, p4));
FBLOCK();
ret = getAttributeForConnection(0, kTempAttribute, &value[0]);
FBUNLOCK();
if (kIOReturnSuccess == ret)
*((UInt32 *)p2) = ((value[0] & 0xffff) << 16);
return (ret);
}
IOWorkLoop * IOFramebuffer::getWorkLoop() const
{
return (gIOFBWorkLoop);
}
void IOFramebuffer::setCaptured( bool isCaptured )
{
captured = isCaptured;
}
void IOFramebuffer::setDimDisable( bool dimDisable )
{
__private->dimDisable = dimDisable;
}
bool IOFramebuffer::getDimDisable( void )
{
return (__private->dimDisable);
}
void IOFramebuffer::setNextDependent( IOFramebuffer * dependent )
{
nextDependent = dependent;
}
IOFramebuffer * IOFramebuffer::getNextDependent( void )
{
return (nextDependent);
}
void IOFramebuffer::close( void ) { mach_msg_header_t * msgh;
unsigned int idx;
if (this == gIOFBConsoleFramebuffer)
getPlatform()->setConsoleInfo( 0, kPEAcquireScreen);
msgh = (mach_msg_header_t *) serverMsg;
if (msgh)
msgh->msgh_remote_port = MACH_PORT_NULL;
serverConnect = 0;
captured = false;
if (gRunawayFramebuffers)
{
FBLOCK();
idx = gAllFramebuffers->getNextIndexOfObject( this, 0 );
if (idx != (unsigned int) -1)
gAllFramebuffers->removeObject(idx);
idx = gRunawayFramebuffers->getNextIndexOfObject( this, 0 );
if (idx != (unsigned int) -1)
gRunawayFramebuffers->removeObject(idx);
FBUNLOCK();
if (idx != (unsigned int) -1)
{
terminate();
}
}
}
IODeviceMemory * IOFramebuffer::getVRAMRange( void )
{
return (getApertureRange(kIOFBSystemAperture));
}
IOReturn IOFramebuffer::setUserRanges( void )
{
#if RLOG
UInt32 i, numRanges;
IODeviceMemory * mem;
numRanges = userAccessRanges->getCount();
DEBG(thisIndex, " ranges num:%ld\n", numRanges);
for (i = 0; i < numRanges; i++)
{
mem = (IODeviceMemory *) userAccessRanges->getObject( i );
if (0 == mem)
continue;
DEBG(thisIndex, " start:%lx size:%lx\n",
mem->getPhysicalAddress(), mem->getLength() );
}
#endif
return (kIOReturnSuccess);
}
IOReturn IOFramebuffer::setupForCurrentConfig( void )
{
return (doSetup(true));
}
IOReturn IOFramebuffer::doSetup( bool full )
{
IOReturn err;
IODisplayModeID mode;
IOIndex depth;
IOPixelInformation info;
IODeviceMemory * mem;
IODeviceMemory * fbRange;
IOPhysicalAddress base;
UInt32 value;
bool haveFB;
PE_Video newConsole;
err = getAttribute( kIOHardwareCursorAttribute, &value );
__private->cursorPanning = ((err == kIOReturnSuccess) && (0 != (kIOFBCursorPans & value)));
err = getCurrentDisplayMode( &mode, &depth );
if (kIOReturnSuccess == err)
err = getPixelInformation( mode, depth, kIOFBSystemAperture, &info );
haveFB = ((kIOReturnSuccess == err) && (info.activeWidth >= 128));
IOTimingInformation timingInfo;
timingInfo.flags = kIODetailedTimingValid;
if (haveFB
&& (kIOReturnSuccess == getTimingInfoForDisplayMode(mode, &timingInfo))
&& (kIODetailedTimingValid & timingInfo.flags))
{
setProperty(kIOFBCurrentPixelClockKey, timingInfo.detailedInfo.v2.pixelClock, 64);
setProperty(kIOFBCurrentPixelCountKey, ((UInt64)(timingInfo.detailedInfo.v2.horizontalActive
+ timingInfo.detailedInfo.v2.horizontalBlanking))
* ((UInt64)(timingInfo.detailedInfo.v2.verticalActive
+ timingInfo.detailedInfo.v2.verticalBlanking)), 64);
}
else
{
removeProperty(kIOFBCurrentPixelClockKey);
removeProperty(kIOFBCurrentPixelCountKey);
}
fbRange = getApertureRange( kIOFBSystemAperture );
if (full && fbRange)
{
userAccessRanges->removeObject( kIOFBSystemAperture );
userAccessRanges->setObject( kIOFBSystemAperture, fbRange );
err = setUserRanges();
base = fbRange->getPhysicalAddress();
if ((mem = getVRAMRange()))
{
vramMapOffset = base - mem->getPhysicalAddress();
if (vramMapOffset > mem->getLength())
vramMapOffset &= (mem->getLength() - 1);
setProperty( kIOFBMemorySizeKey, mem->getLength(), 32 );
mem->release();
}
if (vramMap)
vramMap->release();
vramMap = fbRange->map( kIOFBMapCacheMode );
assert( vramMap );
if (vramMap)
base = vramMap->getVirtualAddress();
if (haveFB && (this == gIOFBConsoleFramebuffer) || !gIOFBConsoleFramebuffer)
{
newConsole.v_baseAddr = base;
newConsole.v_rowBytes = info.bytesPerRow;
newConsole.v_width = info.activeWidth;
newConsole.v_height = info.activeHeight;
newConsole.v_depth = info.bitsPerPixel;
getPlatform()->setConsoleInfo( &newConsole, kPEReleaseScreen );
getPlatform()->setConsoleInfo( &newConsole, kPEEnableScreen );
gIOFBConsoleFramebuffer = this;
}
DEBG(thisIndex, " using (%ldx%ld,%ld bpp)\n",
info.activeWidth, info.activeHeight, info.bitsPerPixel );
}
if (full)
deliverFramebufferNotification( kIOFBNotifyDisplayModeDidChange, 0 );
if (fbRange)
fbRange->release();
if (vramMap && haveFB)
setupCursor( &info );
return (kIOReturnSuccess);
}
IOReturn IOFramebuffer::extSetDisplayMode( IODisplayModeID displayMode,
IOIndex depth )
{
IOReturn err;
bool wasSuspended;
if ((err = extEntry()))
return (err);
stopCursor();
checkDeferredCLUTSet();
if (this == gIOFBConsoleFramebuffer)
{
getPlatform()->setConsoleInfo( 0, kPEDisableScreen);
gIOFBConsoleFramebuffer = 0;
}
wasSuspended = (suspended && messaged);
DEBG(thisIndex, " susp(%d)\n", wasSuspended);
if (!wasSuspended)
deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange );
err = setDisplayMode( displayMode, depth );
clutValid = false;
DEBG(thisIndex, " paramHandler\n");
if (__private->paramHandler)
__private->paramHandler->displayModeChange();
setupForCurrentConfig();
if (wasSuspended)
{
suspended = false;
--gIOFBSuspendCount;
__private->disabledForConnectChange = false;
}
if (connectChange)
checkConnectionChange();
if (wasSuspended && !suspended)
{
AbsoluteTime deadline;
clock_interval_to_deadline( 10*1000, kMillisecondScale, &deadline );
thread_call_enter1_delayed( gIOFBClamshellCallout,
(thread_call_param_t) 0, deadline );
}
FBUNLOCK();
return (err);
}
IOReturn IOFramebuffer::extSetAttribute(
IOSelect attribute, UInt32 value, IOFramebuffer * other )
{
IOReturn err;
UInt32 data[2];
if ((err = extEntry()))
return (err);
switch (attribute)
{
case kIOMirrorAttribute:
DEBG(thisIndex, " kIOMirrorAttribute(%ld) susp(%d), curr(%d)\n",
value, suspended, __private->mirrorState);
value = (value != 0);
if (value)
{
err = checkMirrorSafe(value, other);
if (kIOReturnSuccess != err)
break;
}
if (suspended)
break;
if (value == __private->mirrorState)
break;
stopCursor();
checkDeferredCLUTSet();
if (this == gIOFBConsoleFramebuffer)
getPlatform()->setConsoleInfo( 0, kPEDisableScreen);
deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange );
data[0] = value;
data[1] = (UInt32) other;
err = setAttribute( attribute, (UInt32) &data );
if (kIOReturnSuccess == err)
__private->mirrorState = value;
clutValid = false;
setupForCurrentConfig();
break;
default:
err = setAttribute( attribute, value );
break;
}
FBUNLOCK();
return (err);
}
IOReturn IOFramebuffer::extGetAttribute(
IOSelect attribute, UInt32 * value, IOFramebuffer * other )
{
IOReturn err = kIOReturnSuccess;
bool nowOnline;
if ((err = extEntry()))
return (err);
switch (attribute)
{
case kConnectionChanged:
{
UInt32 connectEnabled;
DEBG(thisIndex, " kConnectionChanged susp(%d)\n", suspended);
if (!suspended)
break;
checkDeferredCLUTSet();
if (!__private->disabledForConnectChange)
{
__private->disabledForConnectChange = true;
deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange );
}
__private->enableScalerUnderscan = false;
err = getAttributeForConnection( 0, kConnectionChanged, (UInt32 *) &connectChange );
__private->mirrorState = false;
if (__private->paramHandler)
__private->paramHandler->setDisplay(0);
err = getAttributeForConnection( 0, kConnectionEnable, &connectEnabled );
nowOnline = (!dead && ((kIOReturnSuccess != err) || connectEnabled));
temporaryPowerClampOn();
FBUNLOCK();
IODisplayWrangler::destroyDisplayConnects( this );
if (nowOnline)
IODisplayWrangler::makeDisplayConnects( this );
FBLOCK();
__private->transform = __private->selectedTransform;
setProperty(kIOFBTransformKey, __private->transform, 64);
if (nowOnline)
{
if (__private->cursorAttributes && !__private->cursorAttributes->getCount())
{
__private->cursorAttributes->release();
__private->cursorAttributes = 0;
}
if (!__private->cursorAttributes)
{
if ((__private->cursorAttributes = OSArray::withCapacity(2)))
{
__private->testingCursor = true;
setCursorImage( (void *) 0 );
__private->testingCursor = false;
setProperty( kIOFBCursorInfoKey, __private->cursorAttributes );
}
}
}
messaged = true;
err = kIOReturnSuccess;
}
break;
default:
{
*value = (UInt32) other;
err = getAttribute( attribute, value );
}
break;
}
FBUNLOCK();
return (err);
}
IOReturn IOFramebuffer::extGetInformationForDisplayMode(
IODisplayModeID mode, void * info, IOByteCount length )
{
UInt32 flags = 0;
IOReturn err;
bool getTiming;
IOFBDisplayModeDescription * out = (IOFBDisplayModeDescription *) info;
if (length < sizeof(IODisplayModeInformation))
return (kIOReturnBadArgument);
if ((err = extEntry()))
return (err);
err = getInformationForDisplayMode( mode, &out->info );
if (kIOReturnSuccess == err)
{
err = IODisplayWrangler::getFlagsForDisplayMode( this, mode, &flags);
if (kIOReturnSuccess == err)
{
out->info.flags &= ~kDisplayModeSafetyFlags;
out->info.flags |= flags;
}
getTiming = (length >= sizeof(IOFBDisplayModeDescription));
out->timingInfo.flags = getTiming ? kIODetailedTimingValid : 0;
if (kIOReturnSuccess != getTimingInfoForDisplayMode(mode, &out->timingInfo))
{
out->timingInfo.flags &= ~kIODetailedTimingValid;
out->timingInfo.appleTimingID = 0;
}
}
FBUNLOCK();
return (err);
}
IOReturn IOFramebuffer::extSetProperties( OSDictionary * props )
{
OSDictionary * dict;
OSArray * array;
OSNumber * num;
IOReturn err = kIOReturnUnsupported;
if ((err = extEntry()))
return (err);
err = kIOReturnUnsupported;
if ((dict = OSDynamicCast(OSDictionary, props->getObject(kIOFBConfigKey))))
{
setProperty( kIOFBConfigKey, dict );
if ((num = OSDynamicCast(OSNumber,
dict->getObject(kIODisplayConnectFlagsKey))))
setAttributeForConnection( 0, kConnectionFlags, num->unsigned32BitValue() );
if (dict->getObject("IOFBScalerUnderscan"))
{
__private->enableScalerUnderscan = true;
if (__private->paramHandler)
__private->paramHandler->displayModeChange();
}
if ((array = OSDynamicCast(OSArray,
dict->getObject(kIOFBDetailedTimingsKey))))
err = setDetailedTimings( array );
else
err = kIOReturnSuccess;
}
FBUNLOCK();
return (err);
}
IOReturn IOFramebuffer::setAttribute( IOSelect attribute, UInt32 value )
{
IOReturn ret;
IOFramebuffer * next;
unsigned int index;
bool wasCaptured;
bool newCaptured, newDimDisable;
switch (attribute)
{
case kIOCapturedAttribute:
{
wasCaptured = captured;
DEBG(thisIndex, " kIOCapturedAttribute(%ld)\n", value);
newCaptured = (kIOCaptureDisableDisplayChange & value);
newDimDisable = (kIOCaptureDisableDisplayDimming & value);
next = this;
do
{
next->setCaptured( newCaptured );
}
while ((next = next->getNextDependent()) && (next != this));
if (wasCaptured && !captured)
{
next = this;
do
{
next->getAttributeForConnection( 0, kConnectionChanged, 0 );
}
while ((next = next->getNextDependent()) && (next != this));
next = this;
do
{
next->checkConnectionChange();
}
while ((next = next->getNextDependent()) && (next != this));
}
setDimDisable(newDimDisable);
for (index = 0;
(next = (IOFramebuffer *) gAllFramebuffers->getObject(index));
index++)
{
newDimDisable |= next->getDimDisable();
}
if (newDimDisable != gIOFBDimDisable)
{
gIOFBDimDisable = newDimDisable;
FBUNLOCK();
getPMRootDomain()->setAggressiveness( kIOFBCaptureAggressiveness, newDimDisable );
FBLOCK();
}
ret = kIOReturnSuccess;
break;
}
case kIOCursorControlAttribute:
{
IOFBCursorControlAttribute * crsrControl;
crsrControl = (IOFBCursorControlAttribute *) value;
if (__private->cursorThread)
{
__private->cursorThread->release();
__private->cursorThread = 0;
}
if (crsrControl && crsrControl->callouts)
{
__private->cursorControl = *((IOFBCursorControlAttribute *) value);
__private->cursorThread = IOInterruptEventSource::interruptEventSource(this, &cursorWork);
if (gIOFBWorkLoop && __private->cursorThread)
gIOFBWorkLoop->addEventSource(__private->cursorThread);
}
ret = kIOReturnSuccess;
break;
}
default:
ret = kIOReturnUnsupported;
break;
}
return (ret);
}
IOReturn IOFramebuffer::getAttribute( IOSelect attribute, UInt32 * value )
{
return (kIOReturnUnsupported);
}
bool IOFramebuffer::setNumber( OSDictionary * dict, const char * key,
UInt32 value )
{
OSNumber * num;
bool ok;
num = OSNumber::withNumber( value, 32 );
if (!num)
return (false);
ok = dict->setObject( key, num );
num->release();
return (ok);
}
bool IOFramebuffer::serializeInfo( OSSerialize * s )
{
IOReturn err;
IODisplayModeInformation info;
IOPixelInformation pixelInfo;
IODisplayModeID * modeIDs;
IOItemCount modeCount, modeNum, aperture;
IOIndex depthNum;
OSDictionary * infoDict;
OSDictionary * modeDict;
OSDictionary * pixelDict;
char keyBuf[12];
bool ok = true;
modeCount = getDisplayModeCount();
modeIDs = IONew( IODisplayModeID, modeCount );
if (!modeIDs)
return (false);
err = getDisplayModes( modeIDs );
if (err)
return (false);
infoDict = OSDictionary::withCapacity( 10 );
if (!infoDict)
return (false);
for (modeNum = 0; modeNum < modeCount; modeNum++)
{
err = getInformationForDisplayMode( modeIDs[modeNum], &info );
if (err)
continue;
modeDict = OSDictionary::withCapacity( 10 );
if (!modeDict)
break;
ok = setNumber( modeDict, kIOFBWidthKey,
info.nominalWidth )
&& setNumber( modeDict, kIOFBHeightKey,
info.nominalHeight )
&& setNumber( modeDict, kIOFBRefreshRateKey,
info.refreshRate )
&& setNumber( modeDict, kIOFBFlagsKey,
info.flags );
if (!ok)
break;
for (depthNum = 0; depthNum < info.maxDepthIndex; depthNum++)
{
for (aperture = 0; ; aperture++)
{
err = getPixelInformation( modeIDs[modeNum], depthNum,
aperture, &pixelInfo );
if (err)
break;
pixelDict = OSDictionary::withCapacity( 10 );
if (!pixelDict)
continue;
ok = setNumber( pixelDict, kIOFBBytesPerRowKey,
pixelInfo.bytesPerRow )
&& setNumber( pixelDict, kIOFBBytesPerPlaneKey,
pixelInfo.bytesPerPlane )
&& setNumber( pixelDict, kIOFBBitsPerPixelKey,
pixelInfo.bitsPerPixel )
&& setNumber( pixelDict, kIOFBComponentCountKey,
pixelInfo.componentCount )
&& setNumber( pixelDict, kIOFBBitsPerComponentKey,
pixelInfo.bitsPerComponent )
&& setNumber( pixelDict, kIOFBFlagsKey,
pixelInfo.flags )
&& setNumber( pixelDict, kIOFBWidthKey,
pixelInfo.activeWidth )
&& setNumber( pixelDict, kIOFBHeightKey,
pixelInfo.activeHeight );
if (!ok)
break;
sprintf( keyBuf, "%lx", depthNum + (aperture << 16) );
modeDict->setObject( keyBuf, pixelDict );
pixelDict->release();
}
}
sprintf( keyBuf, "%lx", modeIDs[modeNum] );
infoDict->setObject( keyBuf, modeDict );
modeDict->release();
}
IODelete( modeIDs, IODisplayModeID, modeCount );
ok &= infoDict->serialize( s );
infoDict->release();
return (ok);
}
OSDefineMetaClassAndStructors(_IOFramebufferNotifier, IONotifier)
#define LOCKNOTIFY()
#define UNLOCKNOTIFY()
void _IOFramebufferNotifier::remove()
{
LOCKNOTIFY();
if (whence)
{
whence->removeObject( (OSObject *) this );
whence = 0;
}
fEnable = false;
UNLOCKNOTIFY();
release();
}
bool _IOFramebufferNotifier::disable()
{
bool ret;
LOCKNOTIFY();
ret = fEnable;
fEnable = false;
UNLOCKNOTIFY();
return (ret);
}
void _IOFramebufferNotifier::enable( bool was )
{
LOCKNOTIFY();
fEnable = was;
UNLOCKNOTIFY();
}
IONotifier * IOFramebuffer::addFramebufferNotification(
IOFramebufferNotificationHandler handler,
OSObject * self, void * ref)
{
_IOFramebufferNotifier * notify = 0;
notify = new _IOFramebufferNotifier;
if (notify && !notify->init())
{
notify->release();
notify = 0;
}
if (notify)
{
notify->handler = handler;
notify->self = self;
notify->ref = ref;
notify->fEnable = true;
if (0 == fbNotifications)
fbNotifications = OSSet::withCapacity(1);
notify->whence = fbNotifications;
if (fbNotifications)
fbNotifications->setObject( notify );
}
return (notify);
}
IOReturn IOFramebuffer::deliverFramebufferNotification(
IOIndex event, void * info )
{
OSIterator * iter;
_IOFramebufferNotifier * notify;
IOReturn ret = kIOReturnSuccess;
IOReturn r;
DEBG(thisIndex, "(%ld)\n", event);
LOCKNOTIFY();
iter = OSCollectionIterator::withCollection( fbNotifications );
if (iter)
{
while ((notify = (_IOFramebufferNotifier *) iter->getNextObject()))
{
if (notify->fEnable)
{
r = (*notify->handler)( notify->self, notify->ref, this,
event, info );
if (kIOReturnSuccess != r)
ret = r;
}
}
iter->release();
}
UNLOCKNOTIFY();
return (ret);
}
IOReturn IOFramebuffer::enableController ( void )
{
return (kIOReturnSuccess);
}
bool IOFramebuffer::isConsoleDevice( void )
{
return (false);
}
IOReturn IOFramebuffer::setDisplayMode( IODisplayModeID ,
IOIndex )
{
return (kIOReturnUnsupported);
}
IOReturn IOFramebuffer::setApertureEnable(
IOPixelAperture , IOOptionBits )
{
return (kIOReturnUnsupported);
}
IOReturn IOFramebuffer::setStartupDisplayMode(
IODisplayModeID , IOIndex )
{
return (kIOReturnUnsupported);
}
IOReturn IOFramebuffer::getStartupDisplayMode(
IODisplayModeID * , IOIndex * )
{
return (kIOReturnUnsupported);
}
IOReturn IOFramebuffer::setCLUTWithEntries(
IOColorEntry * , UInt32 ,
UInt32 , IOOptionBits )
{
return (kIOReturnUnsupported);
}
IOReturn IOFramebuffer::setGammaTable( UInt32 ,
UInt32 , UInt32 , void * )
{
return (kIOReturnUnsupported);
}
IOReturn IOFramebuffer::getTimingInfoForDisplayMode(
IODisplayModeID ,
IOTimingInformation * )
{
return (kIOReturnUnsupported);
}
IOReturn IOFramebuffer::validateDetailedTiming(
void * description, IOByteCount descripSize )
{
return (kIOReturnUnsupported);
}
IOReturn IOFramebuffer::setDetailedTimings( OSArray * array )
{
return (kIOReturnUnsupported);
}
IOItemCount IOFramebuffer::getConnectionCount( void )
{
return (1);
}
IOReturn IOFramebuffer::setAttributeForConnection( IOIndex connectIndex,
IOSelect attribute, UInt32 info )
{
IOReturn err;
switch( attribute )
{
case kConnectionOverscan:
UInt64 newTransform;
DEBG(thisIndex, " set oscn %d, ena %d\n", info, __private->enableScalerUnderscan);
if (info)
newTransform = __private->selectedTransform & ~kIOFBScalerUnderscan;
else
newTransform = __private->selectedTransform | kIOFBScalerUnderscan;
if (__private->enableScalerUnderscan)
{
if (newTransform != __private->selectedTransform)
{
__private->selectedTransform = newTransform;
if (!__private->disabledForConnectChange)
connectChangeInterrupt(this, 0);
else
{
__private->transform = newTransform;
setProperty(kIOFBTransformKey, newTransform, 64);
}
}
err = kIOReturnSuccess;
break;
}
default:
err = kIOReturnUnsupported;
break;
}
return( err );
}
IOReturn IOFramebuffer::getAttributeForConnection( IOIndex connectIndex,
IOSelect attribute, UInt32 * value )
{
IOReturn err;
switch( attribute )
{
case kConnectionDisplayParameterCount:
if (__private->enableScalerUnderscan)
*value = 1;
else
*value = 0;
err = kIOReturnSuccess;
break;
case kConnectionDisplayParameters:
if (__private->enableScalerUnderscan)
*value = kConnectionOverscan;
err = kIOReturnSuccess;
break;
case kConnectionOverscan:
if (__private->enableScalerUnderscan)
{
value[0] = (0 == (kIOFBScalerUnderscan & __private->selectedTransform));
DEBG(thisIndex, " oscn %d (%qx)\n", value[0], __private->selectedTransform);
value[1] = 0;
value[2] = 1;
err = kIOReturnSuccess;
}
else
err = kIOReturnUnsupported;
break;
case kConnectionSupportsHLDDCSense:
if (__private->lli2c)
{
err = kIOReturnSuccess;
break;
}
default:
err = kIOReturnUnsupported;
break;
}
return( err );
}
IOReturn IOFramebuffer::setCursorImage( void * cursorImage )
{
return (kIOReturnUnsupported);
}
IOReturn IOFramebuffer::setCursorState( SInt32 x, SInt32 y, bool visible )
{
return (kIOReturnUnsupported);
}
void IOFramebuffer::flushCursor( void )
{}
IOReturn IOFramebuffer::registerForInterruptType( IOSelect interruptType,
IOFBInterruptProc proc, OSObject * target, void * ref,
void ** interruptRef )
{
return (kIOReturnUnsupported);
}
IOReturn IOFramebuffer::unregisterInterrupt( void * interruptRef )
{
return (kIOReturnUnsupported);
}
IOReturn IOFramebuffer::setInterruptState( void * interruptRef, UInt32 state )
{
return (kIOReturnUnsupported);
}
IOReturn IOFramebuffer::getAppleSense(
IOIndex ,
UInt32 * ,
UInt32 * ,
UInt32 * ,
UInt32 * )
{
return (kIOReturnUnsupported);
}
IOReturn IOFramebuffer::connectFlags( IOIndex ,
IODisplayModeID , IOOptionBits * )
{
return (kIOReturnUnsupported);
}
void IOFramebuffer::setDDCClock( IOIndex , UInt32 )
{}
void IOFramebuffer::setDDCData( IOIndex , UInt32 )
{}
bool IOFramebuffer::readDDCClock( IOIndex )
{
return (false);
}
bool IOFramebuffer::readDDCData( IOIndex )
{
return (false);
}
IOReturn IOFramebuffer::enableDDCRaster( bool )
{
return (kIOReturnUnsupported);
}
enum { kDDCBlockSize = 128 };
bool IOFramebuffer::hasDDCConnect( IOIndex connectIndex )
{
return (__private->lli2c);
}
IOReturn IOFramebuffer::getDDCBlock( IOIndex bus, UInt32 blockNumber,
IOSelect blockType, IOOptionBits options,
UInt8 * data, IOByteCount * length )
{
UInt8 startAddress;
IOReturn err;
UInt32 badsums, timeouts;
IOI2CBusTiming * timing = &__private->defaultI2CTiming;
if (!__private->lli2c)
return (kIOReturnUnsupported);
startAddress = kDDCBlockSize * (blockNumber - 1);
if (length)
*length = kDDCBlockSize;
i2cSend9Stops(bus, timing);
badsums = timeouts = 0;
do
{
err = readDDCBlock(bus, timing, 0xa0, startAddress, data);
if (kIOReturnSuccess == err)
break;
IOLog("readDDCBlock returned error\n");
i2cSend9Stops(bus, timing);
if (kIOReturnNotResponding == err)
{
IOLog("timeout\n");
timeouts++;
}
else if (kIOReturnUnformattedMedia == err)
{
IOLog("bad sum\n");
badsums++;
}
else
break;
}
while ((timeouts < 2) && (badsums < 4));
return (err);
}
IOReturn IOFramebuffer::doI2CRequest( UInt32 bus, IOI2CBusTiming * timing, IOI2CRequest * request )
{
IOReturn err = kIOReturnError;
if (!__private->lli2c)
return (kIOReturnUnsupported);
if (!timing)
timing = &__private->defaultI2CTiming;
if (request->sendTransactionType == kIOI2CSimpleTransactionType)
{
if ( request->sendAddress & 0x01 )
{
err = i2cReadData(bus, timing, request->sendAddress, request->sendBytes, (UInt8 *) request->sendBuffer);
}
else
{
err = i2cWriteData(bus, timing, request->sendAddress, request->sendBytes, (UInt8 *) request->sendBuffer);
}
}
if (request->replyTransactionType == kIOI2CDDCciReplyTransactionType )
{
err = i2cReadDDCciData(bus, timing, request->replyAddress, request->replyBytes, (UInt8 *) request->replyBuffer);
}
else if (request->replyTransactionType == kIOI2CSimpleTransactionType )
{
err = i2cReadData(bus, timing, request->replyAddress, request->replyBytes, (UInt8 *) request->replyBuffer);
}
request->result = err;
if (request->completion)
(*request->completion)(request);
err = kIOReturnSuccess;
return (err);
}
IOReturn IOFramebuffer::stopDDC1SendCommand(IOIndex bus, IOI2CBusTiming * timing)
{
UInt8 data;
IOReturn err = kIOReturnSuccess;
UInt8 address;
setDDCClock(bus, kIODDCLow);
IOSleep( 34 );
address = 0;
err = i2cWrite(bus, timing, 0xa0, 1, &address);
if (kIOReturnSuccess == err)
{
i2cStart(bus, timing);
i2cSendByte(bus, timing, 0xa1 );
err = i2cWaitForAck(bus, timing);
if (kIOReturnSuccess == err)
err = i2cReadByte(bus, timing, &data);
}
i2cSendNack(bus, timing);
i2cStop(bus, timing);
return (err);
}
IOReturn IOFramebuffer::i2cReadData(IOIndex bus, IOI2CBusTiming * timing,
UInt8 deviceAddress, UInt8 count, UInt8 * buffer)
{
IOReturn err = kIOReturnError;
UInt32 attempts = 10;
while ((kIOReturnSuccess != err) && (attempts-- > 0))
{
i2cSend9Stops(bus, timing);
err = i2cRead(bus, timing, deviceAddress, count, buffer);
}
return (err);
}
IOReturn IOFramebuffer::i2cWriteData(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 count, UInt8 * buffer)
{
IOReturn err = kIOReturnError;
UInt32 attempts = 10;
while ((kIOReturnSuccess != err) && (attempts-- > 0))
{
i2cSend9Stops(bus, timing);
err = i2cWrite(bus, timing, deviceAddress, count, buffer);
}
return (err);
}
void IOFramebuffer::waitForDDCDataLine(IOIndex bus, IOI2CBusTiming * timing, UInt32 waitTime)
{
AbsoluteTime now, expirationTime;
UInt32 dataLine;
setDDCData(bus, kIODDCTristate);
clock_interval_to_deadline(waitTime, kMillisecondScale, &expirationTime);
dataLine = readDDCData(bus);
while (true)
{
if (dataLine != readDDCData(bus))
break;
clock_get_uptime(&now);
if (CMP_ABSOLUTETIME(&now, &expirationTime) > 0)
break;
}
}
IOReturn IOFramebuffer::readDDCBlock(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 startAddress, UInt8 * data)
{
IOReturn err;
UInt32 i;
UInt8 sum = 0;
err = i2cWrite(bus, timing, deviceAddress, 1, &startAddress);
if (kIOReturnSuccess != err)
goto ErrorExit;
err = i2cRead(bus, timing, deviceAddress, kDDCBlockSize, data);
if (kIOReturnSuccess != err)
goto ErrorExit;
for (i = 0; i < kDDCBlockSize; i++)
sum += data[i];
if (sum)
err = kIOReturnUnformattedMedia;
ErrorExit:
return (err);
}
void IOFramebuffer::i2cStart(IOIndex bus, IOI2CBusTiming * timing)
{
setDDCData(bus, kIODDCHigh);
setDDCClock(bus, kIODDCHigh);
IODelay( 100 );
setDDCData(bus, kIODDCLow);
IODelay( 100 );
setDDCClock(bus, kIODDCLow);
IODelay( 100 );
}
void IOFramebuffer::i2cStop(IOIndex bus, IOI2CBusTiming * timing)
{
IODelay( 200 );
setDDCData(bus, kIODDCLow);
setDDCClock(bus, kIODDCLow);
IODelay( 100 );
setDDCClock(bus, kIODDCHigh);
IODelay( 200 );
setDDCData(bus, kIODDCHigh);
IODelay( 100 );
setDDCData(bus, kIODDCTristate);
setDDCClock(bus, kIODDCTristate);
}
void IOFramebuffer::i2cSendAck(IOIndex bus, IOI2CBusTiming * timing)
{
setDDCClock(bus, kIODDCLow);
IODelay(20);
IODelay( 40 );
setDDCData(bus, kIODDCLow);
IODelay( 100 );
setDDCClock(bus, kIODDCHigh);
IODelay( 200 );
setDDCClock(bus, kIODDCLow);
IODelay( 40 );
setDDCData(bus, kIODDCTristate);
}
void IOFramebuffer::i2cSendNack(IOIndex bus, IOI2CBusTiming * timing)
{
setDDCClock(bus, kIODDCLow);
IODelay( 20 );
IODelay( 40 );
setDDCData(bus, kIODDCHigh);
IODelay( 100 );
setDDCClock(bus, kIODDCHigh);
IODelay( 200 );
setDDCClock(bus, kIODDCLow);
IODelay( 40 );
setDDCData(bus, kIODDCTristate);
IODelay( 100 );
IODelay( 100 );
}
IOReturn IOFramebuffer::i2cWaitForAck(IOIndex bus, IOI2CBusTiming * timing)
{
AbsoluteTime now, expirationTime;
IOReturn err = kIOReturnSuccess;
IODelay( 40 );
clock_interval_to_deadline(1, kMillisecondScale, &expirationTime);
while ((0 != readDDCData(bus)) && (kIOReturnSuccess == err))
{
clock_get_uptime(&now);
if (CMP_ABSOLUTETIME(&now, &expirationTime) > 0)
err = kIOReturnNotResponding; }
IODelay( 40 );
setDDCClock(bus, kIODDCHigh);
IODelay( 200 );
setDDCClock(bus, kIODDCLow);
IODelay( 40 );
return (err);
}
void IOFramebuffer::i2cSendByte(IOIndex bus, IOI2CBusTiming * timing, UInt8 data)
{
UInt8 valueToSend;
int i;
for ( i = 0 ; i < 8; i++ )
{
IODelay( 100 );
valueToSend = ( data >> (7 - i)) & 0x01;
setDDCData(bus, valueToSend);
IODelay( 40 );
setDDCClock(bus, kIODDCHigh);
IODelay( 200 );
setDDCClock(bus, kIODDCLow);
IODelay( 40 );
}
setDDCData(bus, kIODDCTristate);
}
IOReturn IOFramebuffer::i2cReadByte(IOIndex bus, IOI2CBusTiming * timing, UInt8 *data)
{
AbsoluteTime now, expirationTime;
IOReturn err = kIOReturnSuccess;
UInt32 i;
UInt32 value;
setDDCClock(bus, kIODDCLow);
setDDCData(bus, kIODDCTristate);
for (i = 0 ; (kIOReturnSuccess == err) && (i < 8); i++)
{
IODelay( 100 );
setDDCClock(bus, kIODDCTristate);
clock_interval_to_deadline(2, kMillisecondScale, &expirationTime);
while ((0 == readDDCClock(bus)) && (kIOReturnSuccess == err))
{
clock_get_uptime(&now);
if (CMP_ABSOLUTETIME(&now, &expirationTime) > 0)
err = kIOReturnNotResponding; }
value = readDDCData(bus);
*data |= (value << (7-i));
IODelay( 200 );
setDDCClock(bus, kIODDCLow);
IODelay( 40 );
}
return (err);
}
IOReturn IOFramebuffer::i2cWaitForBus(IOIndex bus, IOI2CBusTiming * timing)
{
setDDCClock(bus, kIODDCTristate);
setDDCData(bus, kIODDCTristate);
IODelay( 200 );
return kIOReturnSuccess;
}
IOReturn IOFramebuffer::i2cReadDDCciData(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 count, UInt8 *buffer)
{
IOReturn err = kIOReturnSuccess;
UInt32 i;
UInt8 readLength;
UInt32 bufferSize;
Boolean reportShortRead = false;
bufferSize = count;
err = i2cWaitForBus(bus, timing);
if( kIOReturnSuccess != err ) goto ErrorExit;
i2cStart(bus, timing);
i2cSendByte(bus, timing, deviceAddress | 0x01 );
err = i2cWaitForAck(bus, timing);
if( kIOReturnSuccess != err ) goto ErrorExit;
for ( i = 0; i < bufferSize; i++ )
{
err = i2cReadByte(bus, timing, &buffer[i] );
if( kIOReturnSuccess != err ) goto ErrorExit;
i2cSendAck(bus, timing);
if ( i == 1 )
{
readLength = buffer[i] & 0x07;
if ( (readLength + 1) <= count )
{
bufferSize = (readLength + 1);
}
else
{
reportShortRead = true;
}
}
}
ErrorExit:
i2cSendNack(bus, timing);
i2cStop(bus, timing);
if ( reportShortRead )
err = kIOReturnOverrun;
return (err);
}
IOReturn IOFramebuffer::i2cRead(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 numberOfBytes, UInt8 * data)
{
IOReturn err = kIOReturnSuccess;
int i;
err = i2cWaitForBus(bus, timing);
if (kIOReturnSuccess != err)
goto ErrorExit;
i2cStart(bus, timing);
i2cSendByte(bus, timing, deviceAddress | 0x01 );
err = i2cWaitForAck(bus, timing);
if (kIOReturnSuccess != err)
goto ErrorExit;
for (i = 0; i < numberOfBytes; i++)
{
data[i] = 0;
err = i2cReadByte(bus, timing, &data[i] );
if (kIOReturnSuccess != err)
break;
if (i != (numberOfBytes - 1))
i2cSendAck(bus, timing);
}
ErrorExit:
i2cSendNack(bus, timing);
i2cStop(bus, timing);
return (err);
}
IOReturn IOFramebuffer::i2cWrite(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 numberOfBytes, UInt8 * data)
{
IOReturn err = kIOReturnSuccess;
UInt32 i;
err = i2cWaitForBus(bus, timing);
if (kIOReturnSuccess != err)
goto ErrorExit;
i2cStart(bus, timing);
i2cSendByte(bus, timing, deviceAddress);
err = i2cWaitForAck(bus, timing);
if (kIOReturnSuccess != err)
goto ErrorExit;
for (i = 0; i < numberOfBytes; i++)
{
i2cSendByte(bus, timing, data[i] );
err = i2cWaitForAck(bus, timing);
if (kIOReturnSuccess != err)
break;
}
ErrorExit:
if (kIOReturnSuccess != err)
i2cStop(bus, timing);
return (err);
}
void IOFramebuffer::i2cSend9Stops(IOIndex bus, IOI2CBusTiming * timing)
{
for (UInt32 i = 0; i < 9; i++)
i2cStop(bus, timing);
}
IOReturn IOFramebuffer::setPreferences( IOService * props, OSDictionary * prefs )
{
if (!gIOFBPrefs)
{
prefs->retain();
gIOFBPrefs = prefs;
gIOFBPrefsParameters = OSDynamicCast(OSDictionary,
props->getProperty(kIOGraphicsPrefsParametersKey));
}
return (kIOReturnSuccess);
}
OSObject * IOFramebuffer::copyPreferences( void )
{
if (gIOFBPrefsSerializer)
gIOFBPrefsSerializer->retain();
return (gIOFBPrefsSerializer);
}
OSObject * IOFramebuffer::copyPreference( IODisplay * display, const OSSymbol * key )
{
const OSSymbol * displayKey;
OSDictionary * dict;
OSObject * value = 0;
if (!gIOFBPrefs)
return (value);
displayKey = (const OSSymbol *) display->copyProperty(kIODisplayPrefKeyKey);
if (!displayKey)
return (value);
if ((dict = OSDynamicCast(OSDictionary, gIOFBPrefs->getObject(displayKey))))
{
value = dict->getObject(key);
if (value)
value->retain();
}
displayKey->release();
return (value);
}
bool IOFramebuffer::getIntegerPreference( IODisplay * display, const OSSymbol * key, UInt32 * value )
{
bool found = false;
OSObject *
pref = copyPreference(display, key);
if (pref)
{
OSNumber * num;
if ((num = OSDynamicCast(OSNumber, pref)))
{
value[0] = num->unsigned32BitValue();
DEBG(thisIndex, " found %s = %d\n", key->getCStringNoCopy(), value[0]);
found = true;
}
pref->release();
}
return (found);
}
bool IOFramebuffer::setPreference( IODisplay * display, const OSSymbol * key, OSObject * value )
{
const OSSymbol * displayKey;
OSDictionary * dict;
OSObject * oldValue = 0;
bool madeChanges = false;
if (!gIOFBPrefs)
return (false);
displayKey = (const OSSymbol *) display->copyProperty(kIODisplayPrefKeyKey);
if (!displayKey)
return (false);
dict = OSDynamicCast(OSDictionary, gIOFBPrefs->getObject(displayKey));
if (!dict)
{
dict = OSDictionary::withCapacity(4);
if (dict)
{
gIOFBPrefs->setObject(displayKey, dict);
dict->release();
madeChanges = true;
}
}
else if (key)
oldValue = dict->getObject(key);
if (key && dict)
{
if (!oldValue || (!oldValue->isEqualTo(value)))
{
dict->setObject(key, value);
madeChanges = true;
}
}
if (madeChanges)
{
DEBG(thisIndex, " sched prefs\n");
gIOFBDelayedPrefsEvent->setTimeoutMS((UInt32) 2000);
}
displayKey->release();
return (true);
}
bool IOFramebuffer::setIntegerPreference( IODisplay * display, const OSSymbol * key, UInt32 value )
{
bool ok = false;
OSNumber *
num = OSNumber::withNumber(value, 32);
if (num)
{
ok = setPreference(display, key, num);
num->release();
}
DEBG(0, " %s = %d\n", key->getCStringNoCopy(), value);
return (ok);
}
void IOFramebuffer::getTransformPrefs( IODisplay * display )
{
UInt32 value;
if (getIntegerPreference(display, gIODisplayOverscanKey, &value))
{
if (value)
__private->selectedTransform = __private->selectedTransform & ~kIOFBScalerUnderscan;
else
__private->selectedTransform = __private->selectedTransform | kIOFBScalerUnderscan;
}
if (__private->userSetTransform)
{
__private->userSetTransform = false;
setIntegerPreference(display, gIOFBRotateKey, __private->selectedTransform & ~kIOFBScalerUnderscan);
}
else if (getIntegerPreference(display, gIOFBRotateKey, &value))
selectTransform(value, false);
else if (__private->transform & ~kIOFBScalerUnderscan)
selectTransform(0, false);
}
#undef super
#define super IODisplayParameterHandler
OSDefineMetaClassAndStructors(IOFramebufferParameterHandler, IODisplayParameterHandler)
IOFramebufferParameterHandler * IOFramebufferParameterHandler::withFramebuffer( IOFramebuffer * framebuffer )
{
IOFramebufferParameterHandler * handler;
UInt32 count = 0;
if ((kIOReturnSuccess != framebuffer->getAttributeForConnection(
0, kConnectionDisplayParameterCount, &count)))
return (0);
handler = new IOFramebufferParameterHandler;
if (handler && !handler->init())
{
handler->release();
handler = 0;
}
if (handler)
handler->fFramebuffer = framebuffer;
return (handler);
}
void IOFramebufferParameterHandler::free()
{
if (fDisplayParams)
fDisplayParams->release();
super::free();
}
bool IOFramebufferParameterHandler::setDisplay( IODisplay * display )
{
IOReturn ret;
UInt32 count = 0;
UInt32 str[2];
const OSSymbol * sym;
UInt32 value[16];
UInt32 * attributes;
OSDictionary * allParams;
OSDictionary * newDict = 0;
OSDictionary * oldParams;
const OSSymbol * key;
OSIterator * iter;
fDisplay = display;
if (!fDisplay)
return (false);
FBLOCK();
fFramebuffer->setPreference(display, 0, 0);
fFramebuffer->getTransformPrefs(display);
allParams = OSDynamicCast(OSDictionary, display->copyProperty(gIODisplayParametersKey));
if (allParams)
{
newDict = OSDictionary::withDictionary(allParams);
allParams->release();
}
ret = fFramebuffer->getAttributeForConnection(
0, kConnectionDisplayParameterCount, &count);
if (kIOReturnSuccess != ret)
count = 0;
DEBG(0, " (%x) count %d\n", ret, count);
oldParams = fDisplayParams;
do
{
if (count)
fDisplayParams = OSDictionary::withCapacity(count);
else
fDisplayParams = 0;
if (!fDisplayParams)
continue;
attributes = IONew(UInt32, count);
if (!attributes)
continue;
if (kIOReturnSuccess != fFramebuffer->getAttributeForConnection(
0, kConnectionDisplayParameters, attributes))
continue;
str[1] = 0;
for (UInt32 i = 0; i < count; i++)
{
if (attributes[i] < 0x00ffffff)
continue;
str[0] = attributes[i];
sym = OSSymbol::withCString((const char *) str);
if (!sym)
continue;
if (kIOReturnSuccess == fFramebuffer->getAttributeForConnection(0, attributes[i], &value[0]))
{
if (gIOFBPrefsParameters && gIOFBPrefsParameters->getObject(sym))
fFramebuffer->getIntegerPreference(display, sym, &value[0]);
IODisplay::addParameter(fDisplayParams, sym, value[1], value[2]);
IODisplay::setParameter(fDisplayParams, sym, value[0]);
}
DEBG(0, " [%d] %s = %d, (%d - %d)\n", i, (const char *) str, value[0], value[1], value[2]);
sym->release();
}
IODelete(attributes, UInt32, count);
}
while (false);
if (oldParams)
{
if (newDict)
{
iter = OSCollectionIterator::withCollection(oldParams);
if (iter)
{
while ((key = (const OSSymbol *) iter->getNextObject()))
{
if (!fDisplayParams || !fDisplayParams->getObject(key))
newDict->removeObject(key);
}
iter->release();
}
}
oldParams->release();
}
if (newDict)
{
if (fDisplayParams)
newDict->merge(fDisplayParams);
display->setProperty(gIODisplayParametersKey, newDict);
newDict->release();
}
else if (fDisplayParams)
display->setProperty(gIODisplayParametersKey, fDisplayParams);
FBUNLOCK();
return (true);
}
void IOFramebufferParameterHandler::displayModeChange( void )
{
if (fDisplay)
setDisplay( fDisplay );
}
bool IOFramebufferParameterHandler::doIntegerSet( OSDictionary * params,
const OSSymbol * paramName, UInt32 value )
{
UInt32 attribute;
bool ok;
FBLOCK();
if (fDisplayParams && fDisplayParams->getObject(paramName))
{
if (fDisplay && gIOFBPrefsParameters && gIOFBPrefsParameters->getObject(paramName))
fFramebuffer->setIntegerPreference(fDisplay, paramName, value);
attribute = *((UInt32 *) paramName->getCStringNoCopy());
ok = (kIOReturnSuccess == fFramebuffer->setAttributeForConnection(
0, attribute, value));
}
else
ok = false;
FBUNLOCK();
return (ok);
}
bool IOFramebufferParameterHandler::doDataSet( const OSSymbol * paramName, OSData * value )
{
return (false);
}
bool IOFramebufferParameterHandler::doUpdate( void )
{
bool ok = true;
return (ok);
}
#undef super
#define super IOI2CInterface
OSDefineMetaClassAndStructors(IOFramebufferI2CInterface, IOI2CInterface)
IOFramebufferI2CInterface * IOFramebufferI2CInterface::withFramebuffer(
IOFramebuffer * framebuffer, OSDictionary * info )
{
IOFramebufferI2CInterface * interface;
interface = new IOFramebufferI2CInterface;
info = OSDictionary::withDictionary(info);
if (interface && info)
{
interface->fFramebuffer = framebuffer;
if (!interface->init(info)
|| !interface->attach(framebuffer)
|| !interface->start(framebuffer)
)
{
interface->detach( framebuffer );
interface->release();
interface = 0;
}
}
if (info)
info->release();
return (interface);
}
bool IOFramebufferI2CInterface::start( IOService * provider )
{
bool ok = false;
OSNumber * num;
if (!super::start(provider))
return (false);
do
{
num = OSDynamicCast(OSNumber, getProperty(kIOI2CInterfaceIDKey));
if (!num)
break;
fBusID = num->unsigned32BitValue();
num = OSDynamicCast(OSNumber, getProperty(kIOI2CBusTypeKey));
if (!num)
setProperty(kIOI2CBusTypeKey, (UInt64) kIOI2CBusTypeI2C, 32);
num = OSDynamicCast(OSNumber, getProperty(kIOI2CTransactionTypesKey));
if (num)
fSupportedTypes = num->unsigned32BitValue();
else
{
fSupportedTypes = ((1 << kIOI2CNoTransactionType)
| (1 << kIOI2CSimpleTransactionType)
| (1 << kIOI2CDDCciReplyTransactionType)
| (1 << kIOI2CCombinedTransactionType));
setProperty(kIOI2CTransactionTypesKey, (UInt64) fSupportedTypes, 32);
}
num = OSDynamicCast(OSNumber, getProperty(kIOI2CSupportedCommFlagsKey));
if (num)
fSupportedCommFlags = num->unsigned32BitValue();
else
{
fSupportedCommFlags = kIOI2CUseSubAddressCommFlag;
setProperty(kIOI2CSupportedCommFlagsKey, (UInt64) fSupportedCommFlags, 32);
}
UInt64 id = (((UInt64) (UInt32) fFramebuffer) << 32) | fBusID;
registerI2C(id);
ok = true;
}
while (false);
return (ok);
}
IOReturn IOFramebufferI2CInterface::startIO( IOI2CRequest * request )
{
IOReturn err;
FBLOCK();
do
{
if (0 == ((1 << request->sendTransactionType) & fSupportedTypes))
{
err = kIOReturnUnsupportedMode;
continue;
}
if (0 == ((1 << request->replyTransactionType) & fSupportedTypes))
{
err = kIOReturnUnsupportedMode;
continue;
}
if (request->commFlags != (request->commFlags & fSupportedCommFlags))
{
err = kIOReturnUnsupportedMode;
continue;
}
err = fFramebuffer->doI2CRequest( fBusID, 0, request );
}
while (false);
if (kIOReturnSuccess != err)
{
request->result = err;
if (request->completion)
(*request->completion)(request);
err = kIOReturnSuccess;
}
FBUNLOCK();
return (err);
}
#if __ppc__
class AppleOnboardI2CInterface : public IOI2CInterface
{
OSDeclareDefaultStructors(AppleOnboardI2CInterface)
class PPCI2CInterface * fInterface;
SInt32 fPort;
public:
virtual bool start( IOService * provider );
virtual IOReturn startIO( IOI2CRequest * request );
static AppleOnboardI2CInterface * withInterface( PPCI2CInterface * interface, SInt32 port );
};
#undef super
#define super IOI2CInterface
OSDefineMetaClassAndStructors(AppleOnboardI2CInterface, IOI2CInterface)
AppleOnboardI2CInterface * AppleOnboardI2CInterface::withInterface(
PPCI2CInterface * onboardInterface, SInt32 port )
{
AppleOnboardI2CInterface * interface;
UInt64 id = (((UInt64) (UInt32) onboardInterface) << 32) | port;
interface = new AppleOnboardI2CInterface;
if (interface)
{
interface->fInterface = onboardInterface;
interface->fPort = port;
if (!interface->init()
|| !interface->attach(onboardInterface)
|| !interface->start(onboardInterface)
)
{
interface->detach( onboardInterface );
interface->release();
interface = 0;
}
else
interface->registerI2C(id);
}
return (interface);
}
bool AppleOnboardI2CInterface::start( IOService * provider )
{
if (!super::start(provider))
return (false);
setProperty(kIOI2CBusTypeKey,
(UInt64) kIOI2CBusTypeI2C, 32);
setProperty(kIOI2CTransactionTypesKey,
(UInt64) ((1 << kIOI2CNoTransactionType)
| (1 << kIOI2CSimpleTransactionType)
| (1 << kIOI2CDDCciReplyTransactionType)
| (1 << kIOI2CCombinedTransactionType)), 32);
setProperty(kIOI2CSupportedCommFlagsKey,
(UInt64) kIOI2CUseSubAddressCommFlag, 32);
return (true);
}
IOReturn AppleOnboardI2CInterface::startIO( IOI2CRequest * request )
{
IOReturn err = kIOReturnSuccess;
do
{
fInterface->openI2CBus(fPort);
fInterface->setPollingMode(true);
if (request->sendBytes && (kIOI2CNoTransactionType != request->sendTransactionType))
{
if (kIOI2CCombinedTransactionType == request->sendTransactionType)
fInterface->setCombinedMode();
else if (kIOI2CUseSubAddressCommFlag & request->commFlags)
fInterface->setStandardSubMode();
else
fInterface->setStandardMode();
if (!fInterface->writeI2CBus(request->sendAddress >> 1, request->sendSubAddress,
(UInt8 *) request->sendBuffer, request->sendBytes))
err = kIOReturnNotWritable;
}
if (request->replyBytes && (kIOI2CNoTransactionType != request->replyTransactionType))
{
if (kIOI2CCombinedTransactionType == request->replyTransactionType)
fInterface->setCombinedMode();
else if (kIOI2CUseSubAddressCommFlag & request->commFlags)
fInterface->setStandardSubMode();
else
fInterface->setStandardMode();
if (!fInterface->readI2CBus(request->replyAddress >> 1, request->replySubAddress,
(UInt8 *) request->replyBuffer, request->replyBytes))
err = kIOReturnNotReadable;
}
fInterface->closeI2CBus();
}
while (false);
request->result = err;
err = kIOReturnSuccess;
return (err);
}
#endif
IOReturn IOFramebufferI2CInterface::create( IOFramebuffer * framebuffer )
{
IOReturn err = kIOReturnSuccess;
IOI2CInterface * interface;
UInt32 idx;
OSArray * busArray;
OSArray * interfaceIDArray;
OSDictionary * dict;
OSObject * num;
bool ok = true;
interfaceIDArray = OSArray::withCapacity(1);
if (!interfaceIDArray)
return (kIOReturnNoMemory);
busArray = OSDynamicCast(OSArray, framebuffer->getProperty(kIOFBI2CInterfaceInfoKey));
do
{
if (!busArray)
continue;
for (idx = 0; (dict = OSDynamicCast(OSDictionary, busArray->getObject(idx))); idx++)
{
interface = IOFramebufferI2CInterface::withFramebuffer(framebuffer, dict);
if (!interface)
break;
num = interface->getProperty(kIOI2CInterfaceIDKey);
if (num)
interfaceIDArray->setObject(num);
else
break;
}
ok = (idx == busArray->getCount());
}
while (false);
#if __ppc__
OSData * data = OSDynamicCast( OSData, framebuffer->getProvider()->getProperty("iic-address"));
if (data && (!framebuffer->getProperty(kIOFBDependentIDKey))
&& (0x8c == *((UInt32 *) data->getBytesNoCopy())) )
{
do
{
PPCI2CInterface * onboardInterface =
(PPCI2CInterface*) getResourceService()->getProperty("PPCI2CInterface.i2c-uni-n");
if (!onboardInterface)
continue;
interface = AppleOnboardI2CInterface::withInterface( onboardInterface, 1 );
if (!interface)
break;
num = interface->getProperty(kIOI2CInterfaceIDKey);
if (num)
interfaceIDArray->setObject(num);
else
break;
}
while (false);
}
#endif
if (ok && interfaceIDArray->getCount())
framebuffer->setProperty(kIOFBI2CInterfaceIDsKey, interfaceIDArray);
interfaceIDArray->release();
return (err);
}
OSMetaClassDefineReservedUsed(IOFramebuffer, 0);
OSMetaClassDefineReservedUnused(IOFramebuffer, 1);
OSMetaClassDefineReservedUnused(IOFramebuffer, 2);
OSMetaClassDefineReservedUnused(IOFramebuffer, 3);
OSMetaClassDefineReservedUnused(IOFramebuffer, 4);
OSMetaClassDefineReservedUnused(IOFramebuffer, 5);
OSMetaClassDefineReservedUnused(IOFramebuffer, 6);
OSMetaClassDefineReservedUnused(IOFramebuffer, 7);
OSMetaClassDefineReservedUnused(IOFramebuffer, 8);
OSMetaClassDefineReservedUnused(IOFramebuffer, 9);
OSMetaClassDefineReservedUnused(IOFramebuffer, 10);
OSMetaClassDefineReservedUnused(IOFramebuffer, 11);
OSMetaClassDefineReservedUnused(IOFramebuffer, 12);
OSMetaClassDefineReservedUnused(IOFramebuffer, 13);
OSMetaClassDefineReservedUnused(IOFramebuffer, 14);
OSMetaClassDefineReservedUnused(IOFramebuffer, 15);
OSMetaClassDefineReservedUnused(IOFramebuffer, 16);
OSMetaClassDefineReservedUnused(IOFramebuffer, 17);
OSMetaClassDefineReservedUnused(IOFramebuffer, 18);
OSMetaClassDefineReservedUnused(IOFramebuffer, 19);
OSMetaClassDefineReservedUnused(IOFramebuffer, 20);
OSMetaClassDefineReservedUnused(IOFramebuffer, 21);
OSMetaClassDefineReservedUnused(IOFramebuffer, 22);
OSMetaClassDefineReservedUnused(IOFramebuffer, 23);
OSMetaClassDefineReservedUnused(IOFramebuffer, 24);
OSMetaClassDefineReservedUnused(IOFramebuffer, 25);
OSMetaClassDefineReservedUnused(IOFramebuffer, 26);
OSMetaClassDefineReservedUnused(IOFramebuffer, 27);
OSMetaClassDefineReservedUnused(IOFramebuffer, 28);
OSMetaClassDefineReservedUnused(IOFramebuffer, 29);
OSMetaClassDefineReservedUnused(IOFramebuffer, 30);
OSMetaClassDefineReservedUnused(IOFramebuffer, 31);