/* * 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 "IVAD.h" static void RestoreXPRAM( IODisplay * display, OSDictionary * params ); static void SaveXPRAM( OSDictionary * params ); static IOReturn ApplePMUSendMiscCommand( UInt32 command, IOByteCount sendLength, UInt8 * sendBuffer, IOByteCount * readLength, UInt8 * readBuffer ); IOReturn AppleCudaWriteIIC( UInt8 address, const UInt8 * buffer, IOByteCount * count ); IOReturn AppleCudaReadIIC( UInt8 address, UInt8 * buffer, IOByteCount * count ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ class AppleIVAD : public IODisplayParameterHandler { OSDeclareDefaultStructors(AppleIVAD); private: OSDictionary * fDisplayParams; IOFramebuffer * fFramebuffer; IONotifier * fNotifier; UInt32 fIICAddress; IORegistryEntry * fIVAD; const OSSymbol * fIVADPrefsKey; EEPROM * fEEPROM; IVADUserPrefs * fUserPrefs; UInt32 fModeIndex; bool fUsesXPRAM; bool fTheatreMode; 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 ); virtual IOReturn framebufferEvent( IOFramebuffer * framebuffer, IOIndex event, void * info ); private: bool setupIVAD( void ); bool setTheatreMode( UInt32 newMode ); static IOReturn _framebufferEvent( OSObject * self, void * ref, IOFramebuffer *framebuffer, IOIndex event, void * info ); }; class AppleVCP : public IODisplayParameterHandler { OSDeclareDefaultStructors(AppleVCP); private: OSDictionary * fDisplayParams; UInt32 fIICAddress; EEPROM * fEEPROM; IVADUserPrefs * fUserPrefs; UInt32 fModeIndex; bool fUsesXPRAM; bool fTheatreMode; 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 readVCPRange( UInt8 command, SInt32 * max, SInt32 * current ); bool setupVCP( void ); }; class AppleG3AIO : public IODisplayParameterHandler { OSDeclareDefaultStructors(AppleG3AIO); private: OSDictionary * fDisplayParams; public: virtual IOService * probe( IOService * provider, SInt32 * score ); 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 ); }; 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]; 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(AppleVCP, IODisplayParameterHandler); OSDefineMetaClassAndStructors(AppleG3AIO, IODisplayParameterHandler); OSDefineMetaClass(ApplePanel, IODisplayParameterHandler); OSDefineAbstractStructors(ApplePanel, IODisplayParameterHandler); OSDefineMetaClassAndStructors(ApplePanelA, ApplePanel); OSDefineMetaClassAndStructors(ApplePMUPanel, ApplePanel); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 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"); return( true ); } 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 ); } #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::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( EEPROM, 1 ); if( !fUserPrefs) fUserPrefs = IONew( IVADUserPrefs, 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(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(IVADUserPrefs)); 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 regs[kTMRegCount] = { kIVADContrast, kIVADBrightness, kIVADDrive1, kIVADDrive2, kIVADDrive3, kIVADCutoff1, kIVADCutoff2, kIVADCutoff3, kIVADVBLDCLevel }; 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); } else { values[0] = fUserPrefs->contrast; values[1] = fUserPrefs->brightness; values[2] = fEEPROM->stdParams.drive1; values[3] = fEEPROM->stdParams.drive2; values[4] = fEEPROM->stdParams.drive3; values[5] = fEEPROM->stdParams.cutoff1; values[6] = fEEPROM->stdParams.cutoff2; values[7] = fEEPROM->stdParams.cutoff3; values[8] = fEEPROM->stdParams.vblDCLevel; } 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::_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 = 0x00; switch( event) { case kIOFBNotifyWillPowerOff: 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: regValue = fEEPROM->stdParams.pll1FVC; // fall thru case kIOFBNotifyDidPowerOff: ApplePMUWriteIIC( kPowerSupplyBus, fIICAddress, kIVADPLL1, ®Value, sizeof(regValue) ); break; default: break; } return( kIOReturnSuccess); } bool AppleIVAD::doIntegerSet( OSDictionary * params, const OSSymbol * sym, UInt32 value ) { OSNumber * num; UInt32 reg; UInt8 regValue; bool ok = 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(IVADUserPrefs)); if( data && dtPlaform) ok = (kIOReturnSuccess == dtPlaform->writeNVRAMProperty( fIVAD, fIVADPrefsKey, data )); if( data) data->release(); return( ok ); } else if( sym == gIODisplayParametersTheatreModeKey) return( setTheatreMode( value )); if( !params) return( true ); num = (OSNumber *) params->getObject("reg"); if( !num) return( false ); reg = num->unsigned32BitValue(); if( reg & 0x100) regValue = value ^ 0x7f; else regValue = value; 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 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::doUpdate( void ) { return( false ); } 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 * current ) { UInt8 buffer[16]; IOByteCount count; SInt32 max; UInt32 retries; 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 AppleCudaWriteIIC( fIICAddress, buffer, &count ); bzero( buffer, sizeof( buffer)); count = kIICReadBufferSize; IOSleep( 50 ); // 50 in 9 AppleCudaReadIIC( fIICAddress + 1, buffer, &count ); max = (buffer[0] << 8) | buffer[1]; } while( (max == 0) && (retries++ < 10)); *oMax = max; *current = (buffer[2] << 8) | buffer[3]; return( max != 0 ); } bool AppleVCP::setupVCP( void ) { OSIterator * iter; OSSymbol * sym; OSDictionary * params; OSNumber * num; UInt32 command; SInt32 current, max; IOByteCount count; IOReturn err; current = 0; do { count = 0; IOSleep( 50 ); // 100 in 9 err = AppleCudaWriteIIC( fIICAddress, (UInt8 *) &count, &count ); } while( err && (current++ < 10)); if( kIOReturnSuccess != err) { IOLog("VCP warmup fail (%x)\n", err); return( false ); } iter = OSCollectionIterator::withCollection( fDisplayParams ); if( iter) { while( (sym = (OSSymbol *) iter->getNextObject())) { if( sym == gIODisplayParametersCommitKey) continue; params = OSDynamicCast( OSDictionary, fDisplayParams->getObject(sym)); if( !params) continue; num = (OSNumber *) params->getObject("reg"); if( !num) continue; command = num->unsigned32BitValue(); if( !readVCPRange( command, &max, ¤t )) continue; IODisplay::addParameter( fDisplayParams, sym, 0, max ); IODisplay::setParameter( fDisplayParams, sym, current ); } iter->release(); } return( true ); } bool AppleVCP::doIntegerSet( OSDictionary * params, const OSSymbol * sym, UInt32 value ) { OSNumber * num; UInt8 buffer[16]; IOByteCount count; bool ok = true; UInt8 command; if( sym == gIODisplayParametersDefaultKey) { return( true ); } if( !params) return( true ); num = (OSNumber *) params->getObject("reg"); if( !num) return( false ); command = num->unsigned32BitValue(); if( sym == gIODisplayParametersCommitKey) value = 0; 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]; if( sym == gIODisplayParametersCommitKey) IOSleep( 110 ); else IOSleep( 50 ); // 100 in 9 count = kIICWriteBufferSize; AppleCudaWriteIIC( fIICAddress, buffer, &count ); if( sym == gIODisplayParametersCommitKey) IOSleep( 110 ); 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; iter = getMatchingServices( nameMatching("display") ); if( iter) { while( (next = OSDynamicCast(IOService, iter->getNextObject()))) { while( next && !next->metaCast("IOPCIDevice")) next = OSDynamicCast(IOService, next->getParentEntry( gIODTPlane )); if( 0 == next) continue; attach( next ); break; } iter->release(); } 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) ); } } IOLog("ApplePanel(key %s)\n", key); 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; 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 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)) { 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) { 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) { 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 ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #undef super #define super IODisplayParameterHandler #if 1 #define heathrowBrightnessControl ((volatile UInt8 *)0xf3000033) #define heathrowContrastControl ((volatile UInt8 *)0xf3000032) #endif #if 0 #define defaultBrightness 144 #define defaultContrast 183 #endif IOService * AppleG3AIO::probe( IOService * provider, SInt32 * score ) { if( 0 == getPlatform()->getProperty("AllInOne")) return( 0 ); else return( super::probe( provider, score )); } bool AppleG3AIO::start( IOService * provider ) { if( !super::start( provider)) return( false ); fDisplayParams = OSDynamicCast(OSDictionary, getProperty(gIODisplayParametersKey)); if( !fDisplayParams) return( false ); return( true ); } bool AppleG3AIO::setDisplay( IODisplay * display ) { OSNumber * num; display->setProperty( gIODisplayParametersKey, fDisplayParams); num = OSNumber::withNumber( kAppleOnboardGUID, 64 ); display->setProperty( gIODisplayGUIDKey, num); num->release(); RestoreXPRAM( display, fDisplayParams ); return( true ); } bool AppleG3AIO::doDataSet( const OSSymbol * paramName, OSData * value ) { return( false ); } bool AppleG3AIO::doIntegerSet( OSDictionary * params, const OSSymbol * paramName, UInt32 value ) { if( paramName == gIODisplayBrightnessKey) { *heathrowBrightnessControl = value; } else if( paramName == gIODisplayContrastKey) { *heathrowContrastControl = value; } else if( paramName == gIODisplayParametersCommitKey) SaveXPRAM( fDisplayParams ); else return( false ); return( true ); } bool AppleG3AIO::doUpdate( void ) { return( false ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static void RestoreXPRAM( IODisplay * display, OSDictionary * params ) { UInt8 bytes[2]; SInt32 value, min, max; OSDictionary * param; IODTPlatformExpert * dtPlaform = OSDynamicCast( IODTPlatformExpert, IOService::getPlatform() ); if( !dtPlaform || (kIOReturnSuccess != dtPlaform->readXPRAM( 0x50, (UInt8 *) bytes, 2 ))) bytes[0] = bytes[1] = 0; if( (param = IODisplay::getIntegerRange( params, gIODisplayBrightnessKey, 0, &min, &max))) { value = (bytes[0] + (((UInt8) max) + ((UInt8) min)) / 2) & 0xff; display->setForKey( param, gIODisplayBrightnessKey, value, min, max); } if( (param = IODisplay::getIntegerRange( params, gIODisplayContrastKey, 0, &min, &max))) { value = (bytes[1] + ((UInt8) max)) & 0xff; display->setForKey( param, gIODisplayContrastKey, value, min, max); } } static void SaveXPRAM( OSDictionary * params ) { UInt8 bytes[2]; SInt32 value, min, max; OSDictionary * param; IODTPlatformExpert * dtPlaform = OSDynamicCast( IODTPlatformExpert, IOService::getPlatform() ); if( dtPlaform && (kIOReturnSuccess == dtPlaform->readXPRAM( 0x50, (UInt8 *) bytes, 2 ))) { if( (param = IODisplay::getIntegerRange( params, gIODisplayBrightnessKey, &value, &min, &max))) bytes[0] = value - (min + max) / 2; if( (param = IODisplay::getIntegerRange( params, gIODisplayContrastKey, &value, &min, &max))) bytes[1] = value - max; dtPlaform->writeXPRAM( 0x50, (UInt8 *) bytes, 2 ); } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 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 ); }