/* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1998 Apple Computer, Inc. All rights reserved. * * HISTORY * * 01 Sep 92 Portions from Joe Pasqua, Created. */ #include #include #include #include #include #include #include #define IOFRAMEBUFFER_PRIVATE #include #include #include "IOFramebufferUserClient.h" #include "IODisplayWrangler.h" #include "IOFramebufferReallyPrivate.h" #include #include #include #include /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //#undef DEBUG //#define DEBUG 1 #if DOANIO #include #include #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))) /* * Cursor rendering */ #include "IOCursorBlits.h" inline void IOFramebuffer::StdFBDisplayCursor( IOFramebuffer * inst ) { StdFBShmem_t *shmem; Bounds saveRect; volatile unsigned char *vramPtr; /* screen data pointer */ unsigned int cursStart; unsigned int cursorWidth; int width; int height; shmem = GetShmem(inst); saveRect = shmem->cursorRect; /* Clip saveRect vertical within screen bounds */ 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; /* Remember save rect for RemoveCursor */ 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, /* vramRow */ cursorWidth - width, /* cursRow */ width, height); } // Description: RemoveCursor erases the cursor by replacing the background // image that was saved by the previous call to DisplayCursor. // If the frame buffer is cacheable, flush at the end of the // drawing operation. inline void IOFramebuffer::StdFBRemoveCursor( IOFramebuffer * inst ) { StdFBShmem_t *shmem; volatile unsigned char *vramPtr; /* screen data pointer */ unsigned int vramRow; int width; int height; shmem = GetShmem(inst); vramRow = inst->totalWidth; /* Scanline width in pixels */ 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); /* Calculate temp cursorRect */ 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); } /** ** external methods **/ 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)) { // a default if no one calls IOFBSetBounds() 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; // Init shared memory area 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); } /** ** IOUserClient methods **/ 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 /* aperture */, 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 ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // BEGIN: Implementation of the evScreen protocol // 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; } // // END: Implementation of the evScreen protocol // /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 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; // assumes called with cursorSema held 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; // I guess } } 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)) { /* Transparent black area. Leave dst as is. */ if( kTransparentEncodedPixel & hwDesc->supportedSpecialEncodings) pixel = hwDesc->specialEncodings[kTransparentEncoding]; else ok = false; } else if (0xffff == (red & green & blue)) { /* Transparent white area. Invert dst. */ 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 { /* Indexed pixels */ if( alpha == 0xf ) { /* Opaque cursor pixel. Mark it. */ 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 { /* Alpha is not 0 or 1.0. Sover the cursor. */ 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; } /* x */ } /* y */ // if( !ok) kprintf("Couldnt do a hw curs\n"); 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 // initialize superclass power management variables PMinit(); // attach into the power management hierarchy provider->joinPMtree(this); registerService(); return( true ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Apple standard 8-bit CLUT #if 1 extern UInt8 appleClut8[ 256 * 3 ]; #else UInt8 appleClut8[ 256 * 3 ] = { // 00 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, // 10 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, // 20 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, // 30 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, // 40 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, // 50 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, // 60 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, // 70 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, // 80 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, // 90 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, // a0 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, // b0 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, // c0 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, // d0 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, // e0 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, // f0 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; // checkConnectionChange(); 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; // IOCreateThread( &IOFramebuffer::sleepWork, 0 ); 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) { // server will ack within ten seconds 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 ); // We will ack within 20 seconds 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; // tell the console if it's on this display, it's going away 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 ) // called by the user client when { // the window server exits 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 /* print ranges */ 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(); // console now available 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; // strcpy( consoleInfo->v_pixelFormat, "PPPPPPPP"); 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 ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Some stubs IOReturn IOFramebuffer::enableController ( void ) { return( kIOReturnSuccess ); } bool IOFramebuffer::isConsoleDevice( void ) { return( false ); } // Set display mode and depth IOReturn IOFramebuffer::setDisplayMode( IODisplayModeID /* displayMode */, IOIndex /* depth */ ) { return( kIOReturnUnsupported); } // For pages IOReturn IOFramebuffer::setApertureEnable( IOPixelAperture /* aperture */, IOOptionBits /* enable */ ) { return( kIOReturnUnsupported); } // Display mode and depth for startup IOReturn IOFramebuffer::setStartupDisplayMode( IODisplayModeID /* displayMode */, IOIndex /* depth */ ) { return( kIOReturnUnsupported); } IOReturn IOFramebuffer::getStartupDisplayMode( IODisplayModeID * /* displayMode */, IOIndex * /* depth */ ) { return( kIOReturnUnsupported); } //// CLUTs IOReturn IOFramebuffer::setCLUTWithEntries( IOColorEntry * /* colors */, UInt32 /* index */, UInt32 /* numEntries */, IOOptionBits /* options */ ) { return( kIOReturnUnsupported); } //// Gamma IOReturn IOFramebuffer::setGammaTable( UInt32 /* channelCount */, UInt32 /* dataCount */, UInt32 /* dataWidth */, void * /* data */ ) { return( kIOReturnUnsupported); } //// Controller attributes IOReturn IOFramebuffer::setAttribute( IOSelect /* attribute */, UInt32 /* value */ ) { return( kIOReturnUnsupported); } IOReturn IOFramebuffer::getAttribute( IOSelect /* attribute */, UInt32 * /* value */ ) { return( kIOReturnUnsupported); } //// Display mode timing information IOReturn IOFramebuffer::getTimingInfoForDisplayMode( IODisplayModeID /* displayMode */, IOTimingInformation * /* info */ ) { return( kIOReturnUnsupported); } IOReturn IOFramebuffer::validateDetailedTiming( void * description, IOByteCount descripSize ) { return( kIOReturnUnsupported); } IOReturn IOFramebuffer::setDetailedTimings( OSArray * array ) { return( kIOReturnUnsupported); } //// Connections 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 /* connectIndex */, IOSelect /* attribute */, UInt32 * /* value */ ) { return( kIOReturnUnsupported); } //// HW Cursors IOReturn IOFramebuffer::setCursorImage( void * cursorImage ) { return( kIOReturnUnsupported); } IOReturn IOFramebuffer::setCursorState( SInt32 x, SInt32 y, bool visible ) { return( kIOReturnUnsupported); } void IOFramebuffer::flushCursor( void ) { } //// Interrupts 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); } // Apple sensing IOReturn IOFramebuffer::getAppleSense( IOIndex /* connectIndex */, UInt32 * /* senseType */, UInt32 * /* primary */, UInt32 * /* extended */, UInt32 * /* displayType */ ) { return( kIOReturnUnsupported); } IOReturn IOFramebuffer::connectFlags( IOIndex /* connectIndex */, IODisplayModeID /* displayMode */, IOOptionBits * /* flags */ ) { return( kIOReturnUnsupported); } //// IOLowLevelDDCSense void IOFramebuffer::setDDCClock( IOIndex /* connectIndex */, UInt32 /* value */ ) { } void IOFramebuffer::setDDCData( IOIndex /* connectIndex */, UInt32 /* value */ ) { } bool IOFramebuffer::readDDCClock( IOIndex /* connectIndex */ ) { return( false); } bool IOFramebuffer::readDDCData( IOIndex /* connectIndex */ ) { return( false); } IOReturn IOFramebuffer::enableDDCRaster( bool /* enable */ ) { return( kIOReturnUnsupported); } //// IOHighLevelDDCSense bool IOFramebuffer::hasDDCConnect( IOIndex /* connectIndex */ ) { return( kIOReturnUnsupported); } IOReturn IOFramebuffer::getDDCBlock( IOIndex /* connectIndex */, UInt32 /* blockNumber */, IOSelect /* blockType */, IOOptionBits /* options */, UInt8 * /* data */, IOByteCount * /* length */ ) { 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);