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>
#include <IOKit/pwr_mgt/IOPM.h>
#define super IODisplay
OSDefineMetaClassAndStructors(IOBacklightDisplay, IODisplay)
enum {
kIOBacklightDisplayMaxUsableState = kIODisplayMaxPowerState - 1
};
#define kIOBacklightUserBrightnessKey "IOBacklightUserBrightness"
IOService * IOBacklightDisplay::probe( IOService * provider, SInt32 * score )
{
IOFramebuffer * framebuffer;
IOService * ret = 0;
UInt32 displayType;
uintptr_t 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;
OSDictionary * matching = nameMatching("backlight");
OSIterator * iter = NULL;
if (matching)
{
iter = getMatchingServices(matching);
matching->release();
}
if (iter)
{
haveBacklight = (0 != iter->getNextObject());
iter->release();
}
if (!haveBacklight)
continue;
ret = this; break;
}
}
while (false);
return (ret);
}
void IOBacklightDisplay::stop( IOService * provider )
{
if( fPMSettingNotificationHandle ) {
fPMSettingNotificationHandle->release();
}
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 }
};
static bool displayDimsPublished = false;
OSNumber * num;
OSDictionary * displayParams;
const OSSymbol *settingsArray[2];
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;
if (!displayDimsPublished)
{
displayDimsPublished = true;
getPMRootDomain()->publishFeature("DisplayDims");
}
fDisplaySleepUsesDimSettingKey = (OSSymbol *)OSSymbol::withCString(
kIOPMSettingDisplaySleepUsesDimKey );
settingsArray[0] = fDisplaySleepUsesDimSettingKey;
settingsArray[1] = NULL;
getPMRootDomain()->registerPMSettingController( settingsArray,
OSMemberFunctionCast(IOPMSettingControllerCallback,
(OSObject*)this,
&IOBacklightDisplay::handlePMSettingCallback),
(OSObject *)this,
(uintptr_t)NULL,
(OSObject **)&fPMSettingNotificationHandle);
OSObject * obj = getPMRootDomain()->copyPMSetting(fDisplaySleepUsesDimSettingKey);
if ((num = OSDynamicCast(OSNumber, obj)) && (!num->unsigned32BitValue()))
{
fMaxBrightnessLevel[2] = fMaxBrightness;
}
if (obj)
obj->release();
PMinit();
provider->joinPMtree(this);
registerPowerDriver(this, (IOPMPowerState *) ourPowerStates, kIODisplayNumPowerStates);
}
void IOBacklightDisplay::handlePMSettingCallback(
const OSSymbol *arg_type,
OSObject *arg_val,
uintptr_t refcon)
{
OSNumber *newSetting;
int setting;
UInt16 newLevel;
if( (arg_type == fDisplaySleepUsesDimSettingKey)
&& (newSetting = OSDynamicCast(OSNumber, arg_val)) )
{
setting = newSetting->unsigned32BitValue();
if(setting) {
newLevel = fMinBrightness + 1;
} else {
newLevel = fMaxBrightness;
}
if( newLevel != fMaxBrightnessLevel[2] )
{
fMaxBrightnessLevel[2] = newLevel;
if (2 == fCurrentPowerState)
setBrightness(newLevel);
}
}
return;
}
IOReturn IOBacklightDisplay::setPowerState( unsigned long powerState, IOService * whatDevice )
{
IOReturn ret = IOPMAckImplied;
SInt32 value;
if (isInactive())
return (IOPMAckImplied);
if (powerState >= kIODisplayNumPowerStates)
return (IOPMAckImplied);
fCurrentPowerState = powerState;
value = fMaxBrightnessLevel[fCurrentPowerState];
if (value > fCurrentUserBrightness)
value = fCurrentUserBrightness;
OSObject * obj;
if ((!powerState) && (obj = copyProperty(kIOHibernatePreviewActiveKey, gIOServicePlane)))
{
obj->release();
}
else
{
powerState |= (powerState >= kIOBacklightDisplayMaxUsableState) ? kFBDisplayUsablePowerState : 0;
setBrightness( value );
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 )
{
if (domainState & IOPMPowerOn)
return (kIODisplayMaxPowerState);
else
return (0);
}
unsigned long IOBacklightDisplay::powerStateForDomainState( IOPMPowerFlags domainState )
{
if (domainState & IOPMPowerOn)
return (kIODisplayMaxPowerState);
else
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:
IOInterruptEventSource * fDeferredEvents;
uint8_t fClamshellSlept;
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 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);
fDeferredEvents = IOInterruptEventSource::interruptEventSource(this, _deferredEvent);
if (fDeferredEvents)
getWorkLoop()->addEventSource(fDeferredEvents);
getConnection()->getFramebuffer()->setProperty(kIOFBBuiltInKey, this, 0);
return (true);
}
void AppleBacklightDisplay::stop( IOService * provider )
{
IOFramebuffer::clamshellEnable( -1 );
if (fDeferredEvents)
{
getWorkLoop()->removeEventSource(fDeferredEvents);
fDeferredEvents->release();
fDeferredEvents = 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 );
}
else if (kIOFBNotifyClamshellChange == event)
{
if (kIOPMEnableClamshell & IOFramebuffer::clamshellState())
{
if (kOSBooleanTrue == info)
{
#if LCM_HWSLEEP
fConnection->getFramebuffer()->changePowerStateTo(0);
#endif
changePowerStateToPriv( 0 );
fClamshellSlept = true;
}
else if (fClamshellSlept)
{
fClamshellSlept = false;
makeDisplayUsable();
}
}
if (fDeferredEvents)
fDeferredEvents->interruptOccurred(0, 0, 0);
}
return (super::framebufferEvent( framebuffer, event, info ));
}
bool AppleBacklightDisplay::setBrightness( SInt32 value )
{
#if DEBUG
IOLog("brightness[%d,%d] %d\n", fCurrentPowerState, gIOFBLastClamshellState, value);
#endif
return (super::setBrightness(value));
}