IOBacklightDisplay.cpp [plain text]
#include <IOKit/IOLib.h>
#define IOFRAMEBUFFER_PRIVATE
#include <IOKit/graphics/IODisplay.h>
#include <IOKit/ndrvsupport/IOMacOSVideo.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#ifndef kAppleClamshellStateKey
#define kAppleClamshellStateKey "AppleClamshellState"
#endif
#define super IODisplay
OSDefineMetaClassAndStructors(IOBacklightDisplay, IODisplay)
enum {
kIOBacklightDisplayMaxUsableState = kIODisplayMaxPowerState - 1
};
extern IOOptionBits gIOFBLastClamshellState;
#define kIOBacklightUserBrightnessKey "IOBacklightUserBrightness"
IOService * IOBacklightDisplay::probe( IOService * provider, SInt32 * score )
{
IOFramebuffer * framebuffer;
IOService * ret = 0;
UInt32 displayType;
UInt32 connectFlags;
bool haveBacklight = false;
do {
if( !super::probe( provider, score ))
continue;
framebuffer = (IOFramebuffer *) getConnection()->getFramebuffer();
for( IOItemCount idx = 0; idx < framebuffer->getConnectionCount(); idx++) {
if( kIOReturnSuccess != framebuffer->getAttributeForConnection( idx,
kConnectionFlags, &connectFlags))
continue;
if( 0 == (kIOConnectionBuiltIn & connectFlags))
continue;
if( kIOReturnSuccess != framebuffer->getAppleSense( idx, NULL, NULL, NULL, &displayType))
continue;
if( (kPanelTFTConnect != displayType)
&& (kGenericLCD != displayType)
&& (kPanelFSTNConnect != displayType))
continue;
OSIterator * iter = getMatchingServices( nameMatching("backlight") );
if( iter) {
haveBacklight = (0 != iter->getNextObject());
iter->release();
}
if( !haveBacklight)
continue;
ret = this; break;
}
} while( false );
return( ret );
}
void IOBacklightDisplay::stop( IOService * provider )
{
return( super::stop( provider ));
}
void IOBacklightDisplay::initPowerManagement( IOService * provider )
{
static const IOPMPowerState ourPowerStates[kIODisplayNumPowerStates] = {
{ 1, 0, 0, 0, 0,0,0,0,0,0,0,0 },
{ 1, 0, 0, 0, 0,0,0,0,0,0,0,0 },
{ 1, IOPMDeviceUsable, 0, IOPMPowerOn, 0,0,0,0,0,0,0,0 },
{ 1, IOPMDeviceUsable | IOPMMaxPerformance, 0, IOPMPowerOn, 0,0,0,0,0,0,0,0 }
};
OSNumber * num;
if( !fDisplayParams
|| !getIntegerRange( fDisplayParams, gIODisplayBrightnessKey,
&fCurrentBrightness, &fMinBrightness, &fMaxBrightness )) {
fMinBrightness = 0;
fMaxBrightness = 255;
fCurrentBrightness = fMaxBrightness;
}
if( fCurrentBrightness < (fMinBrightness + 2))
fCurrentBrightness = fMinBrightness + 2;
if( (num = OSDynamicCast(OSNumber,
getConnection()->getFramebuffer()->getProperty(kIOBacklightUserBrightnessKey))))
fCurrentUserBrightness = num->unsigned32BitValue();
else
fCurrentUserBrightness = fCurrentBrightness;
fMaxBrightnessLevel[0] = 0;
fMaxBrightnessLevel[1] = fMinBrightness;
fMaxBrightnessLevel[2] = fMinBrightness + 1;
fMaxBrightnessLevel[3] = fMaxBrightness;
fDisplayPMVars->currentState = kIODisplayMaxPowerState;
PMinit();
provider->joinPMtree(this);
registerPowerDriver(this, (IOPMPowerState *) ourPowerStates, kIODisplayNumPowerStates);
}
IOReturn IOBacklightDisplay::setPowerState( unsigned long powerState, IOService * whatDevice )
{
IOReturn ret = IOPMAckImplied;
SInt32 value;
if( powerState >= kIODisplayNumPowerStates)
return( IOPMAckImplied );
fCurrentPowerState = powerState;
value = fMaxBrightnessLevel[fCurrentPowerState];
if( value > fCurrentUserBrightness)
value = fCurrentUserBrightness;
setBrightness( value );
powerState |= (powerState >= kIOBacklightDisplayMaxUsableState) ? kFBDisplayUsablePowerState : 0;
if( fConnection)
fConnection->setAttributeForConnection( kConnectionPower, powerState );
return( ret );
}
bool IOBacklightDisplay::doIntegerSet( OSDictionary * params,
const OSSymbol * paramName, UInt32 value )
{
if( paramName != gIODisplayBrightnessKey)
return( super::doIntegerSet( params, paramName, value));
else {
if( !gIOFBLastClamshellState)
fCurrentUserBrightness = value;
return( setBrightness( value ));
}
}
bool IOBacklightDisplay::setBrightness( SInt32 value )
{
bool ret = true;
if( !fDisplayParams)
return( false );
#if 0
UInt32 newState;
for( newState = 0; newState < kIODisplayNumPowerStates; newState++ ) {
if( value <= fMaxBrightnessLevel[newState] )
break;
}
if( newState >= kIODisplayNumPowerStates)
return( false );
if( newState != fCurrentPowerState) {
if( IOPMNoErr != changePowerStateToPriv( newState ))
value = fCurrentBrightness;
}
if( value != fCurrentBrightness)
#endif
{
fCurrentBrightness = value;
if( value <= fMinBrightness)
value = 0;
ret = super::doIntegerSet( fDisplayParams, gIODisplayBrightnessKey, value);
}
return( ret );
}
unsigned long IOBacklightDisplay::maxCapabilityForDomainState( IOPMPowerFlags domainState )
{
if( domainState & IOPMPowerOn )
return( kIODisplayMaxPowerState );
else
return( 0 );
}
unsigned long IOBacklightDisplay::initialPowerStateForDomainState( IOPMPowerFlags domainState )
{
UInt32 newState;
if( domainState & IOPMPowerOn ) {
for( newState = 0; newState < kIODisplayNumPowerStates; newState++ ) {
if( fCurrentBrightness <= fMaxBrightnessLevel[newState] )
return( newState );
}
}
return( 0 );
}
unsigned long IOBacklightDisplay::powerStateForDomainState( IOPMPowerFlags domainState )
{
UInt32 newState;
if( domainState & IOPMPowerOn ) {
for( newState = 0; newState < kIODisplayNumPowerStates; newState++ ) {
if( fCurrentBrightness <= fMaxBrightnessLevel[newState] )
return( newState );
}
}
return( 0 );
}
OSMetaClassDefineReservedUnused(IOBacklightDisplay, 0);
OSMetaClassDefineReservedUnused(IOBacklightDisplay, 1);
OSMetaClassDefineReservedUnused(IOBacklightDisplay, 2);
OSMetaClassDefineReservedUnused(IOBacklightDisplay, 3);
OSMetaClassDefineReservedUnused(IOBacklightDisplay, 4);
OSMetaClassDefineReservedUnused(IOBacklightDisplay, 5);
OSMetaClassDefineReservedUnused(IOBacklightDisplay, 6);
OSMetaClassDefineReservedUnused(IOBacklightDisplay, 7);
OSMetaClassDefineReservedUnused(IOBacklightDisplay, 8);
OSMetaClassDefineReservedUnused(IOBacklightDisplay, 9);
class AppleBacklightDisplay : public IOBacklightDisplay
{
OSDeclareDefaultStructors(AppleBacklightDisplay)
protected:
IONotifier * fNotify;
public:
virtual bool start( IOService * provider );
virtual void stop( IOService * provider );
virtual void initPowerManagement( IOService * );
virtual bool setBrightness( SInt32 value );
private:
static bool _clamshellHandler( void * target, void * ref,
IOService * resourceService );
};
#undef super
#define super IOBacklightDisplay
OSDefineMetaClassAndStructors(AppleBacklightDisplay, IOBacklightDisplay)
bool AppleBacklightDisplay::start( IOService * provider )
{
if( !super::start( provider))
return( false );
fNotify = addNotification( gIOPublishNotification,
resourceMatching(kAppleClamshellStateKey),
_clamshellHandler, this, 0, 10000 );
return( true );
}
void AppleBacklightDisplay::stop( IOService * provider )
{
IOFramebuffer::clamshellEnable( -1 );
getPMRootDomain()->removeProperty(kAppleClamshellStateKey);
if( fNotify) {
fNotify->remove();
fNotify = 0;
}
getConnection()->getFramebuffer()->setProperty(kIOBacklightUserBrightnessKey,
fCurrentUserBrightness, 32);
return( super::stop( provider ));
}
void AppleBacklightDisplay::initPowerManagement( IOService * provider )
{
super::initPowerManagement( provider );
IOFramebuffer::clamshellEnable( +1 );
}
bool AppleBacklightDisplay::_clamshellHandler( void * target, void * ref,
IOService * resourceService )
{
AppleBacklightDisplay * self = (AppleBacklightDisplay *) target;
UInt32 value;
OSObject * prop = 0;
OSObject * clamshellProperty;
clamshellProperty = resourceService->getProperty(kAppleClamshellStateKey);
if( !clamshellProperty)
return( true );
value = (clamshellProperty == kOSBooleanTrue);
gIOFBLastClamshellState = value;
getPMRootDomain()->setProperty(kAppleClamshellStateKey, clamshellProperty);
resourceService->removeProperty(kAppleClamshellStateKey);
if( (kOSBooleanTrue == prop) && (kIOPMEnableClamshell & IOFramebuffer::clamshellState())) {
if( value) {
#if LCM_HWSLEEP
self->fConnection->getFramebuffer()->changePowerStateTo(0);
#endif
self->changePowerStateToPriv( 0 );
} else {
self->changePowerStateToPriv( kIODisplayMaxPowerState );
#if LCM_HWSLEEP
self->fConnection->getFramebuffer()->changePowerStateTo(1);
#endif
}
}
if( self->fCurrentPowerState) {
SInt32 brightness = self->fMaxBrightnessLevel[self->fCurrentPowerState];
if( brightness > self->fCurrentUserBrightness)
brightness = self->fCurrentUserBrightness;
self->setBrightness( brightness );
}
return( true );
}
bool AppleBacklightDisplay::setBrightness( SInt32 value )
{
if( gIOFBLastClamshellState)
value = 0;
#if DEBUG
IOLog("brightness[%d,%d] %d\n", fCurrentPowerState, gIOFBLastClamshellState, value);
#endif
return( super::setBrightness( value ) );
}