#include <IOKit/assert.h>
#include <IOKit/IOCommandGate.h>
#include <IOKit/IOKitDebug.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/IOService.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/pwr_mgt/IOPMchangeNoteList.h>
#include <IOKit/pwr_mgt/IOPMinformee.h>
#include <IOKit/pwr_mgt/IOPMinformeeList.h>
#include <IOKit/pwr_mgt/IOPMlog.h>
#include <IOKit/pwr_mgt/IOPowerConnection.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include "IOServicePrivate.h"
#define super IORegistryEntry
#define OUR_PMLog(t, a, b) \
do { pm_vars->thePlatform->PMLog(pm_vars->ourName, t, a, b); } while(0)
static void ack_timer_expired(thread_call_param_t);
static void settle_timer_expired(thread_call_param_t);
static void PM_idle_timer_expired(OSObject *, IOTimerEventSource *);
void tellAppWithResponse ( OSObject * object, void * context);
void tellClientWithResponse ( OSObject * object, void * context);
void tellClient ( OSObject * object, void * context);
IOReturn serializedAllowPowerChange ( OSObject *, void *, void *, void *, void *);
IOReturn serializedCancelPowerChange ( OSObject *, void *, void *, void *, void *);
extern const IORegistryPlane * gIOPowerPlane;
#define ns_per_us 1000
enum {
kIOPM_OurChangeTellClientsPowerDown = 1,
kIOPM_OurChangeTellPriorityClientsPowerDown,
kIOPM_OurChangeNotifyInterestedDriversWillChange,
kIOPM_OurChangeSetPowerState,
kIOPM_OurChangeWaitForPowerSettle,
kIOPM_OurChangeNotifyInterestedDriversDidChange,
kIOPM_OurChangeFinish,
kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate,
kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed,
kIOPM_ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate,
kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed,
kIOPM_ParentDownSetPowerState_Delayed,
kIOPM_ParentDownWaitForPowerSettle_Delayed,
kIOPM_ParentDownAcknowledgeChange_Delayed,
kIOPM_ParentUpSetPowerState_Delayed,
kIOPM_ParentUpSetPowerState_Immediate,
kIOPM_ParentUpWaitForSettleTime_Delayed,
kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed,
kIOPM_ParentUpAcknowledgePowerChange_Delayed,
kIOPM_Finished
};
enum {
kNotifyApps,
kNotifyPriority
};
struct context {
OSArray * responseFlags;
UInt16 serialNumber;
UInt16 counter;
UInt32 maxTimeRequested;
int msgType;
IOService * us;
IOLock * flags_lock;
unsigned long stateNumber;
IOPMPowerFlags stateFlags;
};
#define FIVE_MINUTES 5*60*1000000
#define k30seconds 30*1000000
const char priv_key[ ] = "Power Management private data";
const char prot_key[ ] = "Power Management protected data";
void IOService::PMinit ( void )
{
if ( ! initialized ) {
pm_vars = new IOPMprot;
priv = new IOPMpriv;
pm_vars->init();
priv->init();
setProperty(prot_key, (OSObject *) pm_vars);
setProperty(priv_key, (OSObject *) priv);
priv->owner = this;
pm_vars->theNumberOfPowerStates = 0;
priv->we_are_root = false;
pm_vars->theControllingDriver = NULL;
priv->our_lock = IOLockAlloc();
priv->flags_lock = IOLockAlloc();
priv->queue_lock = IOLockAlloc();
pm_vars->childLock = IOLockAlloc();
pm_vars->parentLock = IOLockAlloc();
priv->interestedDrivers = new IOPMinformeeList;
priv->interestedDrivers->initialize();
priv->changeList = new IOPMchangeNoteList;
priv->changeList->initialize();
pm_vars->aggressiveness = 0;
for (unsigned int i = 0; i <= kMaxType; i++)
{
pm_vars->current_aggressiveness_values[i] = 0;
pm_vars->current_aggressiveness_valid[i] = false;
}
pm_vars->myCurrentState = 0;
priv->imminentState = 0;
priv->ourDesiredPowerState = 0;
pm_vars->parentsCurrentPowerFlags = 0;
pm_vars->maxCapability = 0;
priv->driverDesire = 0;
priv->deviceDesire = 0;
priv->initial_change = true;
priv->need_to_become_usable = false;
priv->previousRequest = 0;
priv->device_overrides = false;
priv->machine_state = kIOPM_Finished;
priv->timerEventSrc = NULL;
priv->clampTimerEventSrc = NULL;
pm_vars->PMworkloop = NULL;
priv->activityLock = NULL;
pm_vars->ourName = getName();
pm_vars->thePlatform = getPlatform();
pm_vars->parentsKnowState = false;
assert( pm_vars->thePlatform != 0 );
priv->clampOn = false;
pm_vars->serialNumber = 0;
pm_vars->responseFlags = NULL;
pm_vars->doNotPowerDown = true;
pm_vars->PMcommandGate = NULL;
priv->ackTimer = thread_call_allocate((thread_call_func_t)ack_timer_expired, (thread_call_param_t)this);
priv->settleTimer = thread_call_allocate((thread_call_func_t)settle_timer_expired, (thread_call_param_t)this);
initialized = true;
}
}
void IOService::PMfree ( void )
{
if ( priv ) {
if ( priv->clampTimerEventSrc != NULL ) {
getPMworkloop()->removeEventSource(priv->clampTimerEventSrc);
priv->clampTimerEventSrc->release();
priv->clampTimerEventSrc = NULL;
}
if ( priv->timerEventSrc != NULL ) {
pm_vars->PMworkloop->removeEventSource(priv->timerEventSrc);
priv->timerEventSrc->release();
priv->timerEventSrc = NULL;
}
if ( priv->settleTimer ) {
thread_call_cancel(priv->settleTimer);
thread_call_free(priv->settleTimer);
priv->settleTimer = NULL;
}
if ( priv->ackTimer ) {
thread_call_cancel(priv->ackTimer);
thread_call_free(priv->ackTimer);
priv->ackTimer = NULL;
}
if ( priv->our_lock ) {
IOLockFree(priv->our_lock);
priv->our_lock = NULL;
}
if ( priv->flags_lock ) {
IOLockFree(priv->flags_lock);
priv->flags_lock = NULL;
}
if ( priv->activityLock ) {
IOLockFree(priv->activityLock);
priv->activityLock = NULL;
}
priv->interestedDrivers->release();
priv->changeList->release();
priv->release();
}
if ( pm_vars ) {
if ( pm_vars->PMcommandGate ) {
if(pm_vars->PMworkloop)
pm_vars->PMworkloop->removeEventSource(pm_vars->PMcommandGate);
pm_vars->PMcommandGate->release();
pm_vars->PMcommandGate = NULL;
}
if ( pm_vars->PMworkloop ) {
pm_vars->PMworkloop = NULL;
}
if ( pm_vars->responseFlags ) {
pm_vars->responseFlags->release();
pm_vars->responseFlags = NULL;
}
pm_vars->release();
}
}
void IOService::PMstop ( void )
{
OSIterator * iter;
OSObject * next;
IOPowerConnection * connection;
IOService * theChild;
IOService * theParent;
removeProperty(prot_key);
removeProperty(priv_key);
iter = getParentIterator(gIOPowerPlane);
if ( iter )
{
while ( (next = iter->getNextObject()) )
{
if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
{
theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
if ( theParent )
{
theParent->removePowerChild(connection);
theParent->release();
}
}
}
iter->release();
}
detachAbove( gIOPowerPlane );
if ( pm_vars )
{
pm_vars->parentsKnowState = false;
}
iter = getChildIterator(gIOPowerPlane);
if ( iter )
{
while ( (next = iter->getNextObject()) )
{
if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
{
theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
if ( theChild )
{
connection->detachFromChild(theChild,gIOPowerPlane);
theChild->release();
}
detachFromChild(connection,gIOPowerPlane);
}
}
iter->release();
}
if ( priv && priv->interestedDrivers )
{
IOPMinformee * informee;
while (( informee = priv->interestedDrivers->firstInList() ))
deRegisterInterestedDriver( informee->whatObject );
}
}
void IOService::joinPMtree ( IOService * driver )
{
IOPlatformExpert * thePlatform;
thePlatform = getPlatform();
assert(thePlatform != 0 );
thePlatform->PMRegisterDevice(this,driver);
}
IOReturn IOService::youAreRoot ( void )
{
priv-> we_are_root = true;
pm_vars->parentsKnowState = true;
attachToParent( getRegistryRoot(),gIOPowerPlane );
return IOPMNoErr;
}
IOReturn IOService::setPowerParent ( IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags currentState )
{
OSIterator * iter;
OSObject * next;
IOPowerConnection * connection;
unsigned long tempDesire;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetParent,stateKnown,currentState);
IOLockLock(pm_vars->parentLock);
if ( stateKnown && ((pm_vars->PMworkloop == NULL) || (pm_vars->PMcommandGate == NULL)) )
{
getPMworkloop();
if ( pm_vars->PMworkloop != NULL )
{
if ( pm_vars->PMcommandGate == NULL )
{
pm_vars->PMcommandGate = IOCommandGate::commandGate((OSObject *)this);
if ( pm_vars->PMcommandGate != NULL )
{
pm_vars->PMworkloop->addEventSource(pm_vars->PMcommandGate);
}
}
}
}
IOLockUnlock(pm_vars->parentLock);
theParent->setParentCurrentPowerFlags(currentState);
theParent->setParentKnowsState(stateKnown);
pm_vars->parentsKnowState = true;
pm_vars->parentsCurrentPowerFlags = 0;
iter = getParentIterator(gIOPowerPlane);
if ( iter )
{
while ( (next = iter->getNextObject()) )
{
if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
{
pm_vars->parentsKnowState &= connection->parentKnowsState();
pm_vars->parentsCurrentPowerFlags |= connection->parentCurrentPowerFlags();
}
}
iter->release();
}
if ( (pm_vars->theControllingDriver != NULL) &&
(pm_vars->parentsKnowState) )
{
pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentsCurrentPowerFlags);
tempDesire = priv->deviceDesire;
priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
computeDesiredState();
priv->previousRequest = 0xffffffff;
changeState();
priv->deviceDesire = tempDesire;
}
return IOPMNoErr;
}
IOReturn IOService::addPowerChild ( IOService * theChild )
{
IOPowerConnection *connection;
unsigned int i;
if ( ! initialized )
{
return IOPMNotYetInitialized;
}
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAddChild,0,0);
makeUsable();
connection = new IOPowerConnection;
connection->init();
connection->start(this);
connection->setAwaitingAck(false);
attachToChild( connection,gIOPowerPlane );
connection->attachToChild( theChild,gIOPowerPlane );
connection->release();
if ( (pm_vars->theControllingDriver == NULL) ||
! (inPlane(gIOPowerPlane)) ||
! (pm_vars->parentsKnowState) )
{
theChild->setPowerParent(connection,false,0);
if ( inPlane(gIOPowerPlane) )
{
for (i = 0; i <= kMaxType; i++) {
if ( pm_vars->current_aggressiveness_valid[i] )
{
theChild->setAggressiveness (i, pm_vars->current_aggressiveness_values[i]);
}
}
}
} else {
theChild->setPowerParent(connection,true,pm_vars->thePowerStates[pm_vars->myCurrentState].outputPowerCharacter);
for (i = 0; i <= kMaxType; i++)
{
if ( pm_vars->current_aggressiveness_valid[i] )
{
theChild->setAggressiveness (i, pm_vars->current_aggressiveness_values[i]);
}
}
add_child_to_active_change(connection);
}
return IOPMNoErr;
}
IOReturn IOService::removePowerChild ( IOPowerConnection * theNub )
{
IORegistryEntry *theChild;
OSIterator *iter;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveChild,0,0);
theNub->retain();
theChild = theNub->copyChildEntry(gIOPowerPlane);
if ( theChild )
{
theNub->detachFromChild(theChild, gIOPowerPlane);
theChild->release();
}
detachFromChild(theNub,gIOPowerPlane);
if ( theNub->getAwaitingAck() )
{
theNub->setAwaitingAck(false);
if ( acquire_lock() )
{
if (priv->head_note_pendingAcks != 0 )
{
priv->head_note_pendingAcks -= 1;
if ( priv->head_note_pendingAcks == 0 )
{
stop_ack_timer();
IOUnlock(priv->our_lock);
all_acked();
} else {
IOUnlock(priv->our_lock);
}
} else {
IOUnlock(priv->our_lock);
}
}
}
theNub->release();
if ( (pm_vars->theControllingDriver == NULL) ||
!(inPlane(gIOPowerPlane)) ||
!(pm_vars->parentsKnowState) )
{
return IOPMNoErr;
}
rebuildChildClampBits();
if(!priv->clampOn)
{
iter = getChildIterator(gIOPowerPlane);
if ( !iter || !iter->getNextObject() )
{
changePowerStateToPriv(0);
}
if(iter) iter->release();
}
computeDesiredState();
changeState();
return IOPMNoErr;
}
IOReturn IOService::registerPowerDriver ( IOService * controllingDriver, IOPMPowerState* powerStates, unsigned long numberOfStates )
{
unsigned long i;
unsigned long tempDesire;
if ( (numberOfStates > pm_vars->theNumberOfPowerStates)
&& (numberOfStates > 1) )
{
if ( priv->changeList->currentChange() == -1 )
{
if ( controllingDriver != NULL )
{
if ( numberOfStates <= IOPMMaxPowerStates )
{
switch ( powerStates[0].version )
{
case 1:
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver,
(unsigned long)numberOfStates, (unsigned long)powerStates[0].version);
for ( i = 0; i < numberOfStates; i++ )
{
pm_vars->thePowerStates[i] = powerStates[i];
}
break;
case 2:
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver,
(unsigned long) numberOfStates,(unsigned long) powerStates[0].version);
for ( i = 0; i < numberOfStates; i++ )
{
pm_vars->thePowerStates[i].version = powerStates[i].version;
pm_vars->thePowerStates[i].capabilityFlags = powerStates[i].capabilityFlags;
pm_vars->thePowerStates[i].outputPowerCharacter = powerStates[i].outputPowerCharacter;
pm_vars->thePowerStates[i].inputPowerRequirement = powerStates[i].inputPowerRequirement;
pm_vars->thePowerStates[i].staticPower = powerStates[i].staticPower;
pm_vars->thePowerStates[i].unbudgetedPower = powerStates[i].unbudgetedPower;
pm_vars->thePowerStates[i].powerToAttain = powerStates[i].powerToAttain;
pm_vars->thePowerStates[i].timeToAttain = powerStates[i].timeToAttain;
pm_vars->thePowerStates[i].settleUpTime = powerStates[i].settleUpTime;
pm_vars->thePowerStates[i].timeToLower = powerStates[i].timeToLower;
pm_vars->thePowerStates[i].settleDownTime = powerStates[i].settleDownTime;
pm_vars->thePowerStates[i].powerDomainBudget = powerStates[i].powerDomainBudget;
}
break;
default:
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr1,
(unsigned long)powerStates[0].version,0);
return IOPMNoErr;
}
pm_vars->myCharacterFlags = 0;
for ( i = 0; i < numberOfStates; i++ ) {
pm_vars->myCharacterFlags |= pm_vars->thePowerStates[i].outputPowerCharacter;
}
pm_vars->theNumberOfPowerStates = numberOfStates;
pm_vars->theControllingDriver = controllingDriver;
if ( priv->interestedDrivers->findItem(controllingDriver) == NULL )
{
registerInterestedDriver (controllingDriver );
}
if ( priv->need_to_become_usable ) {
priv->need_to_become_usable = false;
priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1;
}
if ( inPlane(gIOPowerPlane) &&
(pm_vars->parentsKnowState) ) {
pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentsCurrentPowerFlags);
tempDesire = priv->deviceDesire;
priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
computeDesiredState();
changeState();
priv->deviceDesire = tempDesire;
}
} else {
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr2,(unsigned long)numberOfStates,0);
}
} else {
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr4,0,0);
}
}
}
else {
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr5,(unsigned long)numberOfStates,0);
}
return IOPMNoErr;
}
IOPMPowerFlags IOService::registerInterestedDriver ( IOService * theDriver )
{
IOPMinformee *newInformee;
IOPMPowerFlags futureCapability;
if (theDriver == NULL ) {
return 0;
}
newInformee = new IOPMinformee;
newInformee->initialize(theDriver);
priv->interestedDrivers->addToList(newInformee);
if ( (pm_vars->theControllingDriver == NULL) ||
!(inPlane(gIOPowerPlane)) ||
!(pm_vars->parentsKnowState) )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,IOPMNotPowerManaged,0);
return IOPMNotPowerManaged;
}
switch (priv->machine_state) {
case kIOPM_OurChangeSetPowerState:
case kIOPM_OurChangeFinish:
case kIOPM_ParentDownSetPowerState_Delayed:
case kIOPM_ParentDownAcknowledgeChange_Delayed:
case kIOPM_ParentUpSetPowerState_Delayed:
case kIOPM_ParentUpAcknowledgePowerChange_Delayed:
futureCapability = priv->head_note_capabilityFlags;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,(unsigned long)futureCapability,1);
add_driver_to_active_change(newInformee);
return futureCapability;
}
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,
(unsigned long) pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags,2);
return pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags;
}
IOReturn IOService::deRegisterInterestedDriver ( IOService * theDriver )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveDriver,0,0);
priv->interestedDrivers->removeFromList(theDriver);
return IOPMNoErr;
}
IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
{
IOPMinformee *ackingObject;
unsigned long childPower = kIOPMUnknown;
IOService *theChild;
ackingObject = priv->interestedDrivers->findItem(whichObject);
if ( ackingObject == NULL )
{
if ( ! isChild(whichObject,gIOPowerPlane) )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr1,0,0);
return IOPMNoErr;
} else {
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChildAcknowledge,priv->head_note_pendingAcks,0);
}
} else {
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDriverAcknowledge,priv->head_note_pendingAcks,0);
}
if (! acquire_lock() )
{
return IOPMNoErr;
}
if (priv->head_note_pendingAcks != 0 )
{
if ( ackingObject != NULL )
{
if ( ackingObject->timer != 0 )
{
ackingObject->timer = 0;
priv->head_note_pendingAcks -= 1;
if ( priv->head_note_pendingAcks == 0 )
{
stop_ack_timer();
IOUnlock(priv->our_lock);
all_acked();
return IOPMNoErr;
}
} else {
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr2,0,0);
}
} else {
if ( ((IOPowerConnection *)whichObject)->getAwaitingAck() )
{
priv->head_note_pendingAcks -= 1;
((IOPowerConnection *)whichObject)->setAwaitingAck(false);
theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
if ( theChild )
{
childPower = theChild->currentPowerConsumption();
theChild->release();
}
if ( childPower == kIOPMUnknown )
{
pm_vars->thePowerStates[priv->head_note_state].staticPower = kIOPMUnknown;
} else {
if ( pm_vars->thePowerStates[priv->head_note_state].staticPower != kIOPMUnknown )
{
pm_vars->thePowerStates[priv->head_note_state].staticPower += childPower;
}
}
if ( priv->head_note_pendingAcks == 0 ) {
stop_ack_timer();
IOUnlock(priv->our_lock);
all_acked();
return IOPMNoErr;
}
}
}
} else {
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr3,0,0); }
IOUnlock(priv->our_lock);
return IOPMNoErr;
}
IOReturn IOService::acknowledgeSetPowerState ( void )
{
if (!acquire_lock())
return IOPMNoErr;
IOReturn timer = priv->driver_timer;
if ( timer == -1 ) {
OUR_PMLog(kPMLogDriverAcknowledgeSet, (UInt32) this, timer);
priv->driver_timer = 0;
}
else if ( timer > 0 ) { stop_ack_timer();
priv->driver_timer = 0;
OUR_PMLog(kPMLogDriverAcknowledgeSet, (UInt32) this, timer);
IOUnlock(priv->our_lock);
driver_acked();
return IOPMNoErr;
} else {
OUR_PMLog(kPMLogAcknowledgeErr4, (UInt32) this, 0);
}
IOUnlock(priv->our_lock);
return IOPMNoErr;
}
void IOService::driver_acked ( void )
{
switch (priv->machine_state) {
case kIOPM_OurChangeWaitForPowerSettle:
OurChangeWaitForPowerSettle();
break;
case kIOPM_ParentDownWaitForPowerSettle_Delayed:
ParentDownWaitForPowerSettle_Delayed();
break;
case kIOPM_ParentUpWaitForSettleTime_Delayed:
ParentUpWaitForSettleTime_Delayed();
break;
}
}
IOReturn IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags, IOPowerConnection * whichParent )
{
OSIterator *iter;
OSObject *next;
IOPowerConnection *connection;
unsigned long newStateNumber;
IOPMPowerFlags combinedPowerFlags;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogWillChange,(unsigned long)newPowerStateFlags,0);
if ( ! inPlane(gIOPowerPlane) )
{
return IOPMAckImplied;
}
IOLockLock(pm_vars->parentLock);
if ( (pm_vars->PMworkloop == NULL) || (pm_vars->PMcommandGate == NULL) )
{
getPMworkloop();
if ( pm_vars->PMworkloop != NULL )
{
if ( pm_vars->PMcommandGate == NULL )
{
pm_vars->PMcommandGate = IOCommandGate::commandGate((OSObject *)this);
if ( pm_vars->PMcommandGate != NULL )
{
pm_vars->PMworkloop->addEventSource(pm_vars->PMcommandGate);
}
}
}
}
IOLockUnlock(pm_vars->parentLock);
combinedPowerFlags = 0;
iter = getParentIterator(gIOPowerPlane);
if ( iter )
{
while ( (next = iter->getNextObject()) )
{
if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
{
if ( connection == whichParent ){
combinedPowerFlags |= newPowerStateFlags;
} else {
combinedPowerFlags |= connection->parentCurrentPowerFlags();
}
}
}
iter->release();
}
if ( pm_vars->theControllingDriver == NULL )
{
return IOPMAckImplied;
}
newStateNumber = pm_vars->theControllingDriver->maxCapabilityForDomainState(combinedPowerFlags);
return enqueuePowerChange(IOPMParentInitiated | IOPMDomainWillChange,
newStateNumber,combinedPowerFlags,whichParent,newPowerStateFlags);
}
IOReturn IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags, IOPowerConnection * whichParent )
{
unsigned long newStateNumber;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDidChange,newPowerStateFlags,0);
setParentInfo(newPowerStateFlags,whichParent);
if ( pm_vars->theControllingDriver == NULL ) {
return IOPMAckImplied;
}
newStateNumber = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentsCurrentPowerFlags);
return enqueuePowerChange(IOPMParentInitiated | IOPMDomainDidChange,
newStateNumber,pm_vars->parentsCurrentPowerFlags,whichParent,0);
}
void IOService::setParentInfo ( IOPMPowerFlags newPowerStateFlags, IOPowerConnection * whichParent )
{
OSIterator *iter;
OSObject *next;
IOPowerConnection *connection;
whichParent->setParentCurrentPowerFlags(newPowerStateFlags);
whichParent->setParentKnowsState(true);
IOLockLock(pm_vars->parentLock);
pm_vars->parentsCurrentPowerFlags = 0;
pm_vars->parentsKnowState = true;
iter = getParentIterator(gIOPowerPlane);
if ( iter )
{
while ( (next = iter->getNextObject()) )
{
if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
{
pm_vars->parentsKnowState &= connection->parentKnowsState();
pm_vars->parentsCurrentPowerFlags |= connection->parentCurrentPowerFlags();
}
}
iter->release();
}
IOLockUnlock(pm_vars->parentLock);
}
void IOService::rebuildChildClampBits(void)
{
unsigned long i;
OSIterator *iter;
OSObject *next;
IOPowerConnection *connection;
for ( i = 0; i < pm_vars->theNumberOfPowerStates; i++ )
{
pm_vars->thePowerStates[i].capabilityFlags &= ~(kIOPMChildClamp | kIOPMChildClamp2);
}
iter = getChildIterator(gIOPowerPlane);
if ( iter )
{
while ( (next = iter->getNextObject()) )
{
if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
{
if ( connection->getPreventIdleSleepFlag() )
pm_vars->thePowerStates[connection->getDesiredDomainState()].capabilityFlags |= kIOPMChildClamp;
if ( connection->getPreventSystemSleepFlag() )
pm_vars->thePowerStates[connection->getDesiredDomainState()].capabilityFlags |= kIOPMChildClamp2;
}
}
iter->release();
}
}
IOReturn IOService::requestPowerDomainState ( IOPMPowerFlags desiredState, IOPowerConnection * whichChild, unsigned long specification )
{
unsigned long i;
unsigned long computedState;
unsigned long theDesiredState = desiredState & ~(kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
OSIterator *iter;
OSObject *next;
IOPowerConnection *connection;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDomain,
(unsigned long)desiredState,(unsigned long)specification);
if ( pm_vars->theControllingDriver == NULL)
{
return IOPMNotYetInitialized;
}
switch (specification) {
case IOPMLowestState:
i = 0;
while ( i < pm_vars->theNumberOfPowerStates )
{
if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & theDesiredState) == (theDesiredState & pm_vars->myCharacterFlags) )
{
break;
}
i++;
}
if ( i >= pm_vars->theNumberOfPowerStates )
{
return IOPMNoSuchState;
}
break;
case IOPMNextLowerState:
i = pm_vars->myCurrentState - 1;
while ( (int) i >= 0 )
{
if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & theDesiredState) == (theDesiredState & pm_vars->myCharacterFlags) )
{
break;
}
i--;
}
if ( (int) i < 0 )
{
return IOPMNoSuchState;
}
break;
case IOPMHighestState:
i = pm_vars->theNumberOfPowerStates;
while ( (int) i >= 0 )
{
i--;
if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & theDesiredState) == (theDesiredState & pm_vars->myCharacterFlags) )
{
break;
}
}
if ( (int) i < 0 )
{
return IOPMNoSuchState;
}
break;
case IOPMNextHigherState:
i = pm_vars->myCurrentState + 1;
while ( i < pm_vars->theNumberOfPowerStates )
{
if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & theDesiredState) == (theDesiredState & pm_vars->myCharacterFlags) )
{
break;
}
i++;
}
if ( i == pm_vars->theNumberOfPowerStates )
{
return IOPMNoSuchState;
}
break;
default:
return IOPMBadSpecification;
}
computedState = i;
IOLockLock(pm_vars->childLock);
iter = getChildIterator(gIOPowerPlane);
if ( iter )
{
while ( (next = iter->getNextObject()) )
{
if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
{
if ( connection == whichChild )
{
connection->setDesiredDomainState(computedState);
connection->setPreventIdleSleepFlag(desiredState & kIOPMPreventIdleSleep);
connection->setPreventSystemSleepFlag(desiredState & kIOPMPreventSystemSleep);
connection->setChildHasRequestedPower();
}
}
}
iter->release();
}
rebuildChildClampBits();
IOLockUnlock(pm_vars->childLock);
computeDesiredState();
if ( inPlane(gIOPowerPlane) &&
(pm_vars->parentsKnowState) ) {
changeState();
}
if ( priv->clampOn ) {
priv->clampOn = false;
changePowerStateToPriv(0);
}
return IOPMNoErr;
}
IOReturn IOService::temporaryPowerClampOn ( void )
{
priv->clampOn = true;
makeUsable();
return IOPMNoErr;
}
IOReturn IOService::makeUsable ( void )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogMakeUsable,0,0);
if ( pm_vars->theControllingDriver == NULL )
{
priv->need_to_become_usable = true;
return IOPMNoErr;
}
priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1;
computeDesiredState();
if ( inPlane(gIOPowerPlane) && (pm_vars->parentsKnowState) )
{
return changeState();
}
return IOPMNoErr;
}
IOPMPowerFlags IOService::currentCapability ( void )
{
if ( pm_vars->theControllingDriver == NULL )
{
return 0;
} else {
return pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags;
}
}
IOReturn IOService::changePowerStateTo ( unsigned long ordinal )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateTo,ordinal,0);
if ( ordinal >= pm_vars->theNumberOfPowerStates )
{
return IOPMParameterError;
}
priv->driverDesire = ordinal;
computeDesiredState();
if ( inPlane(gIOPowerPlane) && (pm_vars->parentsKnowState) )
{
return changeState();
}
return IOPMNoErr;
}
IOReturn IOService::changePowerStateToPriv ( unsigned long ordinal )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateToPriv,ordinal,0);
if ( pm_vars->theControllingDriver == NULL)
{
return IOPMNotYetInitialized;
}
if ( ordinal >= pm_vars->theNumberOfPowerStates )
{
return IOPMParameterError;
}
priv->deviceDesire = ordinal;
computeDesiredState();
if ( inPlane(gIOPowerPlane) && (pm_vars->parentsKnowState) )
{
return changeState();
}
return IOPMNoErr;
}
void IOService::computeDesiredState ( void )
{
OSIterator *iter;
OSObject *next;
IOPowerConnection *connection;
unsigned long newDesiredState = 0;
if ( ! priv->device_overrides )
{
iter = getChildIterator(gIOPowerPlane);
if ( iter )
{
while ( (next = iter->getNextObject()) )
{
if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
{
if ( connection->getDesiredDomainState() > newDesiredState )
{
newDesiredState = connection->getDesiredDomainState();
}
}
}
iter->release();
}
if ( priv->driverDesire > newDesiredState )
{
newDesiredState = priv->driverDesire;
}
}
if ( priv->deviceDesire > newDesiredState )
{
newDesiredState = priv->deviceDesire;
}
priv->ourDesiredPowerState = newDesiredState;
}
IOReturn IOService::changeState ( void )
{
if ( (pm_vars->theControllingDriver == NULL) ||
!(inPlane(gIOPowerPlane)) ||
!(pm_vars->parentsKnowState) )
{
return IOPMNoErr;
}
return enqueuePowerChange(IOPMWeInitiated,priv->ourDesiredPowerState,0,0,0);
}
unsigned long IOService::currentPowerConsumption ( void )
{
if ( pm_vars->theControllingDriver == NULL )
{
return kIOPMUnknown;
}
if ( pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags & kIOPMStaticPowerValid )
{
return pm_vars->thePowerStates[pm_vars->myCurrentState].staticPower;
}
return kIOPMUnknown;
}
bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber )
{
IOPMrootDomain *pmRootDomain;
AbsoluteTime uptime;
if ( type == kIOPMSuperclassPolicy1 )
{
if ( pm_vars->theControllingDriver == NULL )
{
return true;
}
if( priv->activityLock == NULL )
{
priv->activityLock = IOLockAlloc();
}
IOTakeLock(priv->activityLock);
priv->device_active = true;
clock_get_uptime(&uptime);
priv->device_active_timestamp = uptime;
if ( pm_vars->myCurrentState >= stateNumber)
{
IOUnlock(priv->activityLock);
return true;
}
IOUnlock(priv->activityLock);
if( (pmRootDomain = getPMRootDomain()) )
pmRootDomain->unIdleDevice(this, stateNumber);
return false;
}
return true;
}
IOWorkLoop * IOService::getPMworkloop ( void )
{
IOService *nub;
IOService *parent;
if ( ! inPlane(gIOPowerPlane) )
{
return NULL;
}
if ( pm_vars->PMworkloop == NULL )
{
nub = (IOService *)copyParentEntry(gIOPowerPlane);
if ( nub )
{
parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
nub->release();
if ( parent )
{
pm_vars->PMworkloop = parent->getPMworkloop();
parent->release();
}
}
}
return pm_vars->PMworkloop;
}
IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMsetIdleTimerPeriod,period, 0);
priv->idle_timer_period = period;
if ( period > 0 )
{
if ( getPMworkloop() == NULL )
{
return kIOReturnError;
}
if ( priv->timerEventSrc == NULL )
{
priv->timerEventSrc = IOTimerEventSource::timerEventSource(this,
PM_idle_timer_expired);
if ((!priv->timerEventSrc) ||
(pm_vars->PMworkloop->addEventSource(priv->timerEventSrc) != kIOReturnSuccess) )
{
return kIOReturnError;
}
}
if ( priv->activityLock == NULL )
{
priv->activityLock = IOLockAlloc();
}
start_PM_idle_timer();
}
return IOPMNoErr;
}
SInt32 IOService::nextIdleTimeout(
AbsoluteTime currentTime,
AbsoluteTime lastActivity,
unsigned int powerState)
{
AbsoluteTime delta;
UInt64 delta_ns;
SInt32 delta_secs;
SInt32 delay_secs;
delta = currentTime;
SUB_ABSOLUTETIME(&delta, &lastActivity);
absolutetime_to_nanoseconds(delta, &delta_ns);
delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
if (delta_secs < (int) priv->idle_timer_period )
delay_secs = (int) priv->idle_timer_period - delta_secs;
else
delay_secs = (int) priv->idle_timer_period;
return (SInt32)delay_secs;
}
void IOService::start_PM_idle_timer ( void )
{
static const int maxTimeout = 100000;
static const int minTimeout = 1;
AbsoluteTime uptime;
SInt32 idle_in = 0;
IOLockLock(priv->activityLock);
clock_get_uptime(&uptime);
idle_in = nextIdleTimeout(uptime,
priv->device_active_timestamp,
pm_vars->myCurrentState);
if(idle_in > maxTimeout)
{
idle_in = IOService::nextIdleTimeout(uptime,
priv->device_active_timestamp,
pm_vars->myCurrentState);
} else if(idle_in < minTimeout) {
idle_in = 0;
}
priv->timerEventSrc->setTimeout(idle_in, NSEC_PER_SEC);
IOLockUnlock(priv->activityLock);
return;
}
void PM_idle_timer_expired(OSObject * ourSelves, IOTimerEventSource *)
{
((IOService *)ourSelves)->PM_idle_timer_expiration();
}
void IOService::PM_idle_timer_expiration ( void )
{
if ( ! initialized )
{
return;
}
if ( priv->idle_timer_period > 0 )
{
IOTakeLock(priv->activityLock);
if ( priv->device_active )
{
priv->device_active = false;
IOUnlock(priv->activityLock);
start_PM_idle_timer();
return;
}
if ( pm_vars->myCurrentState > 0 )
{
IOUnlock(priv->activityLock);
changePowerStateToPriv(pm_vars->myCurrentState - 1);
start_PM_idle_timer();
return;
}
IOUnlock(priv->activityLock);
start_PM_idle_timer();
}
}
void IOService::command_received ( void *statePtr , void *, void * , void * )
{
unsigned long stateNumber;
stateNumber = (unsigned long)statePtr;
if ( ! initialized ) return;
if ( (pm_vars->myCurrentState < stateNumber) &&
(priv->imminentState < stateNumber) )
{
changePowerStateToPriv(stateNumber);
if(priv->timerEventSrc)
start_PM_idle_timer();
}
}
IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
{
OSIterator *iter;
OSObject *next;
IOPowerConnection *connection;
IOService *child;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetAggressiveness,type, newLevel);
if ( type <= kMaxType )
{
pm_vars->current_aggressiveness_values[type] = newLevel;
pm_vars->current_aggressiveness_valid[type] = true;
}
iter = getChildIterator(gIOPowerPlane);
if ( iter )
{
while ( (next = iter->getNextObject()) )
{
if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
{
child = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
if ( child )
{
child->setAggressiveness(type, newLevel);
child->release();
}
}
}
iter->release();
}
return IOPMNoErr;
}
IOReturn IOService::getAggressiveness ( unsigned long type, unsigned long * currentLevel )
{
if ( type > kMaxType )
return kIOReturnBadArgument;
if ( !pm_vars->current_aggressiveness_valid[type] )
return kIOReturnInvalid;
*currentLevel = pm_vars->current_aggressiveness_values[type];
return kIOReturnSuccess;
}
IOReturn IOService::systemWake ( void )
{
OSIterator *iter;
OSObject *next;
IOPowerConnection *connection;
IOService *theChild;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSystemWake,0, 0);
iter = getChildIterator(gIOPowerPlane);
if ( iter )
{
while ( (next = iter->getNextObject()) )
{
if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
{
theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
if ( theChild )
{
theChild->systemWake();
theChild->release();
}
}
}
iter->release();
}
if ( pm_vars->theControllingDriver != NULL )
{
if ( pm_vars->theControllingDriver->didYouWakeSystem() )
{
makeUsable();
}
}
return IOPMNoErr;
}
IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
{
IOService *theParent;
IOService *theNub;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCriticalTemp,0,0);
if ( inPlane(gIOPowerPlane) && !(priv->we_are_root) )
{
theNub = (IOService *)copyParentEntry(gIOPowerPlane);
if ( theNub )
{
theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
theNub->release();
if ( theParent )
{
theParent->temperatureCriticalForZone(whichZone);
theParent->release();
}
}
}
return IOPMNoErr;
}
IOReturn IOService::powerOverrideOnPriv ( void )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOn,0,0);
priv->device_overrides = true;
computeDesiredState();
return changeState();
}
IOReturn IOService::powerOverrideOffPriv ( void )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOff,0,0);
priv->device_overrides = false;
computeDesiredState();
if( priv->clampOn)
{
return makeUsable();
} else {
return changeState();
}
}
IOReturn IOService::enqueuePowerChange ( unsigned long flags, unsigned long whatStateOrdinal, unsigned long domainState, IOPowerConnection * whichParent, unsigned long singleParentState )
{
long newNote;
long previousNote;
IOLockLock(priv->queue_lock);
newNote = priv->changeList->createChangeNote();
if ( newNote == -1 ) {
IOLockUnlock(priv->queue_lock);
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogEnqueueErr,0,0);
return IOPMAckImplied;
}
priv->changeList->changeNote[newNote].newStateNumber = whatStateOrdinal;
priv->changeList->changeNote[newNote].outputPowerCharacter = pm_vars->thePowerStates[whatStateOrdinal].outputPowerCharacter;
priv->changeList->changeNote[newNote].inputPowerRequirement = pm_vars->thePowerStates[whatStateOrdinal].inputPowerRequirement;
priv->changeList->changeNote[newNote].capabilityFlags = pm_vars->thePowerStates[whatStateOrdinal].capabilityFlags;
priv->changeList->changeNote[newNote].flags = flags;
priv->changeList->changeNote[newNote].parent = NULL;
if (flags & IOPMParentInitiated )
{
priv->changeList->changeNote[newNote].domainState = domainState;
priv->changeList->changeNote[newNote].parent = whichParent;
whichParent->retain();
priv->changeList->changeNote[newNote].singleParentState = singleParentState;
}
previousNote = priv->changeList->previousChangeNote(newNote);
if ( previousNote == -1 )
{
if (flags & IOPMWeInitiated )
{
IOLockUnlock(priv->queue_lock);
start_our_change(newNote);
return 0;
} else {
IOLockUnlock(priv->queue_lock);
return start_parent_change(newNote);
}
}
while ( (previousNote != priv->head_note) && (previousNote != -1) &&
(priv->changeList->changeNote[newNote].flags & priv->changeList->changeNote[previousNote].flags & IOPMWeInitiated) )
{
priv->changeList->changeNote[previousNote].outputPowerCharacter = priv->changeList->changeNote[newNote].outputPowerCharacter;
priv->changeList->changeNote[previousNote].inputPowerRequirement = priv->changeList->changeNote[newNote].inputPowerRequirement;
priv->changeList->changeNote[previousNote].capabilityFlags =priv-> changeList->changeNote[newNote].capabilityFlags;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCollapseQueue,priv->changeList->changeNote[newNote].newStateNumber,
priv->changeList->changeNote[previousNote].newStateNumber);
priv->changeList->changeNote[previousNote].newStateNumber = priv->changeList->changeNote[newNote].newStateNumber;
priv->changeList->releaseTailChangeNote();
newNote = previousNote;
previousNote = priv->changeList->previousChangeNote(newNote);
}
IOLockUnlock(priv->queue_lock);
return IOPMWillAckLater;
}
IOReturn IOService::notifyAll ( bool is_prechange )
{
IOPMinformee * nextObject;
OSIterator * iter;
OSObject * next;
IOPowerConnection * connection;
priv->head_note_pendingAcks =1;
nextObject = priv->interestedDrivers->firstInList();
while ( nextObject != NULL ) {
priv->head_note_pendingAcks +=1;
if (! inform(nextObject, is_prechange) )
{
}
nextObject = priv->interestedDrivers->nextInList(nextObject);
}
if (! acquire_lock() ) {
return IOPMNoErr;
}
if ( priv->head_note_pendingAcks > 1 ) {
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
start_ack_timer();
}
IOUnlock(priv->our_lock);
iter = getChildIterator(gIOPowerPlane);
pm_vars->thePowerStates[priv->head_note_state].staticPower = 0;
if ( iter )
{
while ( (next = iter->getNextObject()) )
{
if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
{
priv->head_note_pendingAcks +=1;
notifyChild(connection, is_prechange);
}
}
iter->release();
}
if (! acquire_lock() ) {
return IOPMNoErr;
}
priv->head_note_pendingAcks -= 1;
if (priv->head_note_pendingAcks == 0 ) {
IOUnlock(priv->our_lock);
return IOPMAckImplied;
}
IOUnlock(priv->our_lock);
return IOPMWillAckLater;
}
bool IOService::notifyChild ( IOPowerConnection * theNub, bool is_prechange )
{
IOReturn k = IOPMAckImplied;
unsigned long childPower;
IOService *theChild;
theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
if(!theChild)
{
priv->head_note_pendingAcks--;
return true;
}
theNub->setAwaitingAck(true);
if ( is_prechange )
{
k = theChild->powerDomainWillChangeTo(priv->head_note_outputFlags,theNub);
} else {
k = theChild->powerDomainDidChangeTo(priv->head_note_outputFlags,theNub);
}
if ( k == IOPMAckImplied )
{
priv->head_note_pendingAcks--;
theNub->setAwaitingAck(false);
childPower = theChild->currentPowerConsumption();
if ( childPower == kIOPMUnknown )
{
pm_vars->thePowerStates[priv->head_note_state].staticPower = kIOPMUnknown;
} else {
if ( pm_vars->thePowerStates[priv->head_note_state].staticPower != kIOPMUnknown )
{
pm_vars->thePowerStates[priv->head_note_state].staticPower += childPower;
}
}
theChild->release();
return true;
}
theChild->release();
return false;
}
bool IOService::inform ( IOPMinformee * nextObject, bool is_prechange )
{
IOReturn k = IOPMAckImplied;
nextObject->timer = -1;
if ( is_prechange )
{
pm_vars->thePlatform->PMLog (pm_vars->ourName,PMlogInformDriverPreChange,
(unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state);
k = nextObject->whatObject->powerStateWillChangeTo( priv->head_note_capabilityFlags,priv->head_note_state,this);
} else {
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInformDriverPostChange,
(unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state);
k = nextObject->whatObject->powerStateDidChangeTo(priv->head_note_capabilityFlags,priv->head_note_state,this);
}
if ( nextObject->timer == 0 )
{
return true;
}
if ( k ==IOPMAckImplied )
{
nextObject->timer = 0;
priv->head_note_pendingAcks -= 1;
return true;
}
if ( k<0 )
{
nextObject->timer = 0;
priv-> head_note_pendingAcks -= 1;
return true;
}
nextObject->timer = (k / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
return false;
}
void IOService::OurChangeTellClientsPowerDown ( void )
{
priv->machine_state = kIOPM_OurChangeTellPriorityClientsPowerDown;
if ( tellChangeDown1(priv->head_note_state) )
{
OurChangeTellPriorityClientsPowerDown();
}
}
void IOService::OurChangeTellPriorityClientsPowerDown ( void )
{
priv->machine_state = kIOPM_OurChangeNotifyInterestedDriversWillChange;
if ( tellChangeDown2(priv->head_note_state) )
{
return OurChangeNotifyInterestedDriversWillChange();
}
}
void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
{
priv->machine_state = kIOPM_OurChangeSetPowerState;
if ( notifyAll(true) == IOPMAckImplied )
{
OurChangeSetPowerState();
}
}
void IOService::OurChangeSetPowerState ( void )
{
priv->machine_state = kIOPM_OurChangeWaitForPowerSettle;
if ( instruct_driver(priv->head_note_state) == IOPMAckImplied )
{
OurChangeWaitForPowerSettle();
} else {
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
start_ack_timer();
}
}
void IOService::OurChangeWaitForPowerSettle ( void )
{
priv->settle_time = compute_settle_time();
if ( priv->settle_time == 0 )
{
OurChangeNotifyInterestedDriversDidChange();
} else {
priv->machine_state = kIOPM_OurChangeNotifyInterestedDriversDidChange;
startSettleTimer(priv->settle_time);
}
}
void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
{
priv->machine_state = kIOPM_OurChangeFinish;
if ( notifyAll(false) == IOPMAckImplied )
{
OurChangeFinish();
}
}
void IOService::OurChangeFinish ( void )
{
all_done();
}
IOReturn IOService::ParentDownTellPriorityClientsPowerDown_Immediate ( void )
{
priv->machine_state = kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed;
if ( tellChangeDown2(priv->head_note_state) )
{
return ParentDownNotifyInterestedDriversWillChange_Immediate();
}
return IOPMWillAckLater;
}
IOReturn IOService::ParentDownNotifyInterestedDriversWillChange_Immediate ( void )
{
priv->machine_state = kIOPM_ParentDownSetPowerState_Delayed;
if ( notifyAll(true) == IOPMAckImplied )
{
return ParentDownSetPowerState_Immediate();
}
return IOPMWillAckLater;
}
void IOService::ParentDownTellPriorityClientsPowerDown_Delayed ( void )
{
priv->machine_state = kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed;
if ( tellChangeDown2(priv->head_note_state) )
{
ParentDownNotifyInterestedDriversWillChange_Delayed();
}
}
void IOService::ParentDownNotifyInterestedDriversWillChange_Delayed ( void )
{
priv->machine_state = kIOPM_ParentDownSetPowerState_Delayed;
if ( notifyAll(true) == IOPMAckImplied )
{
ParentDownSetPowerState_Delayed();
}
}
IOReturn IOService::ParentDownSetPowerState_Immediate ( void )
{
priv->machine_state = kIOPM_ParentDownWaitForPowerSettle_Delayed;
if ( instruct_driver(priv->head_note_state) == IOPMAckImplied )
{
return ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate();
}
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
start_ack_timer();
return IOPMWillAckLater;
}
void IOService::ParentDownSetPowerState_Delayed ( void )
{
priv-> machine_state = kIOPM_ParentDownWaitForPowerSettle_Delayed;
if ( instruct_driver(priv->head_note_state) == IOPMAckImplied )
{
ParentDownWaitForPowerSettle_Delayed();
} else {
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
start_ack_timer();
}
}
IOReturn IOService::ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate ( void )
{
IOService * nub;
priv->settle_time = compute_settle_time();
if ( priv->settle_time == 0 )
{
priv->machine_state = kIOPM_ParentDownAcknowledgeChange_Delayed;
if ( notifyAll(false) == IOPMAckImplied )
{
nub = priv->head_note_parent;
nub->retain();
all_done();
nub->release();
return IOPMAckImplied;
}
return IOPMWillAckLater;
} else {
priv->machine_state = kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed;
startSettleTimer(priv->settle_time);
return IOPMWillAckLater;
}
}
void IOService::ParentDownWaitForPowerSettle_Delayed ( void )
{
priv->settle_time = compute_settle_time();
if ( priv->settle_time == 0 )
{
ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed();
} else {
priv->machine_state = kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed;
startSettleTimer(priv->settle_time);
}
}
void IOService::ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed ( void )
{
IORegistryEntry *nub;
IOService *parent;
priv->machine_state = kIOPM_ParentDownAcknowledgeChange_Delayed;
if ( notifyAll(false) == IOPMAckImplied ) {
nub = priv->head_note_parent;
nub->retain();
all_done();
parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
if ( parent ) {
parent->acknowledgePowerChange((IOService *)nub);
parent->release();
}
nub->release();
}
}
void IOService::ParentDownAcknowledgeChange_Delayed ( void )
{
IORegistryEntry *nub;
IOService *parent;
nub = priv->head_note_parent;
nub->retain();
all_done();
parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
if ( parent )
{
parent->acknowledgePowerChange((IOService *)nub);
parent->release();
}
nub->release();
}
void IOService::ParentUpSetPowerState_Delayed ( void )
{
priv->machine_state = kIOPM_ParentUpWaitForSettleTime_Delayed;
if ( instruct_driver(priv->head_note_state) == IOPMAckImplied )
{
ParentUpWaitForSettleTime_Delayed();
} else {
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
start_ack_timer();
}
}
IOReturn IOService::ParentUpSetPowerState_Immediate ( void )
{
priv->machine_state = kIOPM_ParentUpWaitForSettleTime_Delayed;
if ( instruct_driver(priv->head_note_state) == IOPMAckImplied )
{
return ParentUpWaitForSettleTime_Immediate();
}
else {
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
start_ack_timer();
return IOPMWillAckLater;
}
}
IOReturn IOService::ParentUpWaitForSettleTime_Immediate ( void )
{
priv->settle_time = compute_settle_time();
if ( priv->settle_time == 0 )
{
return ParentUpNotifyInterestedDriversDidChange_Immediate();
} else {
priv->machine_state = kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed;
startSettleTimer(priv->settle_time);
return IOPMWillAckLater;
}
}
void IOService::ParentUpWaitForSettleTime_Delayed ( void )
{
priv->settle_time = compute_settle_time();
if ( priv->settle_time == 0 )
{
ParentUpNotifyInterestedDriversDidChange_Delayed();
} else {
priv->machine_state = kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed;
startSettleTimer(priv->settle_time);
}
}
IOReturn IOService::ParentUpNotifyInterestedDriversDidChange_Immediate ( void )
{
IOService * nub;
priv->machine_state = kIOPM_ParentUpAcknowledgePowerChange_Delayed;
if ( notifyAll(false) == IOPMAckImplied )
{
nub = priv->head_note_parent;
nub->retain();
all_done();
nub->release();
return IOPMAckImplied;
}
return IOPMWillAckLater;
}
void IOService::ParentUpNotifyInterestedDriversDidChange_Delayed ( void )
{
priv->machine_state = kIOPM_ParentUpAcknowledgePowerChange_Delayed;
if ( notifyAll(false) == IOPMAckImplied )
{
ParentUpAcknowledgePowerChange_Delayed();
}
}
void IOService::ParentUpAcknowledgePowerChange_Delayed ( void )
{
IORegistryEntry *nub;
IOService *parent;
nub = priv->head_note_parent;
nub->retain();
all_done();
parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
if ( parent )
{
parent->acknowledgePowerChange((IOService *)nub);
parent->release();
}
nub->release();
}
void IOService::all_done ( void )
{
unsigned long previous_state;
IORegistryEntry *nub;
IOService *parent;
priv->machine_state = kIOPM_Finished;
if ( priv->head_note_flags & IOPMWeInitiated )
{
if ( !( priv->head_note_flags & IOPMNotDone) )
{
if ( pm_vars->myCurrentState < priv->head_note_state )
{
tellChangeUp (priv->head_note_state);
} else {
if ( ! priv->we_are_root )
{
ask_parent(priv->head_note_state);
}
}
previous_state = pm_vars->myCurrentState;
pm_vars->myCurrentState = priv->head_note_state;
priv->imminentState = pm_vars->myCurrentState;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0);
powerChangeDone(previous_state);
}
}
if ( priv->head_note_flags & IOPMParentInitiated)
{
if ( ((priv->head_note_flags & IOPMDomainWillChange) && (pm_vars->myCurrentState >= priv->head_note_state)) ||
((priv->head_note_flags & IOPMDomainDidChange) && (pm_vars->myCurrentState < priv->head_note_state)) )
{
if ( pm_vars->myCurrentState < priv->head_note_state )
{
tellChangeUp (priv->head_note_state);
}
previous_state = pm_vars->myCurrentState;
pm_vars->myCurrentState = priv->head_note_state;
priv->imminentState = pm_vars->myCurrentState;
pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(priv->head_note_domainState);
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0);
powerChangeDone(previous_state);
}
}
IOLockLock(priv->queue_lock);
priv->changeList->releaseHeadChangeNote();
priv->head_note = priv->changeList->currentChange();
if ( priv->head_note != -1 )
{
IOLockUnlock(priv->queue_lock);
if (priv->changeList->changeNote[priv->head_note].flags & IOPMWeInitiated )
{
start_our_change(priv->head_note);
} else {
nub = priv->changeList->changeNote[priv->head_note].parent;
if ( start_parent_change(priv->head_note) == IOPMAckImplied )
{
parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
if ( parent )
{
parent->acknowledgePowerChange((IOService *)nub);
parent->release();
}
}
}
} else {
IOLockUnlock(priv->queue_lock);
}
}
void IOService::all_acked ( void )
{
switch (priv->machine_state) {
case kIOPM_OurChangeSetPowerState:
OurChangeSetPowerState();
break;
case kIOPM_OurChangeFinish:
OurChangeFinish();
break;
case kIOPM_ParentDownSetPowerState_Delayed:
ParentDownSetPowerState_Delayed();
break;
case kIOPM_ParentDownAcknowledgeChange_Delayed:
ParentDownAcknowledgeChange_Delayed();
break;
case kIOPM_ParentUpSetPowerState_Delayed:
ParentUpSetPowerState_Delayed();
break;
case kIOPM_ParentUpAcknowledgePowerChange_Delayed:
ParentUpAcknowledgePowerChange_Delayed();
break;
}
}
void IOService::settleTimerExpired ( void )
{
if ( ! initialized )
{
return;
}
switch (priv->machine_state) {
case kIOPM_OurChangeNotifyInterestedDriversDidChange:
OurChangeNotifyInterestedDriversDidChange();
break;
case kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed:
ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed();
break;
case kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed:
ParentUpNotifyInterestedDriversDidChange_Delayed();
break;
}
}
unsigned long IOService::compute_settle_time ( void )
{
unsigned long totalTime;
unsigned long i;
totalTime = 0;
i = pm_vars->myCurrentState;
if ( priv->head_note_state < pm_vars->myCurrentState )
{
while ( i > priv->head_note_state )
{
totalTime += pm_vars->thePowerStates[i].settleDownTime;
i--;
}
}
if ( priv->head_note_state > pm_vars->myCurrentState )
{
while ( i < priv->head_note_state )
{
totalTime += pm_vars->thePowerStates[i+1].settleUpTime;
i++;
}
}
return totalTime;
}
IOReturn IOService::startSettleTimer ( unsigned long delay )
{
AbsoluteTime deadline;
clock_interval_to_deadline(delay, kMicrosecondScale, &deadline);
thread_call_enter_delayed(priv->settleTimer, deadline);
return IOPMNoErr;
}
void IOService::ack_timer_ticked ( void )
{
IOPMinformee * nextObject;
if ( ! initialized )
{
return;
}
if (! acquire_lock() )
{
return;
}
switch (priv->machine_state) {
case kIOPM_OurChangeWaitForPowerSettle:
case kIOPM_ParentDownWaitForPowerSettle_Delayed:
case kIOPM_ParentUpWaitForSettleTime_Delayed:
if ( priv->driver_timer != 0 ) {
priv->driver_timer -= 1;
if ( priv->driver_timer == 0 )
{
IOUnlock(priv->our_lock);
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCtrlDriverTardy,0,0);
driver_acked();
} else {
start_ack_timer();
IOUnlock(priv->our_lock);
}
}
else {
IOUnlock(priv->our_lock);
}
break;
case kIOPM_OurChangeSetPowerState:
case kIOPM_OurChangeFinish:
case kIOPM_ParentDownSetPowerState_Delayed:
case kIOPM_ParentDownAcknowledgeChange_Delayed:
case kIOPM_ParentUpSetPowerState_Delayed:
case kIOPM_ParentUpAcknowledgePowerChange_Delayed:
if (priv->head_note_pendingAcks != 0 )
{
nextObject = priv->interestedDrivers->firstInList();
while ( nextObject != NULL )
{
if ( nextObject->timer > 0 )
{
nextObject->timer -= 1;
if ( nextObject->timer == 0 )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogIntDriverTardy,0,0);
priv->head_note_pendingAcks -= 1;
}
}
nextObject = priv->interestedDrivers->nextInList(nextObject);
}
if ( priv->head_note_pendingAcks == 0 )
{
IOUnlock(priv->our_lock);
all_acked();
} else {
start_ack_timer();
IOUnlock(priv->our_lock);
}
} else {
IOUnlock(priv->our_lock);
}
break;
case kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate:
IOUnlock(priv->our_lock);
IOLockLock(priv->flags_lock);
if (pm_vars->responseFlags)
{
pm_vars->responseFlags->release();
pm_vars->responseFlags = NULL;
}
IOLockUnlock(priv->flags_lock);
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,5);
ParentDownTellPriorityClientsPowerDown_Delayed();
break;
case kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed:
IOUnlock(priv->our_lock);
IOLockLock(priv->flags_lock);
if (pm_vars->responseFlags)
{
pm_vars->responseFlags->release();
pm_vars->responseFlags = NULL;
}
IOLockUnlock(priv->flags_lock);
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,1);
ParentDownNotifyInterestedDriversWillChange_Delayed();
break;
case kIOPM_OurChangeTellClientsPowerDown:
IOUnlock(priv->our_lock);
IOLockLock(priv->flags_lock);
if (pm_vars->responseFlags)
{
pm_vars->responseFlags->release();
pm_vars->responseFlags = NULL;
}
IOLockUnlock(priv->flags_lock);
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,2);
tellNoChangeDown(priv->head_note_state);
priv->head_note_flags |= IOPMNotDone;
all_done();
break;
case kIOPM_OurChangeTellPriorityClientsPowerDown:
IOUnlock(priv->our_lock);
IOLockLock(priv->flags_lock);
if (pm_vars->responseFlags)
{
pm_vars->responseFlags->release();
pm_vars->responseFlags = NULL;
}
IOLockUnlock(priv->flags_lock);
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,4);
OurChangeTellPriorityClientsPowerDown();
break;
case kIOPM_OurChangeNotifyInterestedDriversWillChange:
IOUnlock(priv->our_lock);
IOLockLock(priv->flags_lock);
if (pm_vars->responseFlags)
{
pm_vars->responseFlags->release();
pm_vars->responseFlags = NULL;
}
IOLockUnlock(priv->flags_lock);
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,3);
OurChangeNotifyInterestedDriversWillChange();
break;
default:
IOUnlock(priv->our_lock);
break;
}
}
void IOService::start_ack_timer ( void )
{
AbsoluteTime deadline;
clock_interval_to_deadline(ACK_TIMER_PERIOD, kNanosecondScale, &deadline);
thread_call_enter_delayed(priv->ackTimer, deadline);
}
void IOService::stop_ack_timer ( void )
{
thread_call_cancel(priv->ackTimer);
}
static void ack_timer_expired ( thread_call_param_t us)
{
((IOService *)us)->ack_timer_ticked();
}
static void settle_timer_expired ( thread_call_param_t us)
{
((IOService *)us)->settleTimerExpired();
}
IOReturn IOService::add_child_to_active_change ( IOPowerConnection * newObject )
{
if (! acquire_lock() )
{
return IOPMNoErr;
}
switch (priv->machine_state)
{
case kIOPM_OurChangeSetPowerState:
case kIOPM_ParentDownSetPowerState_Delayed:
case kIOPM_ParentUpSetPowerState_Delayed:
priv->head_note_pendingAcks += 2;
IOUnlock(priv->our_lock);
notifyChild(newObject, true);
if (! acquire_lock() )
{
--priv->head_note_pendingAcks;
return IOPMNoErr;
}
if ( --priv->head_note_pendingAcks == 0 )
{
stop_ack_timer();
IOUnlock(priv->our_lock);
all_acked();
return IOPMNoErr;
}
break;
case kIOPM_OurChangeFinish:
case kIOPM_ParentDownAcknowledgeChange_Delayed:
case kIOPM_ParentUpAcknowledgePowerChange_Delayed:
priv->head_note_pendingAcks += 2;
IOUnlock(priv->our_lock);
notifyChild(newObject, false);
if (! acquire_lock() )
{
--priv->head_note_pendingAcks;
return IOPMNoErr;
}
if ( --priv->head_note_pendingAcks == 0 )
{
stop_ack_timer();
IOUnlock(priv->our_lock);
all_acked();
return IOPMNoErr;
}
break;
}
IOUnlock(priv->our_lock);
return IOPMNoErr;
}
IOReturn IOService::add_driver_to_active_change ( IOPMinformee * newObject )
{
if (! acquire_lock() )
{
return IOPMNoErr;
}
switch (priv->machine_state) {
case kIOPM_OurChangeSetPowerState:
case kIOPM_ParentDownSetPowerState_Delayed:
case kIOPM_ParentUpSetPowerState_Delayed:
priv->head_note_pendingAcks += 2;
IOUnlock(priv->our_lock);
inform(newObject, true);
if (! acquire_lock() )
{
--priv->head_note_pendingAcks;
return IOPMNoErr;
}
if ( --priv->head_note_pendingAcks == 0 )
{
stop_ack_timer();
IOUnlock(priv->our_lock);
all_acked();
return IOPMNoErr;
}
break;
case kIOPM_OurChangeFinish:
case kIOPM_ParentDownAcknowledgeChange_Delayed:
case kIOPM_ParentUpAcknowledgePowerChange_Delayed:
priv->head_note_pendingAcks += 2;
IOUnlock(priv->our_lock);
inform(newObject, false);
if (! acquire_lock() ) {
--priv->head_note_pendingAcks;
return IOPMNoErr;
}
if ( --priv->head_note_pendingAcks == 0 ) {
stop_ack_timer();
IOUnlock(priv->our_lock);
all_acked();
return IOPMNoErr;
}
break;
}
IOUnlock(priv->our_lock);
return IOPMNoErr;
}
IOReturn IOService::start_parent_change ( unsigned long queue_head )
{
priv->head_note = queue_head;
priv->head_note_flags = priv-> changeList->changeNote[priv->head_note].flags;
priv->head_note_state = priv->changeList->changeNote[priv->head_note].newStateNumber;
priv->imminentState = priv->head_note_state;
priv->head_note_outputFlags = priv->changeList->changeNote[priv->head_note].outputPowerCharacter;
priv->head_note_domainState = priv->changeList->changeNote[priv->head_note].domainState;
priv->head_note_parent = priv->changeList->changeNote[priv->head_note].parent;
priv->head_note_capabilityFlags = priv->changeList->changeNote[priv->head_note].capabilityFlags;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartParentChange,
(unsigned long)priv->head_note_state,(unsigned long)pm_vars->myCurrentState);
ask_parent( priv->ourDesiredPowerState);
if ( priv->head_note_state < pm_vars->myCurrentState )
{
setParentInfo(priv->changeList->changeNote[priv->head_note].singleParentState,priv->head_note_parent);
priv->initial_change = false;
priv->machine_state = kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate;
if ( tellChangeDown1(priv->head_note_state) )
{
return ParentDownTellPriorityClientsPowerDown_Immediate();
}
return IOPMWillAckLater;
}
if ( priv->head_note_state > pm_vars->myCurrentState )
{
if ( priv->ourDesiredPowerState > pm_vars->myCurrentState )
{
if ( priv->ourDesiredPowerState < priv->head_note_state )
{
priv->head_note_state = priv->ourDesiredPowerState;
priv->imminentState = priv->head_note_state;
priv->head_note_outputFlags = pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter;
priv->head_note_capabilityFlags = pm_vars->thePowerStates[priv->head_note_state].capabilityFlags;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0);
}
} else {
priv->head_note_state = pm_vars->myCurrentState;
priv->imminentState = priv->head_note_state;
priv->head_note_outputFlags = pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter;
priv->head_note_capabilityFlags = pm_vars->thePowerStates[priv->head_note_state].capabilityFlags;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0);
}
}
if ( (priv->head_note_state > pm_vars->myCurrentState) &&
(priv->head_note_flags & IOPMDomainDidChange) )
{
priv->initial_change = false;
priv->machine_state = kIOPM_ParentUpSetPowerState_Delayed;
if ( notifyAll(true) == IOPMAckImplied ) {
return ParentUpSetPowerState_Immediate();
}
return IOPMWillAckLater;
}
all_done();
return IOPMAckImplied;
}
void IOService::start_our_change ( unsigned long queue_head )
{
priv->head_note = queue_head;
priv->head_note_flags = priv->changeList->changeNote[priv->head_note].flags;
priv->head_note_state = priv->changeList->changeNote[priv->head_note].newStateNumber;
priv->imminentState = priv->head_note_state;
priv->head_note_outputFlags = priv->changeList->changeNote[priv->head_note].outputPowerCharacter;
priv->head_note_capabilityFlags = priv->changeList->changeNote[priv->head_note].capabilityFlags;
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartDeviceChange,
(unsigned long)priv->head_note_state,(unsigned long)pm_vars->myCurrentState);
if ( priv->head_note_capabilityFlags & IOPMNotAttainable )
{
if ( ! priv->we_are_root )
{
ask_parent(priv->head_note_state);
}
priv-> head_note_flags |= IOPMNotDone;
all_done();
return;
}
if ( (pm_vars->maxCapability < priv->head_note_state) && (! priv->we_are_root) )
{
if ( ! priv->we_are_root )
{
ask_parent(priv->head_note_state);
}
priv->head_note_flags |= IOPMNotDone;
all_done();
return;
}
if ( ! priv->initial_change )
{
if ( priv->head_note_state == pm_vars->myCurrentState )
{
all_done();
return;
}
}
priv->initial_change = false;
if ( priv->head_note_state < pm_vars->myCurrentState )
{
priv->machine_state = kIOPM_OurChangeTellClientsPowerDown;
pm_vars->doNotPowerDown = false;
pm_vars->outofbandparameter = kNotifyApps;
if ( askChangeDown(priv->head_note_state) )
{
if ( pm_vars->doNotPowerDown )
{
tellNoChangeDown(priv->head_note_state);
priv-> head_note_flags |= IOPMNotDone;
all_done();
} else {
OurChangeTellClientsPowerDown();
}
}
} else {
if ( ! priv->we_are_root )
{
ask_parent(priv->head_note_state);
}
priv->machine_state = kIOPM_OurChangeSetPowerState;
if ( notifyAll(true) == IOPMAckImplied )
{
OurChangeSetPowerState();
}
}
}
IOReturn IOService::ask_parent ( unsigned long requestedState )
{
OSIterator *iter;
OSObject *next;
IOPowerConnection *connection;
IOService *parent;
unsigned long ourRequest = pm_vars->thePowerStates[requestedState].inputPowerRequirement;
if ( pm_vars->thePowerStates[requestedState].capabilityFlags & (kIOPMChildClamp | kIOPMPreventIdleSleep) )
{
ourRequest |= kIOPMPreventIdleSleep;
}
if ( pm_vars->thePowerStates[requestedState].capabilityFlags & (kIOPMChildClamp2 | kIOPMPreventSystemSleep) )
{
ourRequest |= kIOPMPreventSystemSleep;
}
if ( priv->previousRequest == ourRequest )
{
return IOPMNoErr;
}
if ( priv->we_are_root )
{
return IOPMNoErr;
}
priv->previousRequest = ourRequest;
iter = getParentIterator(gIOPowerPlane);
if ( iter )
{
while ( (next = iter->getNextObject()) )
{
if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
{
parent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
if ( parent ) {
if ( parent->requestPowerDomainState(ourRequest,connection,IOPMLowestState)!= IOPMNoErr )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDenied,
(unsigned long)priv->previousRequest,0);
}
parent->release();
}
}
}
iter->release();
}
return IOPMNoErr;
}
IOReturn IOService::instruct_driver ( unsigned long newState )
{
IOReturn delay;
if ( pm_vars->thePowerStates[newState].capabilityFlags & IOPMNotAttainable )
{
return IOPMAckImplied;
}
priv->driver_timer = -1;
OUR_PMLog( kPMLogProgramHardware, (UInt32) this, newState);
delay = pm_vars->theControllingDriver->setPowerState( newState,this );
OUR_PMLog((UInt32) -kPMLogProgramHardware, (UInt32) this, (UInt32) delay);
if ( delay == IOPMAckImplied )
{
priv->driver_timer = 0;
return IOPMAckImplied;
}
if ( priv->driver_timer == 0 )
{
return IOPMAckImplied;
}
if ( delay < 0 )
{
return IOPMAckImplied;
}
priv->driver_timer = (delay / ( ACK_TIMER_PERIOD / ns_per_us )) + 1;
return IOPMWillAckLater;
}
bool IOService::acquire_lock ( void )
{
long current_change_note;
current_change_note = priv->head_note;
if ( current_change_note == -1 ) {
return FALSE;
}
IOTakeLock(priv->our_lock);
if ( current_change_note == priv->head_note )
{
return TRUE;
} else {
IOUnlock(priv->our_lock);
return FALSE;
}
}
bool IOService::askChangeDown ( unsigned long stateNum )
{
return tellClientsWithResponse(kIOMessageCanDevicePowerOff);
}
bool IOService::tellChangeDown1 ( unsigned long stateNum )
{
pm_vars->outofbandparameter = kNotifyApps;
return tellChangeDown(stateNum);
}
bool IOService::tellChangeDown2 ( unsigned long stateNum )
{
pm_vars->outofbandparameter = kNotifyPriority;
return tellChangeDown(stateNum);
}
bool IOService::tellChangeDown ( unsigned long stateNum )
{
return tellClientsWithResponse(kIOMessageDeviceWillPowerOff);
}
bool IOService::tellClientsWithResponse ( int messageType )
{
struct context theContext;
AbsoluteTime deadline;
OSBoolean *aBool;
pm_vars->responseFlags = OSArray::withCapacity( 1 );
pm_vars->serialNumber += 1;
theContext.responseFlags = pm_vars->responseFlags;
theContext.serialNumber = pm_vars->serialNumber;
theContext.flags_lock = priv->flags_lock;
theContext.counter = 1;
theContext.msgType = messageType;
theContext.us = this;
theContext.maxTimeRequested = 0;
theContext.stateNumber = priv->head_note_state;
theContext.stateFlags = priv->head_note_capabilityFlags;
IOLockLock(priv->flags_lock);
aBool = OSBoolean::withBoolean(false);
theContext.responseFlags->setObject(0,aBool);
aBool->release();
IOLockUnlock(priv->flags_lock);
switch ( pm_vars->outofbandparameter ) {
case kNotifyApps:
applyToInterested(gIOAppPowerStateInterest,tellAppWithResponse,(void *)&theContext);
applyToInterested(gIOGeneralInterest,tellClientWithResponse,(void *)&theContext);
break;
case kNotifyPriority:
applyToInterested(gIOPriorityPowerStateInterest,tellClientWithResponse,(void *)&theContext);
break;
}
if (! acquire_lock() )
{
return true;
}
IOLockLock(priv->flags_lock);
aBool = OSBoolean::withBoolean(true);
theContext.responseFlags->replaceObject(0,aBool);
aBool->release();
IOLockUnlock(priv->flags_lock);
if ( ! checkForDone() )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,theContext.maxTimeRequested,0);
clock_interval_to_deadline(theContext.maxTimeRequested / 1000, kMillisecondScale, &deadline);
thread_call_enter_delayed(priv->ackTimer, deadline);
IOUnlock(priv->our_lock);
return false;
}
IOUnlock(priv->our_lock);
IOLockLock(priv->flags_lock);
pm_vars->responseFlags->release();
pm_vars->responseFlags = NULL;
IOLockUnlock(priv->flags_lock);
return true;
}
void tellAppWithResponse ( OSObject * object, void * context)
{
struct context *theContext = (struct context *)context;
OSBoolean *aBool;
IOPMprot *pm_vars = theContext->us->pm_vars;
if( OSDynamicCast( IOService, object) )
{
IOLockLock(theContext->flags_lock);
aBool = OSBoolean::withBoolean(true);
theContext->responseFlags->setObject(theContext->counter,aBool);
aBool->release();
IOLockUnlock(theContext->flags_lock);
const char *who = ((IOService *) object)->getName();
pm_vars->thePlatform->PMLog(who,
kPMLogClientAcknowledge, theContext->msgType, * (UInt32 *) object);
} else {
UInt32 refcon = ((theContext->serialNumber & 0xFFFF)<<16)
+ (theContext->counter & 0xFFFF);
IOLockLock(theContext->flags_lock);
aBool = OSBoolean::withBoolean(false);
theContext->responseFlags->setObject(theContext->counter,aBool);
aBool->release();
IOLockUnlock(theContext->flags_lock);
OUR_PMLog(kPMLogAppNotify, theContext->msgType, refcon);
theContext->us->messageClient(theContext->msgType,object,(void *)refcon);
if ( theContext->maxTimeRequested < k30seconds )
{
theContext->maxTimeRequested = k30seconds;
}
}
theContext->counter += 1;
}
void tellClientWithResponse ( OSObject * object, void * context)
{
struct context *theContext = (struct context *)context;
IOPowerStateChangeNotification notify;
UInt32 refcon;
IOReturn retCode;
OSBoolean *aBool;
OSObject *theFlag;
refcon = ((theContext->serialNumber & 0xFFFF)<<16) + (theContext->counter & 0xFFFF);
IOLockLock(theContext->flags_lock);
aBool = OSBoolean::withBoolean(false);
theContext->responseFlags->setObject(theContext->counter,aBool);
aBool->release();
IOLockUnlock(theContext->flags_lock);
IOPMprot *pm_vars = theContext->us->pm_vars;
if (gIOKitDebug & kIOLogPower) {
OUR_PMLog(kPMLogClientNotify, refcon, (UInt32) theContext->msgType);
if (OSDynamicCast(IOService, object)) {
const char *who = ((IOService *) object)->getName();
pm_vars->thePlatform->PMLog(who,
kPMLogClientNotify, * (UInt32 *) object, (UInt32) object);
} else if (OSDynamicCast(_IOServiceInterestNotifier, object)) {
_IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
OUR_PMLog(kPMLogClientNotify, (UInt32) n->handler, 0);
}
}
notify.powerRef = (void *)refcon;
notify.returnValue = 0;
notify.stateNumber = theContext->stateNumber;
notify.stateFlags = theContext->stateFlags;
retCode = theContext->us->messageClient(theContext->msgType,object,(void *)¬ify);
if ( retCode == kIOReturnSuccess )
{
if ( notify.returnValue == 0 )
{
IOLockLock(theContext->flags_lock);
aBool = OSBoolean::withBoolean(true);
theContext->responseFlags->replaceObject(theContext->counter,aBool);
aBool->release();
IOLockUnlock(theContext->flags_lock);
OUR_PMLog(kPMLogClientAcknowledge, refcon, (UInt32) object);
} else {
IOLockLock(theContext->flags_lock);
theFlag = theContext->responseFlags->getObject(theContext->counter);
if ( theFlag != 0 )
{
if ( ((OSBoolean *)theFlag)->isFalse() )
{
if ( theContext->maxTimeRequested < notify.returnValue )
{
theContext->maxTimeRequested = notify.returnValue;
}
}
}
IOLockUnlock(theContext->flags_lock);
}
} else {
OUR_PMLog(kPMLogClientAcknowledge, refcon, 0);
IOLockLock(theContext->flags_lock);
aBool = OSBoolean::withBoolean(true);
theContext->responseFlags->replaceObject(theContext->counter,aBool);
aBool->release();
IOLockUnlock(theContext->flags_lock);
}
theContext->counter += 1;
}
void IOService::tellNoChangeDown ( unsigned long )
{
return tellClients(kIOMessageDeviceWillNotPowerOff);
}
void IOService::tellChangeUp ( unsigned long )
{
return tellClients(kIOMessageDeviceHasPoweredOn);
}
void IOService::tellClients ( int messageType )
{
struct context theContext;
theContext.msgType = messageType;
theContext.us = this;
theContext.stateNumber = priv->head_note_state;
theContext.stateFlags = priv->head_note_capabilityFlags;
applyToInterested(gIOAppPowerStateInterest,tellClient,(void *)&theContext);
applyToInterested(gIOGeneralInterest,tellClient,(void *)&theContext);
}
void tellClient ( OSObject * object, void * context)
{
struct context *theContext = (struct context *)context;
IOPowerStateChangeNotification notify;
notify.powerRef = (void *) 0;
notify.returnValue = 0;
notify.stateNumber = theContext->stateNumber;
notify.stateFlags = theContext->stateFlags;
theContext->us->messageClient(theContext->msgType,object, ¬ify);
}
bool IOService::checkForDone ( void )
{
int i = 0;
OSObject *theFlag;
IOLockLock(priv->flags_lock);
if ( pm_vars->responseFlags == NULL )
{
IOLockUnlock(priv->flags_lock);
return true;
}
for ( i = 0; ; i++ )
{
theFlag = pm_vars->responseFlags->getObject(i);
if ( theFlag == NULL )
{
break;
}
if ( ((OSBoolean *)theFlag)->isFalse() )
{
IOLockUnlock(priv->flags_lock);
return false;
}
}
IOLockUnlock(priv->flags_lock);
return true;
}
bool IOService::responseValid ( unsigned long x )
{
UInt16 serialComponent;
UInt16 ordinalComponent;
OSObject * theFlag;
unsigned long refcon = (unsigned long)x;
OSBoolean * aBool;
serialComponent = (refcon>>16) & 0xFFFF;
ordinalComponent = refcon & 0xFFFF;
if ( serialComponent != pm_vars->serialNumber )
{
return false;
}
IOLockLock(priv->flags_lock);
if ( pm_vars->responseFlags == NULL )
{
IOLockUnlock(priv->flags_lock);
return false;
}
theFlag = pm_vars->responseFlags->getObject(ordinalComponent);
if ( theFlag == 0 )
{
IOLockUnlock(priv->flags_lock);
return false;
}
if ( ((OSBoolean *)theFlag)->isFalse() )
{
aBool = OSBoolean::withBoolean(true);
pm_vars->responseFlags->replaceObject(ordinalComponent,aBool);
aBool->release();
}
IOLockUnlock(priv->flags_lock);
return true;
}
IOReturn IOService::allowPowerChange ( unsigned long refcon )
{
if ( ! initialized )
{
return kIOReturnSuccess;
}
return pm_vars->PMcommandGate->runAction(serializedAllowPowerChange,(void *)refcon);
}
IOReturn serializedAllowPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
{
return ((IOService *)owner)->serializedAllowPowerChange2((unsigned long)refcon);
}
IOReturn IOService::serializedAllowPowerChange2 ( unsigned long refcon )
{
if ( ! responseValid(refcon) )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr5,refcon,0);
return kIOReturnSuccess;
}
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientAcknowledge,refcon,0);
return allowCancelCommon();
}
IOReturn IOService::cancelPowerChange ( unsigned long refcon )
{
if ( ! initialized )
{
return kIOReturnSuccess;
}
return pm_vars->PMcommandGate->runAction(serializedCancelPowerChange,(void *)refcon);
}
IOReturn serializedCancelPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
{
return ((IOService *)owner)->serializedCancelPowerChange2((unsigned long)refcon);
}
IOReturn IOService::serializedCancelPowerChange2 ( unsigned long refcon )
{
if ( ! responseValid(refcon) )
{
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr5,refcon,0);
return kIOReturnSuccess;
}
pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientCancel,refcon,0);
pm_vars->doNotPowerDown = true;
return allowCancelCommon();
}
IOReturn IOService::allowCancelCommon ( void )
{
if (! acquire_lock() )
{
return kIOReturnSuccess;
}
if ( checkForDone() )
{
stop_ack_timer();
IOUnlock(priv->our_lock);
IOLockLock(priv->flags_lock);
if ( pm_vars->responseFlags )
{
pm_vars->responseFlags->release();
pm_vars->responseFlags = NULL;
}
IOLockUnlock(priv->flags_lock);
switch (priv->machine_state) {
case kIOPM_OurChangeTellClientsPowerDown:
if ( ! pm_vars->doNotPowerDown )
{
OurChangeTellClientsPowerDown();
} else {
tellNoChangeDown(priv->head_note_state);
priv->head_note_flags |= IOPMNotDone;
all_done();
}
break;
case kIOPM_OurChangeTellPriorityClientsPowerDown:
OurChangeTellPriorityClientsPowerDown();
break;
case kIOPM_OurChangeNotifyInterestedDriversWillChange:
OurChangeNotifyInterestedDriversWillChange();
break;
case kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate:
ParentDownTellPriorityClientsPowerDown_Delayed();
break;
case kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed:
ParentDownNotifyInterestedDriversWillChange_Delayed();
break;
}
} else {
IOUnlock(priv->our_lock);
}
return kIOReturnSuccess;
}
#if 0
static void c_PM_Clamp_Timer_Expired (OSObject * client, IOTimerEventSource *)
{
if (client)
((IOService *)client)->PM_Clamp_Timer_Expired ();
}
#endif
void IOService::PM_Clamp_Timer_Expired (void)
{
#if 0
if ( ! initialized )
{
return;
}
changePowerStateToPriv (0);
#endif
}
#define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
void IOService::clampPowerOn (unsigned long duration)
{
#if 0
changePowerStateToPriv (pm_vars->theNumberOfPowerStates-1);
if ( priv->clampTimerEventSrc == NULL ) {
priv->clampTimerEventSrc = IOTimerEventSource::timerEventSource(this,
c_PM_Clamp_Timer_Expired);
IOWorkLoop * workLoop = getPMworkloop ();
if ( !priv->clampTimerEventSrc || !workLoop ||
( workLoop->addEventSource( priv->clampTimerEventSrc) != kIOReturnSuccess) ) {
}
}
priv->clampTimerEventSrc->setTimeout(300*USEC_PER_SEC, USEC_PER_SEC);
#endif
}
IOReturn IOService::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice )
{
return IOPMNoErr;
}
unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
{
int i;
if (pm_vars->theNumberOfPowerStates == 0 )
{
return 0;
}
for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- )
{
if ( (domainState & pm_vars->thePowerStates[i].inputPowerRequirement) == pm_vars->thePowerStates[i].inputPowerRequirement )
{
return i;
}
}
return 0;
}
unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
{
int i;
if (pm_vars->theNumberOfPowerStates == 0 )
{
return 0;
}
for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- )
{
if ( (domainState & pm_vars->thePowerStates[i].inputPowerRequirement) == pm_vars->thePowerStates[i].inputPowerRequirement )
{
return i;
}
}
return 0;
}
unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
{
int i;
if (pm_vars->theNumberOfPowerStates == 0 )
{
return 0;
}
for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- )
{
if ( (domainState & pm_vars->thePowerStates[i].inputPowerRequirement) == pm_vars->thePowerStates[i].inputPowerRequirement )
{
return i;
}
}
return 0;
}
bool IOService::didYouWakeSystem ( void )
{
return false;
}
IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService*)
{
return 0;
}
IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService*)
{
return 0;
}
void IOService::powerChangeDone ( unsigned long )
{
}
IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
{
return IOPMNoErr;
}
#undef super
#define super OSObject
OSDefineMetaClassAndStructors(IOPMprot, OSObject)
bool IOPMprot::serialize(OSSerialize *s) const
{
OSString * theOSString;
char * buffer;
char * ptr;
int buf_size;
int i;
bool rtn_code;
buf_size = 150 + (275 * (int)theNumberOfPowerStates) + 100;
buffer = ptr = IONew(char, buf_size);
if(!buffer)
return false;
ptr += sprintf(ptr,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates);
if ( theNumberOfPowerStates != 0 ) {
ptr += sprintf(ptr,"version %d, ",(unsigned int)thePowerStates[0].version);
}
if ( theNumberOfPowerStates != 0 ) {
for ( i = 0; i < (int)theNumberOfPowerStates; i++ ) {
ptr += sprintf(ptr, "power state %d = { ",i);
ptr += sprintf(ptr,"capabilityFlags %08x, ",(unsigned int)thePowerStates[i].capabilityFlags);
ptr += sprintf(ptr,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates[i].outputPowerCharacter);
ptr += sprintf(ptr,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates[i].inputPowerRequirement);
ptr += sprintf(ptr,"staticPower %d, ",(unsigned int)thePowerStates[i].staticPower);
ptr += sprintf(ptr,"unbudgetedPower %d, ",(unsigned int)thePowerStates[i].unbudgetedPower);
ptr += sprintf(ptr,"powerToAttain %d, ",(unsigned int)thePowerStates[i].powerToAttain);
ptr += sprintf(ptr,"timeToAttain %d, ",(unsigned int)thePowerStates[i].timeToAttain);
ptr += sprintf(ptr,"settleUpTime %d, ",(unsigned int)thePowerStates[i].settleUpTime);
ptr += sprintf(ptr,"timeToLower %d, ",(unsigned int)thePowerStates[i].timeToLower);
ptr += sprintf(ptr,"settleDownTime %d, ",(unsigned int)thePowerStates[i].settleDownTime);
ptr += sprintf(ptr,"powerDomainBudget %d }, ",(unsigned int)thePowerStates[i].powerDomainBudget);
}
}
ptr += sprintf(ptr,"aggressiveness = %d, ",(unsigned int)aggressiveness);
ptr += sprintf(ptr,"myCurrentState = %d, ",(unsigned int)myCurrentState);
ptr += sprintf(ptr,"parentsCurrentPowerFlags = %08x, ",(unsigned int)parentsCurrentPowerFlags);
ptr += sprintf(ptr,"maxCapability = %d }",(unsigned int)maxCapability);
theOSString = OSString::withCString(buffer);
rtn_code = theOSString->serialize(s);
theOSString->release();
IODelete(buffer, char, buf_size);
return rtn_code;
}
#undef super
#define super OSObject
OSDefineMetaClassAndStructors(IOPMpriv, OSObject)
bool IOPMpriv::serialize(OSSerialize *s) const
{
OSString * theOSString;
bool rtn_code;
char * buffer;
char * ptr;
IOPMinformee * nextObject;
buffer = ptr = IONew(char, 2000);
if(!buffer)
return false;
ptr += sprintf(ptr,"{ this object = %08x",(unsigned int)owner);
if ( we_are_root ) {
ptr += sprintf(ptr," (root)");
}
ptr += sprintf(ptr,", ");
nextObject = interestedDrivers->firstInList(); while ( nextObject != NULL ) {
ptr += sprintf(ptr,"interested driver = %08x, ",(unsigned int)nextObject->whatObject);
nextObject = interestedDrivers->nextInList(nextObject);
}
if ( machine_state != kIOPM_Finished ) {
ptr += sprintf(ptr,"machine_state = %d, ",(unsigned int)machine_state);
ptr += sprintf(ptr,"driver_timer = %d, ",(unsigned int)driver_timer);
ptr += sprintf(ptr,"settle_time = %d, ",(unsigned int)settle_time);
ptr += sprintf(ptr,"head_note_flags = %08x, ",(unsigned int)head_note_flags);
ptr += sprintf(ptr,"head_note_state = %d, ",(unsigned int)head_note_state);
ptr += sprintf(ptr,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags);
ptr += sprintf(ptr,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState);
ptr += sprintf(ptr,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags);
ptr += sprintf(ptr,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks);
}
if ( device_overrides ) {
ptr += sprintf(ptr,"device overrides, ");
}
ptr += sprintf(ptr,"driverDesire = %d, ",(unsigned int)driverDesire);
ptr += sprintf(ptr,"deviceDesire = %d, ",(unsigned int)deviceDesire);
ptr += sprintf(ptr,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState);
ptr += sprintf(ptr,"previousRequest = %d }",(unsigned int)previousRequest);
theOSString = OSString::withCString(buffer);
rtn_code = theOSString->serialize(s);
theOSString->release();
IODelete(buffer, char, 2000);
return rtn_code;
}