/* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The 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, QUIET ENJOYMENT 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 #include #include #ifndef offsetof #include #endif #include "IVAD.h" enum { kIVADInvertDataMask = 0x100, }; static IOReturn ApplePMUSendMiscCommand( UInt32 command, IOByteCount sendLength, UInt8 * sendBuffer, IOByteCount * readLength, UInt8 * readBuffer ); static IOReturn AppleCudaWriteIIC( UInt8 address, const UInt8 * buffer, IOByteCount * count ); static IOReturn AppleCudaReadIIC( UInt8 address, UInt8 * buffer, IOByteCount * count ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ class AppleIVAD : public IODisplayParameterHandler { OSDeclareDefaultStructors( AppleIVAD ); private: OSDictionary* fDisplayParams; IOFramebuffer* fFramebuffer; IONotifier* fNotifier; IONotifier* fPowerDownNotifier; UInt32 fIICAddress; IORegistryEntry* fIVAD; const OSSymbol* fIVADPrefsKey; IVAD1_EEPROM* fEEPROM; IVAD1UserPrefs* fUserPrefs; UInt32 fModeIndex; bool fTheatreMode; bool fAreChangingMode; bool fIsSystemSleeping; bool fIsDisplayOff; public: virtual bool start( IOService* provider ); virtual IOReturn message( UInt32 type, IOService* nub, void* arg ); 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 ); virtual IOReturn framebufferEvent( IOFramebuffer* framebuffer, IOIndex event, void* info ); virtual IOReturn powerDownHandler( void* refCon, UInt32 messageType, IOService* provider, void* messageArgument, vm_size_t argSize ); private: bool setupIVAD( void ); bool setTheatreMode( UInt32 newMode ); static IOReturn _framebufferEvent( OSObject* self, void* ref, IOFramebuffer* framebuffer, IOIndex event, void* info ); static IOReturn _powerDownHandler( void* target, void* refCon, UInt32 messageType, IOService* provider, void* messageArgument, vm_size_t argSize ); }; class AppleIVAD2 : public IODisplayParameterHandler { OSDeclareDefaultStructors( AppleIVAD2 ); private: OSDictionary* fDisplayParams; IOFramebuffer* fFramebuffer; IONotifier* fNotifier; IONotifier* fPowerDownNotifier; UInt32 fIICAddress; UInt32 fPWMIICAddress; IORegistryEntry* fIVAD; const OSSymbol* fIVADPrefsKey; IVAD2_EEPROM* fEEPROM; IVAD2UserPrefs* fUserPrefs; ModalDisplayParams* fCurrentModeParams; UInt32 fIVADPHandle; UInt32 fIVADEEPROMPHandle; UInt32 fIVADPWMPHandle; bool fTheatreMode; bool fAreChangingMode; bool fIsSystemSleeping; bool fIsDisplayOff; public: virtual bool start( IOService* provider ); virtual IOReturn message( UInt32 type, IOService* nub, void* arg ); 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 ); virtual IOReturn framebufferEvent( IOFramebuffer* framebuffer, IOIndex event, void* info ); virtual IOReturn powerDownHandler( void* refCon, UInt32 messageType, IOService* provider, void* messageArgument, vm_size_t argSize ); IOReturn writeI2CData( UInt8 bus, UInt8 address, UInt8 subAddress, UInt8* buffer, IOByteCount count ); IOReturn readI2CData( UInt8 bus, UInt8 address, UInt8 subAddress, UInt8* buffer, IOByteCount count ); private: bool setupIVAD( void ); bool setTheatreMode( UInt32 newMode ); void resetModeParams( void ); OSData* PackGeometryProperty( void ); void UnpackGeometryProperty( OSData * data ); IORegistryEntry* searchDeviceTreeForPHandle( UInt32 pHandleValue ); IOReturn doI2CReadWrite( const char* functionName, UInt8 bus, UInt8 address, UInt8 subAddress, UInt8* buffer, IOByteCount count ); static IOReturn _framebufferEvent( OSObject* self, void* ref, IOFramebuffer* framebuffer, IOIndex event, void* info ); static IOReturn _powerDownHandler( void* target, void* refCon, UInt32 messageType, IOService* provider, void* messageArgument, vm_size_t argSize ); }; class AppleVCP : public IODisplayParameterHandler { OSDeclareDefaultStructors( AppleVCP ); private: OSDictionary* fDisplayParams; UInt32 fIICAddress; public: virtual bool start( IOService* provider ); 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 ); private: bool getSymbolRange( const OSSymbol* sym, SInt32* oMin, SInt32* oMax, SInt32* oCurrent ); bool readVCPRange( UInt8 command, SInt32* max, SInt32* current ); bool setupVCP( void ); }; class ApplePanel : public IODisplayParameterHandler { OSDeclareAbstractStructors(ApplePanel); protected: struct ApplePanelInfo { UInt8 off; UInt8 min; UInt8 mid; UInt8 max; }; OSDictionary * fDisplayParams; IORegistryEntry * fBacklightNode; UInt32 fPanelFamily; ApplePanelInfo * fPanelInfo; public: virtual bool start( IOService * provider ); virtual bool setDisplay( IODisplay * display ); virtual bool doDataSet( const OSSymbol * paramName, OSData * value ); }; class ApplePanelA : public ApplePanel { OSDeclareDefaultStructors(ApplePanelA); enum { kApplePanelLevels = 128 }; private: IONDRVFramebuffer* fFramebuffer; UInt8 fValues[ kApplePanelLevels + 1 ]; bool fNoNVRAM ; public: virtual bool start( IOService * provider ); virtual bool setDisplay( IODisplay * display ); virtual bool doIntegerSet( OSDictionary * params, const OSSymbol * paramName, UInt32 value ); virtual bool doUpdate( void ); }; class ApplePMUPanel : public ApplePanel { OSDeclareDefaultStructors(ApplePMUPanel); UInt8 fHasContrast; public: virtual bool start( IOService * provider ); virtual bool setDisplay( IODisplay * display ); virtual bool doIntegerSet( OSDictionary * params, const OSSymbol * paramName, UInt32 value ); virtual bool doUpdate( void ); }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define super IODisplayParameterHandler OSDefineMetaClassAndStructors(AppleIVAD, IODisplayParameterHandler); OSDefineMetaClassAndStructors(AppleIVAD2, IODisplayParameterHandler); OSDefineMetaClassAndStructors(AppleVCP, IODisplayParameterHandler); OSDefineMetaClass(ApplePanel, IODisplayParameterHandler); OSDefineAbstractStructors(ApplePanel, IODisplayParameterHandler); OSDefineMetaClassAndStructors(ApplePanelA, ApplePanel); OSDefineMetaClassAndStructors(ApplePMUPanel, ApplePanel); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #pragma options align=mac68k enum { kATISetAuxWin = 0x96, kATIGetAuxWin = 0x96, kATISetFader = 0x97, kATIGetFader = 0x97, kAuxWinDelay = 6, kAuxWinPolarity = 0, kEnableAuxWinDelay = 1 }; struct ATIAuxWinRec { UInt16 x; UInt16 y; UInt16 w; UInt16 h; UInt8 enable; UInt8 delay; UInt8 bppDelayEnable; UInt8 polarity; UInt32 neededPadding[4]; }; struct ATIFaderRec { UInt8 enableFader; }; #pragma options align=reset /* PMU99 I2C command equates (command $9A)*/ enum { kPMUI2CCmd = 0x9A, kI2CStatusBus = 0, /* pseudo bus used for status retrieval*/ kSystemClockBus = 1, kPowerSupplyBus = 2, /* (IVAD is here)*/ kSimpleI2CStream = 0, kSubaddressI2CStream = 1, kCombinedI2CStream = 2, kI2CReplyPendingErr = -4, kI2CTransactionErr = -3, kI2CBusyErr = -2, kI2CParameterErr = -1, kI2CNoErr = 0, kI2CReadData = 1, kI2CDataBufSize = 249 }; struct PMUI2CPB { UInt8 bus; UInt8 xferType; UInt8 secondaryBusNum; UInt8 address; UInt8 subAddr; UInt8 combAddr; UInt8 dataCount; UInt8 data[249]; /* sizeof(PMUI2CPB) = 256*/ }; typedef struct PMUI2CPB PMUI2CPB; #define MAXIICRETRYCOUNT 10 #define STATUS_DATAREAD 1 #define STATUS_OK 0 #define STATUS_BUSY 0xfe static IOReturn ApplePMUReadIIC( UInt8 bus, UInt8 address, UInt8 subAddress, UInt8 * readBuf, IOByteCount count ) { PMUI2CPB iicPB; IOByteCount readLen; UInt32 retries; // loop counter for retry attempts IOReturn ioResult; ioResult = kIOReturnError; // assume error retries = MAXIICRETRYCOUNT; while (retries--) { iicPB.bus = bus; iicPB.xferType = kCombinedI2CStream; iicPB.secondaryBusNum = 0; iicPB.address = address; iicPB.subAddr = subAddress; iicPB.combAddr = 1 + address; iicPB.dataCount = count - 1; readLen = count; readBuf[0] = 0xff; ApplePMUSendMiscCommand( kPMUI2CCmd, 8, (UInt8 *) &iicPB, &readLen, readBuf ); if (readBuf[0] == STATUS_OK) break; // if pb accepted, proceed to status/read phase IOSleep( 15 ); } if (readBuf[0] == STATUS_OK) { retries = MAXIICRETRYCOUNT; while (retries--) { IOSleep( 15 ); iicPB.bus = kI2CStatusBus; readLen = count; readBuf[0] = 0xff; ApplePMUSendMiscCommand( kPMUI2CCmd, 1, (UInt8 *) &iicPB, &readLen, readBuf ); if (readBuf[0] == STATUS_DATAREAD) { ioResult = kIOReturnSuccess; break; } } } return( ioResult ); } static IOReturn ApplePMUWriteIIC( UInt8 bus, UInt8 address, UInt8 subAddress, UInt8 * buffer, IOByteCount count ) { PMUI2CPB iicPB; IOByteCount readLen; UInt8 readBuf[8]; UInt32 retries; // loop counter for retry attempts IOReturn ioResult; ioResult = kIOReturnError; // assume error retries = MAXIICRETRYCOUNT; while (retries--) { iicPB.bus = bus; iicPB.xferType = kSimpleI2CStream; iicPB.secondaryBusNum = 0; iicPB.address = address; iicPB.subAddr = 0; iicPB.combAddr = 0; iicPB.dataCount = 2; iicPB.data[0] = subAddress; bcopy( buffer, &iicPB.data[1], count ); readLen = sizeof( readBuf ); readBuf[0] = 0xff; ApplePMUSendMiscCommand( kPMUI2CCmd, 8 + count, (UInt8 *) &iicPB, &readLen, readBuf ); if (readBuf[0] == STATUS_OK) break; // if pb accepted, proceed to status phase IOSleep( 15 ); } if (readBuf[0] == STATUS_OK) { retries = MAXIICRETRYCOUNT; while (retries--) { IOSleep( 15 ); // attempt to recover status iicPB.bus = kI2CStatusBus; readLen = sizeof( readBuf ); readBuf[0] = 0xff; ApplePMUSendMiscCommand( kPMUI2CCmd, 1, (UInt8 *) &iicPB, &readLen, readBuf ); if (readBuf[0] == STATUS_OK) { ioResult = kIOReturnSuccess; break; } } } return( ioResult ); } bool AppleIVAD::start( IOService* provider ) { OSData* data; if ( !super::start( provider ) ) return( false ); if ( 0 == ( data = OSDynamicCast( OSData, provider->getProperty( "iic-address" ) ) ) ) return( false ); fIVAD = provider->childFromPath( "ivad", gIODTPlane ); // (iicAddress == iicIVAD) if ( !fIVAD ) return( false ); fDisplayParams = OSDynamicCast( OSDictionary, getProperty( gIODisplayParametersKey ) ); if ( !fDisplayParams ) return( false ); fIICAddress = *( ( UInt32 * ) data->getBytesNoCopy() ); fIVADPrefsKey = OSSymbol::withCString( "geometry" ); fAreChangingMode = false; fIsSystemSleeping = false; fIsDisplayOff = false; // Install handler for shutdown notifications fPowerDownNotifier = registerPrioritySleepWakeInterest( &AppleIVAD::_powerDownHandler, this ); return( true ); } IOReturn AppleIVAD::message( UInt32 type, IOService* nub, void* arg ) { IOReturn status = kIOReturnSuccess; if ( type == kIOMessageServiceIsRequestingClose ) { // Being asked to close. Remove notifiers. We cannot do this from a stop, as there // is the possibility of a race condition between getting notified, and trying to // dispose of the notifier. if ( fPowerDownNotifier ) { fPowerDownNotifier->remove(); fPowerDownNotifier = NULL; } if ( fNotifier ) { fNotifier->remove(); fNotifier = NULL; } } else { status = super::message( type, nub, arg ); } return( status ); } bool AppleIVAD::setDisplay( IODisplay * display ) { OSNumber * num; fFramebuffer = OSDynamicCast(IOFramebuffer, display->getProvider()->getProvider()); if( !fFramebuffer) return( false ); fNotifier = fFramebuffer->addFramebufferNotification( &AppleIVAD::_framebufferEvent, this, NULL ); setupIVAD(); display->setProperty( gIODisplayParametersKey, fDisplayParams); num = OSNumber::withNumber( kAppleOnboardGUID, 64 ); display->setProperty( gIODisplayGUIDKey, num); num->release(); return( true ); } bool AppleIVAD::doUpdate( void ) { IOReturn err; IODisplayModeID mode; IOIndex depth; IOPixelInformation pixInfo; err = fFramebuffer->getCurrentDisplayMode( &mode, &depth ); if( kIOReturnSuccess == err) err = fFramebuffer->getPixelInformation( mode, depth, kIOFBSystemAperture, &pixInfo ); if( kIOReturnSuccess == err) switch( pixInfo.activeWidth ) { case 640: fModeIndex = 0; break; case 800: default: fModeIndex = 1; break; case 1024: fModeIndex = 2; break; } IODisplay::setParameter( fDisplayParams, gIODisplayContrastKey, fUserPrefs->contrast ); IODisplay::setParameter( fDisplayParams, gIODisplayBrightnessKey, fUserPrefs->brightness ); IODisplay::setParameter( fDisplayParams, gIODisplayHorizontalPositionKey, fUserPrefs->modeParams[fModeIndex].horizontalPosition ^ 0x7f ); IODisplay::setParameter( fDisplayParams, gIODisplayHorizontalSizeKey, fUserPrefs->modeParams[fModeIndex].horizontalSize ^ 0x7f ); IODisplay::setParameter( fDisplayParams, gIODisplayVerticalPositionKey, fUserPrefs->modeParams[fModeIndex].verticalPosition ^ 0x7f ); IODisplay::setParameter( fDisplayParams, gIODisplayVerticalSizeKey, fUserPrefs->modeParams[fModeIndex].verticalSize ); IODisplay::setParameter( fDisplayParams, gIODisplayTrapezoidKey, fUserPrefs->modeParams[fModeIndex].keystone ); IODisplay::setParameter( fDisplayParams, gIODisplayPincushionKey, fUserPrefs->modeParams[fModeIndex].pincushion ); IODisplay::setParameter( fDisplayParams, gIODisplayParallelogramKey, fUserPrefs->parallelogram ^ 0x7f); IODisplay::setParameter( fDisplayParams, gIODisplayRotationKey, fUserPrefs->tilt); IODisplay::setParameter( fDisplayParams, gIODisplayParametersTheatreModeKey, fTheatreMode ); return( true ); } bool AppleIVAD::setupIVAD( void ) { UInt8 buffer[96 + 32]; OSData * data; UInt32 address; SInt32 i; bool ok = false; if( 0 == (data = OSDynamicCast(OSData, fIVAD->getProperty("eeprom-address")))) return( false ); address = *((UInt32 *) data->getBytesNoCopy()); if( !fEEPROM) fEEPROM = IONew( IVAD1_EEPROM, 1 ); if( !fUserPrefs) fUserPrefs = IONew( IVAD1UserPrefs, 1 ); if( !fEEPROM || !fUserPrefs) return( false ); bzero( buffer, sizeof(buffer) ); for (i = 0; i < (6 * 16); i += 16) { if (kIOReturnSuccess == ApplePMUReadIIC( kPowerSupplyBus, address, i, buffer + i, 17 )) bcopy(1 + buffer + i, buffer + i, 16 ); } bcopy( buffer, fEEPROM, sizeof(IVAD1_EEPROM) ); #if DEBUG IOLog("IVAD EEPROM(%x):\n", fEEPROM->id ); for (int i = 0; i < (6 * 16); i++) { IOLog("%02x ", buffer[i]); if( 15 == (i & 15)) IOLog("\n"); } #endif if( (data = OSDynamicCast(OSData, fIVAD->getProperty(fIVADPrefsKey)))) bcopy( data->getBytesNoCopy(), fUserPrefs, sizeof(IVAD1UserPrefs)); else { bcopy( fEEPROM->modeParams, fUserPrefs->modeParams, sizeof(fUserPrefs->modeParams)); fUserPrefs->contrast = fEEPROM->stdParams.contrast; fUserPrefs->brightness = fEEPROM->stdParams.brightness; fUserPrefs->parallelogram = fEEPROM->stdParams.parallelogram; fUserPrefs->tilt = fEEPROM->stdParams.tilt; } // fDisplayParams->setCapacityIncrement(1); IODisplay::addParameter( fDisplayParams, gIODisplayContrastKey, fEEPROM->userLimits.contrast.min, fEEPROM->userLimits.contrast.max ); IODisplay::addParameter( fDisplayParams, gIODisplayBrightnessKey, fEEPROM->userLimits.brightness.min, fEEPROM->userLimits.brightness.max ); IODisplay::addParameter( fDisplayParams, gIODisplayHorizontalPositionKey, fEEPROM->userLimits.horizontalPosition.min, fEEPROM->userLimits.horizontalPosition.max ); IODisplay::addParameter( fDisplayParams, gIODisplayHorizontalSizeKey, fEEPROM->userLimits.horizontalSize.min, fEEPROM->userLimits.horizontalSize.max ); IODisplay::addParameter( fDisplayParams, gIODisplayVerticalPositionKey, fEEPROM->userLimits.verticalPosition.min, fEEPROM->userLimits.verticalPosition.max ); IODisplay::addParameter( fDisplayParams, gIODisplayVerticalSizeKey, fEEPROM->userLimits.verticalSize.min, fEEPROM->userLimits.verticalSize.max ); IODisplay::addParameter( fDisplayParams, gIODisplayTrapezoidKey, fEEPROM->userLimits.keystone.min, fEEPROM->userLimits.keystone.max ); IODisplay::addParameter( fDisplayParams, gIODisplayPincushionKey, fEEPROM->userLimits.pincushion.min, fEEPROM->userLimits.pincushion.max ); IODisplay::addParameter( fDisplayParams, gIODisplayParallelogramKey, fEEPROM->userLimits.parallelogram.min, fEEPROM->userLimits.parallelogram.max ); IODisplay::addParameter( fDisplayParams, gIODisplayRotationKey, fEEPROM->userLimits.tilt.min, fEEPROM->userLimits.tilt.max ); IODisplay::addParameter( fDisplayParams, gIODisplayParametersTheatreModeKey, 0, 1 ); ATIFaderRec fader; IONDRVFramebuffer * ndrv = OSDynamicCast( IONDRVFramebuffer, fFramebuffer); if( ndrv && (kIOReturnSuccess == ndrv->doStatus( kATIGetFader, &fader))) IODisplay::addParameter( fDisplayParams, gIODisplayParametersTheatreModeWindowKey, 0, 1 ); return( ok ); } bool AppleIVAD::doDataSet( const OSSymbol * paramName, OSData * value ) { IONDRVFramebuffer * ndrv = OSDynamicCast( IONDRVFramebuffer, fFramebuffer); ATIFaderRec fader; ATIAuxWinRec auxWin; IOGBounds * rect; UInt32 newMode; bool ok = true; if( paramName != gIODisplayParametersTheatreModeWindowKey) return( false ); if( sizeof(IOGBounds) != value->getLength()) return( false ); rect = (IOGBounds *) value->getBytesNoCopy(); ok = (ndrv != 0); if( ok) do { newMode = (rect->maxx != rect->minx); bzero( &auxWin, sizeof( auxWin)); auxWin.enable = true; auxWin.delay = kAuxWinDelay; auxWin.bppDelayEnable = kEnableAuxWinDelay; fader.enableFader = newMode; if( newMode) { auxWin.x = rect->minx; auxWin.y = rect->miny; auxWin.w = rect->maxx - rect->minx; auxWin.h = rect->maxy - rect->miny; auxWin.polarity = kAuxWinPolarity; ok &= (kIOReturnSuccess == ndrv->doControl( kATISetAuxWin, &auxWin)); ok &= (kIOReturnSuccess == ndrv->doControl( kATISetFader, &fader)); } else { auxWin.x = 0; auxWin.y = 0; auxWin.w = 1; auxWin.h = 1; auxWin.polarity = 0; ok &= (kIOReturnSuccess == ndrv->doControl( kATISetFader, &fader)); ok &= (kIOReturnSuccess == ndrv->doControl( kATISetAuxWin, &auxWin)); } } while( false ); return( ok ); } bool AppleIVAD::setTheatreMode( UInt32 newMode ) { enum { kTMRegCount = 9 }; static const UInt8 turningOnRegs[ kTMRegCount ] = { kIVADContrast, kIVADBrightness, kIVADDrive1, kIVADDrive2, kIVADDrive3, kIVADCutoff1, kIVADCutoff2, kIVADCutoff3, kIVADVBLDCLevel }; static const UInt8 turningOffRegs[ kTMRegCount ] = { kIVADVBLDCLevel, kIVADCutoff3, kIVADCutoff2, kIVADCutoff1, kIVADDrive3, kIVADDrive2, kIVADDrive1, kIVADBrightness, kIVADContrast }; const UInt8* regs; UInt8 values[ kTMRegCount ]; bool ok = true; ok = true; newMode = ( newMode != 0 ); if ( newMode != fTheatreMode ) { if ( newMode ) { values[ 0 ] = fEEPROM->briteParams.contrast; values[ 1 ] = fEEPROM->briteParams.brightness; values[ 2 ] = fEEPROM->briteParams.drive1; values[ 3 ] = fEEPROM->briteParams.drive2; values[ 4 ] = fEEPROM->briteParams.drive3; values[ 5 ] = fEEPROM->briteParams.cutoff1; values[ 6 ] = fEEPROM->briteParams.cutoff2; values[ 7 ] = fEEPROM->briteParams.cutoff3; values[ 8 ] = fEEPROM->stdParams.vblDCLevel | ( fEEPROM->briteParams.gainBoost ? kGainWin : 0 ); regs = turningOnRegs; } else { // // #2864322 // When we are turning theater mode off, program the registers in the reverse order from above. // values[ 0 ] = fEEPROM->stdParams.vblDCLevel; values[ 1 ] = fEEPROM->stdParams.cutoff3; values[ 2 ] = fEEPROM->stdParams.cutoff2; values[ 3 ] = fEEPROM->stdParams.cutoff1; values[ 4 ] = fEEPROM->stdParams.drive3; values[ 5 ] = fEEPROM->stdParams.drive2; values[ 6 ] = fEEPROM->stdParams.drive1; values[ 7 ] = fUserPrefs->brightness; values[ 8 ] = fUserPrefs->contrast; regs = turningOffRegs; } for ( int i = 0; i < kTMRegCount; i++ ) { ok &= ( kIOReturnSuccess == ApplePMUWriteIIC( kPowerSupplyBus, fIICAddress, regs[ i ], &values[ i ], sizeof( UInt8 ) ) ); } if ( ok ) fTheatreMode = newMode; } return( ok ); } IOReturn AppleIVAD::_powerDownHandler( void* target, void* refCon, UInt32 messageType, IOService* provider, void* messageArgument, vm_size_t argSize ) { AppleIVAD* self = ( AppleIVAD * ) target; return( self->powerDownHandler( refCon, messageType, provider, messageArgument, argSize ) ); } IOReturn AppleIVAD::powerDownHandler( void* refCon, UInt32 messageType, IOService* provider, void* messageArgument, vm_size_t argSize ) { IOReturn status = kIOReturnUnsupported; UInt8 regValue; switch ( messageType ) { case kIOMessageSystemWillRestart: case kIOMessageSystemWillPowerOff: { // We need to set the contrast to 0 on restarts and shutdown, to minimize the flash // that occurs when the power supply is turning off. regValue = 0; ApplePMUWriteIIC( kPowerSupplyBus, fIICAddress, kIVADContrast, ®Value, sizeof( regValue) ); status = kIOReturnSuccess; break; } case kIOMessageSystemWillSleep: { fIsSystemSleeping = true; status = kIOReturnSuccess; if ( fIsDisplayOff ) { // If the display is already off, then we won't get another frame buffer notification // telling us to turn off. So, we need to turn off the PLL1 register here. regValue = 0; ApplePMUWriteIIC( kPowerSupplyBus, fIICAddress, kIVADPLL1, ®Value, sizeof( regValue ) ); } break; } case kIOMessageSystemHasPoweredOn: { fIsSystemSleeping = false; status = kIOReturnSuccess; break; } } return( status ); } IOReturn AppleIVAD::_framebufferEvent( OSObject* _self, void* ref, IOFramebuffer* framebuffer, IOIndex event, void* info ) { AppleIVAD* self = ( AppleIVAD * ) _self; return( self->framebufferEvent( framebuffer, event, info ) ); } IOReturn AppleIVAD::framebufferEvent( IOFramebuffer* framebuffer, IOIndex event, void* info ) { UInt8 regValue; switch ( event ) { case kIOFBNotifyDisplayModeWillChange: { fAreChangingMode = true; // Before changing resolution, turn off IVAD by setting contrast to 0. regValue = 0; ApplePMUWriteIIC( kPowerSupplyBus, fIICAddress, kIVADContrast, ®Value, sizeof( regValue) ); break; } case kIOFBNotifyDisplayModeDidChange: { fAreChangingMode = false; // After changing resolution, turn on IVAD by restoring contrast to user preferences. regValue = fUserPrefs->contrast; ApplePMUWriteIIC( kPowerSupplyBus, fIICAddress, kIVADContrast, ®Value, sizeof( regValue ) ); break; } case kIOFBNotifyWillPowerOff: { regValue = 0; ApplePMUWriteIIC( kPowerSupplyBus, fIICAddress, kIVADContrast, ®Value, sizeof( regValue ) ); regValue = fEEPROM->userLimits.verticalSize.min; ApplePMUWriteIIC( kPowerSupplyBus, fIICAddress, kIVADVRamp, ®Value, sizeof( regValue ) ); break; } case kIOFBNotifyDidPowerOn: { regValue = fUserPrefs->modeParams[ fModeIndex ].verticalSize; ApplePMUWriteIIC( kPowerSupplyBus, fIICAddress, kIVADVRamp, ®Value, sizeof( regValue ) ); regValue = fUserPrefs->contrast; ApplePMUWriteIIC( kPowerSupplyBus, fIICAddress, kIVADContrast, ®Value, sizeof( regValue ) ); break; } case kIOFBNotifyWillPowerOn: { if ( fIsSystemSleeping ) { // // #2983513 // Restore the PLL1 register. // regValue = fEEPROM->stdParams.pll1FVC; ApplePMUWriteIIC( kPowerSupplyBus, fIICAddress, kIVADPLL1, ®Value, sizeof( regValue ) ); fIsSystemSleeping = false; } fIsDisplayOff = false; break; } case kIOFBNotifyDidPowerOff: { if ( fIsSystemSleeping ) { // // #2983513 // Put PLL1 register in free-running mode. Only do this at system sleep time. // regValue = 0; ApplePMUWriteIIC( kPowerSupplyBus, fIICAddress, kIVADPLL1, ®Value, sizeof( regValue ) ); } fIsDisplayOff = true; break; } } return( kIOReturnSuccess ); } bool AppleIVAD::doIntegerSet( OSDictionary * params, const OSSymbol * sym, UInt32 value ) { OSNumber* num; UInt32 reg; UInt8 regValue; bool ok = true; bool skipUpdatingHardware = false; if ( sym == gIODisplayParametersDefaultKey ) { bcopy( fEEPROM->modeParams, fUserPrefs->modeParams, sizeof( fUserPrefs->modeParams ) ); fUserPrefs->contrast = fEEPROM->stdParams.contrast; fUserPrefs->brightness = fEEPROM->stdParams.brightness; fUserPrefs->parallelogram = fEEPROM->stdParams.parallelogram; fUserPrefs->tilt = fEEPROM->stdParams.tilt; return( true ); } else if ( sym == gIODisplayParametersCommitKey ) { IODTPlatformExpert* dtPlaform = OSDynamicCast( IODTPlatformExpert, getPlatform() ); OSData* data = OSData::withBytesNoCopy( fUserPrefs, sizeof( IVAD1UserPrefs ) ); if ( data && dtPlaform) ok = ( kIOReturnSuccess == dtPlaform->writeNVRAMProperty( fIVAD, fIVADPrefsKey, data ) ); if ( data) data->release(); return( ok ); } else if ( sym == gIODisplayParametersTheatreModeKey ) return( setTheatreMode( value ) ); // Since we want to leave the contrast off while we are updating IVAD, delay updating // contrast until we get the kIOFBNotifyDisplayModeDidChange message in framebufferEvent(). if ( ( fAreChangingMode == true ) && ( sym == gIODisplayContrastKey ) ) { skipUpdatingHardware = true; } if ( !params ) return( true ); num = ( OSNumber * ) params->getObject( "reg" ); if ( !num ) return( false ); reg = num->unsigned32BitValue(); if ( reg & kIVADInvertDataMask ) regValue = value ^ 0x7F; else regValue = value; if ( !skipUpdatingHardware ) { ok = ( kIOReturnSuccess == ApplePMUWriteIIC( kPowerSupplyBus, fIICAddress, reg & 0x1F, ®Value, sizeof( regValue ) ) ); } if ( ok ) { if ( sym == gIODisplayContrastKey ) fUserPrefs->contrast = regValue; else if ( sym == gIODisplayBrightnessKey ) fUserPrefs->brightness = regValue; else if ( sym == gIODisplayHorizontalPositionKey ) fUserPrefs->modeParams[ fModeIndex ].horizontalPosition = regValue; else if ( sym == gIODisplayHorizontalSizeKey ) fUserPrefs->modeParams[ fModeIndex ].horizontalSize = regValue; else if ( sym == gIODisplayVerticalPositionKey ) fUserPrefs->modeParams[ fModeIndex ].verticalPosition = regValue; else if ( sym == gIODisplayVerticalSizeKey ) fUserPrefs->modeParams[ fModeIndex ].verticalSize = regValue; else if ( sym == gIODisplayTrapezoidKey ) fUserPrefs->modeParams[ fModeIndex ].keystone = regValue; else if ( sym == gIODisplayPincushionKey ) fUserPrefs->modeParams[ fModeIndex ].pincushion = regValue; else if ( sym == gIODisplayParallelogramKey ) fUserPrefs->parallelogram = regValue; else if ( sym == gIODisplayRotationKey ) fUserPrefs->tilt = regValue; } return( ok ); } bool AppleIVAD2::start( IOService* provider ) { OSData* data; if ( !super::start( provider ) ) return( false ); if ( !provider ) return( false ); // Even though we matched against the "ivad2" node, we need to attach ourselves to it's parent. // The display software will searching through the framebuffers, looking for the "IODisplayParameters" // dictionary that I publish. IOService* frameBufferDevice; frameBufferDevice = OSDynamicCast( IOService, provider->copyParentEntry( gIODTPlane ) ); if ( !frameBufferDevice ) return( false ); attach( frameBufferDevice ); fIVAD = provider; fDisplayParams = OSDynamicCast( OSDictionary, getProperty( gIODisplayParametersKey ) ); if ( !fDisplayParams ) return( false ); // Get the IVAD2 IIC address. if ( 0 == (data = OSDynamicCast( OSData, fIVAD->getProperty( "iic-address" ) ) ) ) return( false ); fIICAddress = *( ( UInt32 * ) data->getBytesNoCopy() ); // Get the IVAD2 PWM IIC address. if ( 0 == ( data = OSDynamicCast( OSData, fIVAD->getProperty( "pwm-iic-address" ) ) ) ) return( false ); fPWMIICAddress = *( ( UInt32 * ) data->getBytesNoCopy() ); // Get the saved geometry preferences. fIVADPrefsKey = OSSymbol::withCString( "geometry" ); // Get "platform-*" information, to allow us to communicate to the different IVAD-related I2C devices. if ( ( data = OSDynamicCast( OSData, fIVAD->getProperty( "platform-ivad" ) ) ) != NULL ) { fIVADPHandle = *( ( UInt32 * ) data->getBytesNoCopy() ); } if ( ( data = OSDynamicCast( OSData, fIVAD->getProperty( "platform-ivad-eeprom" ) ) ) != NULL ) { fIVADEEPROMPHandle = *( ( UInt32 * ) data->getBytesNoCopy() ); } if ( ( data = OSDynamicCast( OSData, fIVAD->getProperty( "platform-ivad-pwm" ) ) ) != NULL ) { fIVADPWMPHandle = *( ( UInt32 * ) data->getBytesNoCopy() ); } fAreChangingMode = false; fIsSystemSleeping = false; fIsDisplayOff = false; // Install handler for shutdown notifications fPowerDownNotifier = registerPrioritySleepWakeInterest( &AppleIVAD2::_powerDownHandler, this ); return( true ); } IOReturn AppleIVAD2::message( UInt32 type, IOService* nub, void* arg ) { IOReturn status = kIOReturnSuccess; if ( type == kIOMessageServiceIsRequestingClose ) { // Being asked to close. Remove notifiers. We cannot do this from a stop, as there // is the possibility of a race condition between getting notified, and trying to // dispose of the notifier. if ( fPowerDownNotifier ) { fPowerDownNotifier->remove(); fPowerDownNotifier = NULL; } if ( fNotifier ) { fNotifier->remove(); fNotifier = NULL; } } else { status = super::message( type, nub, arg ); } return( status ); } bool AppleIVAD2::setDisplay( IODisplay* display ) { OSNumber* num; fFramebuffer = OSDynamicCast( IOFramebuffer, display->getProvider()->getProvider() ); if ( !fFramebuffer ) return( false ); fNotifier = fFramebuffer->addFramebufferNotification( &AppleIVAD2::_framebufferEvent, this, NULL ); setupIVAD(); display->setProperty( gIODisplayParametersKey, fDisplayParams ); num = OSNumber::withNumber( kAppleOnboardGUID, 64 ); display->setProperty( gIODisplayGUIDKey, num ); num->release(); return( true ); } bool AppleIVAD2::doUpdate( void ) { IOReturn err; IODisplayModeID mode; IOIndex depth; IOPixelInformation pixInfo; err = fFramebuffer->getCurrentDisplayMode( &mode, &depth ); if ( kIOReturnSuccess == err ) err = fFramebuffer->getPixelInformation( mode, depth, kIOFBSystemAperture, &pixInfo ); if ( kIOReturnSuccess == err) { UInt32 width; // Find the mode which corresponds to the current horizontal screen width. width = pixInfo.activeWidth; for ( int i = 0; i < fUserPrefs->modeParamsCount; i++ ) { if ( fUserPrefs->modeParams[ i ].width == width ) { fCurrentModeParams = &fUserPrefs->modeParams[ i ].mode; break; } } } // Initialize the dictionary to contain the current values for all the display parameters. IODisplay::setParameter( fDisplayParams, gIODisplayContrastKey, fUserPrefs->contrast ); IODisplay::setParameter( fDisplayParams, gIODisplayBrightnessKey, fUserPrefs->brightness ); IODisplay::setParameter( fDisplayParams, gIODisplayHorizontalPositionKey, fCurrentModeParams->horizontalPosition ^ 0x7f ); IODisplay::setParameter( fDisplayParams, gIODisplayHorizontalSizeKey, fCurrentModeParams->horizontalSize ^ 0x7f ); IODisplay::setParameter( fDisplayParams, gIODisplayVerticalPositionKey, fCurrentModeParams->verticalPosition ^ 0x7f ); IODisplay::setParameter( fDisplayParams, gIODisplayVerticalSizeKey, fCurrentModeParams->verticalSize ); IODisplay::setParameter( fDisplayParams, gIODisplayTrapezoidKey, fCurrentModeParams->keystone ); IODisplay::setParameter( fDisplayParams, gIODisplayPincushionKey, fCurrentModeParams->pincushion ); IODisplay::setParameter( fDisplayParams, gIODisplayParallelogramKey, fUserPrefs->parallelogram ^ 0x7f ); IODisplay::setParameter( fDisplayParams, gIODisplayRotationKey, fUserPrefs->tilt ); IODisplay::setParameter( fDisplayParams, gIODisplayParametersTheatreModeKey, fTheatreMode ); return( true ); } void AppleIVAD2::UnpackGeometryProperty( OSData* data ) { UInt8* buffer; if ( !data ) return; buffer = ( UInt8 * ) data->getBytesNoCopy(); fUserPrefs->contrast = *buffer++; fUserPrefs->brightness = *buffer++; fUserPrefs->parallelogram = *buffer++; fUserPrefs->tilt = *buffer++; fUserPrefs->pad = *buffer++; // Not really used, just to be explicit. fUserPrefs->modeParamsCount = *buffer++; for ( int i = 0; i < fUserPrefs->modeParamsCount; i++ ) { fUserPrefs->modeParams[ i ].width = *( UInt32 * ) buffer; buffer = ( UInt8 * ) ( ( UInt32 ) buffer + sizeof( UInt32 ) ); fUserPrefs->modeParams[ i ].mode.horizontalPosition = *buffer++; fUserPrefs->modeParams[ i ].mode.horizontalSize = *buffer++; fUserPrefs->modeParams[ i ].mode.verticalPosition = *buffer++; fUserPrefs->modeParams[ i ].mode.verticalSize = *buffer++; fUserPrefs->modeParams[ i ].mode.keystone = *buffer++; fUserPrefs->modeParams[ i ].mode.pincushion = *buffer++; } } OSData* AppleIVAD2::PackGeometryProperty( void ) { OSData* data; UInt32 geometryPropertySize; geometryPropertySize = 6 + ( fUserPrefs->modeParamsCount * 10 ); data = OSData::withCapacity( geometryPropertySize ); if ( data ) { // If there is a specific call for appending a byte, then why do I have to pass in the length? // Dumb... data->appendByte( fUserPrefs->contrast, 1 ); data->appendByte( fUserPrefs->brightness, 1 ); data->appendByte( fUserPrefs->parallelogram, 1 ); data->appendByte( fUserPrefs->tilt, 1 ); data->appendByte( fUserPrefs->pad, 1 ); // Make space for pad byte. data->appendByte( fUserPrefs->modeParamsCount, 1 ); for ( int i = 0; i < fUserPrefs->modeParamsCount; i++ ) { data->appendBytes( &fUserPrefs->modeParams[ i ].width, sizeof( UInt32 ) ); data->appendByte( fUserPrefs->modeParams[ i ].mode.horizontalPosition, 1 ); data->appendByte( fUserPrefs->modeParams[ i ].mode.horizontalSize, 1 ); data->appendByte( fUserPrefs->modeParams[ i ].mode.verticalPosition, 1 ); data->appendByte( fUserPrefs->modeParams[ i ].mode.verticalSize, 1 ); data->appendByte( fUserPrefs->modeParams[ i ].mode.keystone, 1 ); data->appendByte( fUserPrefs->modeParams[ i ].mode.pincushion, 1 ); } } return( data ); } IORegistryEntry* AppleIVAD2::searchDeviceTreeForPHandle( UInt32 pHandleValue ) { IORegistryIterator* iterator; IORegistryEntry* matchingEntry = NULL; iterator = IORegistryIterator::iterateOver( gIODTPlane, kIORegistryIterateRecursively ); if ( iterator == NULL ) return( matchingEntry ); while ( ( matchingEntry = iterator->getNextObject() ) != NULL ) { OSData* property; if ( ( property = OSDynamicCast( OSData, matchingEntry->getProperty( "AAPL,phandle" ) ) ) != NULL ) { if ( pHandleValue == *( ( UInt32 * ) property->getBytesNoCopy() ) ) break; } } iterator->release(); return( matchingEntry ); } IOReturn AppleIVAD2::doI2CReadWrite( const char* functionName, UInt8 bus, UInt8 address, UInt8 subAddress, UInt8* buffer, IOByteCount count ) { static IOService* pmuI2CDriver = NULL; IOReturn status = kIOReturnSuccess; UInt8 adjustedAddress; if ( !pmuI2CDriver ) { // I know that all of the IVAD properties are under the same I2C bus. So, just find the parent of the node which // has a "AAPL,phandle" property with the value of fIVADPHandle. IORegistryEntry* phandleEntry; IOService* parentDevice; phandleEntry = searchDeviceTreeForPHandle( fIVADPHandle ); if ( phandleEntry ) { parentDevice = ( IOService * ) phandleEntry->getParentEntry( gIODTPlane ); if ( parentDevice ) { while ( ( pmuI2CDriver = ( IOService * ) parentDevice->getChildEntry( gIOServicePlane ) ) == NULL ) IOSleep( 200 ); } } } if ( !pmuI2CDriver ) { return( kIOReturnError ); } status = pmuI2CDriver->callPlatformFunction( "openI2CBus", true, ( void * ) ( ( UInt32 ) bus ), NULL, NULL, NULL ); if ( status != kIOReturnSuccess ) { return( status ); } if ( address & 0x01 ) { // Read case is combined mode. ( void ) pmuI2CDriver->callPlatformFunction( "setCombinedMode", true, NULL, NULL, NULL, NULL ); } else { // Write case is subStandard mode. ( void ) pmuI2CDriver->callPlatformFunction( "setStandardSubMode", true, NULL, NULL, NULL, NULL ); } // Traditionally, the low bit of the device address indicates whether this is a read or a write. So, the PMU I2C driver // doesn't need that, as it knows whether this is a read or a write. In either case, it will be the one who inserts the // write bit into the address. adjustedAddress = address >> 1; status = pmuI2CDriver->callPlatformFunction( functionName, true, ( void * ) ( ( UInt32 ) adjustedAddress ), ( void * ) ( ( UInt32 ) subAddress ), ( void * ) buffer, ( void * ) count ); ( void ) pmuI2CDriver->callPlatformFunction( "closeI2CBus", true, NULL, NULL, NULL, NULL ); return( status ); } IOReturn AppleIVAD2::writeI2CData( UInt8 bus, UInt8 address, UInt8 subAddress, UInt8* buffer, IOByteCount count ) { return( doI2CReadWrite( "writeI2CBus", bus, address & ~1, subAddress, buffer, count ) ); } IOReturn AppleIVAD2::readI2CData( UInt8 bus, UInt8 address, UInt8 subAddress, UInt8* buffer, IOByteCount count ) { return( doI2CReadWrite( "readI2CBus", bus, address | 1, subAddress, buffer, count ) ); } // // resetModeParams // // Reset the individual geometry parameters for all of the supported modes to the default // parameters read from the EEPROM. // Reset the global geometry parameters to the default parameters read from the EEPROM. // #define detectIVADModes 0 void AppleIVAD2::resetModeParams( void ) { #if !detectIVADModes const UInt32 supportedModes[ kIVAD2SupportedModes ] = { 640, 800, 1024, 1152, 1280 }; #else IOItemCount modeCount; IODisplayModeID* displayModeList; IODisplayModeInformation modeInfo; IOReturn result; #endif UInt32 i; #if detectIVADModes modeCount = fUserPrefs->modeParamsCount; displayModeList = IONew( IODisplayModeID, modeCount ); if ( !displayModeList ) return; //ееее should default to known modes. result = fFramebuffer->getDisplayModes( displayModeList ); if ( result != kIOReturnSuccess ) goto resetModeParams_getDisplayModesErr; for ( i = 0; i < modeCount; i++ ) { bcopy( &fEEPROM->modeParams[ i ], &fUserPrefs->modeParams[ i ].mode, sizeof( fUserPrefs->modeParams[ i ].mode ) ); fFramebuffer->getInformationForDisplayMode( displayModeList[ i ], &modeInfo ); fUserPrefs->modeParams[ i ].width = modeInfo.nominalWidth; } resetModeParams_getDisplayModesErr: IODelete( displayModeList, IODisplayModeID, modeCount ); #else for ( i = 0; i < fUserPrefs->modeParamsCount; i++ ) { bcopy( &fEEPROM->modeParams[ i ], &fUserPrefs->modeParams[ i ].mode, sizeof( fUserPrefs->modeParams[ i ].mode ) ); fUserPrefs->modeParams[ i ].width = supportedModes[ i ]; } #endif fUserPrefs->contrast = fEEPROM->stdParams.contrast; fUserPrefs->brightness = fEEPROM->stdParams.brightness; fUserPrefs->parallelogram = fEEPROM->stdParams.parallelogram; fUserPrefs->tilt = fEEPROM->stdParams.tilt; } bool AppleIVAD2::setupIVAD( void ) { UInt8 buffer[ sizeof( IVAD2_EEPROM ) + 32 ]; OSData* data; IOItemCount modeCount; UInt32 address; UInt32 userPrefsSize; SInt32 i; SInt32 chunks; bool ok = false; if ( 0 == ( data = OSDynamicCast( OSData, fIVAD->getProperty( "eeprom-address" ) ) ) ) return( false ); address = *( ( UInt32 * ) data->getBytesNoCopy() ); #if detectIVADModes modeCount = fFramebuffer->getDisplayModeCount(); #else modeCount = kIVAD2SupportedModes; #endif if ( !fEEPROM ) fEEPROM = IONew( IVAD2_EEPROM, 1 ); userPrefsSize = sizeof( ModalWidthDisplayParams ) * modeCount + offsetof( IVAD2UserPrefs, modeParams ); if ( !fUserPrefs ) fUserPrefs = ( IVAD2UserPrefs * ) IOMalloc( userPrefsSize ); if ( !fEEPROM || !fUserPrefs ) return( false ); fUserPrefs->modeParamsCount = modeCount; // Read in the EEPROM in 16 byte chunks. 16 bytes is the largest amount the PMU can transfer in // a single request. bzero( buffer, sizeof(buffer) ); chunks = sizeof( IVAD2_EEPROM ) / 16 + 1; for ( i = 0; i < chunks * 16; i += 16 ) { readI2CData( kPowerSupplyBus, address, i, buffer + i, 16 ); } bcopy( buffer, fEEPROM, sizeof( IVAD2_EEPROM ) ); // Try and get the saved geometry preferences. If we cannot find it, // then regenerate it from the EEPROM data. //ееее Do we need to release data? if ( ( data = OSDynamicCast( OSData, fIVAD->getProperty( fIVADPrefsKey ) ) ) ) { UnpackGeometryProperty( data ); } else { // We couldn't get the geometry preferences. Build a new one from the EEPROM. resetModeParams(); } // Set the current, default mode to the first entry. fCurrentModeParams = &fUserPrefs->modeParams[ 0 ].mode; // fDisplayParams->setCapacityIncrement(1); IODisplay::addParameter( fDisplayParams, gIODisplayContrastKey, fEEPROM->userLimits.contrast.min, fEEPROM->userLimits.contrast.max ); IODisplay::addParameter( fDisplayParams, gIODisplayBrightnessKey, fEEPROM->userLimits.brightness.min, fEEPROM->userLimits.brightness.max ); IODisplay::addParameter( fDisplayParams, gIODisplayHorizontalPositionKey, fEEPROM->userLimits.horizontalPosition.min, fEEPROM->userLimits.horizontalPosition.max ); IODisplay::addParameter( fDisplayParams, gIODisplayHorizontalSizeKey, fEEPROM->userLimits.horizontalSize.min, fEEPROM->userLimits.horizontalSize.max ); IODisplay::addParameter( fDisplayParams, gIODisplayVerticalPositionKey, fEEPROM->userLimits.verticalPosition.min, fEEPROM->userLimits.verticalPosition.max ); IODisplay::addParameter( fDisplayParams, gIODisplayVerticalSizeKey, fEEPROM->userLimits.verticalSize.min, fEEPROM->userLimits.verticalSize.max ); IODisplay::addParameter( fDisplayParams, gIODisplayTrapezoidKey, fEEPROM->userLimits.keystone.min, fEEPROM->userLimits.keystone.max ); IODisplay::addParameter( fDisplayParams, gIODisplayPincushionKey, fEEPROM->userLimits.pincushion.min, fEEPROM->userLimits.pincushion.max ); IODisplay::addParameter( fDisplayParams, gIODisplayParallelogramKey, fEEPROM->userLimits.parallelogram.min, fEEPROM->userLimits.parallelogram.max ); IODisplay::addParameter( fDisplayParams, gIODisplayRotationKey, fEEPROM->userLimits.tilt.min, fEEPROM->userLimits.tilt.max ); IODisplay::addParameter( fDisplayParams, gIODisplayParametersTheatreModeKey, 0, 1 ); ATIFaderRec fader; IONDRVFramebuffer* ndrv = OSDynamicCast( IONDRVFramebuffer, fFramebuffer); if ( ndrv && ( kIOReturnSuccess == ndrv->doStatus( kATIGetFader, &fader ) ) ) IODisplay::addParameter( fDisplayParams, gIODisplayParametersTheatreModeWindowKey, 0, 1 ); return( ok ); } bool AppleIVAD2::doDataSet( const OSSymbol* paramName, OSData* value ) { IOGBounds* rect; IONDRVFramebuffer* ndrv = OSDynamicCast( IONDRVFramebuffer, fFramebuffer ); bool ok = true; if ( paramName != gIODisplayParametersTheatreModeWindowKey ) return( false ); if ( sizeof( IOGBounds ) != value->getLength() ) return( false ); rect = ( IOGBounds * ) value->getBytesNoCopy(); ok = ( ndrv != 0 ); if ( ok ) { ATIFaderRec fader; ATIAuxWinRec auxWin; UInt32 newMode; newMode = ( rect->maxx != rect->minx ); bzero( &auxWin, sizeof( auxWin ) ); auxWin.enable = true; auxWin.delay = kAuxWinDelay; auxWin.bppDelayEnable = kEnableAuxWinDelay; fader.enableFader = newMode; if ( newMode ) { auxWin.x = rect->minx; auxWin.y = rect->miny; auxWin.w = rect->maxx - rect->minx; auxWin.h = rect->maxy - rect->miny; auxWin.polarity = kAuxWinPolarity; ok &= ( kIOReturnSuccess == ndrv->doControl( kATISetAuxWin, &auxWin ) ); ok &= ( kIOReturnSuccess == ndrv->doControl( kATISetFader, &fader ) ); } else { auxWin.x = 0; auxWin.y = 0; auxWin.w = 1; auxWin.h = 1; auxWin.polarity = 0; ok &= ( kIOReturnSuccess == ndrv->doControl( kATISetFader, &fader ) ); ok &= ( kIOReturnSuccess == ndrv->doControl( kATISetAuxWin, &auxWin ) ); } } return( ok ); } bool AppleIVAD2::setTheatreMode( UInt32 newMode ) { enum { kTMRegCount = 9 }; static const UInt16 turningOnRegs[ kTMRegCount ] = { kIVADContrast, kIVADBrightness, kIVADDrive1, kIVADDrive2, kIVADDrive3, kIVADPWMCutoff1 + kIVADUsePWMAddress, kIVADPWMCutoff2 + kIVADUsePWMAddress, kIVADPWMCutoff3 + kIVADUsePWMAddress, kIVADVBLDCLevel }; static const UInt16 turningOffRegs[ kTMRegCount ] = { kIVADVBLDCLevel, kIVADPWMCutoff3 + kIVADUsePWMAddress, kIVADPWMCutoff2 + kIVADUsePWMAddress, kIVADPWMCutoff1 + kIVADUsePWMAddress, kIVADDrive3, kIVADDrive2, kIVADDrive1, kIVADBrightness, kIVADContrast }; const UInt16* regs; UInt8 values[ kTMRegCount ]; bool ok = true; ok = true; newMode = ( newMode != 0 ); if ( newMode != fTheatreMode ) { if ( newMode ) { values[ 0 ] = fEEPROM->briteParams.contrast; values[ 1 ] = fEEPROM->briteParams.brightness; values[ 2 ] = fEEPROM->briteParams.drive1; values[ 3 ] = fEEPROM->briteParams.drive2; values[ 4 ] = fEEPROM->briteParams.drive3; values[ 5 ] = fEEPROM->briteParams.cutoff1; values[ 6 ] = fEEPROM->briteParams.cutoff2; values[ 7 ] = fEEPROM->briteParams.cutoff3; values[ 8 ] = fEEPROM->stdParams.vblDCLevel | ( fEEPROM->briteParams.gainBoost ? kGainWin : 0 ); regs = turningOnRegs; } else { // // #2864322 // When we are turning theater mode off, program the registers in the reverse order from above. // values[ 0 ] = fEEPROM->stdParams.vblDCLevel; values[ 1 ] = fEEPROM->stdParams.cutoff3; values[ 2 ] = fEEPROM->stdParams.cutoff2; values[ 3 ] = fEEPROM->stdParams.cutoff1; values[ 4 ] = fEEPROM->stdParams.drive3; values[ 5 ] = fEEPROM->stdParams.drive2; values[ 6 ] = fEEPROM->stdParams.drive1; values[ 7 ] = fUserPrefs->brightness; values[ 8 ] = fUserPrefs->contrast; regs = turningOffRegs; } for ( int i = 0; i < kTMRegCount; i++ ) { UInt16 subAddr; UInt8 iicAddress; subAddr = regs[ i ]; // Certain IVAD control registers have moved to the new PWM part. Those registers have // the kIVADUsePWMAddress mask set in the above regs structure. if ( subAddr & kIVADUsePWMAddress ) iicAddress = fPWMIICAddress; else iicAddress = fIICAddress; ok &= ( kIOReturnSuccess == writeI2CData( kPowerSupplyBus, iicAddress, subAddr & 0x1F, &values[ i ], sizeof( UInt8 ) ) ); } if ( ok ) fTheatreMode = newMode; } return( ok ); } IOReturn AppleIVAD2::_powerDownHandler( void* target, void* refCon, UInt32 messageType, IOService* provider, void* messageArgument, vm_size_t argSize ) { AppleIVAD2* self = ( AppleIVAD2 * ) target; return( self->powerDownHandler( refCon, messageType, provider, messageArgument, argSize ) ); } IOReturn AppleIVAD2::powerDownHandler( void* refCon, UInt32 messageType, IOService* provider, void* messageArgument, vm_size_t argSize ) { IOReturn status = kIOReturnUnsupported; UInt8 regValue; switch ( messageType ) { case kIOMessageSystemWillRestart: case kIOMessageSystemWillPowerOff: { // On a restart or shutdown, we need to: set the contrast to 0 and set all the cutoff // PWM registers to 0. This minimizes the flash that occurs when the power supply is turning off. regValue = 0; writeI2CData( kPowerSupplyBus, fIICAddress, kIVADContrast, ®Value, sizeof( regValue) ); writeI2CData( kPowerSupplyBus, fPWMIICAddress, kIVADPWMCutoff1, ®Value, sizeof( regValue ) ); writeI2CData( kPowerSupplyBus, fPWMIICAddress, kIVADPWMCutoff2, ®Value, sizeof( regValue ) ); writeI2CData( kPowerSupplyBus, fPWMIICAddress, kIVADPWMCutoff3, ®Value, sizeof( regValue ) ); status = kIOReturnSuccess; break; } case kIOMessageSystemWillSleep: { fIsSystemSleeping = true; status = kIOReturnSuccess; if ( fIsDisplayOff ) { // If the display is already off, then we won't get another frame buffer notification // telling us to turn off. So, we need to turn off the PLL1 register here. regValue = 0; writeI2CData( kPowerSupplyBus, fIICAddress, kIVADPLL1, ®Value, sizeof( regValue ) ); } break; } case kIOMessageSystemHasPoweredOn: { fIsSystemSleeping = false; status = kIOReturnSuccess; break; } } return( status ); } IOReturn AppleIVAD2::_framebufferEvent( OSObject* _self, void* ref, IOFramebuffer* framebuffer, IOIndex event, void* info ) { AppleIVAD2* self = ( AppleIVAD2 * ) _self; return( self->framebufferEvent( framebuffer, event, info ) ); } IOReturn AppleIVAD2::framebufferEvent( IOFramebuffer* framebuffer, IOIndex event, void* info ) { UInt8 regValue; switch ( event ) { case kIOFBNotifyDisplayModeWillChange: { fAreChangingMode = true; // Before changing resolution, turn off IVAD by setting contrast to 0. regValue = 0; writeI2CData( kPowerSupplyBus, fIICAddress, kIVADContrast, ®Value, sizeof( regValue ) ); break; } case kIOFBNotifyDisplayModeDidChange: { fAreChangingMode = false; // After changing resolution, turn on IVAD by restoring contrast to user preferences. regValue = fUserPrefs->contrast; writeI2CData( kPowerSupplyBus, fIICAddress, kIVADContrast, ®Value, sizeof( regValue ) ); break; } case kIOFBNotifyWillPowerOff: { regValue = 0; writeI2CData( kPowerSupplyBus, fIICAddress, kIVADContrast, ®Value, sizeof( regValue ) ); regValue = fEEPROM->userLimits.verticalSize.min; writeI2CData( kPowerSupplyBus, fIICAddress, kIVADVRamp, ®Value, sizeof( regValue ) ); break; } case kIOFBNotifyDidPowerOn: { regValue = fCurrentModeParams->verticalSize; writeI2CData( kPowerSupplyBus, fIICAddress, kIVADVRamp, ®Value, sizeof( regValue ) ); // Need to delay for 20 ms before setting the contrast. IOSleep( 20 ); regValue = fUserPrefs->contrast; writeI2CData( kPowerSupplyBus, fIICAddress, kIVADContrast, ®Value, sizeof( regValue ) ); break; } case kIOFBNotifyWillPowerOn: { if ( fIsSystemSleeping ) { // // #2983513 // Restore the PLL1 register. // regValue = fEEPROM->stdParams.pll1FVC; writeI2CData( kPowerSupplyBus, fIICAddress, kIVADPLL1, ®Value, sizeof( regValue ) ); fIsSystemSleeping = false; } regValue = fEEPROM->stdParams.cutoff1; writeI2CData( kPowerSupplyBus, fPWMIICAddress, kIVADPWMCutoff1, ®Value, sizeof( regValue ) ); regValue = fEEPROM->stdParams.cutoff2; writeI2CData( kPowerSupplyBus, fPWMIICAddress, kIVADPWMCutoff2, ®Value, sizeof( regValue ) ); regValue = fEEPROM->stdParams.cutoff3; writeI2CData( kPowerSupplyBus, fPWMIICAddress, kIVADPWMCutoff3, ®Value, sizeof( regValue ) ); fIsDisplayOff = false; break; } case kIOFBNotifyDidPowerOff: { regValue = 0; writeI2CData( kPowerSupplyBus, fPWMIICAddress, kIVADPWMCutoff1, ®Value, sizeof( regValue ) ); writeI2CData( kPowerSupplyBus, fPWMIICAddress, kIVADPWMCutoff2, ®Value, sizeof( regValue ) ); writeI2CData( kPowerSupplyBus, fPWMIICAddress, kIVADPWMCutoff3, ®Value, sizeof( regValue ) ); if ( fIsSystemSleeping ) { // // #2983513 // Put PLL1 register in free-running mode. Only do this at system sleep time. // writeI2CData( kPowerSupplyBus, fIICAddress, kIVADPLL1, ®Value, sizeof( regValue ) ); } fIsDisplayOff = true; break; } } return( kIOReturnSuccess ); } bool AppleIVAD2::doIntegerSet( OSDictionary* params, const OSSymbol* sym, UInt32 value ) { OSNumber* num; UInt32 reg; UInt8 regValue; UInt8 iicAddress; bool ok = true; bool skipUpdatingHardware = false; if ( sym == gIODisplayParametersDefaultKey ) { resetModeParams(); return( true ); } // Since we want to leave the contrast off while we are updating IVAD, delay updating // contrast until we get the kIOFBNotifyDisplayModeDidChange message in framebufferEvent(). if ( ( fAreChangingMode == true ) && ( sym == gIODisplayContrastKey ) ) { skipUpdatingHardware = true; } if ( sym == gIODisplayParametersCommitKey ) { IODTPlatformExpert* dtPlaform = OSDynamicCast( IODTPlatformExpert, getPlatform() ); OSData* data; // Create the data for the NVRAM property. data = PackGeometryProperty(); if ( data && dtPlaform ) ok = ( kIOReturnSuccess == dtPlaform->writeNVRAMProperty( fIVAD, fIVADPrefsKey, data ) ); if ( data ) data->release(); return( ok ); } if ( sym == gIODisplayParametersTheatreModeKey ) return( setTheatreMode( value ) ); if ( !params ) return( true ); num = ( OSNumber * ) params->getObject( "reg" ); if ( !num ) return( false ); reg = num->unsigned32BitValue(); if ( reg & kIVADInvertDataMask ) regValue = value ^ 0x7F; else regValue = value; // Certain IVAD control registers have moved to the new PWM part. Those registers have // the kIVADUsePWMAddress mask set in the IODisplayParameters dictionary. if ( reg & kIVADUsePWMAddress ) iicAddress = fPWMIICAddress; else iicAddress = fIICAddress; if ( !skipUpdatingHardware ) { ok = ( kIOReturnSuccess == writeI2CData( kPowerSupplyBus, iicAddress, reg & 0x1F, ®Value, sizeof( regValue ) ) ); } if ( ok ) { if ( sym == gIODisplayContrastKey ) fUserPrefs->contrast = regValue; else if ( sym == gIODisplayBrightnessKey ) fUserPrefs->brightness = regValue; else if ( sym == gIODisplayHorizontalPositionKey ) fCurrentModeParams->horizontalPosition = regValue; else if ( sym == gIODisplayHorizontalSizeKey ) fCurrentModeParams->horizontalSize = regValue; else if ( sym == gIODisplayVerticalPositionKey ) fCurrentModeParams->verticalPosition = regValue; else if ( sym == gIODisplayVerticalSizeKey ) fCurrentModeParams->verticalSize = regValue; else if ( sym == gIODisplayTrapezoidKey ) fCurrentModeParams->keystone = regValue; else if ( sym == gIODisplayPincushionKey ) fCurrentModeParams->pincushion = regValue; else if ( sym == gIODisplayParallelogramKey ) fUserPrefs->parallelogram = regValue; else if ( sym == gIODisplayRotationKey ) fUserPrefs->tilt = regValue; } return( ok ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ bool AppleVCP::start( IOService* provider ) { OSData* data; if ( !super::start( provider ) ) return( false ); if ( 0 == (data = OSDynamicCast( OSData, provider->getProperty( "iic-address" ) ) ) ) return( false ); fDisplayParams = OSDynamicCast( OSDictionary, getProperty( gIODisplayParametersKey ) ); if ( !fDisplayParams ) return( false ); fIICAddress = *( ( UInt32 * ) data->getBytesNoCopy() ); if ( !setupVCP() ) return( false ); return( true ); } bool AppleVCP::setDisplay( IODisplay* display ) { OSNumber* num; display->setProperty( gIODisplayParametersKey, fDisplayParams ); num = OSNumber::withNumber( kAppleOnboardGUID, 64 ); display->setProperty( gIODisplayGUIDKey, num ); num->release(); return( true ); } bool AppleVCP::getSymbolRange( const OSSymbol* sym, SInt32* oMin, SInt32* oMax, SInt32* oCurrent ) { OSNumber* num; OSDictionary* params; UInt32 command; bool success = false; if ( ( params = OSDynamicCast( OSDictionary, fDisplayParams->getObject( sym ) ) ) == NULL ) return( false ); if ( ( num = ( OSNumber * ) params->getObject( "reg" ) ) == NULL ) return( false ); *oMin = 0; command = num->unsigned32BitValue(); success = readVCPRange( command, oMax, oCurrent ); return( success ); } bool AppleVCP::doUpdate( void ) { OSIterator* iter; iter = OSCollectionIterator::withCollection( fDisplayParams ); if ( iter ) { const OSSymbol* sym; while( ( sym = ( const OSSymbol * ) iter->getNextObject() ) ) { SInt32 current; SInt32 max; SInt32 min; if ( sym == gIODisplayParametersCommitKey ) continue; if ( sym == gIODisplayParametersDefaultKey ) continue; if ( !getSymbolRange( sym, &min, &max, ¤t ) ) continue; IODisplay::setParameter( fDisplayParams, sym, current ); } iter->release(); } return( true ); } bool AppleVCP::doDataSet( const OSSymbol* paramName, OSData* value ) { return( false ); } enum { kGetVCPFeature = 0x01, kReplyVCPFeature = 0x02, kSetVCPFeature = 0x03, kGetControlKeyMode = 0x04, kReplyControlKeyMode = 0x05, kSetControlKeyMode = 0x06, kGetTimingReport = 0x07, kGetKeyReport = 0x08, kResetVCPFeature = 0x09, kDisableVCPFeature = 0x0A, kEnableVCPFeature = 0x0B, kSaveCurrentSettings = 0x0C }; // VCP minor commands from LGE enum { kDegaussCommand = 0x00, kPresetDefaultCommand = 0x04, kExtBrightnessCommand = 0x10, kExtContrastCommand = 0x12, kRedDriveCommand = 0x16, kGreenDriveCommand = 0x18, kBlueDriveCommand = 0x1A, kHorizontalPositionCommand = 0x20, kHorizontalSizeCommand = 0x22, kPincushionCommand = 0x24, kPincushionBalanceCommand = 0x26, kVerticalPositionCommand = 0x30, kVerticalSizeCommand = 0x32, kParallelogramCommand = 0x40, kTrapezoidCommand = 0x42, kRotationCommand = 0x44, kRedCutoffCommand = 0x80, kGreenCutoffCommand = 0x82, kBlueCutoffCommand = 0x84, kSubContrastCommand = 0x86, kSubBrightnessCommand = 0x88, kABLCommand = 0x8A, kPresetStartCommand = 0xE0, kPresetEndCommand = 0xE2, kClearDataCommand = 0xE4, kSaveDataCommand = 0xEA, kSaveColorCommand = 0xEB, kSaveSystemDataCommand = 0xEC }; enum { // this many byte to read to get vcp feature kIICReadBufferSize = 4, kIICWriteBufferSize = 7, kIICSourceAddress = 0x50, kVCPCommandDataLength = 0x84, // special address that LGE check to not to go into master mode (Cuda can't do multi master mode) kIICBogusSourceAddress = 0xAF, // Throttle to 30 times a second and round up a bit. kMinMillisecondsBetweenIICCommands = 35 }; bool AppleVCP::readVCPRange( UInt8 command, SInt32* oMax, SInt32* oCurrent ) { UInt8 buffer[ 16 ]; IOByteCount count; UInt32 retries; SInt32 max; SInt32 current; retries = 0; do { buffer[ 0 ] = kIICBogusSourceAddress; buffer[ 1 ] = kVCPCommandDataLength; buffer[ 2 ] = kSetVCPFeature; buffer[ 3 ] = command; buffer[ 4 ] = 0; buffer[ 5 ] = 0; buffer[ 6 ] = fIICAddress ^ buffer[ 0 ] ^ buffer[ 1 ] ^ buffer[ 2 ] ^ buffer[ 3 ]; count = kIICWriteBufferSize; IOSleep( 100 ); // 100 in 9 ( void ) AppleCudaWriteIIC( fIICAddress, buffer, &count ); bzero( buffer, sizeof( buffer ) ); count = kIICReadBufferSize; IOSleep( 50 ); // 50 in 9 ( void ) AppleCudaReadIIC( fIICAddress + 1, buffer, &count ); max = ( buffer[ 0 ] << 8 ) | buffer[ 1 ]; current = ( buffer[ 2 ] << 8 ) | buffer[ 3 ]; } while ( ( max == 0 ) && ( retries++ < 10 ) ); *oMax = max; *oCurrent = current; return( max != 0 ); } bool AppleVCP::setupVCP( void ) { OSIterator* iter; IOByteCount zeroData; IOReturn err; int count; count = 0; do { zeroData = 0; IOSleep( 50 ); // 100 in 9 err = AppleCudaWriteIIC( fIICAddress, ( UInt8 * ) &zeroData, &zeroData ); } while ( err && ( count++ < 10 ) ); if ( kIOReturnSuccess != err ) { #if DEBUG IOLog( "VCP warmup fail (%x)\n", err ); #endif return( false ); } iter = OSCollectionIterator::withCollection( fDisplayParams ); if ( iter ) { const OSSymbol* sym; while( ( sym = ( const OSSymbol * ) iter->getNextObject() ) ) { SInt32 current; SInt32 max; SInt32 min; if ( sym == gIODisplayParametersCommitKey ) continue; if ( sym == gIODisplayParametersDefaultKey ) continue; if ( !getSymbolRange( sym, &min, &max, ¤t ) ) continue; IODisplay::addParameter( fDisplayParams, sym, min, max ); IODisplay::setParameter( fDisplayParams, sym, current ); } iter->release(); } return( true ); } bool AppleVCP::doIntegerSet( OSDictionary* params, const OSSymbol* sym, UInt32 value ) { UInt8 buffer[ 16 ]; OSNumber* num; IOByteCount count; IOReturn err; UInt8 command; bool ok = true; if ( !params ) { return( true ); } if ( ( sym == gIODisplayParametersCommitKey ) || ( sym == gIODisplayParametersDefaultKey ) ) { value = 0; } IOSleep( 50 ); // 100 in 9 if ( sym == gIODisplayParametersCommitKey ) { // We need to issue two separate commands to save away the current graphics state: a kSaveDataCommand and // kSaveSystemDataCommand. command = kSaveDataCommand; buffer[ 0 ] = kIICSourceAddress; buffer[ 1 ] = kVCPCommandDataLength; buffer[ 2 ] = kSetVCPFeature; buffer[ 3 ] = command; buffer[ 4 ] = 0; buffer[ 5 ] = value; buffer[ 6 ] = fIICAddress ^ buffer[ 0 ] ^ buffer[ 1 ] ^ buffer[ 2 ] ^ buffer[ 3 ] ^ buffer[ 4 ] ^ buffer[ 5 ]; count = kIICWriteBufferSize; err = AppleCudaWriteIIC( fIICAddress, buffer, &count ); IOSleep( 50 ); // 100 in 9 command = kSaveSystemDataCommand; buffer[ 0 ] = kIICSourceAddress; buffer[ 1 ] = kVCPCommandDataLength; buffer[ 2 ] = kSetVCPFeature; buffer[ 3 ] = command; buffer[ 4 ] = 0; buffer[ 5 ] = value; buffer[ 6 ] = fIICAddress ^ buffer[ 0 ] ^ buffer[ 1 ] ^ buffer[ 2 ] ^ buffer[ 3 ] ^ buffer[ 4 ] ^ buffer[ 5 ]; count = kIICWriteBufferSize; err = AppleCudaWriteIIC( fIICAddress, buffer, &count ); } else { num = ( OSNumber * ) params->getObject( "reg" ); if ( !num ) { return( false ); } command = num->unsigned32BitValue(); buffer[ 0 ] = kIICSourceAddress; buffer[ 1 ] = kVCPCommandDataLength; buffer[ 2 ] = kSetVCPFeature; buffer[ 3 ] = command; buffer[ 4 ] = 0; buffer[ 5 ] = value; buffer[ 6 ] = fIICAddress ^ buffer[ 0 ] ^ buffer[ 1 ] ^ buffer[ 2 ] ^ buffer[ 3 ] ^ buffer[ 4 ] ^ buffer[ 5 ]; count = kIICWriteBufferSize; err = AppleCudaWriteIIC( fIICAddress, buffer, &count ); } if ( ( sym == gIODisplayParametersCommitKey ) || ( sym == gIODisplayParametersDefaultKey ) ) IOSleep( 110 ); else IOSleep( 50 ); return( ok ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ bool ApplePanel::start( IOService * provider ) { OSData * data; OSIterator * iter; IOService * next; if( !super::start( provider)) return( false ); fDisplayParams = OSDynamicCast(OSDictionary, getProperty(gIODisplayParametersKey)); if( !fDisplayParams) return( false ); fBacklightNode = provider; if( fBacklightNode && (data = OSDynamicCast( OSData, fBacklightNode->getProperty("panel-family")))) fPanelFamily = *((UInt32 *) data->getBytesNoCopy()); else fPanelFamily = 1; return( true ); } bool ApplePanel::setDisplay( IODisplay * display ) { OSNumber * num; OSData * data; OSDictionary * panelInfo; char key[32]; if( !OSDynamicCast( IOBacklightDisplay, display)) return( false ); if( !fPanelInfo) do { data = 0; panelInfo = OSDynamicCast( OSDictionary, getProperty("ApplePanels")); if( panelInfo) { if( (num = OSDynamicCast( OSNumber, display->getProperty(kDisplayProductID)))) { sprintf( key, "F%ldP%04x", fPanelFamily, num->unsigned32BitValue() ); data = OSDynamicCast( OSData, panelInfo->getObject(key) ); } if( !data && (num = OSDynamicCast( OSNumber, display->getProperty(kAppleSenseKey)))) { sprintf( key, "F%ldS%04x", fPanelFamily, num->unsigned32BitValue() ); data = OSDynamicCast( OSData, panelInfo->getObject(key) ); } if( !data) { sprintf( key, "F%ld", fPanelFamily ); data = OSDynamicCast( OSData, panelInfo->getObject( key )); } if( !data) { sprintf( key, "Default" ); data = OSDynamicCast( OSData, panelInfo->getObject(key) ); } } #if DEBUG IOLog("ApplePanel(key %s)\n", key); #endif if( !data) return( false ); fPanelInfo = (ApplePanelInfo *) data->getBytesNoCopy(); } while( false ); display->setProperty( gIODisplayParametersKey, fDisplayParams); num = OSNumber::withNumber( kAppleOnboardGUID, 64 ); display->setProperty( gIODisplayGUIDKey, num); num->release(); return( true ); } bool ApplePanel::doDataSet( const OSSymbol * paramName, OSData * value ) { return( false ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #undef super #define super ApplePanel enum { kPanelABacklightControl = 0xc0, kBacklightPowerOff = 0, kBacklightPowerOn = 7 }; struct VDBacklightControlInfo { UInt32 backlightOnOff; UInt32 backlightLevel; UInt32 saveNVRAM; }; bool ApplePanelA::start( IOService * provider ) { IORegistryEntry * parent; IORegistryEntry * regEntry; bool pmu = false; OSData* data; parent = provider->copyParentEntry( gIODTPlane ); if( parent) { pmu = (0 == strcmp("via-pmu", parent->getName())); parent->release(); } if( pmu) return( false ); if( !super::start( provider)) return( false ); // Assume that there is no NVRAM fNoNVRAM = true; if ((regEntry = IORegistryEntry::fromPath("/options", gIODTPlane))) { if ( 0 != ( data = OSDynamicCast( OSData, regEntry->getProperty( "aapl,pci" ) ) ) ) { // If there is value in the aapl,pci property, NVRAM has been initialized if (data->getLength() > 0) fNoNVRAM = false; } regEntry->release(); } return( true ); } bool ApplePanelA::setDisplay( IODisplay * display ) { IONDRVFramebuffer * fb; VDBacklightControlInfo info; IOReturn err; if( (fb = OSDynamicCast(IONDRVFramebuffer, display->getProvider()->getProvider())) && super::setDisplay( display )) { fFramebuffer = fb; IODisplay::addParameter( fDisplayParams, gIODisplayBrightnessKey, // fPanelInfo->min, fPanelInfo->max ); // 0 + (16*fPanelInfo->min - fPanelInfo->max) / 15, fPanelInfo->max ); 0, kApplePanelLevels ); UInt32 i, j, k; fValues[0] = fPanelInfo->off; for( i = 1, k = (kApplePanelLevels/16); i <= k; i++) fValues[i] = fPanelInfo->min; for( j = i, k = (15*kApplePanelLevels)/16; i <= k; i++) fValues[i] = (i - j) * (fPanelInfo->mid - fPanelInfo->min - 1) / (k - j) + fPanelInfo->min + 1; for( j = i, k = kApplePanelLevels; i <= k; i++) fValues[i] = (i - j) * (fPanelInfo->max - fPanelInfo->mid - 1) / (k - j) + fPanelInfo->mid + 1; fBacklightNode->setProperty("ApplePanelRawTable", fValues, sizeof(fValues)); bzero(&info, sizeof(info)); err = fFramebuffer->doStatus( kPanelABacklightControl, &info); if( (kIOReturnSuccess == err) && (kBacklightPowerOff == info.backlightOnOff) && (0 == info.backlightLevel) || fNoNVRAM ) { info.saveNVRAM = 0; info.backlightLevel = fPanelInfo->max; info.backlightOnOff = kBacklightPowerOn; fFramebuffer->doControl( kPanelABacklightControl, &info); } return( true ); } else return( false ); } bool ApplePanelA::doIntegerSet( OSDictionary * params, const OSSymbol * paramName, UInt32 value ) { VDBacklightControlInfo info; IOReturn err; bool ok = false; if( (paramName != gIODisplayBrightnessKey) && (paramName != gIODisplayParametersCommitKey)) return( false ); do { bzero(&info, sizeof(info)); err = fFramebuffer->doStatus( kPanelABacklightControl, &info); if( err) continue; if( paramName == gIODisplayParametersCommitKey) { if (kBacklightPowerOff == info.backlightOnOff) info.backlightLevel = fPanelInfo->off; info.saveNVRAM = 1; } else { info.saveNVRAM = 0; info.backlightLevel = (value <= kApplePanelLevels) ? fValues[value] : fPanelInfo->max; if(info.backlightLevel) info.backlightOnOff = kBacklightPowerOn; else info.backlightOnOff = kBacklightPowerOff; } err = fFramebuffer->doControl( kPanelABacklightControl, &info); if( err) continue; fBacklightNode->setProperty("ApplePanelRawBrightness", info.backlightLevel, 32); ok = true; } while( false ); return( ok ); } bool ApplePanelA::doUpdate( void ) { VDBacklightControlInfo info; IOReturn err; SInt32 value = kApplePanelLevels; bzero(&info, sizeof(info)); err = fFramebuffer->doStatus( kPanelABacklightControl, &info); if( kIOReturnSuccess == err) { if (kBacklightPowerOff == info.backlightOnOff) value = 0; else { UInt32 raw = info.backlightLevel; for( value = kApplePanelLevels; (value > 0) && ((raw < fValues[value]) || (raw == fValues[value - 1])); value--) {} } } IODisplay::setParameter( fDisplayParams, gIODisplayBrightnessKey, value ); return( true ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #undef super #define super ApplePanel enum { kPMUSetContrast = 0x40, kPMUSetBrightness = 0x41, kPMUReadContrast = 0x48, kPMUReadBrightness = 0x49, }; enum { kSTNPanelSense = 0x02, kSTNContrastMin = 0, kSTNContrastMax = 63, }; #if 0 enum { kPMUpower1Read = 0x19, // more power status (DBLite) kPMUpower1Cntl = 0x11, // more power control (DBLite) }; UInt8 displayOn = kDisplayOn; UInt8 displayOff = kDisplayOff; localSendMiscCommand(kPMUpower1Cntl,1, &displayOn, &unused,NULL); #define kScreenBit 0x01 #define kPowerOn 0x80 #define kPowerOff 0x00 #define kDisplayOn kScreenBit | kPowerOn #define kDisplayOff kScreenBit | kPowerOff #endif bool ApplePMUPanel::start( IOService * provider ) { IORegistryEntry * parent; bool pmu = false; parent = provider->copyParentEntry( gIODTPlane ); if( parent) { pmu = (0 == strcmp("via-pmu", parent->getName())); parent->release(); } if( !pmu) return( false ); if( !super::start( provider)) return( false ); return( true ); } bool ApplePMUPanel::setDisplay( IODisplay * display ) { OSNumber * num; if( !super::setDisplay( display )) return( false ); IODisplay::addParameter( fDisplayParams, gIODisplayBrightnessKey, fPanelInfo->min, fPanelInfo->max ); do { if( 1 != fPanelFamily) continue; num = OSDynamicCast( OSNumber, display->getProperty(kAppleSenseKey)); if( !num) continue; if( kSTNPanelSense != (num->unsigned32BitValue() >> 8)) continue; fHasContrast = true; OSDictionary * dict = OSDictionary::withCapacity(1); if( dict) { fDisplayParams->setObject(gIODisplayContrastKey, dict); dict->release(); IODisplay::addParameter( fDisplayParams, gIODisplayContrastKey, kSTNContrastMin, kSTNContrastMax ); } } while( false ); return( true ); } bool ApplePMUPanel::doIntegerSet( OSDictionary * params, const OSSymbol * paramName, UInt32 value ) { UInt32 command; SInt32 contrast; IOByteCount readBytes = 0; OSDictionary * param; if( !params) return( true ); if( paramName == gIODisplayBrightnessKey) command = kPMUSetBrightness; else if( fHasContrast && (paramName == gIODisplayContrastKey)) command = kPMUSetContrast; else return( false ); if( value > 127) value = 127; UInt8 byte = 127 - value; ApplePMUSendMiscCommand( command, 1, &byte, &readBytes, NULL ); if( fHasContrast && (paramName == gIODisplayBrightnessKey)) { if( (param = IODisplay::getIntegerRange( fDisplayParams, gIODisplayContrastKey, &contrast, 0, 0))) { if( contrast > 127) contrast = 127; byte = 127 - contrast; readBytes = 0; ApplePMUSendMiscCommand( kPMUSetContrast, 1, &byte, &readBytes, NULL ); } } return( true ); } bool ApplePMUPanel::doUpdate( void ) { SInt32 value; UInt8 buf[ 10 ]; IOByteCount readBytes = sizeof( buf ); bzero( buf, sizeof(buf) ); ApplePMUSendMiscCommand( kPMUReadBrightness, 0, NULL, &readBytes, buf ); value = buf[0]; if( value > 127) value = 127; IODisplay::setParameter( fDisplayParams, gIODisplayBrightnessKey, 127 - value ); if( fHasContrast) { readBytes = sizeof( buf ); bzero( buf, sizeof(buf) ); ApplePMUSendMiscCommand( kPMUReadContrast, 0, NULL, &readBytes, buf ); value = buf[0]; if( value > 127) value = 127; IODisplay::setParameter( fDisplayParams, gIODisplayContrastKey, 127 - value ); } return( true ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 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; // Wait for the PMU to show up: if( !pmu) pmu = IOService::waitForService(IOService::serviceMatching("ApplePMU")); SendMiscCommandParameterBlock params = { command, sendLength, sendBuffer, readLength, readBuffer }; if( pmu) ret = pmu->callPlatformFunction( "sendMiscCommand", true, (void*)¶ms, NULL, NULL, NULL ); return( ret ); } static IOReturn AppleCudaIIC( const OSSymbol * sym, UInt8 address, UInt8 * buffer, IOByteCount * count ) { static IOService * cuda; IOReturn ret = kIOReturnError; // Wait for Cuda to show up: if (!cuda) cuda = IOService::waitForService(IOService::serviceMatching("AppleCuda")); if (cuda) ret = cuda->callPlatformFunction( sym, false, (void *) (UInt32) address, buffer, count, 0 ); return (ret); } static IOReturn AppleCudaWriteIIC( UInt8 address, const UInt8 * buffer, IOByteCount * count ) { static const OSSymbol * sym; if (!sym) sym = OSSymbol::withCString("write_iic"); return (AppleCudaIIC(sym, address, (UInt8 *) buffer, count)); } static IOReturn AppleCudaReadIIC( UInt8 address, UInt8 * buffer, IOByteCount * count ) { static const OSSymbol * sym; if (!sym) sym = OSSymbol::withCString("read_iic"); return (AppleCudaIIC(sym, address, buffer, count)); }