#include <IOKit/IOLib.h>
#include <libkern/c++/OSContainers.h>
#include <libkern/OSByteOrder.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#define IOFRAMEBUFFER_PRIVATE
#include <IOKit/graphics/IOFramebuffer.h>
#include <IOKit/graphics/IODisplay.h>
#include "IOFramebufferUserClient.h"
#include "IODisplayWrangler.h"
#include "IOFramebufferReallyPrivate.h"
#include <IOKit/pwr_mgt/RootDomain.h>
#include <string.h>
#include <IOKit/assert.h>
#include <sys/kdebug.h>
#if DOANIO
#include <sys/uio.h>
#include <sys/conf.h>
#endif
#undef super
#define super IOGraphicsDevice
OSDefineMetaClass( IOFramebuffer, IOGraphicsDevice )
OSDefineAbstractStructors( IOFramebuffer, IOGraphicsDevice )
static OSArray * gAllFramebuffers;
static IOLock * gIOFBSleepStateLock;
static thread_call_t gIOFBSleepCallout;
static IONotifier * gIOFBRootNotifier;
static IOService * gIOFBSystemPowerAckTo;
static UInt32 gIOFBSystemPowerAckRef;
static bool gIOFBSystemPower = true;
static bool gIOFBSleepThread;
#define GetShmem(instance) ((StdFBShmem_t *)(instance->priv))
#define CLEARSEMA(shmem) 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)))
#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[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[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[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[shmem->frame].width;
shmem->cursorRect.maxy = (shmem->cursorRect.miny = y)
+ shmem->cursorSize[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[shmem->frame];
tempRect.maxx = (tempRect.minx = (shmem->cursorLoc).x - hs->x)
+ shmem->cursorSize[shmem->frame].width;
tempRect.maxy = (tempRect.miny = (shmem->cursorLoc).y - hs->y)
+ shmem->cursorSize[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;
rowBytes = info->bytesPerRow;
totalWidth = (rowBytes * 8) / info->bitsPerPixel;
bytesPerPixel = info->bitsPerPixel / 8;
frameBuffer = (volatile unsigned char *) vramMap->getVirtualAddress();
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;
}
cursorImageBytes = maxCursorSize.width * maxCursorSize.height
* bytesPerPixel;
bits = shmem->cursor;
for( int i = 0; i < kIOFBNumCursorFrames; i++ ) {
cursorImages[i] = bits;
bits += cursorImageBytes;
shmem->cursorSize[i] = maxCursorSize;
}
if( info->bitsPerPixel <= 8) {
for( int i = 0; i < kIOFBNumCursorFrames; i++ ) {
cursorMasks[i] = bits;
bits += 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::createSharedCursor(
int shmemVersion, int maxWidth, int maxHeight )
{
StdFBShmem_t * shmem;
IOByteCount size, maxImageSize;
kprintf("createSharedCursor vers = %d, %d x %d\n",
shmemVersion, maxWidth, maxHeight);
if( shmemVersion != kIOFBCurrentShmemVersion)
return( kIOReturnUnsupported);
shmemClientVersion = shmemVersion;
maxImageSize = (maxWidth * maxHeight * kIOFBMaxCursorDepth) / 8;
size = sizeof( StdFBShmem_t)
+ ((kIOFBNumCursorFrames + 1) * maxImageSize);
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 = kIOFBCurrentShmemVersion;
shmem->structSize = size;
shmem->cursorShow = 1;
shmem->hardwareCursorCapable = haveHWCursor;
for( int i = 0; i < kIOFBNumCursorFrames; i++)
shmem->hardwareCursorFlags[i] = kIOFBCursorImageNew;
maxCursorSize.width = maxWidth;
maxCursorSize.height = maxHeight;
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( isConsoleDevice())
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);
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 )
{
*count = getDisplayModeCount();
return( kIOReturnSuccess);
}
IOReturn IOFramebuffer::extGetDisplayModes( IODisplayModeID * allModes, IOByteCount * size )
{
IOReturn err;
IOByteCount outSize;
outSize = getDisplayModeCount() * sizeof( IODisplayModeID);
if( *size < outSize)
return( kIOReturnBadArgument);
*size = outSize;
err = getDisplayModes( allModes );
return( err);
}
IOReturn IOFramebuffer::extGetVRAMMapOffset( IOPixelAperture ,
IOByteCount * offset )
{
*offset = vramMapOffset;
return( kIOReturnSuccess );
}
IOReturn IOFramebuffer::extSetBounds( Bounds * bounds )
{
StdFBShmem_t *shmem;
shmem = GetShmem(this);
if( shmem)
shmem->screenBounds = *bounds;
return( kIOReturnSuccess );
}
IOReturn IOFramebuffer::extValidateDetailedTiming(
void * description, void * outDescription,
IOByteCount inSize, IOByteCount * outSize )
{
IOReturn err;
if( *outSize != inSize)
return( kIOReturnBadArgument );
err = validateDetailedTiming( description, inSize );
if( kIOReturnSuccess == err)
bcopy( description, outDescription, inSize );
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) };
UInt8 * table;
IODisplayModeID mode;
IOIndex depth;
IOPixelInformation info;
if( select > 3)
return( kIOReturnBadArgument );
if( length != checkLength[select])
return( kIOReturnBadArgument );
table = colorConvert.tables[select];
if( 0 == table) {
table = (UInt8 *) IOMalloc( length );
colorConvert.tables[select] = table;
}
if( !table)
return( kIOReturnNoMemory );
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 );
return( kIOReturnSuccess );
}
IOReturn IOFramebuffer::extSetCLUTWithEntries( UInt32 index, IOOptionBits options,
IOColorEntry * colors, IOByteCount inputCount )
{
IOReturn kr;
kr = setCLUTWithEntries( colors, index,
inputCount / sizeof( IOColorEntry),
options );
return( kr );
}
void IOFramebuffer::hideCursor( void )
{
StdFBShmem_t *shmem = GetShmem(this);
SETSEMA(shmem);
SysHideCursor(this);
CLEARSEMA(shmem);
}
#if 0
void IOFramebuffer::free()
{
if( vblSemaphore)
semaphore_destroy(kernel_task, vblSemaphore);
super::free();
}
#endif
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[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();
}
inst->needCursorService = (kIOReturnBusy == err);
}
void IOFramebuffer::moveCursor( Point * cursorLoc, int frame )
{
nextCursorLoc = *cursorLoc;
nextCursorFrame = frame;
needCursorService = true;
StdFBShmem_t *shmem = GetShmem(this);
SETSEMA(shmem);
if( frame != shmem->frame) {
if( shmem->hardwareCursorFlags[frame]) {
hwCursorLoaded = (kIOReturnSuccess == setCursorImage( (void *) frame ));
shmem->hardwareCursorFlags[frame] = hwCursorLoaded ? kIOFBCursorHWCapable : 0;
} else
hwCursorLoaded = false;
shmem->frame = frame;
if( shmem->hardwareCursorActive != hwCursorLoaded) {
SysHideCursor( this );
shmem->hardwareCursorActive = hwCursorLoaded;
if (shmem->shieldFlag
&& ((false == shmem->hardwareCursorActive) || (shmem->hardwareCursorShields)))
CheckShield(this);
SysShowCursor( this );
}
}
if( !haveVBLService) {
shmem->cursorLoc = *cursorLoc;
shmem->frame = frame;
deferredMoveCursor( this );
}
CLEARSEMA(shmem);
}
void IOFramebuffer::handleVBL( IOFramebuffer * inst, void * ref )
{
StdFBShmem_t * shmem = GetShmem(inst);
AbsoluteTime now;
if( !shmem)
return;
clock_get_uptime( &now );
shmem->vblDelta = now;
SUB_ABSOLUTETIME( &shmem->vblDelta, &shmem->vblTime );
shmem->vblTime = now;
KERNEL_DEBUG(0xc000030 | DBG_FUNC_NONE,
shmem->vblDelta.hi, shmem->vblDelta.lo, 0, 0, 0);
if( inst->vblSemaphore)
semaphore_signal_all(inst->vblSemaphore);
SETSEMA(shmem);
if( inst->needCursorService) {
shmem->cursorLoc = inst->nextCursorLoc;
shmem->frame = inst->nextCursorFrame;
deferredMoveCursor( inst );
}
CLEARSEMA(shmem);
}
void IOFramebuffer::showCursor( Point * cursorLoc, int frame )
{
StdFBShmem_t *shmem;
shmem = GetShmem(this);
SETSEMA(shmem);
if( frame != shmem->frame) {
if( shmem->hardwareCursorFlags[frame]) {
hwCursorLoaded = (kIOReturnSuccess == setCursorImage( (void *) frame ));
shmem->hardwareCursorFlags[frame] = hwCursorLoaded ? kIOFBCursorHWCapable : 0;
} else
hwCursorLoaded = false;
shmem->frame = frame;
}
shmem->hardwareCursorActive = hwCursorLoaded;
shmem->cursorLoc = *cursorLoc;
if (shmem->shieldFlag
&& ((false == shmem->hardwareCursorActive) || (shmem->hardwareCursorShields)))
CheckShield(this);
SysShowCursor(this);
CLEARSEMA(shmem);
}
void IOFramebuffer::resetCursor( void )
{
StdFBShmem_t * shmem;
int frame;
shmem = GetShmem(this);
hwCursorLoaded = false;
if( !shmem)
return;
shmem->hardwareCursorActive = false;
frame = shmem->frame;
shmem->frame = frame ^ kIOFBNumCursorFrames;
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
time->hi = time->lo = 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 = GetShmem(this);
if( shmem->hardwareCursorActive ) {
hs = &shmem->hotSpot[shmem->frame];
err = setCursorState(
shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx,
shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny,
visible );
} else
err = kIOReturnBadArgument;
return( err );
}
IOReturn IOFramebuffer::extSetCursorPosition( SInt32 x, SInt32 y )
{
return( kIOReturnUnsupported );
}
IOReturn IOFramebuffer::extSetNewCursor( void * cursor, IOIndex frame,
IOOptionBits options )
{
StdFBShmem_t * shmem = GetShmem(this);
IOReturn err;
if( cursor || options || (frame >= kIOFBNumCursorFrames))
err = kIOReturnBadArgument;
else {
if( (shmem->cursorSize[frame].width > maxCursorSize.width)
|| (shmem->cursorSize[frame].height > maxCursorSize.height))
err = kIOReturnBadArgument;
else if( haveHWCursor) {
if( frame == shmem->frame) {
err = setCursorImage( (void *) frame );
hwCursorLoaded = (kIOReturnSuccess == err);
shmem->hardwareCursorActive = hwCursorLoaded;
shmem->hardwareCursorFlags[frame] = hwCursorLoaded ? kIOFBCursorHWCapable : 0;
} else {
shmem->hardwareCursorFlags[frame] = kIOFBCursorImageNew;
err = kIOReturnSuccess; }
} else
err = kIOReturnUnsupported;
}
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, y;
UInt32 index, numColors = 0;
UInt32 alpha, red, green, blue;
UInt16 s16;
UInt32 s32;
UInt32 pixel = 0;
UInt8 data = 0;
bool ok = true;
bool isDirect;
assert( frame < kIOFBNumCursorFrames );
if( bytesPerPixel == 4) {
cursPtr32 = (volatile unsigned int *) cursorImages[ frame ];
cursPtr16 = 0;
} else if( bytesPerPixel == 2) {
cursPtr32 = 0;
cursPtr16 = (volatile unsigned short *) cursorImages[ frame ];
} else
return( false );
x = shmem->cursorSize[frame].width;
y = shmem->cursorSize[frame].height;
if( (x > (SInt32) hwDesc->width) || (y > (SInt32) hwDesc->height))
return( false );
isDirect = (hwDesc->bitDepth > 8);
if(isDirect && (hwDesc->bitDepth != 32))
return( false);
#if 0
hwCursorInfo->cursorWidth = x;
hwCursorInfo->cursorHeight = y;
while( (--y != -1) ) {
x = shmem->cursorSize[frame].width;
while( (--x != -1) ) {
if( cursPtr32) {
s32 = *(cursPtr32++);
alpha = (s32 >> 28) & 0xf;
if( alpha && (alpha != 0xf))
*(cursPtr32 - 1) = 0x00ffffff;
} else {
s16 = *(cursPtr16++);
alpha = s16 & 0x000F;
if( alpha && (alpha != 0xf))
*(cursPtr16 - 1) = 0xfff0;
}
}
}
#endif
hwCursorInfo->cursorWidth = x;
hwCursorInfo->cursorHeight = y;
while( ok && (--y != -1) ) {
x = shmem->cursorSize[frame].width;
while( ok && (--x != -1) ) {
if( cursPtr32) {
s32 = *(cursPtr32++);
alpha = (s32 >> 28) & 0xf;
red = (s32 >> 16) & 0xff;
red |= (red << 8);
green = (s32 >> 8) & 0xff;
green |= (green << 8);
blue = (s32) & 0xff;
blue |= (blue << 8);
} else {
#define RMASK16 0xF000
#define GMASK16 0x0F00
#define BMASK16 0x00F0
#define AMASK16 0x000F
s16 = *(cursPtr16++);
alpha = s16 & AMASK16;
red = s16 & RMASK16;
red |= (red >> 4) | (red >> 8) | (red >> 12);
green = s16 & GMASK16;
green |= (green << 4) | (green >> 4) | (green >> 8);
blue = s16 & BMASK16;
blue |= (blue << 8) | (blue << 4) | (blue >> 4);
}
if( alpha == 0 ) {
if( 0 == (red | green | blue)) {
if( kTransparentEncodedPixel
& hwDesc->supportedSpecialEncodings)
pixel = hwDesc->specialEncodings[kTransparentEncoding];
else
ok = false;
} else if (0xffff == (red & green & blue)) {
if( kInvertingEncodedPixel
& hwDesc->supportedSpecialEncodings)
pixel = hwDesc->specialEncodings[kInvertingEncoding];
else
ok = false;
} else
ok = false;
} else if( isDirect) {
pixel = (alpha << 24)
| (alpha << 28)
| ((red & 0xff00) << 8)
| (green & 0xff00)
| ((blue & 0xff00) >> 8);
} else {
if( alpha == 0xf ) {
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;
}
}
if( hwDesc->bitDepth <= 8) {
data <<= hwDesc->bitDepth;
data |= pixel;
if( 0 == (x & ((8 / hwDesc->bitDepth) - 1)))
*dataOut++ = data;
} else
*((UInt32 *)dataOut)++ = pixel;
}
}
return( ok );
}
void IOFramebuffer::initialize()
{
}
#if 0
static bool serializeInfoCB( void * target, void * ref, OSSerialize * s )
{
return( ((IOFramebuffer *)target)->serializeInfo(s) );
}
#endif
bool IOFramebuffer::start( IOService * provider )
{
if( ! super::start( provider))
return( false );
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));
#if 0
OSSerializer * infoSerializer = OSSerializer::forTarget( (void *) this, &serializeInfoCB );
if( !infoSerializer)
return( false );
setProperty( kIOFramebufferInfoKey, infoSerializer );
infoSerializer->release();
#endif
PMinit();
provider->joinPMtree(this);
registerService();
return( true );
}
#if 1
extern UInt8 appleClut8[ 256 * 3 ];
#else
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
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;
err = ((*cdevsw[major(device)].d_read)(device, &uio, 0));
}
#endif
IOReturn IOFramebuffer::handleEvent( IOIndex event, void * info = 0 )
{
IOReturn ret;
#if DEBUG
IOLog("FBEV(%p:%ld, %d)\n", this, event, pagingState);
#endif
switch( event ) {
case kIOFBNotifyWillPowerOff:
hideCursor();
if( isConsoleDevice())
killprint = 1;
if( pagingState) {
pagingState = false;
deliverFramebufferNotification( kIOFBNotifyWillSleep, info );
}
ret = deliverFramebufferNotification( event, info );
configPending = true;
break;
case kIOFBNotifyDidPowerOn:
if( isConsoleDevice()) {
killprint = 0;
kmputc( 033 );
kmputc( 'c' );
}
ret = deliverFramebufferNotification( event, info );
if( !pagingState && gIOFBSystemPower) {
pagingState = true;
deliverFramebufferNotification( kIOFBNotifyDidWake, info );
}
#if DOANIO
IOLog("FBIO(%p)\n", this);
doanio();
IOLog("FBIO(%p:%08lx)\n", this, doaniobuf[0]);
#endif
resetCursor();
configPending = false;
break;
case kIOFBNotifyWillSleep:
#if DOANIO
IOLog("FBIO(%p)\n", this);
doanio();
IOLog("FBIO(%p:%08lx)\n", this, doaniobuf[0]);
#endif
default:
ret = deliverFramebufferNotification( event, info );
}
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;
#if DEBUG
IOLog("FB(%p:%p, %d->%d, %d)\n", this, msgh->msgh_remote_port,
serverState, serverNotified, serverPendingAck);
#endif
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;
}
}
return( err );
}
bool IOFramebuffer::getIsUsable( void )
{
return( 0 != isUsable );
}
void IOFramebuffer::notifyServerAll( UInt8 state )
{
unsigned int index;
IOFramebuffer * fb;
bool doNotify = true;
IOLockLock( gIOFBSleepStateLock );
if( state) {
doNotify = gIOFBSystemPower;
for( index = 0;
doNotify && (fb = (IOFramebuffer *) gAllFramebuffers->getObject( index));
index++) {
doNotify = fb->getIsUsable();
}
if( doNotify)
IOSleep(20);
}
if( doNotify) {
for( index = 0;
(fb = (IOFramebuffer *) gAllFramebuffers->getObject( index));
index++) {
fb->notifyServer( state );
}
}
IOLockUnlock( gIOFBSleepStateLock );
}
enum {
kIOFBDidWork = 0x00000001,
kIOFBPaging = 0x00000002,
};
void IOFramebuffer::sleepWork( void * arg )
{
unsigned int index;
IOFramebuffer * fb;
IOOptionBits allState;
#if DEBUG
IOLog("IOFB::sleepWork()\n");
#endif
IOLockLock( gIOFBSleepStateLock );
do {
for( index = 0, allState = 0;
(fb = (IOFramebuffer *) gAllFramebuffers->getObject( index));
index++) {
allState |= fb->checkPowerWork();
}
if( (0 == (kIOFBPaging & allState)) && gIOFBSystemPowerAckTo) {
#if DEBUG
IOLog("IOFBAckRoot(%ld)\n", gIOFBSystemPowerAckRef);
#endif
IOService * ackTo = gIOFBSystemPowerAckTo;
UInt32 ackRef = gIOFBSystemPowerAckRef;
gIOFBSystemPowerAckTo = 0;
IOLockUnlock( gIOFBSleepStateLock );
ackTo->allowPowerChange( ackRef );
IOLockLock( gIOFBSleepStateLock );
allState |= kIOFBDidWork;
}
} while( kIOFBDidWork & allState );
gIOFBSleepThread = false;
IOLockUnlock( gIOFBSleepStateLock );
}
IOOptionBits IOFramebuffer::checkPowerWork( void )
{
UInt32 newState;
IOOptionBits ourState = kIOFBPaging;
#if DEBUG
IOLog("IOFB::checkPowerWork(%p, %d, %d)\n", this,
gIOFBSystemPower, pendingPowerChange);
#endif
if( !gIOFBSystemPower) {
notifyServer( false );
if( !serverState) {
if( pagingState) {
pagingState = false;
IOLockUnlock( gIOFBSleepStateLock );
handleEvent( kIOFBNotifyWillSleep );
IOLockLock( gIOFBSleepStateLock );
ourState |= kIOFBDidWork;
}
ourState &= ~kIOFBPaging;
}
}
if( pendingPowerChange) {
pendingPowerChange = false;
newState = pendingPowerState;
IOLockUnlock( gIOFBSleepStateLock );
#if DEBUG
IOLog("kIOPowerAttribute(%p, ->%ld)\n", this, newState);
#endif
setAttribute( kIOPowerAttribute, newState );
#if DEBUG
IOLog("acknowledgeSetPowerState(%p)\n", this);
#endif
acknowledgeSetPowerState();
IOLockLock( gIOFBSleepStateLock );
ourState |= kIOFBDidWork;
}
return( ourState );
}
static void startThread( void )
{
if( !gIOFBSleepThread) {
gIOFBSleepThread = true;
thread_call_enter1( gIOFBSleepCallout, (thread_call_param_t) 0);
}
}
IOReturn IOFramebuffer::setPowerState( unsigned long powerStateOrdinal,
IOService * whichDevice )
{
bool now;
#if DEBUG
IOLog("IOFB::setPowerState(%p, ->%ld)\n", this, powerStateOrdinal);
#endif
IOLockLock( gIOFBSleepStateLock );
pendingPowerState = powerStateOrdinal;
now = (0xffffffff == gAllFramebuffers->getNextIndexOfObject( this, 0 ));
if( !now) {
pendingPowerChange = true;
startThread();
}
IOLockUnlock( gIOFBSleepStateLock );
if( now)
setAttribute( kIOPowerAttribute, powerStateOrdinal );
return( now ? 0 : 45 * 1000 * 1000 );
}
IOReturn IOFramebuffer::powerStateWillChangeTo( IOPMPowerFlags flags,
unsigned long state, IOService * whatDevice )
{
IOReturn ret;
#if DEBUG
IOLog("IOFB::powerStateWillChangeTo(%p, ->%08lx)\n", this, flags);
#endif
if( state && !pm_vars->myCurrentState)
gIOFBSystemPower = true;
if( IOPMDeviceUsable & flags)
return( kIOReturnSuccess );
notifyServerAll( false );
IOLockLock( gIOFBSleepStateLock );
if( serverState != serverNotified) {
serverPendingAck = true;
ret = 10 * 1000 * 1000;
} else
ret = IOPMAckImplied;
IOLockUnlock( gIOFBSleepStateLock );
return( ret );
}
IOReturn IOFramebuffer::powerStateDidChangeTo( IOPMPowerFlags flags,
unsigned long, IOService* whatDevice )
{
#if DEBUG
IOLog("IOFB::powerStateDidChangeTo(%p, ->%08lx)\n", this, flags);
#endif
isUsable = (0 != (IOPMDeviceUsable & flags));
serverState = serverNotified;
if( !isUsable)
return kIOReturnSuccess;
notifyServerAll( true );
return( kIOReturnSuccess );
}
IOReturn IOFramebuffer::systemPowerChange( void * target, void * refCon,
UInt32 messageType, IOService * service,
void * messageArgument, vm_size_t argSize )
{
IOReturn ret;
IOPowerStateChangeNotification * params = (IOPowerStateChangeNotification *) messageArgument;
#if DEBUG
IOLog("IOFramebuffer::systemPowerChange(%08lx, %ld)\n",
messageType, (UInt32) params->powerRef);
#endif
switch (messageType) {
case kIOMessageSystemWillSleep:
IOLockLock( gIOFBSleepStateLock );
gIOFBSystemPower = false;
gIOFBSystemPowerAckRef = (UInt32) params->powerRef;
gIOFBSystemPowerAckTo = service;
startThread();
IOLockUnlock( gIOFBSleepStateLock );
params->returnValue = 20 * 1000 * 1000;
ret = kIOReturnSuccess;
break;
case kIOMessageSystemHasPoweredOn:
params->returnValue = 0;
ret = kIOReturnSuccess;
break;
default:
ret = kIOReturnUnsupported;
break;
}
return( ret );
}
IOReturn
IOFramebuffer::extAcknowledgeNotification( void )
{
bool needConnectCheck, needAck;
IOLockLock( gIOFBSleepStateLock );
#if DEBUG
IOLog("FBACK(%p, %d->%d, %d)\n", this,
serverState, serverNotified, serverPendingAck);
#endif
needConnectCheck = (serverState != serverNotified);
serverState = serverNotified;
needAck = serverPendingAck;
serverPendingAck = false;
startThread();
IOLockUnlock( gIOFBSleepStateLock );
if( needConnectCheck)
checkConnectionChange();
if( needAck)
acknowledgePowerChange(this);
return( kIOReturnSuccess );
}
IOReturn IOFramebuffer::extRegisterNotificationPort(
mach_port_t port,
UInt32 type,
UInt32 refCon )
{
mach_msg_header_t * msgh;
IOLockLock( gIOFBSleepStateLock );
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;
serverNotified = true;
serverState = true;
serverPendingAck = false;
IOLockUnlock( gIOFBSleepStateLock );
return( kIOReturnSuccess);
}
void IOFramebuffer::connectChangeInterrupt( IOFramebuffer * inst, void * ref )
{
OSIncrementAtomic( &inst->connectChange);
if( 0 == inst->configPending)
inst->deferredEvents->interruptOccurred(0, 0, 0);
}
void IOFramebuffer::deferredInterrupt( OSObject * owner,
IOInterruptEventSource * evtSrc, int intCount )
{
IOFramebuffer * self = (IOFramebuffer *) owner;
self->checkConnectionChange();
}
void IOFramebuffer::checkConnectionChange( void )
{
IOReturn err;
UInt32 connectEnabled;
if( connectChange) {
err = getAttributeForConnection( 0, kConnectionChanged, (UInt32 *) &connectChange );
if( (kIOReturnSuccess != err) || connectChange) {
temporaryPowerClampOn();
IODisplayWrangler::destroyDisplayConnects( this );
err = getAttributeForConnection( 0, kConnectionEnable, &connectEnabled );
if( (kIOReturnSuccess != err) || connectEnabled)
IODisplayWrangler::makeDisplayConnects( this );
messageClients( kIOMessageServiceIsSuspended, (void *) connectChange );
setProperty("IOFBConnectChange", connectChange, 32);
}
connectChange = 0;
}
}
IOReturn IOFramebuffer::open( void )
{
IOReturn err = kIOReturnSuccess;
UInt32 value;
void * vblInterrupt;
void * connectInterrupt;
do {
if( opened)
continue;
if( dead) {
err = kIOReturnNotOpen;
continue;
}
if( !gAllFramebuffers)
gAllFramebuffers = OSArray::withCapacity(1);
if( !gAllFramebuffers)
continue;
if( !gIOFBSleepStateLock)
gIOFBSleepStateLock = IOLockAlloc();
if( !gIOFBSleepStateLock)
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( isConsoleDevice())
getPlatform()->setConsoleInfo( 0, kPEDisableScreen);
deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange );
err = enableController();
if( kIOReturnSuccess != err) {
dead = true;
deliverFramebufferNotification( kIOFBNotifyDisplayModeDidChange );
continue;
}
IOLockLock( gIOFBSleepStateLock );
pagingState = true;
gAllFramebuffers->setObject(this);
IOLockUnlock( gIOFBSleepStateLock );
err = registerForInterruptType( kIOFBVBLInterruptType,
(IOFBInterruptProc) &handleVBL,
this, priv, &vblInterrupt );
haveVBLService = (err == kIOReturnSuccess );
deferredEvents = IOInterruptEventSource::interruptEventSource(this, deferredInterrupt);
if( deferredEvents)
getWorkLoop()->addEventSource(deferredEvents);
err = registerForInterruptType( kIOFBConnectInterruptType,
(IOFBInterruptProc) &connectChangeInterrupt,
this, priv, &connectInterrupt );
err = getAttribute( kIOHardwareCursorAttribute, &value );
haveHWCursor = ((err == kIOReturnSuccess) && value);
OSNumber * num = OSDynamicCast( OSNumber, getProperty(kIOFBDependentIDKey) );
if( num && !nextDependent) do {
OSDictionary * matching;
OSDictionary * propMatch;
OSIterator * iter;
matching = serviceMatching("IOFramebuffer");
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 * next;
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);
UInt32 connectEnabled;
err = getAttributeForConnection( 0, kConnectionEnable, &connectEnabled );
if( (kIOReturnSuccess != err) || connectEnabled) {
IODisplayWrangler::makeDisplayConnects( this );
setupForCurrentConfig();
err = kIOReturnSuccess;
} else
deliverFramebufferNotification( kIOFBNotifyDisplayModeDidChange, 0 );
opened = true;
} while( false );
checkConnectionChange();
return( err );
}
void IOFramebuffer::setNextDependent( IOFramebuffer * dependent )
{
nextDependent = dependent;
}
void IOFramebuffer::close( void ) { mach_msg_header_t * msgh;
if( isConsoleDevice())
getPlatform()->setConsoleInfo( 0, kPEAcquireScreen);
msgh = (mach_msg_header_t *) serverMsg;
msgh->msgh_remote_port = MACH_PORT_NULL;
serverConnect = 0;
}
IODeviceMemory * IOFramebuffer::getVRAMRange( void )
{
return( getApertureRange( kIOFBSystemAperture ));
}
IOReturn IOFramebuffer::setUserRanges( void )
{
#if 1
UInt32 i, numRanges;
IODeviceMemory * mem;
numRanges = userAccessRanges->getCount();
IOLog("%s: user ranges num:%ld", getName(), numRanges);
for( i = 0; i < numRanges; i++) {
mem = (IODeviceMemory *) userAccessRanges->getObject( i );
if( 0 == mem)
continue;
IOLog(" start:%lx size:%lx",
mem->getPhysicalAddress(), mem->getLength() );
}
IOLog("\n");
#endif
return( kIOReturnSuccess);
}
IOReturn IOFramebuffer::setupForCurrentConfig( void )
{
return( doSetup( true ));
}
IOReturn IOFramebuffer::doSetup( bool full )
{
IOReturn err;
IODisplayModeID mode;
IOIndex depth;
IOPixelInformation info;
IODisplayModeInformation dmInfo;
IODeviceMemory * mem;
IODeviceMemory * fbRange;
IOPhysicalAddress base;
PE_Video newConsole;
err = getCurrentDisplayMode( &mode, &depth );
if( err)
IOLog("%s: getCurrentDisplayMode %d\n", getName(), err);
err = getPixelInformation( mode, depth, kIOFBSystemAperture, &info );
if( err)
IOLog("%s: getPixelInformation %d\n", getName(), err);
if( full && (clutValid == false) && (info.pixelType == kIOCLUTPixels)) {
IOColorEntry * tempTable;
int i;
tempTable = (IOColorEntry *) IOMalloc( 256 * sizeof( *tempTable));
if( tempTable) {
for( i = 0; i < 256; i++) {
if( currentMono) {
UInt32 lum;
lum = 0x0101 * i;
tempTable[ i ].red = lum;
tempTable[ i ].green = lum;
tempTable[ i ].blue = lum;
} else {
tempTable[ i ].red = (appleClut8[ i * 3 + 0 ] << 8)
| appleClut8[ i * 3 + 0 ];
tempTable[ i ].green = (appleClut8[ i * 3 + 1 ] << 8)
| appleClut8[ i * 3 + 1 ];
tempTable[ i ].blue = (appleClut8[ i * 3 + 2 ] << 8)
| appleClut8[ i * 3 + 2 ];
}
}
setCLUTWithEntries( tempTable, 0, 256, 1 * kSetCLUTImmediately );
IOFree( tempTable, 256 * sizeof( *tempTable));
}
clutValid = true;
}
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();
assert( vramMap );
if( vramMap)
base = vramMap->getVirtualAddress();
if( info.activeWidth >= 128) {
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, kPEEnableScreen );
}
deliverFramebufferNotification( kIOFBNotifyDisplayModeDidChange, 0 );
(void) getInformationForDisplayMode( mode, &dmInfo );
IOLog( "%s: using (%ldx%ld@%ldHz,%ld bpp)\n", getName(),
info.activeWidth, info.activeHeight,
(dmInfo.refreshRate + 0x8000) >> 16, info.bitsPerPixel );
}
if( fbRange)
fbRange->release();
if( vramMap)
setupCursor( &info );
return( kIOReturnSuccess );
}
IOReturn IOFramebuffer::extSetDisplayMode( IODisplayModeID displayMode,
IOIndex depth )
{
IOReturn err;
stopCursor();
if( isConsoleDevice())
getPlatform()->setConsoleInfo( 0, kPEDisableScreen);
deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange );
err = setDisplayMode( displayMode, depth );
clutValid = false;
setupForCurrentConfig();
removeProperty("IOFBConnectChange");
return( err );
}
IOReturn IOFramebuffer::extSetAttribute(
IOSelect attribute, UInt32 value, IOFramebuffer * other )
{
IOReturn err;
UInt32 data[2];
stopCursor();
if( isConsoleDevice())
getPlatform()->setConsoleInfo( 0, kPEDisableScreen);
deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange );
data[0] = value;
data[1] = (UInt32) other;
err = setAttribute( attribute, (UInt32) &data );
clutValid = false;
setupForCurrentConfig();
return( err );
}
IOReturn IOFramebuffer::extGetAttribute(
IOSelect attribute, UInt32 * value, IOFramebuffer * other )
{
IOReturn err;
*value = (UInt32) other;
err = getAttribute( attribute, value );
return( err );
}
IOReturn IOFramebuffer::extGetInformationForDisplayMode(
IODisplayModeID mode, void * info, IOByteCount length )
{
UInt32 flags = 0;
IOReturn err;
bool getTiming;
struct AllInfo {
IODisplayModeInformation info;
IOTimingInformation timingInfo;
};
AllInfo * out = (AllInfo *) info;
if( length < sizeof( IODisplayModeInformation))
return( kIOReturnBadArgument );
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(AllInfo));
out->timingInfo.flags = getTiming ? kIODetailedTimingValid : 0;
if( getTiming
&& (kIOReturnSuccess == getTimingInfoForDisplayMode( mode, &out->timingInfo )))
out->info.reserved[0] = out->timingInfo.appleTimingID;
}
return( err );
}
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 = 0 )
{
OSIterator * iter;
_IOFramebufferNotifier * notify;
IOReturn ret = kIOReturnSuccess;
IOReturn r;
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::setAttribute( IOSelect , UInt32 )
{
return( kIOReturnUnsupported);
}
IOReturn IOFramebuffer::getAttribute( IOSelect ,
UInt32 * )
{
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 = kIOReturnSuccess;
switch( attribute ) {
case kConnectionPower:
#if DEBUG
IOLog("setAttributeForConnection(%p, ->%d)\n", this,
0 != (kFBDisplayUsablePowerState & info));
#endif
isUsable = (0 != (kFBDisplayUsablePowerState & info));
notifyServerAll( 0 != (kFBDisplayUsablePowerState & info) );
default:
break;
}
return( err );
}
IOReturn IOFramebuffer::getAttributeForConnection( IOIndex ,
IOSelect , UInt32 * )
{
return( kIOReturnUnsupported);
}
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);
}
bool IOFramebuffer::hasDDCConnect( IOIndex )
{
return( kIOReturnUnsupported);
}
IOReturn IOFramebuffer::getDDCBlock( IOIndex , UInt32 ,
IOSelect , IOOptionBits ,
UInt8 * , IOByteCount * )
{
return( kIOReturnUnsupported);
}
OSMetaClassDefineReservedUnused(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);