X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/fa4905b191e0d16b0fffd53bd565eca71d01fae0..de355530ae67247cbd0da700edb3a2a1dae884c2:/iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp diff --git a/iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp b/iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp index ebc0a8b23..4378b4ee7 100644 --- a/iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp +++ b/iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp @@ -1,4 +1,4 @@ -/* + /* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ @@ -20,23 +20,34 @@ * @APPLE_LICENSE_HEADER_END@ */ #include -#include +#include #include #include +#include +#include #include -#include +#include #include #include "RootDomainUserClient.h" #include "IOKit/pwr_mgt/IOPowerConnection.h" -extern "C" { -extern void kprintf(const char *, ...); -} +extern "C" void kprintf(const char *, ...); extern const IORegistryPlane * gIOPowerPlane; -void PMreceiveCmd ( OSObject *, void *, void *, void *, void * ); +// debug trace function +static inline void +ioSPMTrace(unsigned int csc, + unsigned int a = 0, unsigned int b = 0, + unsigned int c = 0, unsigned int d = 0) +{ + if (gIOKitDebug & kIOLogTracePower) + IOTimeStampConstant(IODBG_POWER(csc), a, b, c, d); +} + +IOReturn broadcast_aggressiveness ( OSObject *, void *, void *, void *, void * ); static void sleepTimerExpired(thread_call_param_t); +static void wakeupClamshellTimerExpired ( thread_call_param_t us); #define number_of_power_states 5 @@ -186,6 +197,8 @@ static void disk_sync_callout(thread_call_param_t p0, thread_call_param_t p1) bool IOPMrootDomain::start ( IOService * nub ) { + OSDictionary *tmpDict; + super::start(nub); gRootDomain = this; @@ -201,15 +214,15 @@ bool IOPMrootDomain::start ( IOService * nub ) canSleep = true; wrangler = NULL; sleepASAP = false; + ignoringClamshellDuringWakeup = false; + tmpDict = OSDictionary::withCapacity(1); + setProperty(kRootDomainSupportedFeatures, tmpDict); + tmpDict->release(); + pm_vars->PMworkloop = IOWorkLoop::workLoop(); // make the workloop - pm_vars->commandQueue = IOCommandQueue::commandQueue(this, PMreceiveCmd); // make a command queue - if (! pm_vars->commandQueue || - ( pm_vars->PMworkloop->addEventSource( pm_vars->commandQueue) != kIOReturnSuccess) ) { - return IOPMNoErr; - } extraSleepTimer = thread_call_allocate((thread_call_func_t)sleepTimerExpired, (thread_call_param_t) this); - + clamshellWakeupIgnore = thread_call_allocate((thread_call_func_t)wakeupClamshellTimerExpired, (thread_call_param_t) this); diskSyncCalloutEntry = thread_call_allocate(&disk_sync_callout, (thread_call_param_t) this); patriarch = new IORootParent; // create our parent @@ -235,6 +248,27 @@ bool IOPMrootDomain::start ( IOService * nub ) return true; } +// ********************************************************************************** +// setProperties +// +// Receive a setProperty call +// The "System Boot" property means the system is completely booted. +// ********************************************************************************** +IOReturn IOPMrootDomain::setProperties ( OSObject *props_obj) +{ + OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj); + + if(!dict) return kIOReturnBadArgument; + + if(dict->getObject(OSString::withCString("System Boot Complete"))) { + systemBooting = false; + kprintf("IOPM: received System Boot Complete property"); + adjustPowerState(); + } + + return kIOReturnSuccess; +} + //********************************************************************************* // youAreRoot @@ -252,46 +286,58 @@ IOReturn IOPMrootDomain::youAreRoot ( void ) // ********************************************************************************** // command_received // -// We have received a command from ourselves on the command queue. -// If it is to send a recently-received aggressiveness factor, do so. -// Otherwise, it's something the superclass enqueued. +// No longer used // ********************************************************************************** -void IOPMrootDomain::command_received ( void * command, void * x, void * y, void * z ) +void IOPMrootDomain::command_received ( void * w, void * x, void * y, void * z ) { - switch ( (int)command ) { - case kIOPMBroadcastAggressiveness: - - super::setAggressiveness((unsigned long)x,(unsigned long)y); + super::command_received(w,x,y,z); +} - // Save user's spin down timer to restore after we replace it for idle sleep - if( (int)x == kPMMinutesToSpinDown ) user_spindown = (unsigned int) y; - // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer - longestNonSleepSlider = pm_vars->current_aggressiveness_values[kPMMinutesToDim]; +// ********************************************************************************** +// broadcast_aggressiveness +// +// ********************************************************************************** +IOReturn broadcast_aggressiveness ( OSObject * root, void * x, void * y, void *, void * ) +{ + ((IOPMrootDomain *)root)->broadcast_it((unsigned long)x,(unsigned long)y); + return IOPMNoErr; +} - if ( (int)x == kPMMinutesToSleep ) { - if ( (sleepSlider == 0) && ((int)y != 0) ) { - sleepSlider = (int)y; - adjustPowerState(); // idle sleep is now enabled, maybe sleep now - } - sleepSlider = (int)y; - if ( sleepSlider == 0 ) { - adjustPowerState(); // idle sleep is now disabled - patriarch->wakeSystem(); // make sure we're powered - } - } - if ( sleepSlider > longestNonSleepSlider ) { - extraSleepDelay = sleepSlider - longestNonSleepSlider ; - } - else { - extraSleepDelay = 0; - } - break; - - default: - super::command_received(command,x,y,z); - break; +// ********************************************************************************** +// broadcast_it +// +// We are behind the command gate to broadcast an aggressiveness factor. We let the +// superclass do it, but we need to snoop on factors that affect idle sleep. +// ********************************************************************************** +void IOPMrootDomain::broadcast_it (unsigned long type, unsigned long value) +{ + super::setAggressiveness(type,value); + + // Save user's spin down timer to restore after we replace it for idle sleep + if( type == kPMMinutesToSpinDown ) user_spindown = value; + + // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer + longestNonSleepSlider = pm_vars->current_aggressiveness_values[kPMMinutesToDim]; + + + if ( type == kPMMinutesToSleep ) { + if ( (sleepSlider == 0) && (value != 0) ) { + sleepSlider = value; + adjustPowerState(); // idle sleep is now enabled, maybe sleep now + } + sleepSlider = value; + if ( sleepSlider == 0 ) { + adjustPowerState(); // idle sleep is now disabled + patriarch->wakeSystem(); // make sure we're powered + } + } + if ( sleepSlider > longestNonSleepSlider ) { + extraSleepDelay = sleepSlider - longestNonSleepSlider ; + } + else { + extraSleepDelay = 0; } } @@ -305,6 +351,12 @@ static void sleepTimerExpired ( thread_call_param_t us) ((IOPMrootDomain *)us)->handleSleepTimerExpiration(); } + +static void wakeupClamshellTimerExpired ( thread_call_param_t us) +{ + ((IOPMrootDomain *)us)->stopIgnoringClamshellEventsDuringWakeup(); +} + // ********************************************************************************** // handleSleepTimerExpiration @@ -323,11 +375,21 @@ void IOPMrootDomain::handleSleepTimerExpiration ( void ) } +void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void) +{ + OSObject * state; + + // Allow clamshell-induced sleep now + ignoringClamshellDuringWakeup = false; + + if ((state = getProperty(kAppleClamshellStateKey))) + publishResource(kAppleClamshellStateKey, state); +} + //********************************************************************************* // setAggressiveness // -// Some aggressiveness factor has changed. We put this change on our -// command queue so that we can broadcast it to the hierarchy while on +// Some aggressiveness factor has changed. We broadcast it to the hierarchy while on // the Power Mangement workloop thread. This enables objects in the // hierarchy to successfully alter their idle timers, which are all on the // same thread. @@ -335,13 +397,9 @@ void IOPMrootDomain::handleSleepTimerExpiration ( void ) IOReturn IOPMrootDomain::setAggressiveness ( unsigned long type, unsigned long newLevel ) { - if ( systemBooting && (type == kPMMinutesToDim) ) { - systemBooting = false; // when the login window launches, this method gets called -- system booting is done. - IOLog("Root power domain receiving initial preferences\n"); - adjustPowerState(); + if ( pm_vars->PMcommandGate ) { + pm_vars->PMcommandGate->runAction(broadcast_aggressiveness,(void *)type,(void *)newLevel); } - - pm_vars->commandQueue->enqueueCommand(true, (void *)kIOPMBroadcastAggressiveness, (void *) type, (void *) newLevel ); return kIOReturnSuccess; } @@ -412,17 +470,32 @@ void IOPMrootDomain::powerChangeDone ( unsigned long previousState ) idleSleepPending = false; // re-enable this timer for next sleep IOLog("System Sleep\n"); pm_vars->thePlatform->sleepKernel(); // sleep now - - // now we're waking + + ioSPMTrace(IOPOWER_WAKE, * (int *) this); // now we're waking + clock_interval_to_deadline(30, kSecondScale, &deadline); // stay awake for at least 30 seconds thread_call_enter_delayed(extraSleepTimer, deadline); idleSleepPending = true; // this gets turned off when we sleep again + + // Ignore closed clamshell during wakeup and for a few seconds + // after wakeup is complete + ignoringClamshellDuringWakeup = true; + gSleepOrShutdownPending = 0; // sleep transition complete patriarch->wakeSystem(); // get us some power IOLog("System Wake\n"); systemWake(); // tell the tree we're waking - + + // Allow drivers to request extra processing time before clamshell + // sleep if kIOREMSleepEnabledKey is present. + // Ignore clamshell events for at least 5 seconds + if(getProperty(kIOREMSleepEnabledKey)) { + // clamshellWakeupIgnore callout clears ignoreClamshellDuringWakeup bit + clock_interval_to_deadline(5, kSecondScale, &deadline); + if(clamshellWakeupIgnore) thread_call_enter_delayed(clamshellWakeupIgnore, deadline); + } else ignoringClamshellDuringWakeup = false; + propertyPtr = OSDynamicCast(OSNumber,getProperty("WakeEvent")); if ( propertyPtr ) { // find out what woke us theProperty = propertyPtr->unsigned16BitValue(); @@ -486,6 +559,21 @@ void IOPMrootDomain::wakeFromDoze( void ) } +// ********************************************************************************** +// publishFeature +// +// Adds a new feature to the supported features dictionary +// +// +// ********************************************************************************** +void IOPMrootDomain::publishFeature( const char * feature ) +{ + OSDictionary *features = (OSDictionary *)getProperty(kRootDomainSupportedFeatures); + + features->setObject(feature, kOSBooleanTrue); +} + + // ********************************************************************************** // newUserClient // @@ -520,6 +608,32 @@ IOReturn IOPMrootDomain::newUserClient( task_t owningTask, void * /* security_ IOReturn IOPMrootDomain::receivePowerNotification (UInt32 msg) { + if (msg & kIOPMOverTemp) { + IOLog("Power Management received emergency overtemp signal. Going to sleep."); + (void) sleepSystem (); + } + if (msg & kIOPMSetDesktopMode) { + desktopMode = (0 != (msg & kIOPMSetValue)); + msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue); + } + if (msg & kIOPMSetACAdaptorConnected) { + acAdaptorConnect = (0 != (msg & kIOPMSetValue)); + msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue); + } + if (msg & kIOPMEnableClamshell) { + ignoringClamshell = false; + } + if (msg & kIOPMDisableClamshell) { + ignoringClamshell = true; + } + + if (msg & kIOPMProcessorSpeedChange) { + IOService *pmu = waitForService(serviceMatching("ApplePMU")); + pmu->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0); + pm_vars->thePlatform->sleepKernel(); + pmu->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0); + } + if (msg & kIOPMSleepNow) { (void) sleepSystem (); } @@ -529,16 +643,11 @@ IOReturn IOPMrootDomain::receivePowerNotification (UInt32 msg) } if (msg & kIOPMClamshellClosed) { - if ( ! ignoringClamshell ) { - (void) sleepSystem (); - } - } + if ( !ignoringClamshell && !ignoringClamshellDuringWakeup + && (!desktopMode || !acAdaptorConnect) ) { - if (msg & kIOPMEnableClamshell) { - ignoringClamshell = false; - } - if (msg & kIOPMDisableClamshell) { - ignoringClamshell = true; + (void) sleepSystem (); + } } if (msg & kIOPMPowerButton) { // toggle state of sleep/wake @@ -643,7 +752,7 @@ IOReturn IOPMrootDomain::requestPowerDomainState ( IOPMPowerFlags desiredState, } iter->release(); } - + if ( (extraSleepDelay == 0) && (powerRequestFlag == 0) ) { sleepASAP = true; } @@ -779,14 +888,29 @@ void IOPMrootDomain::setQuickSpinDownTimeout ( void ) void IOPMrootDomain::restoreUserSpinDownTimeout ( void ) { - if(systemBooting) { - IOLog("!!!!! WARNING !!!!! restoreUserSpinDownTimeout called too early\n"); - } - //IOLog("restoreUserSpinDownTimeout, user_spindown = %u\n", user_spindown); - super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)user_spindown); } +//********************************************************************************* +// changePowerStateTo & changePowerStateToPriv +// +// Override of these methods for logging purposes. +//********************************************************************************* + +IOReturn IOPMrootDomain::changePowerStateTo ( unsigned long ordinal ) +{ + ioSPMTrace(IOPOWER_ROOT, * (int *) this, (int) true, (int) ordinal); + + return super::changePowerStateTo(ordinal); +} + +IOReturn IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal ) +{ + ioSPMTrace(IOPOWER_ROOT, * (int *) this, (int) false, (int) ordinal); + + return super::changePowerStateToPriv(ordinal); +} + //********************************************************************************* // sysPowerDownHandler @@ -830,7 +954,7 @@ IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon, // Another option is not to schedule the thread and wait for // ack timeout... AbsoluteTime deadline; - clock_interval_to_deadline( 15, kSecondScale, &deadline ); + clock_interval_to_deadline( 30, kSecondScale, &deadline ); thread_call_enter1_delayed( rootDomain->diskSyncCalloutEntry, (thread_call_param_t)params->powerRef, deadline ); @@ -842,6 +966,7 @@ IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon, case kIOMessageSystemWillPowerOff: case kIOMessageSystemWillRestart: + ret = kIOReturnUnsupported; break; default: @@ -899,7 +1024,8 @@ IOReturn IOPMrootDomain::displayWranglerNotification( void * target, void * refC } else { // accelerate disk spin down if spin down timer is non-zero (zero = never spin down) - if(0 != rootDomain->user_spindown) + // and if system sleep is non-Never + if( (0 != rootDomain->user_spindown) && (0 != rootDomain->sleepSlider) ) rootDomain->setQuickSpinDownTimeout(); }