IOBacklightDisplay.cpp [plain text]
#include <IOKit/IOLib.h>
#include <IOKit/graphics/IOGraphicsPrivate.h>
#define IOFRAMEBUFFER_PRIVATE
#include <IOKit/graphics/IODisplay.h>
#include <IOKit/ndrvsupport/IOMacOSVideo.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#define super IODisplay
OSDefineMetaClassAndStructors(IOBacklightDisplay, IODisplay)
enum {
kIOBacklightDisplayMaxUsableState = kIODisplayMaxPowerState - 1
};
extern IOOptionBits gIOFBLastClamshellState;
extern bool gIOFBSystemPower;
#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;
OSDictionary * displayParams;
displayParams = OSDynamicCast(OSDictionary, copyProperty(gIODisplayParametersKey));
if (!displayParams
|| !getIntegerRange(displayParams, 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();
if (displayParams)
setParameter(displayParams, gIODisplayBrightnessKey, fCurrentUserBrightness);
}
else
fCurrentUserBrightness = fCurrentBrightness;
if (displayParams)
displayParams->release();
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 )
{
OSDictionary * displayParams;
bool ret = true;
displayParams = OSDynamicCast(OSDictionary, copyProperty(gIODisplayParametersKey));
if (!displayParams)
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(displayParams, gIODisplayBrightnessKey, value);
}
displayParams->release();
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;
IOInterruptEventSource * fDeferredEvents;
public:
virtual bool start( IOService * provider );
virtual void stop( IOService * provider );
virtual void initPowerManagement( IOService * );
virtual bool setBrightness( SInt32 value );
virtual IOReturn framebufferEvent( IOFramebuffer * framebuffer,
IOIndex event, void * info );
private:
static bool _clamshellHandler( void * target, void * ref,
IOService * resourceService );
static void _deferredEvent( OSObject * target,
IOInterruptEventSource * evtSrc, int intCount );
};
#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 );
fDeferredEvents = IOInterruptEventSource::interruptEventSource(this, _deferredEvent);
if (fDeferredEvents)
getWorkLoop()->addEventSource(fDeferredEvents);
return (true);
}
void AppleBacklightDisplay::stop( IOService * provider )
{
IOFramebuffer::clamshellEnable( -1 );
getPMRootDomain()->removeProperty(kAppleClamshellStateKey);
if (fDeferredEvents)
{
getWorkLoop()->removeEventSource(fDeferredEvents);
fDeferredEvents = 0;
}
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 );
}
void AppleBacklightDisplay::_deferredEvent( OSObject * target,
IOInterruptEventSource * evtSrc, int intCount )
{
AppleBacklightDisplay * self = (AppleBacklightDisplay *) target;
if (self->fCurrentPowerState)
{
SInt32 brightness = self->fMaxBrightnessLevel[self->fCurrentPowerState];
if (brightness > self->fCurrentUserBrightness)
brightness = self->fCurrentUserBrightness;
self->setBrightness( brightness );
}
}
IOReturn AppleBacklightDisplay::framebufferEvent( IOFramebuffer * framebuffer,
IOIndex event, void * info )
{
SInt32 value;
if ((kIOFBNotifyDidWake == event) && (info))
{
value = fMaxBrightnessLevel[kIODisplayMaxPowerState];
if (value > fCurrentUserBrightness)
value = fCurrentUserBrightness;
setBrightness( value );
}
return (kIOReturnSuccess);
}
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->fDeferredEvents)
self->fDeferredEvents->interruptOccurred(0, 0, 0);
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));
}