IODisplayWrangler.cpp [plain text]
#include <IOKit/assert.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include "IODisplayWrangler.h"
#undef super
#define super IOService
OSDefineMetaClassAndStructors(IODisplayConnect, IOService)
bool IODisplayConnect::initWithConnection( IOIndex _connection )
{
char name[ 12 ];
if( !super::init())
return( false);
connection = _connection;
sprintf( name, "display%ld", connection);
setName( name);
return( true);
}
IOFramebuffer * IODisplayConnect::getFramebuffer( void )
{
return( (IOFramebuffer *) getProvider());
}
IOIndex IODisplayConnect::getConnection( void )
{
return( connection);
}
IOReturn IODisplayConnect::getAttributeForConnection( IOSelect selector, UInt32 * value )
{
if( !getProvider())
return( kIOReturnNotReady);
return ((IOFramebuffer *) getProvider())->getAttributeForConnection( connection, selector, value );
}
IOReturn IODisplayConnect::setAttributeForConnection( IOSelect selector, UInt32 value )
{
if( !getProvider())
return( kIOReturnNotReady);
return ((IOFramebuffer *) getProvider())->setAttributeForConnection( connection, selector, value );
}
void IODisplayConnect::joinPMtree ( IOService * driver )
{
getProvider()->addPowerChild(driver);
}
#define super IOService
OSDefineMetaClassAndStructors(IODisplayWrangler, IOService);
IODisplayWrangler * gIODisplayWrangler;
bool IODisplayWrangler::start( IOService * provider )
{
OSObject * notify;
if( !super::start( provider))
return( false);
assert( gIODisplayWrangler == 0 );
gIODisplayWrangler = this;
fMatchingLock = IOLockAlloc();
fFramebuffers = OSSet::withCapacity( 1 );
fDisplays = OSSet::withCapacity( 1 );
assert( fMatchingLock && fFramebuffers && fDisplays );
notify = addNotification( gIOPublishNotification,
serviceMatching("IODisplay"), _displayHandler,
this, fDisplays );
assert( notify );
notify = addNotification( gIOPublishNotification,
serviceMatching("IODisplayConnect"), _displayConnectHandler,
this, 0, 50000 );
assert( notify );
gIODisplayWrangler->initForPM();
gIODisplayWrangler->setAggressiveness ( kPMMinutesToDim, 30 );
return( true );
}
bool IODisplayWrangler::_displayHandler( void * target, void * ref,
IOService * newService )
{
return( ((IODisplayWrangler *)target)->displayHandler( (OSSet *) ref,
(IODisplay *) newService ));
}
bool IODisplayWrangler::_displayConnectHandler( void * target, void * ref,
IOService * newService )
{
return( ((IODisplayWrangler *)target)->displayConnectHandler( ref,
(IODisplayConnect *) newService ));
}
bool IODisplayWrangler::displayHandler( OSSet * set,
IODisplay * newDisplay )
{
assert( OSDynamicCast( IODisplay, newDisplay ));
IOTakeLock( fMatchingLock );
set->setObject( newDisplay );
IOUnlock( fMatchingLock );
return( true );
}
bool IODisplayWrangler::displayConnectHandler( void * ,
IODisplayConnect * connect )
{
SInt32 score = 50000;
OSIterator * iter;
IODisplay * display;
bool found = false;
assert( OSDynamicCast( IODisplayConnect, connect ));
IOTakeLock( fMatchingLock );
iter = OSCollectionIterator::withCollection( fDisplays );
if( iter) {
while( !found && (display = (IODisplay *) iter->getNextObject())) {
if( display->getConnection())
continue;
do {
if( !display->attach( connect ))
continue;
found = ((display->probe( connect, &score ))
&& (display->start( connect )));
if( !found)
display->detach( connect );
} while( false);
}
iter->release();
}
IOUnlock( fMatchingLock );
return( true);
}
bool IODisplayWrangler::makeDisplayConnects( IOFramebuffer * fb )
{
IODisplayConnect * connect;
IOItemCount i;
for( i = 0; i < 1 ; i++) {
connect = new IODisplayConnect;
if( 0 == connect)
continue;
if( (connect->initWithConnection( i ))
&& (connect->attach( fb ))) {
connect->registerService( kIOServiceSynchronous );
}
connect->release();
}
return( true );
}
void IODisplayWrangler::destroyDisplayConnects( IOFramebuffer * fb )
{
OSIterator * iter;
OSObject * next;
IODisplayConnect * connect;
IODisplay * display;
iter = fb->getClientIterator();
if( iter) {
while( (next = iter->getNextObject())) {
if( (connect = OSDynamicCast( IODisplayConnect, next))) {
if( connect->isInactive())
continue;
display = OSDynamicCast( IODisplay, connect->getClient());
if( display) {
gIODisplayWrangler->fDisplays->removeObject( display );
display->PMstop();
}
connect->terminate( kIOServiceSynchronous );
}
}
iter->release();
}
}
IODisplayConnect * IODisplayWrangler::getDisplayConnect(
IOFramebuffer * fb, IOIndex connect )
{
OSIterator * iter;
OSObject * next;
IODisplayConnect * connection = 0;
iter = fb->getClientIterator();
if( iter) {
while( (next = iter->getNextObject())) {
connection = OSDynamicCast( IODisplayConnect, next);
if( connection) {
if( connection->isInactive())
continue;
if( 0 == (connect--))
break;
}
}
iter->release();
}
return( connection );
}
IOReturn IODisplayWrangler::getConnectFlagsForDisplayMode(
IODisplayConnect * connect,
IODisplayModeID mode, UInt32 * flags )
{
IOReturn err = kIOReturnUnsupported;
IODisplay * display;
display = OSDynamicCast( IODisplay, connect->getClient());
if( display)
err = display->getConnectFlagsForDisplayMode( mode, flags );
else {
kprintf("%s: no display\n", connect->getFramebuffer()->getName());
err = connect->getFramebuffer()->connectFlags(
connect->getConnection(), mode, flags );
}
return( err );
}
IOReturn IODisplayWrangler::getFlagsForDisplayMode(
IOFramebuffer * fb,
IODisplayModeID mode, UInt32 * flags )
{
IODisplayConnect * connect;
connect = gIODisplayWrangler->getDisplayConnect( fb, 0 );
if( !connect) {
kprintf("%s: no display connect\n", fb->getName());
return( fb->connectFlags( 0, mode, flags ));
}
return( gIODisplayWrangler->
getConnectFlagsForDisplayMode( connect, mode, flags ));
}
enum {
kIODisplayWranglerNumPowerStates = kIODisplayNumPowerStates + 1,
kIODisplayWranglerMaxPowerState = kIODisplayWranglerNumPowerStates - 1,
};
static IOPMPowerState ourPowerStates[kIODisplayWranglerNumPowerStates] = {
{ 1, 0, 0, 0, 0,0,0,0,0,0,0,0 },
{ 1, 0, 0, IOPMPowerOn, 0,0,0,0,0,0,0,0 },
{ 1, 0, 0, IOPMPowerOn, 0,0,0,0,0,0,0,0 },
{ 1, IOPMDeviceUsable | kIOPMPreventIdleSleep, 0, IOPMPowerOn, 0,0,0,0,0,0,0,0 },
{ 1, IOPMDeviceUsable | kIOPMPreventIdleSleep, 0, IOPMPowerOn, 0,0,0,0,0,0,0,0 }
};
void IODisplayWrangler::initForPM(void )
{
PMinit();
pm_vars->thePlatform->PMRegisterDevice( 0, this );
registerPowerDriver( this, ourPowerStates, kIODisplayWranglerNumPowerStates );
makeUsable();
registerService();
}
unsigned long IODisplayWrangler::initialPowerStateForDomainState( IOPMPowerFlags domainState )
{
if( domainState & IOPMPowerOn)
return( kIODisplayWranglerMaxPowerState );
else
return( 0 );
}
IOReturn IODisplayWrangler::setAggressiveness( unsigned long type, unsigned long newLevel )
{
if( type == kPMMinutesToDim) {
if( newLevel == 0) {
if( pm_vars->myCurrentState < kIODisplayWranglerMaxPowerState) {
changePowerStateToPriv( kIODisplayWranglerMaxPowerState );
}
}
fMinutesToDim = newLevel;
fUseGeneralAggressiveness = false;
if( pm_vars->aggressiveness < kIOPowerEmergencyLevel) {
setIdleTimerPeriod( newLevel*60 / 2);
}
} else if( type == kPMGeneralAggressiveness) {
if( newLevel >= kIOPowerEmergencyLevel ) {
setIdleTimerPeriod( 5 );
}
else {
if( pm_vars->aggressiveness >= kIOPowerEmergencyLevel ) {
if( fUseGeneralAggressiveness) {
setIdleTimerPeriod( (333 - (newLevel/3)) / 2 );
}
else {
setIdleTimerPeriod( fMinutesToDim * 60 / 2);
}
}
else {
if( fUseGeneralAggressiveness) {
setIdleTimerPeriod( (333 - (newLevel/3)) / 2 );
}
}
}
}
super::setAggressiveness(type, newLevel);
return( IOPMNoErr );
}
bool IODisplayWrangler::activityTickle( unsigned long, unsigned long )
{
if( super::activityTickle(kIOPMSuperclassPolicy1, kIODisplayWranglerMaxPowerState))
return( true );
getPMRootDomain()->wakeFromDoze();
return( false );
}
IOReturn IODisplayWrangler::setPowerState( unsigned long powerStateOrdinal, IOService * whatDevice )
{
if( powerStateOrdinal == 0) {
changePowerStateToPriv(0);
return( IOPMNoErr );
}
if( powerStateOrdinal < pm_vars->myCurrentState ) {
idleDisplays();
return( IOPMNoErr );
}
if( powerStateOrdinal == kIODisplayWranglerMaxPowerState ) {
makeDisplaysUsable();
return( IOPMNoErr );
}
return( IOPMNoErr );
}
void IODisplayWrangler::makeDisplaysUsable ( void )
{
OSIterator * iter;
IODisplay * display;
IOTakeLock( fMatchingLock );
iter = OSCollectionIterator::withCollection( fDisplays );
if( iter ) {
while( (display = (IODisplay *) iter->getNextObject()) ) {
display->makeDisplayUsable();
}
iter->release();
}
IOUnlock( fMatchingLock );
}
void IODisplayWrangler::idleDisplays ( void )
{
OSIterator * iter;
IODisplay * display;
IOTakeLock( fMatchingLock );
iter = OSCollectionIterator::withCollection( fDisplays );
if( iter ) {
while( (display = (IODisplay *) iter->getNextObject()) ) {
display->dropOneLevel();
}
iter->release();
}
IOUnlock( fMatchingLock );
}