]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp
xnu-344.23.tar.gz
[apple/xnu.git] / iokit / Drivers / platform / drvAppleRootDomain / RootDomain.cpp
index f3373a0dc8c74bd1951105331b59e3949d108c84..4378b4ee7edfedc2a19719d2b6d061a48a66d5f7 100644 (file)
@@ -1,4 +1,4 @@
-/*
+   /*
  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * @APPLE_LICENSE_HEADER_END@
  */
 #include <IOKit/IOWorkLoop.h>
-#include <IOKit/IOCommandQueue.h>
+#include <IOKit/IOCommandGate.h>
 #include <IOKit/IOTimerEventSource.h>
 #include <IOKit/IOPlatformExpert.h>
+#include <IOKit/IOKitDebug.h>
+#include <IOKit/IOTimeStamp.h>
 #include <IOKit/pwr_mgt/RootDomain.h>
-#include <IOKit/pwr_mgt/IOPM.h>
+#include <IOKit/pwr_mgt/IOPMPrivate.h>
 #include <IOKit/IOMessage.h>
 #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;
     }
@@ -733,9 +842,11 @@ void IOPMrootDomain::tellNoChangeDown ( unsigned long )
 // type to the client or application being notified.
 //*********************************************************************************
 
-void IOPMrootDomain::tellChangeUp ( unsigned long )
+void IOPMrootDomain::tellChangeUp ( unsigned long stateNum)
 {
-    return tellClients(kIOMessageSystemHasPoweredOn);
+    if ( stateNum == ON_STATE ) {
+        return tellClients(kIOMessageSystemHasPoweredOn);
+    }
 }
 
 //*********************************************************************************
@@ -777,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
@@ -811,8 +937,6 @@ IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon,
         case kIOMessageSystemWillSleep:
             rootDomain->powerOverrideOnPriv();         // start ignoring children's requests
                                                         // (fall through to other cases)
-        case kIOMessageSystemWillPowerOff:
-        case kIOMessageSystemWillRestart:
 
             // Interested applications have been notified of an impending power
             // change and have acked (when applicable).
@@ -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 );
@@ -839,6 +963,12 @@ IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon,
                 thread_call_enter1(rootDomain->diskSyncCalloutEntry, (thread_call_param_t)params->powerRef);
             ret = kIOReturnSuccess;
             break;
+
+        case kIOMessageSystemWillPowerOff:
+        case kIOMessageSystemWillRestart:
+            ret = kIOReturnUnsupported;
+            break;
+
         default:
             ret = kIOReturnUnsupported;
             break;
@@ -894,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();
             }