/* * 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@ */ #include #include #include #include #include #include #include #include #include #define IOFRAMEBUFFER_PRIVATE #include #include #include #include #include #include #include "IOFramebufferUserClient.h" #include "IODisplayWrangler.h" #include "IOFramebufferReallyPrivate.h" #include #include #include #include #include #include /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define ACCEL_OFF_ON_DIM false #define DOANIO 0 #define VRAM_SAVE 1 #define VRAM_COMPRESS 1 #ifdef __i386__ enum { kIOFBMapCacheMode = kIOMapWriteCombineCache }; #else enum { kIOFBMapCacheMode = kIOMapInhibitCache }; #endif #if VRAM_COMPRESS #include "bmcompress.h" #endif #if DOANIO #include #include #endif enum { kIOFBClamshellProbeDelayMS = 2000 }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static OSArray * gAllFramebuffers; static OSArray * gRunawayFramebuffers; static class IOFBGate * gIOFBGate; static thread_call_t gIOFBSleepCallout; static IOWorkLoop * gIOFBWorkLoop; static IOTimerEventSource * gIOFBDelayedPrefsEvent; static IONotifier * gIOFBRootNotifier; static IONotifier * gIOFBClamshellNotify; static IOTimerEventSource * gIOFBClamshellProbeTES; static IOService * gIOFBSystemPowerAckTo; static UInt32 gIOFBSystemPowerAckRef; bool gIOFBSystemPower = true; static bool gIOFBSleepThread; static thread_call_t gIOFBClamshellCallout; static SInt32 gIOFBClamshellEnable; static IOOptionBits gIOFBClamshellState; static SInt32 gIOFBSuspendCount; static IOFramebuffer * gIOFBConsoleFramebuffer; bool gIOFBDesktopModeAllowed = true; IOOptionBits gIOFBLastClamshellState; const OSSymbol * gIOFBGetSensorValueKey; const OSSymbol * gIOFramebufferKey; const OSSymbol * gIOFBRotateKey; static bool gIOFBDimDisable; OSDictionary * gIOFBPrefs; OSDictionary * gIOFBPrefsParameters; OSSerializer * gIOFBPrefsSerializer; #define kIOFBGetSensorValueKey "getSensorValue" enum { kIOFBDefaultScalerUnderscan = 0*kIOFBScalerUnderscan }; // console clut extern UInt8 appleClut8[256 * 3]; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct IOFramebufferPrivate { IOGSize maxWaitCursorSize; UInt32 numCursorFrames; UInt8 * cursorFlags; volatile unsigned char ** cursorImages; volatile unsigned char ** cursorMasks; class IOFramebufferParameterHandler * paramHandler; OSArray * cursorAttributes; IOFBCursorControlAttribute cursorControl; IOInterruptEventSource * cursorThread; IOOptionBits cursorToDo; UInt32 framePending; SInt32 xPending; SInt32 yPending; IOGPoint cursorHotSpotAdjust[2]; IOByteCount gammaHeaderSize; UInt32 desiredGammaDataWidth; UInt32 desiredGammaDataCount; IOInterruptEventSource * deferredCLUTSetEvent; IOInterruptEventSource * deferredSpeedChangeEvent; IOTimerEventSource * delayedConnectInterrupt; UInt32 delayedConnectTime; SInt32 connectChangeAtSleep; IOByteCount gammaDataLen; UInt8 * gammaData; UInt32 gammaChannelCount; UInt32 gammaDataCount; UInt32 gammaDataWidth; IOByteCount clutDataLen; UInt8 * clutData; UInt32 clutIndex; UInt32 clutOptions; UInt32 framebufferWidth; UInt32 framebufferHeight; UInt32 saveLength; void * saveFramebuffer; UInt8 visiblePending; UInt8 testingCursor; UInt8 disabledForConnectChange; UInt8 index; UInt8 cursorSlept; UInt8 cursorPanning; UInt8 mirrorState; UInt8 pendingSpeedChange; UInt8 lli2c; UInt8 cursorClutDependent; UInt8 allowSpeedChanges; UInt8 dimDisable; UInt8 enableScalerUnderscan; UInt8 userSetTransform; UInt8 pad[2]; UInt64 transform; UInt64 selectedTransform; UInt32 reducedSpeed; IOService * temperatureSensor; IOI2CBusTiming defaultI2CTiming; }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define GetShmem(instance) ((StdFBShmem_t *)(instance->priv)) #define KICK_CURSOR(thread) \ thread->interruptOccurred(0, 0, 0); #define CLEARSEMA(shmem, inst) \ if( inst->__private->cursorToDo ) { \ KICK_CURSOR(inst->__private->cursorThread); \ } \ ev_unlock(&shmem->cursorSema) #define SETSEMA(shmem) \ if (!ev_try_lock(&shmem->cursorSema)) return; #define TOUCHBOUNDS(one, two) \ (((one.minx < two.maxx) && (two.minx < one.maxx)) && \ ((one.miny < two.maxy) && (two.miny < one.maxy))) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ class IOFBGate : public IOCommandGate { OSDeclareDefaultStructors(IOFBGate) public: static IOFBGate *gate(IOService *owner); inline void closeGate() { IOCommandGate::closeGate(); }; inline void openGate() { IOCommandGate::openGate(); }; inline bool tryCloseGate() { return IOCommandGate::tryCloseGate(); } inline int sleepGate(void *event, UInt32 interuptibleType) { return IOCommandGate::sleepGate(event, interuptibleType); } inline void wakeupGate(void *event, bool oneThread) { return IOCommandGate::wakeupGate(event, oneThread); } }; #define super IOCommandGate OSDefineMetaClassAndStructors(IOFBGate, IOCommandGate) IOFBGate * IOFBGate::gate(IOService *inOwner) { IOFBGate *me = new IOFBGate; if (me && !me->init(inOwner, 0)) { me->free(); return (0); } return (me); } #define FBLOCK() \ gIOFBGate->closeGate(); #define FBUNLOCK() \ gIOFBGate->openGate(); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ class IOFramebufferParameterHandler : public IODisplayParameterHandler { OSDeclareDefaultStructors(IOFramebufferParameterHandler) OSDictionary * fDisplayParams; IOFramebuffer * fFramebuffer; IODisplay * fDisplay; public: static IOFramebufferParameterHandler * withFramebuffer( IOFramebuffer * framebuffer ); virtual void free(); virtual bool setDisplay( IODisplay * display ); virtual bool doIntegerSet( OSDictionary * params, const OSSymbol * paramName, UInt32 value ); virtual bool doDataSet( const OSSymbol * paramName, OSData * value ); virtual bool doUpdate( void ); void displayModeChange( void ); }; class IOFramebufferSensor : public IOService { OSDeclareDefaultStructors(IOFramebufferSensor) IOFramebuffer * fFramebuffer; public: static IOFramebufferSensor * withFramebuffer( IOFramebuffer * framebuffer ); virtual void free(); virtual IOReturn callPlatformFunction( const OSSymbol * functionName, bool waitForFunction, void *param1, void *param2, void *param3, void *param4 ); virtual IOReturn callPlatformFunction( const char * functionName, bool waitForFunction, void *param1, void *param2, void *param3, void *param4 ); }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ class IOFramebufferI2CInterface : public IOI2CInterface { OSDeclareDefaultStructors(IOFramebufferI2CInterface) IOFramebuffer * fFramebuffer; SInt32 fBusID; UInt32 fSupportedTypes; UInt32 fSupportedCommFlags; public: virtual bool start( IOService * provider ); virtual IOReturn startIO( IOI2CRequest * request ); static IOFramebufferI2CInterface * withFramebuffer( IOFramebuffer * framebuffer, OSDictionary * info ); static IOReturn create( IOFramebuffer * framebuffer ); }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #undef super #define super IOGraphicsDevice OSDefineMetaClass( IOFramebuffer, IOGraphicsDevice ) OSDefineAbstractStructors( IOFramebuffer, IOGraphicsDevice ) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Cursor rendering */ #include "IOCursorBlits.h" inline void IOFramebuffer::StdFBDisplayCursor( IOFramebuffer * inst ) { StdFBShmem_t *shmem; IOGBounds 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[0 != shmem->frame].width; cursStart = (saveRect.miny - shmem->cursorRect.miny) * cursorWidth + (saveRect.minx - shmem->cursorRect.minx); if (inst->cursorBlitProc) inst->cursorBlitProc( inst, (void *) shmem, vramPtr, cursStart, inst->totalWidth - width, /* 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) { IOGPoint * hs; hs = &shmem->hotSpot[0 != shmem->frame]; inst->_setCursorState( shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx, shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny, false ); } else StdFBRemoveCursor(inst); } inline void IOFramebuffer::DisplayCursor( IOFramebuffer * inst ) { IOGPoint * hs; StdFBShmem_t * shmem = GetShmem(inst); SInt32 x, y; hs = &shmem->hotSpot[0 != shmem->frame]; x = shmem->cursorLoc.x - hs->x; y = shmem->cursorLoc.y - hs->y; if (shmem->hardwareCursorActive) inst->_setCursorState( x - shmem->screenBounds.minx, y - shmem->screenBounds.miny, true ); else { shmem->cursorRect.maxx = (shmem->cursorRect.minx = x) + shmem->cursorSize[0 != shmem->frame].width; shmem->cursorRect.maxy = (shmem->cursorRect.miny = y) + shmem->cursorSize[0 != shmem->frame].height; StdFBDisplayCursor(inst); shmem->oldCursorRect = shmem->cursorRect; } } inline void IOFramebuffer::SysHideCursor( IOFramebuffer * inst ) { if (!GetShmem(inst)->cursorShow++) RemoveCursor(inst); } inline void IOFramebuffer::SysShowCursor( IOFramebuffer * inst ) { StdFBShmem_t *shmem; shmem = GetShmem(inst); if (shmem->cursorShow) if (!--(shmem->cursorShow)) DisplayCursor(inst); } inline void IOFramebuffer::CheckShield( IOFramebuffer * inst ) { IOGPoint * hs; int intersect; IOGBounds tempRect; StdFBShmem_t * shmem = GetShmem(inst); /* Calculate temp cursorRect */ hs = &shmem->hotSpot[0 != shmem->frame]; tempRect.maxx = (tempRect.minx = (shmem->cursorLoc).x - hs->x) + shmem->cursorSize[0 != shmem->frame].width; tempRect.maxy = (tempRect.miny = (shmem->cursorLoc).y - hs->y) + shmem->cursorSize[0 != shmem->frame].height; intersect = TOUCHBOUNDS(tempRect, shmem->shieldRect); if (intersect != shmem->shielded) (shmem->shielded = intersect) ? SysHideCursor(inst) : SysShowCursor(inst); } /** ** external methods **/ void IOFramebuffer::setupCursor( IOPixelInformation * info ) { StdFBShmem_t * shmem = GetShmem(this); volatile unsigned char * bits; IOByteCount cursorImageBytes, waitCursorImageBytes; rowBytes = info->bytesPerRow; totalWidth = (rowBytes * 8) / info->bitsPerPixel; bytesPerPixel = info->bitsPerPixel / 8; frameBuffer = (volatile unsigned char *) vramMap->getVirtualAddress(); __private->framebufferWidth = info->activeWidth; __private->framebufferHeight = info->activeHeight; if (shmem) { if ((shmem->screenBounds.maxx == shmem->screenBounds.minx) || (shmem->screenBounds.maxy == shmem->screenBounds.miny)) { // 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; } shmem->cursorSize[0] = maxCursorSize; shmem->cursorSize[1] = __private->maxWaitCursorSize; shmem->cursorSize[2] = __private->maxWaitCursorSize; shmem->cursorSize[3] = __private->maxWaitCursorSize; cursorImageBytes = maxCursorSize.width * maxCursorSize.height * bytesPerPixel; waitCursorImageBytes = __private->maxWaitCursorSize.width * __private->maxWaitCursorSize.height * bytesPerPixel; bits = shmem->cursor; for (UInt32 i = 0; i < __private->numCursorFrames; i++) { __private->cursorFlags[i] = kIOFBCursorImageNew; __private->cursorImages[i] = bits; bits += i ? waitCursorImageBytes : cursorImageBytes; } if (info->bitsPerPixel <= 8) { for (UInt32 i = 0; i < __private->numCursorFrames; i++) { __private->cursorMasks[i] = bits; bits += i ? waitCursorImageBytes : cursorImageBytes; } } cursorSave = bits; } switch (info->bitsPerPixel) { case 8: if (colorConvert.t._bm256To38SampleTable && colorConvert.t._bm38To256SampleTable) { cursorBlitProc = (CursorBlitProc) StdFBDisplayCursor8P; cursorRemoveProc = (CursorRemoveProc) StdFBRemoveCursor8; } break; case 16: if (colorConvert.t._bm34To35SampleTable && colorConvert.t._bm35To34SampleTable) { cursorBlitProc = (CursorBlitProc) StdFBDisplayCursor555; cursorRemoveProc = (CursorRemoveProc) StdFBRemoveCursor16; } break; case 32: if (colorConvert.t._bm256To38SampleTable && colorConvert.t._bm38To256SampleTable) { cursorBlitProc = (CursorBlitProc) StdFBDisplayCursor32Axxx; cursorRemoveProc = (CursorRemoveProc) StdFBRemoveCursor32; } break; default: IOLog("%s: can't do cursor at depth %ld\n", getName(), info->bitsPerPixel); cursorBlitProc = (CursorBlitProc) NULL; cursorRemoveProc = (CursorRemoveProc) NULL; break; } } void IOFramebuffer::stopCursor( void ) { cursorBlitProc = (CursorBlitProc) NULL; cursorRemoveProc = (CursorRemoveProc) NULL; } IOReturn IOFramebuffer::extCreateSharedCursor( int version, int maxWidth, int maxWaitWidth ) { IOReturn err; if ((err = extEntry())) return (err); err = createSharedCursor( version, maxWidth, maxWidth ); FBUNLOCK(); return (err); } IOReturn IOFramebuffer::extGetPixelInformation( IODisplayModeID displayMode, IOIndex depth, IOPixelAperture aperture, IOPixelInformation * pixelInfo ) { IOReturn err; if ((err = extEntry())) return (err); err = getPixelInformation( displayMode, depth, aperture, pixelInfo ); FBUNLOCK(); return (err); } IOReturn IOFramebuffer::extGetCurrentDisplayMode( IODisplayModeID * displayMode, IOIndex * depth ) { IOReturn err; if ((err = extEntry())) return (err); err = getCurrentDisplayMode( displayMode, depth ); FBUNLOCK(); return (err); } IOReturn IOFramebuffer::extSetStartupDisplayMode( IODisplayModeID displayMode, IOIndex depth ) { IOReturn err; if ((err = extEntry())) return (err); err = setStartupDisplayMode( displayMode, depth ); FBUNLOCK(); return (err); } IOReturn IOFramebuffer::extSetGammaTable( UInt32 channelCount, UInt32 dataCount, UInt32 dataWidth, void * data ) { IOReturn err = kIOReturnBadArgument; UInt32 expandCount = 0; IOByteCount dataLen; UInt32 tryWidth; UInt8 * table = 0; bool needAlloc; if ((err = extEntry())) return (err); do { if (!__private->desiredGammaDataWidth) { __private->desiredGammaDataWidth = dataWidth; __private->desiredGammaDataCount = dataCount; } if (dataWidth < __private->desiredGammaDataWidth) continue; if (dataCount < __private->desiredGammaDataCount) { expandCount = __private->desiredGammaDataCount / dataCount; if ((expandCount * dataCount) == __private->desiredGammaDataCount) { dataCount = __private->desiredGammaDataCount; expandCount--; } else expandCount = 0; } dataLen = (dataWidth + 7) / 8; dataLen *= dataCount * channelCount; dataLen += __private->gammaHeaderSize; needAlloc = (0 == __private->gammaDataLen); if (!needAlloc) { table = __private->gammaData; if (__private->gammaDataLen != dataLen) { IODelete(table, UInt8, __private->gammaDataLen); needAlloc = true; } __private->gammaDataLen = 0; } if (needAlloc) { table = IONew(UInt8, dataLen); if (!table) { err = kIOReturnNoMemory; continue; } __private->gammaData = table; } __private->gammaChannelCount = channelCount; __private->gammaDataCount = dataCount; table += __private->gammaHeaderSize; tryWidth = __private->desiredGammaDataWidth; if (!expandCount && (tryWidth == dataWidth)) bcopy(data, table, dataLen - __private->gammaHeaderSize); else { UInt32 pin, pt5, value; pin = (1 << tryWidth) - 1; pt5 = 0; // truncate not round for (UInt32 in = 0, out = 0; out < (dataCount * channelCount);) { value = (((UInt16 *) data)[in++] + pt5) >> (dataWidth - tryWidth); if (value > pin) value = pin; for (UInt32 i = 0; i <= expandCount; i++) { if (tryWidth <= 8) ((UInt8 *) table)[out++] = (value & 0xff); else ((UInt16 *) table)[out++] = value; } } } __private->gammaDataWidth = tryWidth; if (__private->deferredCLUTSetEvent) { __private->gammaDataLen = dataLen; err = kIOReturnSuccess; } else { err = setGammaTable( __private->gammaChannelCount, __private->gammaDataCount, __private->gammaDataWidth, __private->gammaData ); updateCursorForCLUTSet(); IODelete(__private->gammaData, UInt8, dataLen); } } while (false); FBUNLOCK(); return (err); } IOReturn IOFramebuffer::extSetCLUTWithEntries( UInt32 index, IOOptionBits options, IOColorEntry * colors, IOByteCount dataLen ) { IOReturn err; UInt8 * table; bool needAlloc; if ((err = extEntry())) return (err); err = kIOReturnBadArgument; if (__private->deferredCLUTSetEvent) { do { needAlloc = (0 == __private->clutDataLen); if (!needAlloc) { if (index || (__private->clutDataLen != dataLen)) { checkDeferredCLUTSet(); needAlloc = true; } __private->clutDataLen = 0; } if (needAlloc) { table = IONew(UInt8, dataLen); if (!table) { err = kIOReturnNoMemory; continue; } __private->clutData = table; } else table = __private->clutData; __private->clutIndex = index; __private->clutOptions = options; __private->clutDataLen = dataLen; bcopy(colors, table, dataLen); err = kIOReturnSuccess; } while (false); } else { err = setCLUTWithEntries( colors, index, dataLen / sizeof( IOColorEntry), options ); updateCursorForCLUTSet(); } if (this == gIOFBConsoleFramebuffer) { UInt32 count = index + dataLen / sizeof(IOColorEntry); if (count > 256) count = 256; for (; index < count; index++) { appleClut8[index * 3 + 0] = colors[index].red >> 8; appleClut8[index * 3 + 1] = colors[index].green >> 8; appleClut8[index * 3 + 2] = colors[index].blue >> 8; } } FBUNLOCK(); return (err); } void IOFramebuffer::updateCursorForCLUTSet( void ) { if (__private->cursorClutDependent) { StdFBShmem_t *shmem = GetShmem(this); SETSEMA(shmem); if ((kIOFBHardwareCursorActive == shmem->hardwareCursorActive) && !shmem->cursorShow) { setCursorImage( (void *) shmem->frame ); DisplayCursor(this); } CLEARSEMA(shmem, this); } } void IOFramebuffer::deferredCLUTSetInterrupt( OSObject * owner, IOInterruptEventSource * evtSrc, int intCount ) { IOFramebuffer * self = (IOFramebuffer *) owner; self->checkDeferredCLUTSet(); } void IOFramebuffer::checkDeferredCLUTSet( void ) { IOReturn ret; IOByteCount gammaLen = __private->gammaDataLen; IOByteCount clutLen = __private->clutDataLen; if( !gammaLen && !clutLen) return; __private->gammaDataLen = 0; __private->clutDataLen = 0; if (gammaLen) { ret = setGammaTable( __private->gammaChannelCount, __private->gammaDataCount, __private->gammaDataWidth, __private->gammaData ); IODelete(__private->gammaData, UInt8, gammaLen); } if (clutLen) { ret = setCLUTWithEntries( (IOColorEntry *) __private->clutData, __private->clutIndex, clutLen / sizeof( IOColorEntry), __private->clutOptions ); IODelete(__private->clutData, UInt8, clutLen); } updateCursorForCLUTSet(); } IOReturn IOFramebuffer::createSharedCursor( int version, int maxWidth, int maxWaitWidth ) { StdFBShmem_t * shmem; UInt32 shmemVersion; IOByteCount size, maxImageSize, maxWaitImageSize; UInt32 numCursorFrames; DEBG(thisIndex, " vers = %08x, %d x %d\n", version, maxWidth, maxWaitWidth); shmemVersion = version & kIOFBShmemVersionMask; if (shmemVersion == kIOFBTenPtTwoShmemVersion) { numCursorFrames = (kIOFBShmemCursorNumFramesMask & version) >> kIOFBShmemCursorNumFramesShift; setProperty(kIOFBWaitCursorFramesKey, (numCursorFrames - 1), 32); setProperty(kIOFBWaitCursorPeriodKey, 33333333, 32); /* 30 fps */ } else if (shmemVersion == kIOFBTenPtOneShmemVersion) { numCursorFrames = 4; } else return (kIOReturnUnsupported); shmemClientVersion = shmemVersion; if (__private->cursorFlags) { IODelete( __private->cursorFlags, UInt8, __private->numCursorFrames ); __private->cursorFlags = 0; } if (__private->cursorImages) { IODelete( __private->cursorImages, volatile unsigned char *, __private->numCursorFrames ); __private->cursorImages = 0; } if (__private->cursorMasks) { IODelete( __private->cursorMasks, volatile unsigned char *, __private->numCursorFrames ); __private->cursorMasks = 0; } __private->numCursorFrames = numCursorFrames; __private->cursorFlags = IONew( UInt8, numCursorFrames ); __private->cursorImages = IONew( volatile unsigned char *, numCursorFrames ); __private->cursorMasks = IONew( volatile unsigned char *, numCursorFrames ); if (!__private->cursorFlags || !__private->cursorImages || !__private->cursorMasks) return (kIOReturnNoMemory); maxImageSize = (maxWidth * maxWidth * kIOFBMaxCursorDepth) / 8; maxWaitImageSize = (maxWaitWidth * maxWaitWidth * kIOFBMaxCursorDepth) / 8; size = sizeof( StdFBShmem_t) + maxImageSize + max(maxImageSize, maxWaitImageSize) + ((numCursorFrames - 1) * maxWaitImageSize); if (!sharedCursor || (size != sharedCursor->getLength())) { IOBufferMemoryDescriptor * newDesc; priv = 0; newDesc = IOBufferMemoryDescriptor::withOptions( kIODirectionNone | kIOMemoryKernelUserShared, size ); if (!newDesc) return (kIOReturnNoMemory); if (sharedCursor) sharedCursor->release(); sharedCursor = newDesc; } shmem = (StdFBShmem_t *) sharedCursor->getBytesNoCopy(); priv = shmem; // Init shared memory area bzero( shmem, size ); shmem->version = shmemClientVersion; shmem->structSize = size; shmem->cursorShow = 1; shmem->hardwareCursorCapable = haveHWCursor; for (UInt32 i = 0; i < numCursorFrames; i++) __private->cursorFlags[i] = kIOFBCursorImageNew; maxCursorSize.width = maxWidth; maxCursorSize.height = maxWidth; __private->maxWaitCursorSize.width = maxWaitWidth; __private->maxWaitCursorSize.height = maxWaitWidth; doSetup( false ); return (kIOReturnSuccess); } IOReturn IOFramebuffer::setBoundingRect( IOGBounds * 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 ((this == gIOFBConsoleFramebuffer) || !gIOFBConsoleFramebuffer) getPlatform()->setConsoleInfo( 0, kPEReleaseScreen); err = open(); if (kIOReturnSuccess == err) newConnect = IOFramebufferUserClient::withTask(owningTask); } break; case kIOFBSharedConnectType: if (sharedConnect) { theConnect = sharedConnect; theConnect->retain(); } else if (serverConnect) { newConnect = IOFramebufferSharedUserClient::withTask(owningTask); if (newConnect) newConnect->retain(); } else err = kIOReturnNotOpen; break; default: err = kIOReturnBadArgument; } if (newConnect) { if ((false == newConnect->attach(this)) || (false == newConnect->start(this))) { newConnect->detach( this ); newConnect->release(); } else theConnect = newConnect; } *handler = theConnect; return (err); } IOReturn IOFramebuffer::extGetDisplayModeCount( IOItemCount * count ) { IOReturn err; if ((err = extEntry())) return (err); *count = dead ? 0 : getDisplayModeCount(); FBUNLOCK(); return (kIOReturnSuccess); } IOReturn IOFramebuffer::extGetDisplayModes( IODisplayModeID * allModes, IOByteCount * size ) { IOReturn err; IOByteCount outSize; if ((err = extEntry())) return (err); outSize = getDisplayModeCount() * sizeof( IODisplayModeID); if (*size >= outSize) { *size = outSize; err = getDisplayModes( allModes ); } else err = kIOReturnBadArgument; FBUNLOCK(); return (err); } IOReturn IOFramebuffer::extGetVRAMMapOffset( IOPixelAperture /* aperture */, IOByteCount * offset ) { IOReturn err; if ((err = extEntry())) return (err); *offset = vramMapOffset; FBUNLOCK(); return (kIOReturnSuccess); } void IOFramebuffer::wakeServerState(UInt8 state) { if (state) gIOFBGate->wakeupGate(&serverConnect, true); } IOReturn IOFramebuffer::extEntry(void) { IOReturn err = kIOReturnSuccess; FBLOCK(); while (!pagingState) { err = gIOFBGate->sleepGate(&serverConnect, false); if (kIOReturnSuccess != err) { FBUNLOCK(); break; } } return (err); } IOReturn IOFramebuffer::extSetBounds( IOGBounds * bounds ) { IOReturn err; StdFBShmem_t * shmem; if ((err = extEntry())) return (err); shmem = GetShmem(this); if (shmem) { if (kIOFBHardwareCursorActive == shmem->hardwareCursorActive) { IOReturn err; IOGPoint * hs; hs = &shmem->hotSpot[0 != shmem->frame]; err = _setCursorState( shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx, shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny, false ); } shmem->screenBounds = *bounds; } FBUNLOCK(); return (kIOReturnSuccess); } IOReturn IOFramebuffer::extValidateDetailedTiming( void * description, void * outDescription, IOByteCount inSize, IOByteCount * outSize ) { IOReturn err; if (*outSize != inSize) return (kIOReturnBadArgument); if ((err = extEntry())) return (err); err = validateDetailedTiming( description, inSize ); if (kIOReturnSuccess == err) bcopy( description, outDescription, inSize ); FBUNLOCK(); return (err); } IOReturn IOFramebuffer::extSetColorConvertTable( UInt32 select, UInt8 * data, IOByteCount length ) { static const IOByteCount checkLength[] = { 16 * sizeof( UInt8), 32 * sizeof( UInt8), 256 * sizeof( UInt32), 5 * 256 * sizeof( UInt8) }; IOReturn err; UInt8 * table; IODisplayModeID mode; IOIndex depth; IOPixelInformation info; if (select > 3) return (kIOReturnBadArgument); if (length != checkLength[select]) return (kIOReturnBadArgument); if ((err = extEntry())) return (err); do { err = kIOReturnNoMemory; table = colorConvert.tables[select]; if (0 == table) { table = (UInt8 *) IOMalloc( length ); colorConvert.tables[select] = table; } if (!table) continue; bcopy( data, table, length ); if (select == 3) white = data[data[255] + data[511] + data[767] + 1024]; if ((NULL == cursorBlitProc) && colorConvert.tables[0] && colorConvert.tables[1] && colorConvert.tables[2] && colorConvert.tables[3] && vramMap && (kIOReturnSuccess == getCurrentDisplayMode(&mode, &depth)) && (kIOReturnSuccess == getPixelInformation(mode, depth, kIOFBSystemAperture, &info))) setupCursor( &info ); err = kIOReturnSuccess; } while (false); FBUNLOCK(); return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ bool IOFramebuffer::requestTerminate( IOService * provider, IOOptionBits options ) { FBLOCK(); if (opened) { if (!gRunawayFramebuffers) gRunawayFramebuffers = OSArray::withCapacity(4); if (gRunawayFramebuffers) gRunawayFramebuffers->setObject(this); } FBUNLOCK(); return (false); } void IOFramebuffer::stop( IOService * provider ) { if (opened) { FBLOCK(); dead = true; for (UInt32 i = 0; i < pm_vars->theNumberOfPowerStates; i++) pm_vars->thePowerStates[i].capabilityFlags &= ~kIOPMPreventSystemSleep; setAttribute( kIOSystemPowerAttribute, kIOMessageSystemWillPowerOff ); FBUNLOCK(); temporaryPowerClampOn(); // only to clear out kIOPMPreventSystemSleep PMstop(); initialized = false; connectChangeInterrupt(this, 0); } return (super::stop(provider)); } void IOFramebuffer::free() { if (vblSemaphore) semaphore_destroy(kernel_task, vblSemaphore); if (__private) { IODelete( __private, IOFramebufferPrivate, 1 ); __private = 0; } super::free(); } IOService * IOFramebuffer::probe( IOService * provider, SInt32 * score ) { IOFramebuffer * replace = 0; if (gRunawayFramebuffers) { FBLOCK(); replace = (IOFramebuffer *) gRunawayFramebuffers->getObject(0); gRunawayFramebuffers->removeObject(0); FBUNLOCK(); } return (replace ? replace : this); } void IOFramebuffer::initialize() { } bool IOFramebuffer::start( IOService * provider ) { bool runaway; if (!super::start(provider)) return (false); runaway = (__private != 0); if (!__private) { __private = IONew( IOFramebufferPrivate, 1 ); if (!__private) return (false); bzero( __private, sizeof(IOFramebufferPrivate) ); userAccessRanges = OSArray::withCapacity( 1 ); if (!userAccessRanges) return (false); serverMsg = IOMalloc( sizeof (mach_msg_header_t) ); if (!serverMsg) return (false); bzero( serverMsg, sizeof (mach_msg_header_t)); } // initialize superclass power management variables PMinit(); // attach into the power management hierarchy provider->joinPMtree(this); if (runaway) { IOReturn err; FBLOCK(); err = enableController(); if (kIOReturnSuccess == err) { opened = true; dead = false; isUsable = true; configPending = serverState ? 0 : 1; connectChangeInterrupt(this, 0); } FBUNLOCK(); } else registerService(); return (true); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // BEGIN: Implementation of the evScreen protocol // void IOFramebuffer::hideCursor( void ) { StdFBShmem_t *shmem = GetShmem(this); SETSEMA(shmem); SysHideCursor(this); CLEARSEMA(shmem, this); } void IOFramebuffer::deferredMoveCursor( IOFramebuffer * inst ) { StdFBShmem_t * shmem = GetShmem(inst); IOReturn err = kIOReturnSuccess; if (shmem->hardwareCursorActive) { if (shmem->cursorObscured) { shmem->cursorObscured = 0; if (shmem->cursorShow) --shmem->cursorShow; } if (shmem->hardwareCursorShields && shmem->shieldFlag) CheckShield(inst); if (!shmem->cursorShow) { IOGPoint * hs; hs = &shmem->hotSpot[0 != shmem->frame]; err = inst->_setCursorState( shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx, shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny, true ); } } else { if (!shmem->cursorShow++) RemoveCursor(inst); if (shmem->cursorObscured) { shmem->cursorObscured = 0; if (shmem->cursorShow) --shmem->cursorShow; } if (shmem->shieldFlag) CheckShield(inst); if (shmem->cursorShow) if (!--shmem->cursorShow) DisplayCursor(inst); inst->flushCursor(); if (inst->__private->cursorPanning) { IOGPoint * hs; hs = &shmem->hotSpot[0 != shmem->frame]; err = inst->setCursorState( shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx, shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny, false ); } } inst->needCursorService = (kIOReturnBusy == err); } void IOFramebuffer::cursorWork( OSObject * p0, IOInterruptEventSource * evtSrc, int intCount ) { IOFramebuffer * inst = (IOFramebuffer *) p0; StdFBShmem_t * shmem = GetShmem(inst); struct IOFramebufferPrivate * __private = inst->__private; IOFBCursorControlAttribute * cursorControl = &__private->cursorControl; IOReturn ret; IOHardwareCursorDescriptor desc; IOOptionBits todo = inst->__private->cursorToDo; while (todo) { if (2 & todo) { desc.majorVersion = kHardwareCursorDescriptorMajorVersion; desc.minorVersion = kHardwareCursorDescriptorMinorVersion; desc.height = shmem->cursorSize[0 != __private->framePending].height; desc.width = shmem->cursorSize[0 != __private->framePending].width; desc.bitDepth = inst->bytesPerPixel * 8; desc.maskBitDepth = 0; desc.colorEncodings = 0; desc.flags = 0; desc.supportedSpecialEncodings = kTransparentEncodedPixel; ret = (*cursorControl->callouts->setCursorImage) ( cursorControl->self, cursorControl->ref, &desc, (void *) __private->framePending ); } if (1 & todo) ret = (*cursorControl->callouts->setCursorState) ( cursorControl->self, cursorControl->ref, __private->xPending, __private->yPending, __private->visiblePending ); todo = __private->cursorToDo & ~todo; __private->cursorToDo = todo; } } IOOptionBits IOFramebuffer::_setCursorImage( UInt32 frame ) { IOOptionBits flags; flags = (kIOReturnSuccess == setCursorImage( (void *) frame )) ? kIOFBHardwareCursorActive : 0; if (!flags && __private->cursorThread && (bytesPerPixel >= 2)) { __private->framePending = frame; __private->cursorToDo |= 2; flags = kIOFBHardwareCursorActive | kIOFBHardwareCursorInVRAM; } return (flags); } IOReturn IOFramebuffer::_setCursorState( SInt32 x, SInt32 y, bool visible ) { StdFBShmem_t *shmem = GetShmem(this); IOReturn ret = kIOReturnUnsupported; x -= __private->cursorHotSpotAdjust[0].x; y -= __private->cursorHotSpotAdjust[0].y; if (kIOFBHardwareCursorActive == shmem->hardwareCursorActive) ret = setCursorState( x, y, visible ); else if (__private->cursorThread) { __private->cursorToDo |= 1; __private->xPending = x; __private->yPending = y; __private->visiblePending = visible; } return (ret); } void IOFramebuffer::transformLocation(StdFBShmem_t * shmem, IOGPoint * cursorLoc, IOGPoint * transformLoc) { SInt32 x, y; x = cursorLoc->x - shmem->screenBounds.minx; y = cursorLoc->y - shmem->screenBounds.miny; if (__private->transform & kIOFBSwapAxes) { SInt32 t = x; x = y; y = t; } if (__private->transform & kIOFBInvertX) x = __private->framebufferWidth - x - 1; if (__private->transform & kIOFBInvertY) y = __private->framebufferHeight - y - 1; transformLoc->x = x + shmem->screenBounds.minx; transformLoc->y = y + shmem->screenBounds.miny; } void IOFramebuffer::moveCursor( IOGPoint * cursorLoc, int frame ) { nextCursorLoc = *cursorLoc; nextCursorFrame = frame; needCursorService = true; UInt32 hwCursorActive; StdFBShmem_t *shmem = GetShmem(this); SETSEMA(shmem); if (frame != shmem->frame) { if (__private->cursorFlags[frame] && pagingState) { hwCursorActive = _setCursorImage( frame ); __private->cursorFlags[frame] = hwCursorActive ? kIOFBCursorHWCapable : 0; } else hwCursorActive = 0; shmem->frame = frame; if (shmem->hardwareCursorActive != hwCursorActive) { SysHideCursor( this ); shmem->hardwareCursorActive = hwCursorActive; if (shmem->shieldFlag && ((0 == hwCursorActive) || (shmem->hardwareCursorShields))) CheckShield(this); SysShowCursor( this ); } } if ((kIOFBHardwareCursorActive == (shmem->hardwareCursorActive & (kIOFBHardwareCursorActive | kIOFBHardwareCursorInVRAM))) || !haveVBLService) { if (kIOFBRotateFlags & __private->transform) transformLocation(shmem, &nextCursorLoc, &shmem->cursorLoc); else shmem->cursorLoc = nextCursorLoc; shmem->frame = frame; deferredMoveCursor( this ); } CLEARSEMA(shmem, this); } void IOFramebuffer::handleVBL( IOFramebuffer * inst, void * ref ) { StdFBShmem_t * shmem = GetShmem(inst); AbsoluteTime now; AbsoluteTime delta; if (!shmem) return ; shmem->vblCount++; clock_get_uptime( &now ); delta = now; SUB_ABSOLUTETIME( &delta, &shmem->vblTime ); shmem->vblDelta = delta; shmem->vblTime = now; KERNEL_DEBUG(0xc000030 | DBG_FUNC_NONE, (uint32_t)(AbsoluteTime_to_scalar(&shmem->vblDelta) >> 32), (uint32_t)(AbsoluteTime_to_scalar(&shmem->vblDelta)), 0, 0, 0); if (inst->vblSemaphore) semaphore_signal_all(inst->vblSemaphore); SETSEMA(shmem); if (inst->needCursorService) { if (kIOFBRotateFlags & inst->__private->transform) inst->transformLocation(shmem, &inst->nextCursorLoc, &shmem->cursorLoc); else shmem->cursorLoc = inst->nextCursorLoc; shmem->frame = inst->nextCursorFrame; deferredMoveCursor( inst ); } CLEARSEMA(shmem, inst); if (inst->__private->deferredCLUTSetEvent && (inst->__private->gammaDataLen || inst->__private->clutDataLen)) inst->__private->deferredCLUTSetEvent->interruptOccurred(0, 0, 0); } void IOFramebuffer::showCursor( IOGPoint * cursorLoc, int frame ) { StdFBShmem_t *shmem; UInt32 hwCursorActive; shmem = GetShmem(this); SETSEMA(shmem); if (frame != shmem->frame) { if (__private->cursorFlags[frame]) { hwCursorActive = _setCursorImage( frame ); __private->cursorFlags[frame] = hwCursorActive ? kIOFBCursorHWCapable : 0; } else hwCursorActive = 0; shmem->frame = frame; shmem->hardwareCursorActive = hwCursorActive; } shmem->cursorLoc = *cursorLoc; if (shmem->shieldFlag && ((0 == shmem->hardwareCursorActive) || (shmem->hardwareCursorShields))) CheckShield(this); SysShowCursor(this); CLEARSEMA(shmem, this); } void IOFramebuffer::resetCursor( void ) { StdFBShmem_t * shmem; int frame; shmem = GetShmem(this); // hwCursorLoaded = false; if (!shmem) return; shmem->hardwareCursorActive = 0; frame = shmem->frame; shmem->frame = frame ^ 1; showCursor( &shmem->cursorLoc, frame ); } void IOFramebuffer::getVBLTime( AbsoluteTime * time, AbsoluteTime * delta ) { StdFBShmem_t *shmem; shmem = GetShmem(this); if (shmem) { *time = shmem->vblTime; *delta = shmem->vblDelta; } else AbsoluteTime_to_scalar(&time) = 0; } void IOFramebuffer::getBoundingRect( IOGBounds ** 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; IOGPoint * hs; StdFBShmem_t * shmem; if ((err = extEntry())) return (err); shmem = GetShmem(this); if (shmem->hardwareCursorActive) { hs = &shmem->hotSpot[0 != shmem->frame]; err = _setCursorState( shmem->cursorLoc.x - hs->x - shmem->screenBounds.minx, shmem->cursorLoc.y - hs->y - shmem->screenBounds.miny, visible ); if (__private->cursorToDo) KICK_CURSOR(__private->cursorThread); } else err = kIOReturnBadArgument; FBUNLOCK(); return (err); } IOReturn IOFramebuffer::extSetCursorPosition( SInt32 x, SInt32 y ) { return (kIOReturnUnsupported); } void IOFramebuffer::transformCursor( StdFBShmem_t * shmem, IOIndex frame ) { void * buf; unsigned int * out; volatile unsigned int * cursPtr32 = 0; volatile unsigned short * cursPtr16 = 0; SInt32 x, y, dw, dh, sx, sy, sw, sh; if (bytesPerPixel == 4) { cursPtr32 = (volatile unsigned int *) __private->cursorImages[frame]; cursPtr16 = 0; } else if (bytesPerPixel == 2) { cursPtr32 = 0; cursPtr16 = (volatile unsigned short *) __private->cursorImages[frame]; } sw = shmem->cursorSize[0 != frame].width; sh = shmem->cursorSize[0 != frame].height; if (kIOFBSwapAxes & __private->transform) { dw = sh; dh = sw; } else { dw = sw; dh = sh; } buf = IOMalloc(dw * dh * bytesPerPixel); out = (unsigned int *) buf; for (y = 0; y < dh; y++) { for (x = 0; x < dw; x++) { if (kIOFBSwapAxes & __private->transform) { sx = y; sy = x; } else { sx = x; sy = y; } if (__private->transform & kIOFBInvertY) sx = sw - sx - 1; if (__private->transform & kIOFBInvertX) sy = sh - sy - 1; if (cursPtr32) *out++ = cursPtr32[sx + sy * sw]; else STOREINC(out, cursPtr16[sx + sy * sw], UInt16) } } bcopy(buf, (void *) __private->cursorImages[frame], dw * dh * bytesPerPixel); IOFree(buf, dw * dh * bytesPerPixel); shmem->cursorSize[0 != frame].width = dw; shmem->cursorSize[0 != frame].height = dh; if (kIOFBSwapAxes & __private->transform) { x = shmem->hotSpot[0 != frame].y; y = shmem->hotSpot[0 != frame].x; } else { x = shmem->hotSpot[0 != frame].x; y = shmem->hotSpot[0 != frame].y; } if (__private->transform & kIOFBInvertX) x = dw - x - 1; if (__private->transform & kIOFBInvertY) y = dh - y - 1; shmem->hotSpot[0 != frame].x = x; shmem->hotSpot[0 != frame].y = y; } IOReturn IOFramebuffer::extSetNewCursor( void * cursor, IOIndex frame, IOOptionBits options ) { StdFBShmem_t * shmem; IOReturn err; UInt32 hwCursorActive; if ((err = extEntry())) return (err); shmem = GetShmem(this); // assumes called with cursorSema held if (cursor || options || (((UInt32) frame) >= __private->numCursorFrames)) err = kIOReturnBadArgument; else { if (kIOFBRotateFlags & __private->transform) transformCursor(shmem, frame); if ((shmem->cursorSize[0 != frame].width > maxCursorSize.width) || (shmem->cursorSize[0 != frame].height > maxCursorSize.height)) err = kIOReturnBadArgument; else if (haveHWCursor) { if (frame == shmem->frame) { hwCursorActive = _setCursorImage( frame ); shmem->hardwareCursorActive = hwCursorActive; __private->cursorFlags[frame] = hwCursorActive ? kIOFBCursorHWCapable : 0; } else { __private->cursorFlags[frame] = kIOFBCursorImageNew; } err = kIOReturnSuccess; // I guess } else err = kIOReturnUnsupported; } if (__private->cursorToDo) KICK_CURSOR(__private->cursorThread); FBUNLOCK(); return (err); } bool IOFramebuffer::convertCursorImage( void * cursorImage, IOHardwareCursorDescriptor * hwDesc, IOHardwareCursorInfo * hwCursorInfo ) { StdFBShmem_t * shmem = GetShmem(this); UInt8 * dataOut = hwCursorInfo->hardwareCursorData; IOColorEntry * clut = hwCursorInfo->colorMap; UInt32 maxColors = hwDesc->numColors; int frame = (int) cursorImage; volatile unsigned short * cursPtr16; volatile unsigned int * cursPtr32; SInt32 x, lastx, y, lasty; UInt32 width, height, lineBytes = 0; UInt32 index, numColors = 0; UInt32 alpha, red, green, blue; UInt16 s16; UInt32 s32; UInt32 pixel = 0; UInt32 data = 0; UInt32 bits = 0; bool ok = true; bool isDirect; if (__private->testingCursor) { IOHardwareCursorDescriptor copy; if ((hwDesc->numColors == 0) && (hwDesc->bitDepth > 8) && (hwDesc->bitDepth < 32)) { copy = *hwDesc; hwDesc = © copy.bitDepth = 32; } OSData * data = OSData::withBytes( hwDesc, sizeof(IOHardwareCursorDescriptor) ); if (data) { __private->cursorAttributes->setObject( data ); data->release(); } return (false); } else if (!hwCursorInfo || !hwCursorInfo->hardwareCursorData) return (false); assert( frame < __private->numCursorFrames ); if (bytesPerPixel == 4) { cursPtr32 = (volatile unsigned int *) __private->cursorImages[frame]; cursPtr16 = 0; } else if (bytesPerPixel == 2) { cursPtr32 = 0; cursPtr16 = (volatile unsigned short *) __private->cursorImages[frame]; } else return (false); x = shmem->cursorSize[0 != frame].width; y = shmem->cursorSize[0 != frame].height; if ((x > (SInt32) hwDesc->width) || (y > (SInt32) hwDesc->height)) return (false); isDirect = (hwDesc->bitDepth > 8); if (isDirect && (hwDesc->bitDepth != 32) && (hwDesc->bitDepth != 16)) return (false); width = hwDesc->width; height = hwDesc->height; // matrox workaround - 2979661 if ((maxColors > 1) && (&clut[1] == (IOColorEntry *) hwCursorInfo)) width = height = 16; // -- SInt32 adjX = 4 - shmem->hotSpot[0 != frame].x; SInt32 adjY = 4 - shmem->hotSpot[0 != frame].y; if ((adjX < 0) || ((UInt32)(x + adjX) > width)) adjX = 0; else x += adjX; if ((adjY < 0) || ((UInt32)(y + adjY) > height)) adjY = 0; __private->cursorHotSpotAdjust[0 != frame].x = adjX; __private->cursorHotSpotAdjust[0 != frame].y = adjY; while ((width >> 1) >= (UInt32) x) width >>= 1; while ((UInt32)(height >> 1) >= (UInt32)(y + adjY)) height >>= 1; hwCursorInfo->cursorWidth = width; hwCursorInfo->cursorHeight = height; lastx = x - width - 1; if (isDirect && adjY) { lineBytes = width * (hwDesc->bitDepth >> 3); // top lines bzero_nc( dataOut, adjY * lineBytes ); dataOut += adjY * lineBytes; // bottom lines adjY = height - shmem->cursorSize[0 != frame].height - adjY; lasty = -1; } else { y += adjY; lasty = y - height - 1; } while (ok && (--y != lasty)) { x = shmem->cursorSize[0 != frame].width + adjX; while (ok && (--x != lastx)) { if ((x < 0) || (y < 0) || (x >= shmem->cursorSize[0 != frame].width) || (y >= shmem->cursorSize[0 != frame].height)) alpha = red = green = blue = 0; else if (cursPtr32) { s32 = *(cursPtr32++); alpha = (s32 >> 24) & 0xff; red = (s32 >> 16) & 0xff; green = (s32 >> 8) & 0xff; blue = (s32) & 0xff; } else { #define RMASK16 0xF000 #define GMASK16 0x0F00 #define BMASK16 0x00F0 #define AMASK16 0x000F s16 = *(cursPtr16++); alpha = s16 & AMASK16; alpha |= (alpha << 4); red = (s16 & RMASK16) >> 8; red |= (red >> 4); green = (s16 & GMASK16) >> 4; green |= (green >> 4); blue = s16 & BMASK16; blue |= (blue >> 4); } if (isDirect) { if (alpha == 0) { if (0xff == (red & green & blue)) { /* Transparent white area. Invert dst. */ if (kInvertingEncodedPixel & hwDesc->supportedSpecialEncodings) pixel = hwDesc->specialEncodings[kInvertingEncoding]; else ok = false; } else pixel = 0; if (hwDesc->bitDepth == 32) STOREINC(dataOut, pixel, UInt32) else STOREINC(dataOut, pixel, UInt16) } else { if (0xff != alpha) { red = 0xff * red / alpha; green = 0xff * green / alpha; blue = 0xff * blue / alpha; } if (hwDesc->bitDepth == 32) { pixel = (alpha << 24) | ((red & 0xff) << 16) | ((green & 0xff) << 8) | (blue & 0xff); STOREINC(dataOut, pixel, UInt32) } else { pixel = ((alpha & 0xf0) << 8) | ((red & 0xf0) << 4) | ((green & 0xf0) << 0) | ((blue & 0xf0) >> 4); STOREINC(dataOut, pixel, UInt16) } } } else { /* Indexed pixels */ 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 (0xff == (red & green & blue)) { /* Transparent white area. Invert dst. */ if (kInvertingEncodedPixel & hwDesc->supportedSpecialEncodings) pixel = hwDesc->specialEncodings[kInvertingEncoding]; else ok = false; } else ok = false; } else if (alpha == 0xff) { red |= (red << 8); green |= (green << 8); blue |= (blue << 8); /* 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; } data <<= hwDesc->bitDepth; data |= pixel; bits += hwDesc->bitDepth; if (0 == (bits & 31)) { OSWriteBigInt32(dataOut, 0, data); dataOut += sizeof(UInt32); } } } /* x */ } /* y */ if (ok && isDirect && adjY) { // bottom lines bzero_nc( dataOut, adjY * lineBytes ); dataOut += adjY * lineBytes; } __private->cursorClutDependent = (ok && !isDirect); #if 0 if (ok) { static UInt32 lastWidth; static UInt32 lastHeight; if ((width != lastWidth) || (height != lastHeight)) { lastWidth = width; lastHeight = height; IOLog("[%d,%d]", width, height); } if (((UInt32)(dataOut - hwCursorInfo->hardwareCursorData) != ((hwCursorInfo->cursorHeight * hwCursorInfo->cursorWidth * hwDesc->bitDepth) >> 3))) IOLog("dataOut %p, %p @ %d\n", dataOut, hwCursorInfo->hardwareCursorData, hwDesc->bitDepth ); } #endif return (ok); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Apple standard 8-bit CLUT #if 0 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 #warning ** DO AN IO ** static unsigned long doaniobuf[256]; static void doanio( void ) { struct uio uio; struct iovec iovec; int err; dev_t device = makedev( 14, 0 ); iovec.iov_base = (char *) &doaniobuf[0]; iovec.iov_len = 1024; uio.uio_iov = &iovec; uio.uio_iovcnt = 1; uio.uio_rw = UIO_READ; uio.uio_segflg = UIO_SYSSPACE; uio.uio_offset = 0; uio.uio_resid = 1024; DEBG(0, "\n"); err = ((*cdevsw[major(device)].d_read)(device, &uio, 0)); DEBG(0, " done(%08lx)\n", doaniobuf[0]); } #endif IOReturn IOFramebuffer::handleEvent( IOIndex event, void * info ) { IOReturn ret; DEBG(thisIndex, "(%ld, %d)\n", event, pagingState); switch (event) { case kIOFBNotifyWillPowerOff: if (this == gIOFBConsoleFramebuffer) { // getPlatform()->setConsoleInfo( 0, kPEDisableScreen); killprint = 1; } if (ACCEL_OFF_ON_DIM && pagingState) { pagingState = false; deliverFramebufferNotification( kIOFBNotifyWillSleep, info ); } ret = deliverFramebufferNotification( event, info ); configPending = true; break; case kIOFBNotifyDidPowerOff: __private->connectChangeAtSleep = connectChange; ret = kIOReturnSuccess; break; case kIOFBNotifyDidPowerOn: if (this == gIOFBConsoleFramebuffer) { // getPlatform()->setConsoleInfo( 0, kPEEnableScreen); killprint = 0; kmputc( 033 ); kmputc( 'c' ); } ret = deliverFramebufferNotification( event, info ); if (!pagingState && gIOFBSystemPower) { pagingState = true; if (__private->connectChangeAtSleep != connectChange) { if (!__private->disabledForConnectChange) { __private->disabledForConnectChange = true; deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange ); } } deliverFramebufferNotification( kIOFBNotifyDidWake, info ); } #if DOANIO doanio(); #endif configPending = false; // checkConnectionChange(); break; #if DOANIO case kIOFBNotifyWillSleep: if (!info) { doanio(); } // else its the redirection notify ret = deliverFramebufferNotification( event, info ); break; #endif #if VRAM_SAVE case kIOFBNotifyDidWake: if (info) { // restore vram content if (__private->saveLength) { if (!suspended && ((this != gIOFBConsoleFramebuffer) || (kOSBooleanTrue != getPMRootDomain()->getProperty(kIOHibernatePreviewBufferKey)))) { #if VRAM_COMPRESS DecompressData( (UInt8 *) __private->saveFramebuffer, (UInt8 *) frameBuffer, 0, 0, __private->framebufferWidth, __private->framebufferHeight, rowBytes); #else bcopy_nc( __private->saveFramebuffer, (void *) frameBuffer, __private->saveLength ); #endif DEBG(thisIndex, " screen drawn\n"); } if (this == gIOFBConsoleFramebuffer) getPMRootDomain()->removeProperty(kIOHibernatePreviewBufferKey); IOFreePageable( __private->saveFramebuffer, __private->saveLength ); __private->saveFramebuffer = 0; __private->saveLength = 0; } } ret = deliverFramebufferNotification( event, info ); break; #endif /* VRAM_SAVE */ default: ret = deliverFramebufferNotification( event, info ); break; } return (ret); } IOReturn IOFramebuffer::notifyServer( UInt8 state ) { mach_msg_header_t * msgh = (mach_msg_header_t *) serverMsg; IOReturn err = kIOReturnSuccess; if (serverNotified != state) { serverNotified = state; DEBG(thisIndex, "(%p, %d->%d, %d)\n", msgh->msgh_remote_port, serverState, serverNotified, serverPendingAck); msgh->msgh_id = state; if ((MACH_PORT_NULL == msgh->msgh_remote_port) || (KERN_SUCCESS != mach_msg_send_from_kernel(msgh, msgh->msgh_size))) { serverState = serverNotified; } } wakeServerState(serverNotified); return (err); } bool IOFramebuffer::getIsUsable( void ) { return (dead || (0 != isUsable)); } IOReturn IOFramebuffer::postWake( IOOptionBits state ) { IOReturn ret; UInt32 value; sleepConnectCheck = false; configPending = false; ret = getAttributeForConnection(0, kConnectionPostWake, &value); if (!captured) getAttributeForConnection(0, kConnectionChanged, 0); return (ret); } void IOFramebuffer::notifyServerAll( UInt8 state ) { unsigned int index; IOFramebuffer * fb; bool doNotify = true; FBLOCK(); if (state) { doNotify = gIOFBSystemPower; for (index = 0; doNotify && (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index)); index++) { doNotify = fb->getIsUsable(); } if (doNotify) IOSleep(20); } if (doNotify) { if (state) { for (index = 0; (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index)); index++) { fb->postWake( state ); } } for (index = 0; (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index)); index++) { fb->notifyServer( state ); } } FBUNLOCK(); } enum { kIOFBDidWork = 0x00000001, kIOFBPaging = 0x00000002, }; void IOFramebuffer::sleepWork( void * arg ) { unsigned int index; IOFramebuffer * fb; IOOptionBits allState; DEBG(0, "\n"); FBLOCK(); do { for (index = 0, allState = 0; (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index)); index++) { allState |= fb->checkPowerWork(); } if ((0 == (kIOFBPaging & allState)) && gIOFBSystemPowerAckTo) { DEBG(0, " allowPowerChange(%ld)\n", gIOFBSystemPowerAckRef); IOService * ackTo = gIOFBSystemPowerAckTo; UInt32 ackRef = gIOFBSystemPowerAckRef; gIOFBSystemPowerAckTo = 0; FBUNLOCK(); ackTo->allowPowerChange( ackRef ); DEBG(0, " did allowPowerChange()\n"); FBLOCK(); allState |= kIOFBDidWork; } } while (kIOFBDidWork & allState); gIOFBSleepThread = false; FBUNLOCK(); } IOOptionBits IOFramebuffer::checkPowerWork( void ) { UInt32 newState; IOOptionBits ourState = kIOFBPaging; DEBG(thisIndex, "(%d, %d)\n", gIOFBSystemPower, pendingPowerChange); if (!gIOFBSystemPower) { notifyServer( false ); if (!serverState) { bool doSave = (0 != gIOFBSystemPowerAckTo); if (pagingState) { pagingState = false; FBUNLOCK(); handleEvent( kIOFBNotifyWillSleep ); FBLOCK(); ourState |= kIOFBDidWork; } #if VRAM_SAVE // vram content is being lost UInt32 value; if (doSave && !dead && !__private->saveLength && (kIOReturnSuccess == getAttribute(kIOVRAMSaveAttribute, &value)) && value) { vm_size_t sLen; sLen = __private->framebufferHeight * rowBytes; /* * dLen should account for possible growth. (e.g. run-length encoding noise) * Add 5 bytes for header, * 12% for RLE growth * 2 bytes per line for line spans, * 1 additional escape code byte for trailing pixel in each line */ #if VRAM_COMPRESS vm_size_t dLen; dLen = 5 + sLen + ((sLen + 7) >> 3) + (__private->framebufferHeight * 3) + rowBytes; dLen = round_page_32(dLen); __private->saveLength = dLen; #else __private->saveLength = round_page_32(sLen); #endif __private->saveFramebuffer = IOMallocPageable( __private->saveLength, page_size ); if (__private->saveFramebuffer) { #if VRAM_COMPRESS DEBG(thisIndex, " compressing\n"); dLen = CompressData( (UInt8 *) frameBuffer, bytesPerPixel, __private->framebufferWidth, __private->framebufferHeight, rowBytes, (UInt8 *) __private->saveFramebuffer, __private->saveLength ); DEBG(thisIndex, " compressed to %d%%\n", (dLen * 100) / sLen); dLen = round_page_32( dLen ); if (__private->saveLength > dLen) { IOFreePageable( (void *) (((UInt32) __private->saveFramebuffer) + dLen), __private->saveLength - dLen ); __private->saveLength = dLen; } #else bcopy_nc( (void *) frameBuffer, __private->saveFramebuffer, sLen ); #endif if (__private->saveLength) { #if RLOG kern_return_t kr = #endif vm_map_wire( IOPageableMapForAddress( (vm_address_t) __private->saveFramebuffer ), (vm_address_t) __private->saveFramebuffer, ((vm_address_t) __private->saveFramebuffer) + __private->saveLength, VM_PROT_READ | VM_PROT_WRITE, FALSE ); DEBG(thisIndex, " vm_map_wire(%x)\n", kr); if (this == gIOFBConsoleFramebuffer) { OSData * previewBuffer = OSData::withBytesNoCopy( __private->saveFramebuffer, __private->saveLength); if (previewBuffer) { getPMRootDomain()->setProperty(kIOHibernatePreviewBufferKey, previewBuffer); previewBuffer->release(); } } } } else __private->saveLength = 0; } #endif /* VRAM_SAVE */ ourState &= ~kIOFBPaging; } } if (pendingPowerChange) { pendingPowerChange = false; newState = pendingPowerState; // FBUNLOCK(); DEBG(thisIndex, " kIOPowerAttribute(%ld)\n", newState); setAttribute( kIOPowerAttribute, newState ); FBUNLOCK(); DEBG(thisIndex, " acknowledgeSetPowerState\n"); acknowledgeSetPowerState(); FBLOCK(); ourState |= kIOFBDidWork; } if (__private->pendingSpeedChange) { __private->pendingSpeedChange = false; setAttribute(kIOFBSpeedAttribute, __private->reducedSpeed); } return (ourState); } void IOFramebuffer::startThread(bool highPri) { if (!gIOFBSleepThread) { gIOFBSleepThread = true; if (highPri) thread_call_enter1(gIOFBSleepCallout, (thread_call_param_t) 0); else IOCreateThread(&sleepWork, 0); } } IOReturn IOFramebuffer::setPowerState( unsigned long powerStateOrdinal, IOService * whichDevice ) { bool now; DEBG(thisIndex, " (%ld)\n", powerStateOrdinal); FBLOCK(); pendingPowerState = powerStateOrdinal; now = (0xffffffff == gAllFramebuffers->getNextIndexOfObject( this, 0 )); if (!now) { pendingPowerChange = true; startThread(!gIOFBSystemPower || sleepConnectCheck); } // if (now) setAttribute( kIOPowerAttribute, powerStateOrdinal ); FBUNLOCK(); return (now ? 0 : 45 * 1000 * 1000); } IOReturn IOFramebuffer::powerStateWillChangeTo( IOPMPowerFlags flags, unsigned long state, IOService * whatDevice ) { IOReturn ret; DEBG(thisIndex, " (%08lx)\n", flags); FBLOCK(); if (state && !pm_vars->myCurrentState) { gIOFBSystemPower = true; sleepConnectCheck = true; gIOFBLastClamshellState = 0; } if (IOPMDeviceUsable & flags) ret = IOPMAckImplied; else { notifyServerAll( false ); if (serverState != serverNotified) { // server will ack within ten seconds serverPendingAck = true; ret = 10 * 1000 * 1000; } else ret = IOPMAckImplied; } FBUNLOCK(); return (ret); } IOReturn IOFramebuffer::powerStateDidChangeTo( IOPMPowerFlags flags, unsigned long, IOService* whatDevice ) { DEBG(thisIndex, " (%08lx)\n", flags); FBLOCK(); isUsable = (0 != (IOPMDeviceUsable & flags)); serverState = serverNotified; if (isUsable) notifyServerAll( true ); FBUNLOCK(); return (kIOReturnSuccess); } void IOFramebuffer::clamshellWork( thread_call_param_t p0, thread_call_param_t p1 ) { clamshellEnable( (SInt32) p1 ); } void IOFramebuffer::clamshellEnable( SInt32 delta ) { UInt32 change; bool desktopMode; bool notSuspended; OSObject * state; FBLOCK(); gIOFBClamshellEnable += delta; notSuspended = gIOFBSystemPower && (0 == gIOFBSuspendCount); desktopMode = notSuspended && gIOFBDesktopModeAllowed && (gIOFBClamshellEnable <= 0); FBUNLOCK(); if (delta < 0) change = kIOPMDisableClamshell; else if (notSuspended) change = kIOPMEnableClamshell | kIOPMSetDesktopMode | (desktopMode ? kIOPMSetValue : 0); else return ; gIOFBClamshellState = change; getPMRootDomain()->receivePowerNotification( change ); if ((kIOPMEnableClamshell & change) && (state = getPMRootDomain()->getProperty(kAppleClamshellStateKey))) { publishResource(kAppleClamshellStateKey, gIOFBLastClamshellState ? kOSBooleanTrue : kOSBooleanFalse ); } } IOOptionBits IOFramebuffer::clamshellState( void ) { return (gIOFBClamshellState); } IOReturn IOFramebuffer::systemPowerChange( void * target, void * refCon, UInt32 messageType, IOService * service, void * messageArgument, vm_size_t argSize ) { IOReturn ret; IOPowerStateChangeNotification * params = (IOPowerStateChangeNotification *) messageArgument; DEBG(0, "(%08lx, %ld)\n", messageType, (UInt32) params->powerRef); switch (messageType) { case kIOMessageSystemWillSleep: gIOFBClamshellState = kIOPMDisableClamshell; getPMRootDomain()->receivePowerNotification( kIOPMDisableClamshell ); FBLOCK(); gIOFBSystemPower = false; gIOFBSystemPowerAckRef = (UInt32) params->powerRef; gIOFBSystemPowerAckTo = service; startThread(true); FBUNLOCK(); // We will ack within 20 seconds params->returnValue = 20 * 1000 * 1000; ret = kIOReturnSuccess; break; case kIOMessageSystemHasPoweredOn: params->returnValue = 0; ret = kIOReturnSuccess; break; case kIOMessageSystemWillRestart: case kIOMessageSystemWillPowerOff: FBLOCK(); if (gAllFramebuffers) { IOFramebuffer * fb; for (UInt32 index = 0; (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index)); index++) { fb->deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange ); fb->setAttribute( kIOSystemPowerAttribute, messageType ); } } FBUNLOCK(); params->returnValue = 0; ret = kIOReturnSuccess; break; default: ret = kIOReturnUnsupported; break; } return (ret); } void IOFramebuffer::deferredSpeedChangeEvent( OSObject * owner, IOInterruptEventSource * evtSrc, int intCount ) { IOFramebuffer * self = (IOFramebuffer *) owner; if (self->__private->pendingSpeedChange && !gIOFBSleepThread) { self->__private->pendingSpeedChange = false; self->setAttribute(kIOFBSpeedAttribute, self->__private->reducedSpeed); } } IOReturn IOFramebuffer::setAggressiveness( unsigned long type, unsigned long newLevel ) { UInt32 reducedSpeed = newLevel; if (__private && (type == (unsigned long) kIOFBLowPowerAggressiveness)) { __private->reducedSpeed = reducedSpeed; __private->pendingSpeedChange = true; if (__private->allowSpeedChanges && __private->deferredSpeedChangeEvent) __private->deferredSpeedChangeEvent->interruptOccurred(0, 0, 0); } super::setAggressiveness(type, newLevel); return (kIOReturnSuccess); } IOReturn IOFramebuffer::getAggressiveness( unsigned long type, unsigned long * currentLevel ) { IOReturn ret; if (gIOFBGate && (type == (unsigned long) kIOFBLowPowerAggressiveness)) { FBLOCK(); *currentLevel = __private->reducedSpeed; FBUNLOCK(); ret = kIOReturnSuccess; } else ret = super::getAggressiveness(type, currentLevel); return (ret); } IOReturn IOFramebuffer::extAcknowledgeNotification( void ) { IOReturn err; bool needConnectCheck, needAck; if ((err = extEntry())) return (err); DEBG(thisIndex, " (%d->%d, %d)\n", serverState, serverNotified, serverPendingAck); needConnectCheck = (serverState != serverNotified); serverState = serverNotified; needAck = serverPendingAck; serverPendingAck = false; if (serverState && __private->cursorSlept) { resetCursor(); __private->cursorSlept = false; } else if (!serverState && !__private->cursorSlept) { hideCursor(); __private->cursorSlept = true; } checkDeferredCLUTSet(); if (needConnectCheck) checkConnectionChange(); startThread(!gIOFBSystemPower || sleepConnectCheck); FBUNLOCK(); if (needAck) acknowledgePowerChange(this); return (kIOReturnSuccess); } IOReturn IOFramebuffer::extRegisterNotificationPort( mach_port_t port, UInt32 type, UInt32 refCon ) { mach_msg_header_t * msgh; UInt8 currentState; FBLOCK(); msgh = (mach_msg_header_t *) serverMsg; bzero( msgh, sizeof(mach_msg_header_t) ); msgh->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); msgh->msgh_size = sizeof(mach_msg_header_t); msgh->msgh_remote_port = port; currentState = serverNotified; serverNotified = true; // server assumes so at startup wakeServerState(serverNotified); serverPendingAck = false; notifyServer( currentState ); msgh->msgh_id = 0x87654321; mach_msg_send_from_kernel( msgh, msgh->msgh_size ); FBUNLOCK(); return (kIOReturnSuccess); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void IOFramebuffer::writePrefs( OSObject * owner, IOTimerEventSource * sender ) { IOFramebuffer * self = (IOFramebuffer *) owner; DEBG(self->thisIndex, "\n"); self->messageClients( kIOMessageServicePropertyChange, (void *) 'pref' ); } void IOFramebuffer::connectChangeInterrupt( IOFramebuffer * inst, void * delay ) { OSIncrementAtomic( &inst->connectChange); DEBG(inst->thisIndex, "(%ld)\n", inst->connectChange); if (0 == inst->configPending) { if (delay && inst->__private->delayedConnectInterrupt) inst->__private->delayedConnectInterrupt->setTimeoutMS((UInt32) delay); else inst->deferredEvents->interruptOccurred(0, 0, 0); } } void IOFramebuffer::connectChangeDelayedInterrupt( OSObject * owner, IOTimerEventSource * sender ) { IOFramebuffer * self = (IOFramebuffer *) owner; if (0 == self->configPending) self->deferredEvents->interruptOccurred(0, 0, 0); } void IOFramebuffer::deferredInterrupt( OSObject * owner, IOInterruptEventSource * evtSrc, int intCount ) { IOFramebuffer * self = (IOFramebuffer *) owner; self->checkConnectionChange(); } void IOFramebuffer::checkConnectionChange( bool message ) { bool nowSuspended; bool connectChangeOverSleep = (__private->disabledForConnectChange); DEBG(thisIndex, " count(%ld), susp(%d), sleep(%d), capt(%d)\n", connectChange, suspended, connectChangeOverSleep, captured); if ((gIOFBDesktopModeAllowed || !gIOFBLastClamshellState) && (connectChange && (connectChangeOverSleep || !captured))) { FBLOCK(); nowSuspended = !suspended; if (nowSuspended) { suspended = true; messaged = false; connectChange = 0; gIOFBSuspendCount++; } FBUNLOCK(); if (message) { IOFramebuffer * next = this; while ((next = next->getNextDependent()) && (next != this)) { next->checkConnectionChange(false); } } if (nowSuspended) { if (message) messageClients( kIOMessageServiceIsSuspended, (void *) true ); } else DEBG(thisIndex, " spurious\n"); } sleepConnectCheck = false; clamshellEnable(0); } static bool IOFramebufferLockedSerialize(void * target, void * ref, OSSerialize * s) { bool ok; FBLOCK(); ok = ((OSObject *) target)->serialize(s); FBUNLOCK(); return (ok); } IOReturn IOFramebuffer::open( void ) { IOReturn err = kIOReturnSuccess; UInt32 value; void * vblInterrupt; void * connectInterrupt; IOFramebuffer * next; OSNumber * num; bool firstOpen; do { if (gIOFBGate) FBLOCK(); if (opened) continue; if (dead) { err = kIOReturnNotOpen; continue; } if (!gAllFramebuffers) { gAllFramebuffers = OSArray::withCapacity(1); IORegistryEntry * root; OSData * data = 0; if ((root = IORegistryEntry::fromPath("/", gIOServicePlane))) { data = OSDynamicCast(OSData, root->getProperty("graphic-options")); root->release(); } gIOFBDesktopModeAllowed = !data || (0 != (8 & *((UInt32 *) data->getBytesNoCopy()))); OSIterator * iter = getMatchingServices(serviceMatching("IOAccelerator")); if (iter) { IOService * accel; while ((accel = OSDynamicCast(IOService, iter->getNextObject()))) accel->requestProbe(kIOFBUserRequestProbe); iter->release(); } if (gIOFBPrefs) gIOFBPrefsSerializer = OSSerializer::forTarget(gIOFBPrefs, &IOFramebufferLockedSerialize, 0); } if (!gIOFramebufferKey) gIOFramebufferKey = OSSymbol::withCStringNoCopy("IOFramebuffer"); if (!gIOFBGetSensorValueKey) gIOFBGetSensorValueKey = OSSymbol::withCStringNoCopy(kIOFBGetSensorValueKey); if (!gIOFBRotateKey) gIOFBRotateKey = OSSymbol::withCStringNoCopy(kIOFBRotatePrefsKey); if (!gIOFramebufferKey || !gIOFBGetSensorValueKey || !gIOFBRotateKey) continue; if (!gAllFramebuffers) continue; if (!gIOFBRootNotifier) gIOFBRootNotifier = getPMRootDomain()->registerInterest( gIOPriorityPowerStateInterest, &systemPowerChange, 0, 0 ); if (!gIOFBRootNotifier) continue; if (!gIOFBSleepCallout) gIOFBSleepCallout = thread_call_allocate( (thread_call_func_t)&sleepWork, (thread_call_param_t) 0); if (!gIOFBSleepCallout) continue; if (!gIOFBClamshellCallout) gIOFBClamshellCallout = thread_call_allocate( &clamshellWork, (thread_call_param_t) 0); if (!gIOFBClamshellCallout) continue; if (!gIOFBWorkLoop) { OSIterator * iter = getMatchingServices( nameMatching("IOHIDSystem") ); if (iter) { IOService * hidsystem; if ((hidsystem = OSDynamicCast(IOService, iter->getNextObject()))) { gIOFBWorkLoop = hidsystem->getWorkLoop(); if (gIOFBWorkLoop) gIOFBWorkLoop->retain(); } iter->release(); } } if (!gIOFBWorkLoop) gIOFBWorkLoop = IOWorkLoop::workLoop(); if (!gIOFBWorkLoop) continue; if (!gIOFBDelayedPrefsEvent) { gIOFBDelayedPrefsEvent = IOTimerEventSource::timerEventSource( this, &writePrefs); if (gIOFBDelayedPrefsEvent) getWorkLoop()->addEventSource(gIOFBDelayedPrefsEvent); } if (!gIOFBGate) { gIOFBGate = IOFBGate::gate( this ); if (!gIOFBGate) continue; gIOFBWorkLoop->addEventSource( gIOFBGate ); FBLOCK(); } if (!gIOFBClamshellProbeTES) { gIOFBClamshellProbeTES = IOTimerEventSource::timerEventSource( this, &clamshellProbeAction); if (gIOFBClamshellProbeTES) gIOFBWorkLoop->addEventSource(gIOFBClamshellProbeTES); gIOFBClamshellNotify = addNotification( gIOPublishNotification, resourceMatching(kAppleClamshellStateKey), &clamshellHandler, NULL, 0, 10000 ); } serverNotified = true; serverState = true; // tell the console if it's on this display, it's going away if (isConsoleDevice() && !gIOFBConsoleFramebuffer) gIOFBConsoleFramebuffer = this; if ((this == gIOFBConsoleFramebuffer) || !gIOFBConsoleFramebuffer) getPlatform()->setConsoleInfo( 0, kPEDisableScreen); deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange ); err = enableController(); if (kIOReturnSuccess != err) { dead = true; if (nextDependent) { nextDependent->setNextDependent( NULL ); nextDependent = NULL; } deliverFramebufferNotification( kIOFBNotifyDisplayModeDidChange ); continue; } pagingState = true; thisIndex = gAllFramebuffers->getCount(); gAllFramebuffers->setObject(this); DEBG(thisIndex, " this %p \"%s\" \"%s\"\n", this, getName(), getProvider()->getName()); setProperty(kIOFramebufferOpenGLIndexKey, thisIndex, 64); if ((num = OSDynamicCast(OSNumber, getProperty(kIOFBTransformKey)))) __private->selectedTransform = num->unsigned64BitValue(); __private->selectedTransform |= kIOFBDefaultScalerUnderscan; // err = registerForInterruptType( kIOFBVBLInterruptType, (IOFBInterruptProc) &handleVBL, this, priv, &vblInterrupt ); haveVBLService = (err == kIOReturnSuccess ); deferredEvents = IOInterruptEventSource::interruptEventSource(this, deferredInterrupt); if (deferredEvents) getWorkLoop()->addEventSource(deferredEvents); OSObject * obj = copyProperty(kIOFBConnectInterruptDelayKey, gIOServicePlane); if (obj) { OSData * data; if ((data = OSDynamicCast(OSData, obj))) __private->delayedConnectTime = *((UInt32 *) data->getBytesNoCopy()); obj->release(); } if (__private->delayedConnectTime) { __private->delayedConnectInterrupt = IOTimerEventSource::timerEventSource( this, &connectChangeDelayedInterrupt); if (__private->delayedConnectInterrupt) getWorkLoop()->addEventSource(__private->delayedConnectInterrupt); } err = registerForInterruptType( kIOFBConnectInterruptType, (IOFBInterruptProc) &connectChangeInterrupt, this, (void *) __private->delayedConnectTime, &connectInterrupt ); // err = getAttribute( kIOHardwareCursorAttribute, &value ); haveHWCursor = ((err == kIOReturnSuccess) && (0 != (kIOFBHWCursorSupported & value))); clock_interval_to_deadline(40, kMicrosecondScale, &__private->defaultI2CTiming.bitTimeout); clock_interval_to_deadline(40, kMicrosecondScale, &__private->defaultI2CTiming.byteTimeout); clock_interval_to_deadline(40, kMicrosecondScale, &__private->defaultI2CTiming.acknowledgeTimeout); clock_interval_to_deadline(40, kMicrosecondScale, &__private->defaultI2CTiming.startTimeout); __private->lli2c = (kIOReturnSuccess == getAttributeForConnection( 0, kConnectionSupportsLLDDCSense, (UInt32 *) &__private->defaultI2CTiming)); if ((num = OSDynamicCast(OSNumber, getProperty(kIOFBGammaWidthKey)))) __private->desiredGammaDataWidth = num->unsigned32BitValue(); if ((num = OSDynamicCast(OSNumber, getProperty(kIOFBGammaCountKey)))) __private->desiredGammaDataCount = num->unsigned32BitValue(); if ((num = OSDynamicCast(OSNumber, getProperty(kIOFBGammaHeaderSizeKey)))) __private->gammaHeaderSize = num->unsigned32BitValue(); if (haveVBLService && (kIOReturnSuccess == getAttribute( kIODeferCLUTSetAttribute, &value )) && value) { __private->deferredCLUTSetEvent = IOInterruptEventSource::interruptEventSource( this, deferredCLUTSetInterrupt); if (__private->deferredCLUTSetEvent) { getWorkLoop()->addEventSource(__private->deferredCLUTSetEvent); setProperty(kIOFBCLUTDeferKey, kOSBooleanTrue); } } __private->deferredSpeedChangeEvent = IOInterruptEventSource::interruptEventSource( this, deferredSpeedChangeEvent); if (__private->deferredSpeedChangeEvent) getWorkLoop()->addEventSource(__private->deferredSpeedChangeEvent); num = OSDynamicCast( OSNumber, getProperty(kIOFBDependentIDKey) ); firstOpen = num && !nextDependent; if (firstOpen) { do { OSDictionary * matching; OSDictionary * propMatch; OSIterator * iter; matching = serviceMatching(gIOFramebufferKey); if (!matching) continue; propMatch = OSDictionary::withCapacity(1); if (!propMatch) continue; propMatch->setObject( kIOFBDependentIDKey, num ); matching->setObject( gIOPropertyMatchKey, propMatch ); propMatch->release(); iter = getMatchingServices( matching ); matching->release(); if (iter) { IOFramebuffer * first = 0; IOFramebuffer * last = 0; while ((next = (IOFramebuffer *) iter->getNextObject())) { if (!first) first = next; else if (last) last->setNextDependent( next ); last = next; } if (first && last && (first != last)) last->setNextDependent( first ); iter->release(); } } while (false); } opened = true; UInt32 connectEnabled; err = getAttributeForConnection( 0, kConnectionEnable, &connectEnabled ); if (kIOReturnSuccess != err) connectEnabled = true; if (!gIOFBConsoleFramebuffer && connectEnabled) gIOFBConsoleFramebuffer = this; __private->paramHandler = IOFramebufferParameterHandler::withFramebuffer(this); if (__private->paramHandler) setProperty(gIODisplayParametersKey, __private->paramHandler); IOFramebufferI2CInterface::create( this ); if (connectEnabled) IODisplayWrangler::makeDisplayConnects(this); else IODisplayUpdateNVRAM(this, 0); __private->transform = __private->selectedTransform; setProperty(kIOFBTransformKey, __private->transform, 64); if (firstOpen) { next = this; while ((next = next->getNextDependent()) && (next != this)) { next->open(); } } if (connectEnabled) { setupForCurrentConfig(); err = kIOReturnSuccess; } else deliverFramebufferNotification( kIOFBNotifyDisplayModeDidChange, 0 ); // if( firstOpen) { next = this; do { next->postOpen(); } while ((next = next->getNextDependent()) && (next != this)); } } while (false); if (opened) checkConnectionChange(); __private->allowSpeedChanges = true; if (__private->pendingSpeedChange) { __private->pendingSpeedChange = false; setAttribute(kIOFBSpeedAttribute, __private->reducedSpeed); } if (gIOFBGate) FBUNLOCK(); return (err); } void IOFramebuffer::setTransform( UInt64 newTransform, bool generateChange ) { newTransform |= (kIOFBScalerUnderscan & __private->selectedTransform); if (newTransform != __private->selectedTransform) { __private->userSetTransform = true; __private->selectedTransform = newTransform; if (generateChange) connectChangeInterrupt(this, 0); else { __private->transform = newTransform; setProperty(kIOFBTransformKey, newTransform, 64); } } } UInt64 IOFramebuffer::getTransform( void ) { return (__private->transform); } IOReturn IOFramebuffer::selectTransform( UInt64 transform, bool generateChange ) { IOFramebuffer * next; next = this; // do { next->setTransform(transform, generateChange); } // while ((next = next->getNextDependent()) && (next != this)); return (kIOReturnSuccess); } IOReturn IOFramebuffer::checkMirrorSafe( UInt32 value, IOFramebuffer * other ) { IOReturn err = kIOReturnSuccess; IOFramebuffer * next = this; while ((next = next->getNextDependent()) && (next != this)) { if (~kIOFBScalerUnderscan & (__private->transform ^ next->getTransform())) { err = kIOReturnUnsupported; break; } } return (err); } IOReturn IOFramebuffer::requestProbe( IOOptionBits options ) { IOReturn err; if (kIOFBSetTransform & options) { if ((err = extEntry())) return (err); options >>= 16; selectTransform(options, true); FBUNLOCK(); } return (kIOReturnSuccess); } IOReturn IOFramebuffer::postOpen( void ) { IOService * sensor = 0; if (__private->cursorAttributes) { __private->cursorAttributes->release(); __private->cursorAttributes = 0; } __private->cursorAttributes = OSArray::withCapacity(2); if (!__private->cursorAttributes) return (kIOReturnNoMemory); __private->testingCursor = true; setCursorImage( (void *) 0 ); if (__private->cursorThread) { IOHardwareCursorDescriptor desc; desc.majorVersion = kHardwareCursorDescriptorMajorVersion; desc.minorVersion = kHardwareCursorDescriptorMinorVersion; desc.height = 256; desc.width = 256; desc.bitDepth = 32; desc.maskBitDepth = 0; desc.colorEncodings = 0; desc.flags = 0; desc.supportedSpecialEncodings = kTransparentEncodedPixel; (*__private->cursorControl.callouts->setCursorImage) ( __private->cursorControl.self, __private->cursorControl.ref, &desc, (void *) 0 ); if (gIOFBWorkLoop) gIOFBWorkLoop->addEventSource(__private->cursorThread); } __private->testingCursor = false; setProperty( kIOFBCursorInfoKey, __private->cursorAttributes ); UInt32 value[16]; //#define kTempAttribute kConnectionWSSB #define kTempAttribute 'thrm' if (!__private->temperatureSensor && (kIOReturnSuccess == getAttributeForConnection(0, kTempAttribute, &value[0]))) do { UInt32 data; OSNumber * num; num = OSDynamicCast(OSNumber, getProperty(kIOFBDependentIDKey)); if (num && num->unsigned32BitValue()) continue; sensor = new IOService; if (!sensor) continue; if (!sensor->init()) continue; #define kTempSensorName "temp-sensor" sensor->setName(kTempSensorName); sensor->setProperty("name", (void *) kTempSensorName, strlen(kTempSensorName) + 1); sensor->setProperty("compatible", (void *) kTempSensorName, strlen(kTempSensorName) + 1); sensor->setProperty("device_type", (void *) kTempSensorName, strlen(kTempSensorName) + 1); sensor->setProperty("type", "temperature"); sensor->setProperty("location", "GPU"); data = 0xff000002; sensor->setProperty("zone", &data, sizeof(data)); data = 0x00000001; sensor->setProperty("version", &data, sizeof(data)); OSData * prop; IOService * device; data = 0x12345678; if ((device = getProvider()) && (prop = OSDynamicCast(OSData, device->getProperty("AAPL,phandle")))) data = (*((UInt32 *) prop->getBytesNoCopy())) << 8; sensor->setProperty("sensor-id", &data, sizeof(data)); if (!sensor->attach(this)) continue; sensor->registerService(); __private->temperatureSensor = sensor; } while (false); if (sensor) sensor->release(); return (kIOReturnSuccess); } IOReturn IOFramebuffer::callPlatformFunction( const OSSymbol * functionName, bool waitForFunction, void *p1, void *p2, void *p3, void *p4 ) { UInt32 value[16]; IOReturn ret; if (functionName != gIOFBGetSensorValueKey) return (super::callPlatformFunction(functionName, waitForFunction, p1, p2, p3, p4)); FBLOCK(); ret = getAttributeForConnection(0, kTempAttribute, &value[0]); FBUNLOCK(); if (kIOReturnSuccess == ret) *((UInt32 *)p2) = ((value[0] & 0xffff) << 16); return (ret); } IOWorkLoop * IOFramebuffer::getWorkLoop() const { return (gIOFBWorkLoop); } void IOFramebuffer::setCaptured( bool isCaptured ) { captured = isCaptured; } void IOFramebuffer::setDimDisable( bool dimDisable ) { __private->dimDisable = dimDisable; } bool IOFramebuffer::getDimDisable( void ) { return (__private->dimDisable); } void IOFramebuffer::setNextDependent( IOFramebuffer * dependent ) { nextDependent = dependent; } IOFramebuffer * IOFramebuffer::getNextDependent( void ) { return (nextDependent); } void IOFramebuffer::close( void ) // called by the user client when { // the window server exits mach_msg_header_t * msgh; unsigned int idx; if (this == gIOFBConsoleFramebuffer) getPlatform()->setConsoleInfo( 0, kPEAcquireScreen); msgh = (mach_msg_header_t *) serverMsg; if (msgh) msgh->msgh_remote_port = MACH_PORT_NULL; serverConnect = 0; captured = false; if (gRunawayFramebuffers) { FBLOCK(); idx = gAllFramebuffers->getNextIndexOfObject( this, 0 ); if (idx != (unsigned int) -1) gAllFramebuffers->removeObject(idx); idx = gRunawayFramebuffers->getNextIndexOfObject( this, 0 ); if (idx != (unsigned int) -1) gRunawayFramebuffers->removeObject(idx); FBUNLOCK(); if (idx != (unsigned int) -1) { terminate(); } } } IODeviceMemory * IOFramebuffer::getVRAMRange( void ) { return (getApertureRange(kIOFBSystemAperture)); } IOReturn IOFramebuffer::setUserRanges( void ) { #if RLOG // print ranges UInt32 i, numRanges; IODeviceMemory * mem; numRanges = userAccessRanges->getCount(); DEBG(thisIndex, " ranges num:%ld\n", numRanges); for (i = 0; i < numRanges; i++) { mem = (IODeviceMemory *) userAccessRanges->getObject( i ); if (0 == mem) continue; DEBG(thisIndex, " start:%lx size:%lx\n", mem->getPhysicalAddress(), mem->getLength() ); } #endif return (kIOReturnSuccess); } IOReturn IOFramebuffer::setupForCurrentConfig( void ) { return (doSetup(true)); } IOReturn IOFramebuffer::doSetup( bool full ) { IOReturn err; IODisplayModeID mode; IOIndex depth; IOPixelInformation info; IODeviceMemory * mem; IODeviceMemory * fbRange; IOPhysicalAddress base; UInt32 value; bool haveFB; PE_Video newConsole; err = getAttribute( kIOHardwareCursorAttribute, &value ); __private->cursorPanning = ((err == kIOReturnSuccess) && (0 != (kIOFBCursorPans & value))); err = getCurrentDisplayMode( &mode, &depth ); if (kIOReturnSuccess == err) err = getPixelInformation( mode, depth, kIOFBSystemAperture, &info ); haveFB = ((kIOReturnSuccess == err) && (info.activeWidth >= 128)); IOTimingInformation timingInfo; timingInfo.flags = kIODetailedTimingValid; if (haveFB && (kIOReturnSuccess == getTimingInfoForDisplayMode(mode, &timingInfo)) && (kIODetailedTimingValid & timingInfo.flags)) { setProperty(kIOFBCurrentPixelClockKey, timingInfo.detailedInfo.v2.pixelClock, 64); setProperty(kIOFBCurrentPixelCountKey, ((UInt64)(timingInfo.detailedInfo.v2.horizontalActive + timingInfo.detailedInfo.v2.horizontalBlanking)) * ((UInt64)(timingInfo.detailedInfo.v2.verticalActive + timingInfo.detailedInfo.v2.verticalBlanking)), 64); } else { removeProperty(kIOFBCurrentPixelClockKey); removeProperty(kIOFBCurrentPixelCountKey); } fbRange = getApertureRange( kIOFBSystemAperture ); if (full && fbRange) { userAccessRanges->removeObject( kIOFBSystemAperture ); userAccessRanges->setObject( kIOFBSystemAperture, fbRange ); err = setUserRanges(); base = fbRange->getPhysicalAddress(); if ((mem = getVRAMRange())) { vramMapOffset = base - mem->getPhysicalAddress(); if (vramMapOffset > mem->getLength()) vramMapOffset &= (mem->getLength() - 1); setProperty( kIOFBMemorySizeKey, mem->getLength(), 32 ); mem->release(); } if (vramMap) vramMap->release(); vramMap = fbRange->map( kIOFBMapCacheMode ); assert( vramMap ); if (vramMap) base = vramMap->getVirtualAddress(); // console now available if (haveFB && ((this == gIOFBConsoleFramebuffer) || !gIOFBConsoleFramebuffer)) { newConsole.v_baseAddr = base; newConsole.v_rowBytes = info.bytesPerRow; newConsole.v_width = info.activeWidth; newConsole.v_height = info.activeHeight; newConsole.v_depth = info.bitsPerPixel; // strcpy( consoleInfo->v_pixelFormat, "PPPPPPPP"); getPlatform()->setConsoleInfo( &newConsole, kPEReleaseScreen ); getPlatform()->setConsoleInfo( &newConsole, kPEEnableScreen ); gIOFBConsoleFramebuffer = this; } DEBG(thisIndex, " using (%ldx%ld,%ld bpp)\n", info.activeWidth, info.activeHeight, info.bitsPerPixel ); } if (full) deliverFramebufferNotification( kIOFBNotifyDisplayModeDidChange, 0 ); if (fbRange) fbRange->release(); if (vramMap && haveFB) setupCursor( &info ); return (kIOReturnSuccess); } IOReturn IOFramebuffer::extSetDisplayMode( IODisplayModeID displayMode, IOIndex depth ) { IOReturn err; bool wasSuspended; if ((err = extEntry())) return (err); stopCursor(); checkDeferredCLUTSet(); if (this == gIOFBConsoleFramebuffer) { getPlatform()->setConsoleInfo( 0, kPEDisableScreen); gIOFBConsoleFramebuffer = 0; } wasSuspended = (suspended && messaged); // this mode set is during connection change ack DEBG(thisIndex, " susp(%d)\n", wasSuspended); if (!wasSuspended) deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange ); err = setDisplayMode( displayMode, depth ); clutValid = false; DEBG(thisIndex, " paramHandler\n"); if (__private->paramHandler) __private->paramHandler->displayModeChange(); setupForCurrentConfig(); if (wasSuspended) { suspended = false; --gIOFBSuspendCount; __private->disabledForConnectChange = false; } if (connectChange) checkConnectionChange(); if (wasSuspended && !suspended) { AbsoluteTime deadline; clock_interval_to_deadline( 10*1000, kMillisecondScale, &deadline ); thread_call_enter1_delayed( gIOFBClamshellCallout, (thread_call_param_t) 0, deadline ); } FBUNLOCK(); return (err); } IOReturn IOFramebuffer::extSetAttribute( IOSelect attribute, UInt32 value, IOFramebuffer * other ) { IOReturn err; UInt32 data[2]; if ((err = extEntry())) return (err); switch (attribute) { case kIOMirrorAttribute: DEBG(thisIndex, " kIOMirrorAttribute(%ld) susp(%d), curr(%d)\n", value, suspended, __private->mirrorState); value = (value != 0); if (value) { err = checkMirrorSafe(value, other); if (kIOReturnSuccess != err) break; } if (suspended) break; if (value == __private->mirrorState) break; stopCursor(); checkDeferredCLUTSet(); if (this == gIOFBConsoleFramebuffer) getPlatform()->setConsoleInfo( 0, kPEDisableScreen); deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange ); data[0] = value; data[1] = (UInt32) other; err = setAttribute( attribute, (UInt32) &data ); if (kIOReturnSuccess == err) __private->mirrorState = value; clutValid = false; setupForCurrentConfig(); break; default: err = setAttribute( attribute, value ); break; } FBUNLOCK(); return (err); } IOReturn IOFramebuffer::extGetAttribute( IOSelect attribute, UInt32 * value, IOFramebuffer * other ) { IOReturn err = kIOReturnSuccess; bool nowOnline; if ((err = extEntry())) return (err); switch (attribute) { case kConnectionChanged: { UInt32 connectEnabled; DEBG(thisIndex, " kConnectionChanged susp(%d)\n", suspended); if (!suspended) break; checkDeferredCLUTSet(); if (!__private->disabledForConnectChange) { __private->disabledForConnectChange = true; deliverFramebufferNotification( kIOFBNotifyDisplayModeWillChange ); } __private->enableScalerUnderscan = false; err = getAttributeForConnection( 0, kConnectionChanged, (UInt32 *) &connectChange ); __private->mirrorState = false; if (__private->paramHandler) __private->paramHandler->setDisplay(0); err = getAttributeForConnection( 0, kConnectionEnable, &connectEnabled ); nowOnline = (!dead && ((kIOReturnSuccess != err) || connectEnabled)); temporaryPowerClampOn(); FBUNLOCK(); IODisplayWrangler::destroyDisplayConnects( this ); if (nowOnline) IODisplayWrangler::makeDisplayConnects( this ); FBLOCK(); __private->transform = __private->selectedTransform; setProperty(kIOFBTransformKey, __private->transform, 64); if (nowOnline) { if (__private->cursorAttributes && !__private->cursorAttributes->getCount()) { __private->cursorAttributes->release(); __private->cursorAttributes = 0; } if (!__private->cursorAttributes) { if ((__private->cursorAttributes = OSArray::withCapacity(2))) { __private->testingCursor = true; setCursorImage( (void *) 0 ); __private->testingCursor = false; setProperty( kIOFBCursorInfoKey, __private->cursorAttributes ); } } } messaged = true; err = kIOReturnSuccess; } break; default: { *value = (UInt32) other; err = getAttribute( attribute, value ); } break; } FBUNLOCK(); return (err); } IOReturn IOFramebuffer::extGetInformationForDisplayMode( IODisplayModeID mode, void * info, IOByteCount length ) { UInt32 flags = 0; IOReturn err; bool getTiming; IOFBDisplayModeDescription * out = (IOFBDisplayModeDescription *) info; if (length < sizeof(IODisplayModeInformation)) return (kIOReturnBadArgument); if ((err = extEntry())) return (err); err = getInformationForDisplayMode( mode, &out->info ); if (kIOReturnSuccess == err) { err = IODisplayWrangler::getFlagsForDisplayMode( this, mode, &flags); if (kIOReturnSuccess == err) { out->info.flags &= ~kDisplayModeSafetyFlags; out->info.flags |= flags; } getTiming = (length >= sizeof(IOFBDisplayModeDescription)); out->timingInfo.flags = getTiming ? kIODetailedTimingValid : 0; if (kIOReturnSuccess != getTimingInfoForDisplayMode(mode, &out->timingInfo)) { out->timingInfo.flags &= ~kIODetailedTimingValid; out->timingInfo.appleTimingID = 0; } } FBUNLOCK(); return (err); } IOReturn IOFramebuffer::extSetProperties( OSDictionary * props ) { OSDictionary * dict; OSArray * array; OSNumber * num; IOReturn err = kIOReturnUnsupported; if ((err = extEntry())) return (err); err = kIOReturnUnsupported; if ((dict = OSDynamicCast(OSDictionary, props->getObject(kIOFBConfigKey)))) { setProperty( kIOFBConfigKey, dict ); if ((num = OSDynamicCast(OSNumber, dict->getObject(kIODisplayConnectFlagsKey)))) setAttributeForConnection( 0, kConnectionFlags, num->unsigned32BitValue() ); if (dict->getObject("IOFBScalerUnderscan")) { __private->enableScalerUnderscan = true; if (__private->paramHandler) __private->paramHandler->displayModeChange(); } if ((array = OSDynamicCast(OSArray, dict->getObject(kIOFBDetailedTimingsKey)))) err = setDetailedTimings( array ); else err = kIOReturnSuccess; } FBUNLOCK(); return (err); } //// Controller attributes IOReturn IOFramebuffer::setAttribute( IOSelect attribute, UInt32 value ) { IOReturn ret; IOFramebuffer * next; unsigned int index; bool wasCaptured; bool newCaptured, newDimDisable; switch (attribute) { case kIOCapturedAttribute: { wasCaptured = captured; DEBG(thisIndex, " kIOCapturedAttribute(%ld)\n", value); newCaptured = (kIOCaptureDisableDisplayChange & value); newDimDisable = (kIOCaptureDisableDisplayDimming & value); // -- capture next = this; do { next->setCaptured( newCaptured ); } while ((next = next->getNextDependent()) && (next != this)); if (wasCaptured && !captured) { next = this; do { next->getAttributeForConnection( 0, kConnectionChanged, 0 ); } while ((next = next->getNextDependent()) && (next != this)); next = this; do { next->checkConnectionChange(); } while ((next = next->getNextDependent()) && (next != this)); } // -- dim disable setDimDisable(newDimDisable); for (index = 0; (next = (IOFramebuffer *) gAllFramebuffers->getObject(index)); index++) { newDimDisable |= next->getDimDisable(); } if (newDimDisable != gIOFBDimDisable) { gIOFBDimDisable = newDimDisable; FBUNLOCK(); getPMRootDomain()->setAggressiveness( kIOFBCaptureAggressiveness, newDimDisable ); FBLOCK(); } ret = kIOReturnSuccess; break; } case kIOCursorControlAttribute: { IOFBCursorControlAttribute * crsrControl; crsrControl = (IOFBCursorControlAttribute *) value; if (__private->cursorThread) { __private->cursorThread->release(); __private->cursorThread = 0; } if (crsrControl && crsrControl->callouts) { __private->cursorControl = *((IOFBCursorControlAttribute *) value); __private->cursorThread = IOInterruptEventSource::interruptEventSource(this, &cursorWork); if (gIOFBWorkLoop && __private->cursorThread) gIOFBWorkLoop->addEventSource(__private->cursorThread); } ret = kIOReturnSuccess; break; } default: ret = kIOReturnUnsupported; break; } return (ret); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if __ppc__ static IOReturn ApplePMUSendMiscCommand( UInt32 command, IOByteCount sendLength, UInt8 * sendBuffer, IOByteCount * readLength, UInt8 * readBuffer ) { struct SendMiscCommandParameterBlock { int command; IOByteCount sLength; UInt8 *sBuffer; IOByteCount *rLength; UInt8 *rBuffer; }; IOReturn ret = kIOReturnError; static IOService * pmu; // See if ApplePMU exists if (!pmu) { OSIterator * iter; iter = IOService::getMatchingServices(IOService::serviceMatching("ApplePMU")); if (iter) { pmu = (IOService *) iter->getNextObject(); iter->release(); } } SendMiscCommandParameterBlock params = { command, sendLength, sendBuffer, readLength, readBuffer }; if (pmu) ret = pmu->callPlatformFunction( "sendMiscCommand", true, (void*)¶ms, NULL, NULL, NULL ); return (ret); } #endif /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ extern "C" IOReturn IOGetHardwareClamshellState( IOOptionBits * result ) { IOReturn ret = kIOReturnUnsupported; // zero -> lid open *result = 0; #if __ppc__ #define readExtSwitches 0xDC UInt8 bootEnvIntData[32]; IOByteCount iLen = sizeof(UInt8); ret = ApplePMUSendMiscCommand(readExtSwitches, 0, NULL, &iLen, &bootEnvIntData[0]); if (kIOReturnSuccess == ret) { gIOFBLastClamshellState = bootEnvIntData[0] & 1; if (gIOFBDesktopModeAllowed) *result = bootEnvIntData[0]; } #elif __i386__ static IOACPIPlatformDevice * lidDevice; UInt32 lidState; if (!lidDevice) { OSIterator * iter; IOService * service; iter = IOService::getMatchingServices(IOService::nameMatching("PNP0C0D")); if (iter) { service = (IOService *)iter->getNextObject(); if (service->metaCast("IOACPIPlatformDevice")) { lidDevice = (IOACPIPlatformDevice *) service; lidDevice->retain(); } iter->release(); } } if (lidDevice) { ret = lidDevice->evaluateInteger("_LID", &lidState); if (kIOReturnSuccess == ret) lidState = (lidState == 0); else lidState = 0; gIOFBLastClamshellState = lidState; if (gIOFBDesktopModeAllowed) *result = lidState; } #endif DEBG(0, "(%ld) result %d\n", ret, *result); return (ret); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void IOFramebuffer::clamshellProbeAction( OSObject * p0, IOTimerEventSource * evtSrc ) { OSObject * clamshellProperty; IOFramebuffer * fb; clamshellProperty = getPMRootDomain()->getProperty(kAppleClamshellStateKey); if (!clamshellProperty) return; for (uint32_t index = 0; (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index)); index++) { fb->deliverFramebufferNotification(kIOFBNotifyClamshellChange, clamshellProperty); } enum { bits = kIOPMSetDesktopMode | kIOPMSetValue }; if (!gIOFBLastClamshellState && (bits == (bits & gIOFBClamshellState))) { // lid open, desktop mode for (uint32_t index = 0; (fb = (IOFramebuffer *) gAllFramebuffers->getObject(index)); index++) { // fb->requestProbe(kIOFBUserRequestProbe); } } } bool IOFramebuffer::clamshellHandler( void * target, void * ref, IOService * resourceService ) { OSObject * clamshellProperty; clamshellProperty = resourceService->getProperty(kAppleClamshellStateKey); if (!clamshellProperty) return (true); gIOFBLastClamshellState = (clamshellProperty == kOSBooleanTrue); resourceService->removeProperty(kAppleClamshellStateKey); if (gIOFBClamshellProbeTES) gIOFBClamshellProbeTES->setTimeoutMS(kIOFBClamshellProbeDelayMS); return (true); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ IOReturn IOFramebuffer::getAttribute( IOSelect attribute, UInt32 * value ) { IOReturn ret = kIOReturnUnsupported; switch (attribute) { case kIOClamshellStateAttribute: ret = IOGetHardwareClamshellState( value ); break; default: break; } return (ret); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ bool IOFramebuffer::setNumber( OSDictionary * dict, const char * key, UInt32 value ) { OSNumber * num; bool ok; num = OSNumber::withNumber( value, 32 ); if (!num) return (false); ok = dict->setObject( key, num ); num->release(); return (ok); } bool IOFramebuffer::serializeInfo( OSSerialize * s ) { IOReturn err; IODisplayModeInformation info; IOPixelInformation pixelInfo; IODisplayModeID * modeIDs; IOItemCount modeCount, modeNum, aperture; IOIndex depthNum; OSDictionary * infoDict; OSDictionary * modeDict; OSDictionary * pixelDict; char keyBuf[12]; bool ok = true; modeCount = getDisplayModeCount(); modeIDs = IONew( IODisplayModeID, modeCount ); if (!modeIDs) return (false); err = getDisplayModes( modeIDs ); if (err) return (false); infoDict = OSDictionary::withCapacity( 10 ); if (!infoDict) return (false); for (modeNum = 0; modeNum < modeCount; modeNum++) { err = getInformationForDisplayMode( modeIDs[modeNum], &info ); if (err) continue; modeDict = OSDictionary::withCapacity( 10 ); if (!modeDict) break; ok = setNumber( modeDict, kIOFBWidthKey, info.nominalWidth ) && setNumber( modeDict, kIOFBHeightKey, info.nominalHeight ) && setNumber( modeDict, kIOFBRefreshRateKey, info.refreshRate ) && setNumber( modeDict, kIOFBFlagsKey, info.flags ); if (!ok) break; for (depthNum = 0; depthNum < info.maxDepthIndex; depthNum++) { for (aperture = 0; ; aperture++) { err = getPixelInformation( modeIDs[modeNum], depthNum, aperture, &pixelInfo ); if (err) break; pixelDict = OSDictionary::withCapacity( 10 ); if (!pixelDict) continue; ok = setNumber( pixelDict, kIOFBBytesPerRowKey, pixelInfo.bytesPerRow ) && setNumber( pixelDict, kIOFBBytesPerPlaneKey, pixelInfo.bytesPerPlane ) && setNumber( pixelDict, kIOFBBitsPerPixelKey, pixelInfo.bitsPerPixel ) && setNumber( pixelDict, kIOFBComponentCountKey, pixelInfo.componentCount ) && setNumber( pixelDict, kIOFBBitsPerComponentKey, pixelInfo.bitsPerComponent ) && setNumber( pixelDict, kIOFBFlagsKey, pixelInfo.flags ) && setNumber( pixelDict, kIOFBWidthKey, pixelInfo.activeWidth ) && setNumber( pixelDict, kIOFBHeightKey, pixelInfo.activeHeight ); if (!ok) break; sprintf( keyBuf, "%lx", depthNum + (aperture << 16) ); modeDict->setObject( keyBuf, pixelDict ); pixelDict->release(); } } sprintf( keyBuf, "%lx", modeIDs[modeNum] ); infoDict->setObject( keyBuf, modeDict ); modeDict->release(); } IODelete( modeIDs, IODisplayModeID, modeCount ); ok &= infoDict->serialize( s ); infoDict->release(); return (ok); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ OSDefineMetaClassAndStructors(_IOFramebufferNotifier, IONotifier) #define LOCKNOTIFY() #define UNLOCKNOTIFY() void _IOFramebufferNotifier::remove() { LOCKNOTIFY(); if (whence) { whence->removeObject( (OSObject *) this ); whence = 0; } fEnable = false; UNLOCKNOTIFY(); release(); } bool _IOFramebufferNotifier::disable() { bool ret; LOCKNOTIFY(); ret = fEnable; fEnable = false; UNLOCKNOTIFY(); return (ret); } void _IOFramebufferNotifier::enable( bool was ) { LOCKNOTIFY(); fEnable = was; UNLOCKNOTIFY(); } IONotifier * IOFramebuffer::addFramebufferNotification( IOFramebufferNotificationHandler handler, OSObject * self, void * ref) { _IOFramebufferNotifier * notify = 0; notify = new _IOFramebufferNotifier; if (notify && !notify->init()) { notify->release(); notify = 0; } if (notify) { notify->handler = handler; notify->self = self; notify->ref = ref; notify->fEnable = true; if (0 == fbNotifications) fbNotifications = OSSet::withCapacity(1); notify->whence = fbNotifications; if (fbNotifications) fbNotifications->setObject( notify ); } return (notify); } IOReturn IOFramebuffer::deliverFramebufferNotification( IOIndex event, void * info ) { OSIterator * iter; _IOFramebufferNotifier * notify; IOReturn ret = kIOReturnSuccess; IOReturn r; DEBG(thisIndex, "(%ld)\n", event); LOCKNOTIFY(); iter = OSCollectionIterator::withCollection( fbNotifications ); if (iter) { while ((notify = (_IOFramebufferNotifier *) iter->getNextObject())) { if (notify->fEnable) { r = (*notify->handler)( notify->self, notify->ref, this, event, info ); if (kIOReturnSuccess != r) ret = r; } } iter->release(); } UNLOCKNOTIFY(); return (ret); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // 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); } //// 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; switch( attribute ) { case kConnectionOverscan: UInt64 newTransform; DEBG(thisIndex, " set oscn %d, ena %d\n", info, __private->enableScalerUnderscan); if (info) newTransform = __private->selectedTransform & ~kIOFBScalerUnderscan; else newTransform = __private->selectedTransform | kIOFBScalerUnderscan; if (__private->enableScalerUnderscan) { if (newTransform != __private->selectedTransform) { __private->selectedTransform = newTransform; if (!__private->disabledForConnectChange) connectChangeInterrupt(this, 0); else { __private->transform = newTransform; setProperty(kIOFBTransformKey, newTransform, 64); } } err = kIOReturnSuccess; break; } /* fall thru */ default: err = kIOReturnUnsupported; break; } return( err ); } IOReturn IOFramebuffer::getAttributeForConnection( IOIndex connectIndex, IOSelect attribute, UInt32 * value ) { IOReturn err; switch( attribute ) { case kConnectionDisplayParameterCount: if (__private->enableScalerUnderscan) *value = 1; else *value = 0; err = kIOReturnSuccess; break; case kConnectionDisplayParameters: if (__private->enableScalerUnderscan) *value = kConnectionOverscan; err = kIOReturnSuccess; break; case kConnectionOverscan: if (__private->enableScalerUnderscan) { value[0] = (0 == (kIOFBScalerUnderscan & __private->selectedTransform)); DEBG(thisIndex, " oscn %d (%qx)\n", value[0], __private->selectedTransform); value[1] = 0; value[2] = 1; err = kIOReturnSuccess; } else err = kIOReturnUnsupported; break; case kConnectionSupportsHLDDCSense: if (__private->lli2c) { err = kIOReturnSuccess; break; } // fall thru default: err = kIOReturnUnsupported; break; } return( err ); } //// 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 enum { kDDCBlockSize = 128 }; bool IOFramebuffer::hasDDCConnect( IOIndex connectIndex ) { return (__private->lli2c); } IOReturn IOFramebuffer::getDDCBlock( IOIndex bus, UInt32 blockNumber, IOSelect blockType, IOOptionBits options, UInt8 * data, IOByteCount * length ) { UInt8 startAddress; IOReturn err; UInt32 badsums, timeouts; IOI2CBusTiming * timing = &__private->defaultI2CTiming; if (!__private->lli2c) return (kIOReturnUnsupported); // Assume that we have already attempted to stop DDC1 // Read the requested block (Block 1 is at 0x0, each additional block is at 0x80 offset) startAddress = kDDCBlockSize * (blockNumber - 1); if (length) *length = kDDCBlockSize; // Attempt to read the DDC data // 1. If the error is a timeout, then it will attempt one more time. If it gets another timeout, then // it will return a timeout error to the caller. // // 2. If the error is a bad checksum error, it will attempt to read the block up to 2 more times. // If it still gets an error, then it will return a bad checksum error to the caller. i2cSend9Stops(bus, timing); badsums = timeouts = 0; do { err = readDDCBlock(bus, timing, 0xa0, startAddress, data); if (kIOReturnSuccess == err) break; IOLog("readDDCBlock returned error\n"); i2cSend9Stops(bus, timing); // We got an error. Determine what kind if (kIOReturnNotResponding == err) { IOLog("timeout\n"); timeouts++; } else if (kIOReturnUnformattedMedia == err) { IOLog("bad sum\n"); badsums++; } else break; } while ((timeouts < 2) && (badsums < 4)); return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // doI2CRequest(), // IOReturn IOFramebuffer::doI2CRequest( UInt32 bus, IOI2CBusTiming * timing, IOI2CRequest * request ) { IOReturn err = kIOReturnError; // Assume failure if (!__private->lli2c) return (kIOReturnUnsupported); if (!timing) timing = &__private->defaultI2CTiming; if (request->sendTransactionType == kIOI2CSimpleTransactionType) { if ( request->sendAddress & 0x01 ) { // Read Transaction // err = i2cReadData(bus, timing, request->sendAddress, request->sendBytes, (UInt8 *) request->sendBuffer); } else { // Read Transaction // err = i2cWriteData(bus, timing, request->sendAddress, request->sendBytes, (UInt8 *) request->sendBuffer); } } // Now, let's check to see if there is a csReplyType // if (request->replyTransactionType == kIOI2CDDCciReplyTransactionType ) { err = i2cReadDDCciData(bus, timing, request->replyAddress, request->replyBytes, (UInt8 *) request->replyBuffer); } else if (request->replyTransactionType == kIOI2CSimpleTransactionType ) { err = i2cReadData(bus, timing, request->replyAddress, request->replyBytes, (UInt8 *) request->replyBuffer); } request->result = err; if (request->completion) (*request->completion)(request); err = kIOReturnSuccess; return (err); } /* with thanks to: File: GraphicsCoreUtils.c Written by: Sean Williams, Kevin Williams, Fernando Urbina */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // stopDDC1SendCommand(), // // The VESA spec for DDC says a display in DDC1 will transition from DDC1 to DDC2 when a valid DDC2 // command is received. // DDC1 constantly spews data on the data line if syncs are active...bad for macintosh sensing // DDC2 only sends data when requested. // The VESA spec illustrates the manner to do this. // Read the first byte of data, send a Nack and a Stop. // This routine does that. // // There is a delay of two vertical clock periods where the clock line is forced low. The // NEC XE15 monitor has a controller that sometimes pulls the clockline low and never releases it. // This is bad, DDC will fail, and the monitor sensing algorithim will think a mono 1152x870 display // is attached. This isn't part of the spec but it fixes the NEC XE15. // IOReturn IOFramebuffer::stopDDC1SendCommand(IOIndex bus, IOI2CBusTiming * timing) { UInt8 data; IOReturn err = kIOReturnSuccess; UInt8 address; // keep clock line low for 2 vclocks....keeps NEC XE15 from locking clock line low // 640x480@67hz has a veritcal frequency of 15 ms // 640x480@60hz has a vertical frequency of 16.7 ms // Lower the clock line for 34 milliseconds setDDCClock(bus, kIODDCLow); IOSleep( 34 ); address = 0; err = i2cWrite(bus, timing, 0xa0, 1, &address); if (kIOReturnSuccess == err) { i2cStart(bus, timing); i2cSendByte(bus, timing, 0xa1 ); err = i2cWaitForAck(bus, timing); if (kIOReturnSuccess == err) err = i2cReadByte(bus, timing, &data); } i2cSendNack(bus, timing); i2cStop(bus, timing); return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cReadData() // // The parameters are described as follows: // // -> deviceAddress device's I2C address // -> count # of bytes to read // <- buffer buffer for the data IOReturn IOFramebuffer::i2cReadData(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 count, UInt8 * buffer) { IOReturn err = kIOReturnError; UInt32 attempts = 10; while ((kIOReturnSuccess != err) && (attempts-- > 0)) { // Attempt to read the I2C data i2cSend9Stops(bus, timing); err = i2cRead(bus, timing, deviceAddress, count, buffer); } return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cWriteData() // // The parameters are described as follows: // // -> deviceAddress device's I2C address // -> count # of bytes to read // -> buffer buffer for the data IOReturn IOFramebuffer::i2cWriteData(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 count, UInt8 * buffer) { IOReturn err = kIOReturnError; UInt32 attempts = 10; while ((kIOReturnSuccess != err) && (attempts-- > 0)) { // Attempt to write the I2C data i2cSend9Stops(bus, timing); err = i2cWrite(bus, timing, deviceAddress, count, buffer); } return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // WaitForDDCDataLine() // // Watch the DDC data line and see if it is toggling. If the data line is toggling, it means // 1) DDC display is connected // 2) DDC controller in the display is ready to receive commands. // // -> waitTime max duration that the DDC data line should be watched void IOFramebuffer::waitForDDCDataLine(IOIndex bus, IOI2CBusTiming * timing, UInt32 waitTime) { AbsoluteTime now, expirationTime; UInt32 dataLine; setDDCData(bus, kIODDCTristate); // make sure data line is tristated // Set up the timeout timer...watch DDC data line for waitTime, see if it changes clock_interval_to_deadline(waitTime, kMillisecondScale, &expirationTime); dataLine = readDDCData(bus); // read present state of dataline while (true) { if (dataLine != readDDCData(bus)) break; clock_get_uptime(&now); if (CMP_ABSOLUTETIME(&now, &expirationTime) > 0) break; } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // readDDCBlock() // Read one block of DDC data // // The parameters are described as follows: // // -> deviceAddress device's I2C address // -> startAddress start address to get data from // <- data a block of EDID data IOReturn IOFramebuffer::readDDCBlock(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 startAddress, UInt8 * data) { IOReturn err; UInt32 i; UInt8 sum = 0; // First, send the address/data as a write err = i2cWrite(bus, timing, deviceAddress, 1, &startAddress); if (kIOReturnSuccess != err) goto ErrorExit; // Now, read the I2C data err = i2cRead(bus, timing, deviceAddress, kDDCBlockSize, data); if (kIOReturnSuccess != err) goto ErrorExit; for (i = 0; i < kDDCBlockSize; i++) sum += data[i]; if (sum) err = kIOReturnUnformattedMedia; ErrorExit: return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cStart() // Start a I2C transaction void IOFramebuffer::i2cStart(IOIndex bus, IOI2CBusTiming * timing) { // Generates a Start condition: // Set DATA and CLK high and enabled setDDCData(bus, kIODDCHigh); setDDCClock(bus, kIODDCHigh); IODelay( 100 ); // Bring DATA low setDDCData(bus, kIODDCLow); IODelay( 100 ); // Bring CLK low setDDCClock(bus, kIODDCLow); IODelay( 100 ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cStop() void IOFramebuffer::i2cStop(IOIndex bus, IOI2CBusTiming * timing) { // Generate a low to high transition on DATA // while SCL is high // Bring DATA and CLK low IODelay( 200 ); setDDCData(bus, kIODDCLow); setDDCClock(bus, kIODDCLow); IODelay( 100 ); // Bring CLK High setDDCClock(bus, kIODDCHigh); IODelay( 200 ); // Bring DATA High setDDCData(bus, kIODDCHigh); IODelay( 100 ); // Release Bus setDDCData(bus, kIODDCTristate); setDDCClock(bus, kIODDCTristate); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cSendAck() // Send an ACK to acknowledge we received the data void IOFramebuffer::i2cSendAck(IOIndex bus, IOI2CBusTiming * timing) { // Here, we have to make sure that the CLK is low while // we bring DATA low and pulse CLK setDDCClock(bus, kIODDCLow); // This routine will release the bus by // tristating the CLK and DATA lines IODelay(20); // should we wait for the SDA to be high before going on??? IODelay( 40 ); // Bring SDA low setDDCData(bus, kIODDCLow); IODelay( 100 ); // pulse the CLK setDDCClock(bus, kIODDCHigh); IODelay( 200 ); setDDCClock(bus, kIODDCLow); IODelay( 40 ); // Release SDA, setDDCData(bus, kIODDCTristate); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cSendNack() // Send an ACK to acknowledge we received the data void IOFramebuffer::i2cSendNack(IOIndex bus, IOI2CBusTiming * timing) { // Here, we have to make sure that the CLK is low while // we bring DATA high and pulse CLK setDDCClock(bus, kIODDCLow); // This routine will release the bus by // tristating the CLK and DATA lines IODelay( 20 ); // should we wait for the SDA to be high before going on??? IODelay( 40 ); // Bring SDA high setDDCData(bus, kIODDCHigh); IODelay( 100 ); // pulse the CLK setDDCClock(bus, kIODDCHigh); IODelay( 200 ); setDDCClock(bus, kIODDCLow); IODelay( 40 ); // Release SDA, setDDCData(bus, kIODDCTristate); IODelay( 100 ); IODelay( 100 ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cWaitForAck() // This routine will poll the SDA line looking for a LOW value and when it finds it, it will pulse // the CLK. IOReturn IOFramebuffer::i2cWaitForAck(IOIndex bus, IOI2CBusTiming * timing) { AbsoluteTime now, expirationTime; IOReturn err = kIOReturnSuccess; IODelay( 40 ); // Set up a watchdog timer that will time us out, in case we never see the SDA LOW. clock_interval_to_deadline(1, kMillisecondScale, &expirationTime); while ((0 != readDDCData(bus)) && (kIOReturnSuccess == err)) { clock_get_uptime(&now); if (CMP_ABSOLUTETIME(&now, &expirationTime) > 0) err = kIOReturnNotResponding; // Timed Out } // OK, now pulse the clock (SDA is not enabled), the CLK // should be low here. IODelay( 40 ); setDDCClock(bus, kIODDCHigh); IODelay( 200 ); setDDCClock(bus, kIODDCLow); IODelay( 40 ); return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cSendByte() // Send a byte of data // void IOFramebuffer::i2cSendByte(IOIndex bus, IOI2CBusTiming * timing, UInt8 data) { UInt8 valueToSend; int i; // CLK should be low when entering this routine // and will be low when exiting for ( i = 0 ; i < 8; i++ ) { // Wait a bit IODelay( 100 ); // Get the bit valueToSend = ( data >> (7 - i)) & 0x01; // Send it out setDDCData(bus, valueToSend); // Wait for 40 us and then pulse the clock IODelay( 40 ); // Raise the CLK line setDDCClock(bus, kIODDCHigh); IODelay( 200 ); // Lower the clock line setDDCClock(bus, kIODDCLow); // Wait a bit IODelay( 40 ); } // Tristate the DATA while keeping CLK low setDDCData(bus, kIODDCTristate); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cReadByte() // Read a byte of data IOReturn IOFramebuffer::i2cReadByte(IOIndex bus, IOI2CBusTiming * timing, UInt8 *data) { AbsoluteTime now, expirationTime; IOReturn err = kIOReturnSuccess; UInt32 i; UInt32 value; // Make sure that DATA is Tristated and that Clock is low setDDCClock(bus, kIODDCLow); setDDCData(bus, kIODDCTristate); for (i = 0 ; (kIOReturnSuccess == err) && (i < 8); i++) { // Wait for 1 msec and then pulse the clock IODelay( 100 ); // Release the CLK line setDDCClock(bus, kIODDCTristate); // Wait for a slow device by reading the SCL line until it is high // (A slow device will keep it low). The DDC spec suggests a timeout // of 2ms here. // Setup for a timeout clock_interval_to_deadline(2, kMillisecondScale, &expirationTime); while ((0 == readDDCClock(bus)) && (kIOReturnSuccess == err)) { clock_get_uptime(&now); if (CMP_ABSOLUTETIME(&now, &expirationTime) > 0) err = kIOReturnNotResponding; // Timed Out } // Read the data value = readDDCData(bus); *data |= (value << (7-i)); //we keep clock high for when sending bits....so do same here. Ensures display sees clock. // reach 100% success rate with NEC XE15 IODelay( 200 ); // Lower the clock line setDDCClock(bus, kIODDCLow); IODelay( 40 ); } return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cWaitForBus() // Tristate DDC Clk and DDC Data lines IOReturn IOFramebuffer::i2cWaitForBus(IOIndex bus, IOI2CBusTiming * timing) { // should we wait for the bus here? setDDCClock(bus, kIODDCTristate); setDDCData(bus, kIODDCTristate); IODelay( 200 ); return kIOReturnSuccess; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cReadDDCciData() // // The parameters are described as follows: // // -> deviceAddress device's I2C address // -> count # of bytes to read // <- buffer buffer for the data // IOReturn IOFramebuffer::i2cReadDDCciData(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 count, UInt8 *buffer) { // This is a funky call that encodes the length of the transaction in the response. // According to the VESA DDC/ci spec, the low 7 bits of second byte returned by the display // will contain the length of the message less the checksum. The card should then attempt to read // that length plus the checksum but should not exceed "count" bytes. // If the size exceeds "count", then the buffer should be filled with "count" bytes and the // transaction should be completed without copying more bytes into the buffer. IOReturn err = kIOReturnSuccess; UInt32 i; UInt8 readLength; UInt32 bufferSize; Boolean reportShortRead = false; // Assume that the bufferSize == count bufferSize = count; err = i2cWaitForBus(bus, timing); if( kIOReturnSuccess != err ) goto ErrorExit; i2cStart(bus, timing); i2cSendByte(bus, timing, deviceAddress | 0x01 ); err = i2cWaitForAck(bus, timing); if( kIOReturnSuccess != err ) goto ErrorExit; for ( i = 0; i < bufferSize; i++ ) { err = i2cReadByte(bus, timing, &buffer[i] ); if( kIOReturnSuccess != err ) goto ErrorExit; i2cSendAck(bus, timing); if ( i == 1 ) { // We have read the 2nd byte, so adjust the // bufferSize accordingly // readLength = buffer[i] & 0x07; if ( (readLength + 1) <= count ) { // The read amount is less than our bufferSize, so // adjust that size // bufferSize = (readLength + 1); } else { // The amount to read > than our bufferSize // so only read up to our buffer size and remember to // report that we didn't read all the data // reportShortRead = true; } } } ErrorExit: i2cSendNack(bus, timing); i2cStop(bus, timing); if ( reportShortRead ) err = kIOReturnOverrun; return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cRead() // Read a bunch of data via I2C // // The parameters are described as follows: // // -> deviceAddress device's I2C address // -> numberOfBytes number of bytes to read // <- data the requested number of bytes of data IOReturn IOFramebuffer::i2cRead(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 numberOfBytes, UInt8 * data) { IOReturn err = kIOReturnSuccess; int i; err = i2cWaitForBus(bus, timing); if (kIOReturnSuccess != err) goto ErrorExit; i2cStart(bus, timing); i2cSendByte(bus, timing, deviceAddress | 0x01 ); err = i2cWaitForAck(bus, timing); if (kIOReturnSuccess != err) goto ErrorExit; for (i = 0; i < numberOfBytes; i++) { data[i] = 0; err = i2cReadByte(bus, timing, &data[i] ); if (kIOReturnSuccess != err) break; if (i != (numberOfBytes - 1)) i2cSendAck(bus, timing); } ErrorExit: i2cSendNack(bus, timing); i2cStop(bus, timing); return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cWrite() // Write a bunch of data via I2C // // The parameters are described as follows: // // -> deviceAddress device's I2C address // -> numberOfBytes number of bytes to write // -> data the number of bytes of data IOReturn IOFramebuffer::i2cWrite(IOIndex bus, IOI2CBusTiming * timing, UInt8 deviceAddress, UInt8 numberOfBytes, UInt8 * data) { IOReturn err = kIOReturnSuccess; UInt32 i; err = i2cWaitForBus(bus, timing); if (kIOReturnSuccess != err) goto ErrorExit; i2cStart(bus, timing); i2cSendByte(bus, timing, deviceAddress); err = i2cWaitForAck(bus, timing); if (kIOReturnSuccess != err) goto ErrorExit; for (i = 0; i < numberOfBytes; i++) { i2cSendByte(bus, timing, data[i] ); err = i2cWaitForAck(bus, timing); if (kIOReturnSuccess != err) break; } ErrorExit: if (kIOReturnSuccess != err) i2cStop(bus, timing); return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // // i2cSend9Stops() // // Assume we are reading the DDC data, and display misses a few clocks, we send ack, display misses ack // The display might still be holding down the data line. Whenever we get an error, send nine stops. // If the display is waiting for a clock before going to the next bit, the stop will be interpreted // as a clock. It will go onto the next bit. Whenever it has finished writing the eigth bit, the // next stop will look like a stop....the display will release the bus. // 8 bits, 9 stops. The display should see at least one stop.... void IOFramebuffer::i2cSend9Stops(IOIndex bus, IOI2CBusTiming * timing) { for (UInt32 i = 0; i < 9; i++) i2cStop(bus, timing); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ IOReturn IOFramebuffer::setPreferences( IOService * props, OSDictionary * prefs ) { if (!gIOFBPrefs) { prefs->retain(); gIOFBPrefs = prefs; gIOFBPrefsParameters = OSDynamicCast(OSDictionary, props->getProperty(kIOGraphicsPrefsParametersKey)); } return (kIOReturnSuccess); } OSObject * IOFramebuffer::copyPreferences( void ) { if (gIOFBPrefsSerializer) gIOFBPrefsSerializer->retain(); return (gIOFBPrefsSerializer); } OSObject * IOFramebuffer::copyPreference( IODisplay * display, const OSSymbol * key ) { const OSSymbol * displayKey; OSDictionary * dict; OSObject * value = 0; if (!gIOFBPrefs) return (value); displayKey = (const OSSymbol *) display->copyProperty(kIODisplayPrefKeyKey); if (!displayKey) return (value); if ((dict = OSDynamicCast(OSDictionary, gIOFBPrefs->getObject(displayKey)))) { value = dict->getObject(key); if (value) value->retain(); } displayKey->release(); return (value); } bool IOFramebuffer::getIntegerPreference( IODisplay * display, const OSSymbol * key, UInt32 * value ) { bool found = false; OSObject * pref = copyPreference(display, key); if (pref) { OSNumber * num; if ((num = OSDynamicCast(OSNumber, pref))) { value[0] = num->unsigned32BitValue(); DEBG(thisIndex, " found %s = %d\n", key->getCStringNoCopy(), value[0]); found = true; } pref->release(); } return (found); } bool IOFramebuffer::setPreference( IODisplay * display, const OSSymbol * key, OSObject * value ) { const OSSymbol * displayKey; OSDictionary * dict; OSObject * oldValue = 0; bool madeChanges = false; if (!gIOFBPrefs) return (false); displayKey = (const OSSymbol *) display->copyProperty(kIODisplayPrefKeyKey); if (!displayKey) return (false); dict = OSDynamicCast(OSDictionary, gIOFBPrefs->getObject(displayKey)); if (!dict) { dict = OSDictionary::withCapacity(4); if (dict) { gIOFBPrefs->setObject(displayKey, dict); dict->release(); madeChanges = true; } } else if (key) oldValue = dict->getObject(key); if (key && dict) { if (!oldValue || (!oldValue->isEqualTo(value))) { dict->setObject(key, value); madeChanges = true; } } if (madeChanges) { DEBG(thisIndex, " sched prefs\n"); gIOFBDelayedPrefsEvent->setTimeoutMS((UInt32) 2000); } displayKey->release(); return (true); } bool IOFramebuffer::setIntegerPreference( IODisplay * display, const OSSymbol * key, UInt32 value ) { bool ok = false; OSNumber * num = OSNumber::withNumber(value, 32); if (num) { ok = setPreference(display, key, num); num->release(); } DEBG(0, " %s = %d\n", key->getCStringNoCopy(), value); return (ok); } void IOFramebuffer::getTransformPrefs( IODisplay * display ) { UInt32 value; if (getIntegerPreference(display, gIODisplayOverscanKey, &value)) { if (value) __private->selectedTransform = __private->selectedTransform & ~kIOFBScalerUnderscan; else __private->selectedTransform = __private->selectedTransform | kIOFBScalerUnderscan; } if (__private->userSetTransform) { __private->userSetTransform = false; setIntegerPreference(display, gIOFBRotateKey, __private->selectedTransform & ~kIOFBScalerUnderscan); } else if (getIntegerPreference(display, gIOFBRotateKey, &value)) selectTransform(value, false); else if (__private->transform & ~kIOFBScalerUnderscan) selectTransform(0, false); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #undef super #define super IODisplayParameterHandler OSDefineMetaClassAndStructors(IOFramebufferParameterHandler, IODisplayParameterHandler) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ IOFramebufferParameterHandler * IOFramebufferParameterHandler::withFramebuffer( IOFramebuffer * framebuffer ) { IOFramebufferParameterHandler * handler; UInt32 count = 0; if ((kIOReturnSuccess != framebuffer->getAttributeForConnection( 0, kConnectionDisplayParameterCount, &count))) return (0); handler = new IOFramebufferParameterHandler; if (handler && !handler->init()) { handler->release(); handler = 0; } if (handler) handler->fFramebuffer = framebuffer; return (handler); } void IOFramebufferParameterHandler::free() { if (fDisplayParams) fDisplayParams->release(); super::free(); } bool IOFramebufferParameterHandler::setDisplay( IODisplay * display ) { IOReturn ret; UInt32 count = 0; UInt32 str[2]; const OSSymbol * sym; UInt32 value[16]; UInt32 * attributes; OSDictionary * allParams; OSDictionary * newDict = 0; OSDictionary * oldParams; const OSSymbol * key; OSIterator * iter; fDisplay = display; if (!fDisplay) return (false); FBLOCK(); fFramebuffer->setPreference(display, 0, 0); // register display fFramebuffer->getTransformPrefs(display); allParams = OSDynamicCast(OSDictionary, display->copyProperty(gIODisplayParametersKey)); if (allParams) { newDict = OSDictionary::withDictionary(allParams); allParams->release(); } ret = fFramebuffer->getAttributeForConnection( 0, kConnectionDisplayParameterCount, &count); if (kIOReturnSuccess != ret) count = 0; DEBG(0, " (%x) count %d\n", ret, count); oldParams = fDisplayParams; do { if (count) fDisplayParams = OSDictionary::withCapacity(count); else fDisplayParams = 0; if (!fDisplayParams) continue; attributes = IONew(UInt32, count); if (!attributes) continue; if (kIOReturnSuccess != fFramebuffer->getAttributeForConnection( 0, kConnectionDisplayParameters, attributes)) continue; str[1] = 0; for (UInt32 i = 0; i < count; i++) { if (attributes[i] < 0x00ffffff) continue; OSWriteBigInt32(str, 0, attributes[i]); sym = OSSymbol::withCString((const char *) str); if (!sym) continue; if (kIOReturnSuccess == fFramebuffer->getAttributeForConnection(0, attributes[i], &value[0])) { if (gIOFBPrefsParameters && gIOFBPrefsParameters->getObject(sym)) fFramebuffer->getIntegerPreference(display, sym, &value[0]); IODisplay::addParameter(fDisplayParams, sym, value[1], value[2]); IODisplay::setParameter(fDisplayParams, sym, value[0]); } DEBG(0, " [%d] %s = %d, (%d - %d)\n", i, (const char *) str, value[0], value[1], value[2]); sym->release(); } IODelete(attributes, UInt32, count); } while (false); if (oldParams) { if (newDict) { iter = OSCollectionIterator::withCollection(oldParams); if (iter) { while ((key = (const OSSymbol *) iter->getNextObject())) { if (!fDisplayParams || !fDisplayParams->getObject(key)) newDict->removeObject(key); } iter->release(); } } oldParams->release(); } if (newDict) { if (fDisplayParams) newDict->merge(fDisplayParams); display->setProperty(gIODisplayParametersKey, newDict); newDict->release(); } else if (fDisplayParams) display->setProperty(gIODisplayParametersKey, fDisplayParams); FBUNLOCK(); return (true); } void IOFramebufferParameterHandler::displayModeChange( void ) { if (fDisplay) setDisplay( fDisplay ); } bool IOFramebufferParameterHandler::doIntegerSet( OSDictionary * params, const OSSymbol * paramName, UInt32 value ) { UInt32 attribute; bool ok; FBLOCK(); if (fDisplayParams && fDisplayParams->getObject(paramName)) { if (fDisplay && gIOFBPrefsParameters && gIOFBPrefsParameters->getObject(paramName)) fFramebuffer->setIntegerPreference(fDisplay, paramName, value); attribute = OSReadBigInt32(paramName->getCStringNoCopy(), 0); ok = (kIOReturnSuccess == fFramebuffer->setAttributeForConnection( 0, attribute, value)); } else ok = false; FBUNLOCK(); return (ok); } bool IOFramebufferParameterHandler::doDataSet( const OSSymbol * paramName, OSData * value ) { return (false); } bool IOFramebufferParameterHandler::doUpdate( void ) { bool ok = true; return (ok); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #undef super #define super IOI2CInterface OSDefineMetaClassAndStructors(IOFramebufferI2CInterface, IOI2CInterface) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ IOFramebufferI2CInterface * IOFramebufferI2CInterface::withFramebuffer( IOFramebuffer * framebuffer, OSDictionary * info ) { IOFramebufferI2CInterface * interface; interface = new IOFramebufferI2CInterface; info = OSDictionary::withDictionary(info); if (interface && info) { interface->fFramebuffer = framebuffer; if (!interface->init(info) || !interface->attach(framebuffer) || !interface->start(framebuffer) ) { interface->detach( framebuffer ); interface->release(); interface = 0; } } if (info) info->release(); return (interface); } bool IOFramebufferI2CInterface::start( IOService * provider ) { bool ok = false; OSNumber * num; if (!super::start(provider)) return (false); do { num = OSDynamicCast(OSNumber, getProperty(kIOI2CInterfaceIDKey)); if (!num) break; fBusID = num->unsigned32BitValue(); num = OSDynamicCast(OSNumber, getProperty(kIOI2CBusTypeKey)); if (!num) setProperty(kIOI2CBusTypeKey, (UInt64) kIOI2CBusTypeI2C, 32); num = OSDynamicCast(OSNumber, getProperty(kIOI2CTransactionTypesKey)); if (num) fSupportedTypes = num->unsigned32BitValue(); else { fSupportedTypes = ((1 << kIOI2CNoTransactionType) | (1 << kIOI2CSimpleTransactionType) | (1 << kIOI2CDDCciReplyTransactionType) | (1 << kIOI2CCombinedTransactionType)); setProperty(kIOI2CTransactionTypesKey, (UInt64) fSupportedTypes, 32); } num = OSDynamicCast(OSNumber, getProperty(kIOI2CSupportedCommFlagsKey)); if (num) fSupportedCommFlags = num->unsigned32BitValue(); else { fSupportedCommFlags = kIOI2CUseSubAddressCommFlag; setProperty(kIOI2CSupportedCommFlagsKey, (UInt64) fSupportedCommFlags, 32); } UInt64 id = (((UInt64) (UInt32) fFramebuffer) << 32) | fBusID; registerI2C(id); ok = true; } while (false); return (ok); } IOReturn IOFramebufferI2CInterface::startIO( IOI2CRequest * request ) { IOReturn err; FBLOCK(); do { if (0 == ((1 << request->sendTransactionType) & fSupportedTypes)) { err = kIOReturnUnsupportedMode; continue; } if (0 == ((1 << request->replyTransactionType) & fSupportedTypes)) { err = kIOReturnUnsupportedMode; continue; } if (request->commFlags != (request->commFlags & fSupportedCommFlags)) { err = kIOReturnUnsupportedMode; continue; } err = fFramebuffer->doI2CRequest( fBusID, 0, request ); } while (false); if (kIOReturnSuccess != err) { request->result = err; if (request->completion) (*request->completion)(request); err = kIOReturnSuccess; } FBUNLOCK(); return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if __ppc__ class AppleOnboardI2CInterface : public IOI2CInterface { OSDeclareDefaultStructors(AppleOnboardI2CInterface) class PPCI2CInterface * fInterface; SInt32 fPort; public: virtual bool start( IOService * provider ); virtual IOReturn startIO( IOI2CRequest * request ); static AppleOnboardI2CInterface * withInterface( PPCI2CInterface * interface, SInt32 port ); }; #undef super #define super IOI2CInterface OSDefineMetaClassAndStructors(AppleOnboardI2CInterface, IOI2CInterface) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ AppleOnboardI2CInterface * AppleOnboardI2CInterface::withInterface( PPCI2CInterface * onboardInterface, SInt32 port ) { AppleOnboardI2CInterface * interface; UInt64 id = (((UInt64) (UInt32) onboardInterface) << 32) | port; interface = new AppleOnboardI2CInterface; if (interface) { interface->fInterface = onboardInterface; interface->fPort = port; if (!interface->init() || !interface->attach(onboardInterface) || !interface->start(onboardInterface) ) { interface->detach( onboardInterface ); interface->release(); interface = 0; } else interface->registerI2C(id); } return (interface); } bool AppleOnboardI2CInterface::start( IOService * provider ) { if (!super::start(provider)) return (false); setProperty(kIOI2CBusTypeKey, (UInt64) kIOI2CBusTypeI2C, 32); setProperty(kIOI2CTransactionTypesKey, (UInt64) ((1 << kIOI2CNoTransactionType) | (1 << kIOI2CSimpleTransactionType) | (1 << kIOI2CDDCciReplyTransactionType) | (1 << kIOI2CCombinedTransactionType)), 32); setProperty(kIOI2CSupportedCommFlagsKey, (UInt64) kIOI2CUseSubAddressCommFlag, 32); return (true); } IOReturn AppleOnboardI2CInterface::startIO( IOI2CRequest * request ) { IOReturn err = kIOReturnSuccess; do { // Open the interface and sets it in the wanted mode: fInterface->openI2CBus(fPort); // the i2c driver does not support well read in interrupt mode // so it is better to "go polling" (read does not timeout on errors // in interrupt mode). fInterface->setPollingMode(true); if (request->sendBytes && (kIOI2CNoTransactionType != request->sendTransactionType)) { if (kIOI2CCombinedTransactionType == request->sendTransactionType) fInterface->setCombinedMode(); else if (kIOI2CUseSubAddressCommFlag & request->commFlags) fInterface->setStandardSubMode(); else fInterface->setStandardMode(); if (!fInterface->writeI2CBus(request->sendAddress >> 1, request->sendSubAddress, (UInt8 *) request->sendBuffer, request->sendBytes)) err = kIOReturnNotWritable; } if (request->replyBytes && (kIOI2CNoTransactionType != request->replyTransactionType)) { if (kIOI2CCombinedTransactionType == request->replyTransactionType) fInterface->setCombinedMode(); else if (kIOI2CUseSubAddressCommFlag & request->commFlags) fInterface->setStandardSubMode(); else fInterface->setStandardMode(); if (!fInterface->readI2CBus(request->replyAddress >> 1, request->replySubAddress, (UInt8 *) request->replyBuffer, request->replyBytes)) err = kIOReturnNotReadable; } fInterface->closeI2CBus(); } while (false); request->result = err; err = kIOReturnSuccess; return (err); } #endif /* __ppc__ */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ IOReturn IOFramebufferI2CInterface::create( IOFramebuffer * framebuffer ) { IOReturn err = kIOReturnSuccess; IOI2CInterface * interface; UInt32 idx; OSArray * busArray; OSArray * interfaceIDArray; OSDictionary * dict; OSObject * num; bool ok = true; interfaceIDArray = OSArray::withCapacity(1); if (!interfaceIDArray) return (kIOReturnNoMemory); busArray = OSDynamicCast(OSArray, framebuffer->getProperty(kIOFBI2CInterfaceInfoKey)); do { if (!busArray) continue; for (idx = 0; (dict = OSDynamicCast(OSDictionary, busArray->getObject(idx))); idx++) { interface = IOFramebufferI2CInterface::withFramebuffer(framebuffer, dict); if (!interface) break; num = interface->getProperty(kIOI2CInterfaceIDKey); if (num) interfaceIDArray->setObject(num); else break; } ok = (idx == busArray->getCount()); } while (false); #if __ppc__ OSData * data = OSDynamicCast( OSData, framebuffer->getProvider()->getProperty("iic-address")); if (data && (!framebuffer->getProperty(kIOFBDependentIDKey)) && (0x8c == *((UInt32 *) data->getBytesNoCopy())) /*iMac*/) { do { PPCI2CInterface * onboardInterface = (PPCI2CInterface*) getResourceService()->getProperty("PPCI2CInterface.i2c-uni-n"); if (!onboardInterface) continue; interface = AppleOnboardI2CInterface::withInterface( onboardInterface, 1 ); if (!interface) break; num = interface->getProperty(kIOI2CInterfaceIDKey); if (num) interfaceIDArray->setObject(num); else break; } while (false); } #endif if (ok && interfaceIDArray->getCount()) framebuffer->setProperty(kIOFBI2CInterfaceIDsKey, interfaceIDArray); interfaceIDArray->release(); return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ OSMetaClassDefineReservedUsed(IOFramebuffer, 0); OSMetaClassDefineReservedUnused(IOFramebuffer, 1); OSMetaClassDefineReservedUnused(IOFramebuffer, 2); OSMetaClassDefineReservedUnused(IOFramebuffer, 3); OSMetaClassDefineReservedUnused(IOFramebuffer, 4); OSMetaClassDefineReservedUnused(IOFramebuffer, 5); OSMetaClassDefineReservedUnused(IOFramebuffer, 6); OSMetaClassDefineReservedUnused(IOFramebuffer, 7); OSMetaClassDefineReservedUnused(IOFramebuffer, 8); OSMetaClassDefineReservedUnused(IOFramebuffer, 9); OSMetaClassDefineReservedUnused(IOFramebuffer, 10); OSMetaClassDefineReservedUnused(IOFramebuffer, 11); OSMetaClassDefineReservedUnused(IOFramebuffer, 12); OSMetaClassDefineReservedUnused(IOFramebuffer, 13); OSMetaClassDefineReservedUnused(IOFramebuffer, 14); OSMetaClassDefineReservedUnused(IOFramebuffer, 15); OSMetaClassDefineReservedUnused(IOFramebuffer, 16); OSMetaClassDefineReservedUnused(IOFramebuffer, 17); OSMetaClassDefineReservedUnused(IOFramebuffer, 18); OSMetaClassDefineReservedUnused(IOFramebuffer, 19); OSMetaClassDefineReservedUnused(IOFramebuffer, 20); OSMetaClassDefineReservedUnused(IOFramebuffer, 21); OSMetaClassDefineReservedUnused(IOFramebuffer, 22); OSMetaClassDefineReservedUnused(IOFramebuffer, 23); OSMetaClassDefineReservedUnused(IOFramebuffer, 24); OSMetaClassDefineReservedUnused(IOFramebuffer, 25); OSMetaClassDefineReservedUnused(IOFramebuffer, 26); OSMetaClassDefineReservedUnused(IOFramebuffer, 27); OSMetaClassDefineReservedUnused(IOFramebuffer, 28); OSMetaClassDefineReservedUnused(IOFramebuffer, 29); OSMetaClassDefineReservedUnused(IOFramebuffer, 30); OSMetaClassDefineReservedUnused(IOFramebuffer, 31);