]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOPMrootDomain.cpp
xnu-3248.60.10.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
index 60f3ec07acc147928283d3e90242a4711cbf4b79..9a5ccd20bc70603c99d5d5892f873b2582dc82ef 100644 (file)
@@ -32,6 +32,7 @@
 #include <IOKit/IOWorkLoop.h>
 #include <IOKit/IOCommandGate.h>
 #include <IOKit/IOPlatformExpert.h>
+#include <IOKit/IOCPU.h>
 #include <IOKit/IOKitDebug.h>
 #include <IOKit/IOTimeStamp.h>
 #include <IOKit/pwr_mgt/IOPMlog.h>
 #include <IOKit/IODeviceTreeSupport.h>
 #include <IOKit/IOMessage.h>
 #include <IOKit/IOReturn.h>
+#include <IOKit/IONVRAM.h>
 #include "RootDomainUserClient.h"
 #include "IOKit/pwr_mgt/IOPowerConnection.h"
 #include "IOPMPowerStateQueue.h"
 #include <IOKit/IOCatalogue.h>
+#include <IOKit/IOReportMacros.h>
+#include "IOKitKernelInternal.h"
 #if HIBERNATION
 #include <IOKit/IOHibernatePrivate.h>
 #endif
+#include <console/video_console.h>
 #include <sys/syslog.h>
 #include <sys/sysctl.h>
+#include <sys/vnode.h>
+#include <sys/vnode_internal.h>
+#include <sys/fcntl.h>
+
 #include <sys/time.h>
-#include "IOServicePrivate.h"  // _IOServiceInterestNotifier
+#include "IOServicePrivate.h"   // _IOServiceInterestNotifier
 #include "IOServicePMPrivate.h"
 
 __BEGIN_DECLS
 #include <mach/shared_region.h>
+#include <kern/clock.h>
 __END_DECLS
 
 #if defined(__i386__) || defined(__x86_64__)
@@ -66,6 +76,7 @@ __END_DECLS
 #define kIOPMrootDomainClass    "IOPMrootDomain"
 #define LOG_PREFIX              "PMRD: "
 
+
 #define MSG(x...) \
     do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
 
@@ -73,8 +84,16 @@ __END_DECLS
     do { kprintf(LOG_PREFIX x); } while (false)
 
 #define DLOG(x...)  do { \
-       if (kIOLogPMRootDomain & gIOKitDebug) \
-        kprintf(LOG_PREFIX x); } while (false)
+    if (kIOLogPMRootDomain & gIOKitDebug) \
+        kprintf(LOG_PREFIX x); \
+} while (false)
+
+#define DMSG(x...)  do { \
+    if (kIOLogPMRootDomain & gIOKitDebug) { \
+        kprintf(LOG_PREFIX x); IOLog(x); \
+    } \
+} while (false)
+
 
 #define _LOG(x...)
 
@@ -108,7 +127,9 @@ do {                                                        \
 #define CAP_HIGHEST(c)  \
         ((_highestCapability & (c)) != 0)
 
-#define DARK_TO_FULL_EVALUATE_CLAMSHELL     0
+#if defined(__i386__) || defined(__x86_64__)
+#define DARK_TO_FULL_EVALUATE_CLAMSHELL     1
+#endif
 
 // Event types for IOPMPowerStateQueue::submitPowerEvent()
 enum {
@@ -124,7 +145,8 @@ enum {
     kPowerEventAssertionRelease,                // 10
     kPowerEventAssertionSetLevel,               // 11
     kPowerEventQueueSleepWakeUUID,              // 12
-    kPowerEventPublishSleepWakeUUID             // 13
+    kPowerEventPublishSleepWakeUUID,            // 13
+    kPowerEventSetDisplayPowerOn                // 14
 };
 
 // For evaluatePolicy()
@@ -138,15 +160,21 @@ enum {
     kStimulusDarkWakeActivityTickle,    // 5
     kStimulusDarkWakeEntry,             // 6
     kStimulusDarkWakeReentry,           // 7
-    kStimulusDarkWakeEvaluate           // 8
+    kStimulusDarkWakeEvaluate,          // 8
+    kStimulusNoIdleSleepPreventers,     // 9
+    kStimulusEnterUserActiveState,      // 10
+    kStimulusLeaveUserActiveState       // 11
 };
 
 extern "C" {
 IOReturn OSKextSystemSleepOrWake( UInt32 );
 }
+extern "C" ppnum_t      pmap_find_phys(pmap_t pmap, addr64_t va);
+extern "C" addr64_t     kvtophys(vm_offset_t va);
+extern "C" int  stack_snapshot_from_kernel(pid_t pid, void *buf, uint32_t size, uint32_t flags, unsigned *bytesTraced);
 
 static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
-static void notifySystemShutdown( IOService * root, unsigned long event );
+static void notifySystemShutdown( IOService * root, uint32_t messageType );
 static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
 static void pmEventTimeStamp(uint64_t *recordTS);
 
@@ -157,18 +185,24 @@ static const OSSymbol *sleepMessagePEFunction   = NULL;
 #define kIOSleepSupportedKey        "IOSleepSupported"
 #define kIOPMSystemCapabilitiesKey  "System Capabilities"
 
+#define kIORequestWranglerIdleKey   "IORequestIdle"
+#define kDefaultWranglerIdlePeriod  25 // in milliseconds
+
+#define kIOSleepWakeDebugKey        "Persistent-memory-note"
+
 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
                            | kIOPMSupportedOnBatt \
                            | kIOPMSupportedOnUPS)
 
-enum 
-{
-    // not idle around autowake time, secs
-    kAutoWakePreWindow  = 45,
-    kAutoWakePostWindow = 15
-};
+#define kLocalEvalClamshellCommand  (1 << 15)
+#define kIdleSleepRetryInterval     (3 * 60)
 
-#define kLocalEvalClamshellCommand        (1 << 15)
+enum {
+    kWranglerPowerStateMin   = 0,
+    kWranglerPowerStateSleep = 2,
+    kWranglerPowerStateDim   = 3,
+    kWranglerPowerStateMax   = 4
+};
 
 enum {
     OFF_STATE           = 0,
@@ -185,23 +219,30 @@ enum {
 static IOPMPowerState ourPowerStates[NUM_POWER_STATES] =
 {
     {1, 0,                      0,              0,             0,0,0,0,0,0,0,0},
-    {1, kIOPMRestartCapability,        kIOPMRestart,   RESTART_POWER, 0,0,0,0,0,0,0,0},        
+    {1, kIOPMRestartCapability, kIOPMRestart,   RESTART_POWER, 0,0,0,0,0,0,0,0},
     {1, kIOPMSleepCapability,   kIOPMSleep,     SLEEP_POWER,   0,0,0,0,0,0,0,0},
     {1, kIOPMPowerOn,           kIOPMPowerOn,   ON_POWER,      0,0,0,0,0,0,0,0}
 };
 
-#define kIOPMRootDomainWakeTypeMaintenance  "Maintenance"
-#define kIOPMRootDomainWakeTypeSleepTimer   "SleepTimer"
-#define kIOPMrootDomainWakeTypeLowBattery   "LowBattery"
-#define kIOPMRootDomainWakeTypeUser         "User"
-#define kIOPMRootDomainWakeTypeAlarm        "Alarm"
-#define kIOPMRootDomainWakeTypeNetwork      "Network"
+#define kIOPMRootDomainWakeTypeSleepService     "SleepService"
+#define kIOPMRootDomainWakeTypeMaintenance      "Maintenance"
+#define kIOPMRootDomainWakeTypeSleepTimer       "SleepTimer"
+#define kIOPMrootDomainWakeTypeLowBattery       "LowBattery"
+#define kIOPMRootDomainWakeTypeUser             "User"
+#define kIOPMRootDomainWakeTypeAlarm            "Alarm"
+#define kIOPMRootDomainWakeTypeNetwork          "Network"
+#define kIOPMRootDomainWakeTypeHIDActivity      "HID Activity"
+#define kIOPMRootDomainWakeTypeNotification     "Notification"
+#define kIOPMRootDomainWakeTypeHibernateError   "HibernateError"
 
 // Special interest that entitles the interested client from receiving
 // all system messages. Only used by powerd.
 //
 #define kIOPMSystemCapabilityInterest       "IOPMSystemCapabilityInterest"
 
+#define WAKEEVENT_LOCK()        IOLockLock(wakeEventLock)
+#define WAKEEVENT_UNLOCK()      IOLockUnlock(wakeEventLock)
+
 /*
  * Aggressiveness
  */
@@ -254,10 +295,9 @@ enum {
     kDarkWakeFlagHIDTickleLate       = 0x02, // hid tickle after gfx suppression
     kDarkWakeFlagHIDTickleNone       = 0x03, // hid tickle is not posted
     kDarkWakeFlagHIDTickleMask       = 0x03,
-    kDarkWakeFlagIgnoreDiskIOInDark  = 0x04, // ignore disk idle in DW
-    kDarkWakeFlagIgnoreDiskIOAlways  = 0x08, // always ignore disk idle
-    kDarkWakeFlagIgnoreDiskIOMask    = 0x0C,
-    kDarkWakeFlagAlarmIsDark         = 0x0100
+    kDarkWakeFlagAlarmIsDark         = 0x0100,
+    kDarkWakeFlagGraphicsPowerState1 = 0x0200,
+    kDarkWakeFlagAudioNotSuppressed  = 0x0400
 };
 
 static IOPMrootDomain * gRootDomain;
@@ -267,12 +307,38 @@ static UInt32           gWillShutdown = 0;
 static UInt32           gPagingOff = 0;
 static UInt32           gSleepWakeUUIDIsSet = false;
 static uint32_t         gAggressivesState = 0;
+
+uuid_string_t bootsessionuuid_string;
+
 static uint32_t         gDarkWakeFlags = kDarkWakeFlagHIDTickleNone;
-static bool             gRAMDiskImageBoot = false;
+static uint32_t         gNoIdleFlag = 0;
+static PMStatsStruct    gPMStats;
+
+#if HIBERNATION
+static IOPMSystemSleepPolicyHandler     gSleepPolicyHandler = 0;
+static IOPMSystemSleepPolicyVariables * gSleepPolicyVars = 0;
+static void *                           gSleepPolicyTarget;
+#endif
 
 struct timeval gIOLastSleepTime;
 struct timeval gIOLastWakeTime;
 
+static char gWakeReasonString[128];
+static bool gWakeReasonSysctlRegistered = false;
+
+#if defined(__i386__) || defined(__x86_64__)
+static bool gSpinDumpBufferFull = false;
+#endif
+
+static unsigned int     gPMHaltBusyCount;
+static unsigned int     gPMHaltIdleCount;
+static int              gPMHaltDepth;
+static uint32_t         gPMHaltMessageType;
+static IOLock *         gPMHaltLock  = 0;
+static OSArray *        gPMHaltArray = 0;
+static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
+static bool             gPMQuiesced;
+
 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
 #define kCPUUnknownIndex    9999999
 enum {
@@ -284,6 +350,10 @@ enum {
 const OSSymbol *gIOPMStatsApplicationResponseTimedOut;
 const OSSymbol *gIOPMStatsApplicationResponseCancel;
 const OSSymbol *gIOPMStatsApplicationResponseSlow;
+const OSSymbol *gIOPMStatsApplicationResponsePrompt;
+const OSSymbol *gIOPMStatsDriverPSChangeSlow;
+
+#define kBadPMFeatureID     0
 
 /*
  * PMSettingHandle
@@ -296,7 +366,7 @@ class PMSettingHandle : public OSObject
 
 private:
     PMSettingObject *pmso;
-    void free(void);
+    void free(void) APPLE_KEXT_OVERRIDE;
 };
 
 /*
@@ -320,7 +390,7 @@ private:
     uint32_t                        settingCount;
     bool                            disabled;
 
-    void free(void);
+    void free(void) APPLE_KEXT_OVERRIDE;
 
 public:
     static PMSettingObject *pmSettingObject(
@@ -346,74 +416,6 @@ struct PMSettingCallEntry {
 #define PMSETTING_WAIT(p)   IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
 
-//*********************************************************************************
-//*********************************************************************************
-//*********************************************************************************
-
-/* @class IOPMTimeline
- * @astract Tracks & records PM activity.
- * @discussion Intended for use only as a helper-class to IOPMrootDomain.
- *      Do not subclass or directly invoke iOPMTimeline
- */
-class IOPMTimeline : public OSObject 
-{
-    OSDeclareDefaultStructors( IOPMTimeline );
-
-public:  
-    static IOPMTimeline* timeline(IOPMrootDomain *root_domain);
-  
-    bool            setProperties(OSDictionary *d);
-    OSDictionary    *copyInfoDictionary(void);
-    
-    IOReturn    recordSystemPowerEvent( PMEventDetails *details );
-                                
-    IOReturn    recordDetailedPowerEvent( PMEventDetails *details );
-
-    IOMemoryDescriptor      *getPMTraceMemoryDescriptor();
-    
-    uint32_t getNumEventsLoggedThisPeriod();    
-    void     setNumEventsLoggedThisPeriod(uint32_t newCount);
-    bool     isSleepCycleInProgress();
-    void     setSleepCycleInProgressFlag(bool flag);
-private:
-    bool        init(void);
-    void        free(void);
-
-    void        setEventsTrackedCount(uint32_t newTracked);
-    void        setEventsRecordingLevel(uint32_t eventsTrackedBits);
-    static uint32_t _atomicIndexIncrement(uint32_t *index, uint32_t limit);
-    
-    enum {
-        kPMTimelineRecordTardyDrivers   = 1 << 0,
-        kPMTmielineRecordSystemEvents   = 1 << 1,
-        kPMTimelineRecordAllDrivers     = 1 << 2,
-        kPMTimelineRecordOff            = 0,
-        kPMTimelineRecordDefault        = 3,
-        kPMTimelineRecordDebug          = 7    
-    };
-
-    // eventsRecordingLevel is a bitfield defining which PM driver events will get logged
-    // into the PM buffer. 
-    uint32_t                    eventsRecordingLevel;
-    
-    // pmTraceMemoryDescriptor represents the memory block that IOPMTimeLine records PM trace points into.
-    IOBufferMemoryDescriptor    *pmTraceMemoryDescriptor;
-
-    // Pointer to starting address in pmTraceMemoryDescriptor
-    IOPMSystemEventRecord       *traceBuffer;
-    IOPMTraceBufferHeader       *hdr;
-
-    uint16_t                    systemState;
-    
-    IOLock                      *logLock;
-    IOPMrootDomain              *owner;
-
-    uint32_t                    numEventsLoggedThisPeriod;
-    bool                        sleepCycleInProgress;
-};
-
-OSDefineMetaClassAndStructors( IOPMTimeline, OSObject )
-
 /*
  * PMTraceWorker
  * Internal helper object for logging trace points to RTC
@@ -438,10 +440,11 @@ public:
     void                        traceLoginWindowPhase(uint8_t phase);
     int                         recordTopLevelPCIDevice(IOService *);
     void                        RTC_TRACE(void);
-    virtual bool                               serialize(OSSerialize *s) const;
+    virtual bool                serialize(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
 
     IOPMTracePointHandler       tracePointHandler;
     void *                      tracePointTarget;
+    uint64_t                    getPMStatusCode();
 private:
     IOPMrootDomain              *owner;
     IOLock                      *pciMappingLock;
@@ -463,7 +466,7 @@ class PMAssertionsTracker : public OSObject
     OSDeclareFinalStructors(PMAssertionsTracker)
 public:
     static PMAssertionsTracker  *pmAssertionsTracker( IOPMrootDomain * );
-    
+
     IOReturn                    createAssertion(IOPMDriverAssertionType, IOPMDriverAssertionLevel, IOService *, const char *, IOPMDriverAssertionID *);
     IOReturn                    releaseAssertion(IOPMDriverAssertionID);
     IOReturn                    setAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
@@ -487,6 +490,7 @@ private:
         uint64_t                    modifiedTime;
         const OSSymbol              *ownerString;
         IOService                   *ownerService;
+        uint64_t                    registryEntryID;
         IOPMDriverAssertionLevel    level;
     } PMAssertStruct;
 
@@ -495,7 +499,7 @@ private:
 
     PMAssertStruct              *detailsForID(IOPMDriverAssertionID, int *);
     void                        tabulate(void);
+
     IOPMrootDomain              *owner;
     OSArray                     *assertionsArray;
     IOLock                      *assertionsArrayLock;
@@ -504,9 +508,9 @@ private:
     IOPMDriverAssertionType     assertionsUser;
     IOPMDriverAssertionType     assertionsCombined;
 };
+
 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
+
 /*
  * PMHaltWorker
  * Internal helper object for Shutdown/Restart notifications.
@@ -530,7 +534,7 @@ public:
     static  void main( void * arg, wait_result_t waitResult );
     static  void work( PMHaltWorker * me );
     static  void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
-    virtual void free( void );
+    virtual void free( void ) APPLE_KEXT_OVERRIDE;
 };
 
 OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
@@ -543,12 +547,12 @@ static void IOPMRootDomainWillShutdown(void)
 {
     if (OSCompareAndSwap(0, 1, &gWillShutdown))
     {
-       OSKext::willShutdown();
-       for (int i = 0; i < 100; i++)
-       {
-           if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break;
-           IOSleep( 100 );
-       }
+    OSKext::willShutdown();
+    for (int i = 0; i < 100; i++)
+    {
+        if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break;
+        IOSleep( 100 );
+    }
     }
 }
 
@@ -573,12 +577,12 @@ extern "C"
     {
         return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
     }
-    
+
     IOReturn rootDomainRestart ( void )
     {
         return gRootDomain->restartSystem();
     }
-    
+
     IOReturn rootDomainShutdown ( void )
     {
         return gRootDomain->shutdownSystem();
@@ -586,16 +590,17 @@ extern "C"
 
     void IOSystemShutdownNotification(void)
     {
-       IOPMRootDomainWillShutdown();
-               if (OSCompareAndSwap(0, 1, &gPagingOff))
-               {
-#if !CONFIG_EMBEDDED
-                       gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
+        IOPMRootDomainWillShutdown();
+#if HIBERNATION
+        IOHibernateSystemPostWake();
 #endif
-               }
+        if (OSCompareAndSwap(0, 1, &gPagingOff))
+        {
+            gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
+        }
     }
 
-    int sync_internal(void);    
+    int sync_internal(void);
 }
 
 /*
@@ -653,6 +658,27 @@ IOPMrootDomain * IOPMrootDomain::construct( void )
     return( root );
 }
 
+//******************************************************************************
+// updateConsoleUsersCallout
+//
+//******************************************************************************
+
+static void updateConsoleUsersCallout(thread_call_param_t p0, thread_call_param_t p1)
+{
+    IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
+    rootDomain->updateConsoleUsers();
+}
+
+void IOPMrootDomain::updateConsoleUsers(void)
+{
+    IOService::updateConsoleUsers(NULL, kIOMessageSystemHasPoweredOn);
+    if (tasksSuspended)
+    {
+        tasksSuspended = FALSE;
+        tasks_system_suspend(tasksSuspended);
+    }
+}
+
 //******************************************************************************
 
 static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
@@ -665,15 +691,15 @@ static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
 
     if (ON_STATE == powerState)
     {
-#if    HIBERNATION
-        IOHibernateSystemSleep();
-#endif
         sync_internal();
     }
-#if    HIBERNATION
+#if HIBERNATION
     else
     {
         IOHibernateSystemPostWake();
+
+        if (gRootDomain)
+            gRootDomain->sleepWakeDebugSaveSpinDumpFile();
     }
 #endif
 
@@ -683,19 +709,33 @@ static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
 
 //******************************************************************************
 
+static void hib_debugSetup_callout( thread_call_param_t p0, thread_call_param_t p1 )
+{
+    IOService * rootDomain = (IOService *) p0;
+    uint32_t    notifyRef  = (uint32_t)(uintptr_t) p1;
+
+#if    HIBERNATION
+    IOOpenDebugDataFile(kSleepWakeStackBinFilename, SWD_BUF_SIZE);
+#endif
+
+    rootDomain->allowPowerChange(notifyRef);
+    DLOG("hib_debugSetup_callout finish\n");
+}
+//******************************************************************************
+
 static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
 {
-       AbsoluteTime    endTime;
-       UInt64                  nano = 0;
+    AbsoluteTime    endTime;
+    UInt64          nano = 0;
 
-       clock_get_uptime(&endTime);
-       if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
-       {
-               SUB_ABSOLUTETIME(&endTime, startTime);
-               absolutetime_to_nanoseconds(endTime, &nano);
-       }
+    clock_get_uptime(&endTime);
+    if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
+    {
+        SUB_ABSOLUTETIME(&endTime, startTime);
+        absolutetime_to_nanoseconds(endTime, &nano);
+    }
 
-       return (UInt32)(nano / 1000000ULL);
+    return (UInt32)(nano / 1000000ULL);
 }
 
 //******************************************************************************
@@ -707,7 +747,7 @@ sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
   struct proc *p = req->p;
 
   if (p == kernproc) {
-    return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);    
+    return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
   } else if(proc_is64bit(p)) {
     struct user64_timeval t;
     t.tv_sec = swt->tv_sec;
@@ -722,12 +762,12 @@ sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
 }
 
 static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
-           CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
-           &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
+        CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+        &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
 
 static SYSCTL_PROC(_kern, OID_AUTO, waketime,
-           CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
-           &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
+        CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+        &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
 
 
 static int
@@ -737,19 +777,20 @@ sysctl_willshutdown
     int new_value, changed;
     int error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
     if (changed) {
-       if (!gWillShutdown && (new_value == 1)) {
-           IOPMRootDomainWillShutdown();
-       } else
-           error = EINVAL;
+    if (!gWillShutdown && (new_value == 1)) {
+        IOPMRootDomainWillShutdown();
+    } else
+        error = EINVAL;
     }
     return(error);
 }
 
 static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
-           CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
-           0, 0, sysctl_willshutdown, "I", "");
+        CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+        0, 0, sysctl_willshutdown, "I", "");
+
+extern struct sysctl_oid sysctl__kern_iokittest;
 
-#if !CONFIG_EMBEDDED
 
 static int
 sysctl_progressmeterenable
@@ -758,10 +799,9 @@ sysctl_progressmeterenable
     int error;
     int new_value, changed;
 
-    error = sysctl_io_number(req, vc_progress_meter_enable, sizeof(int), &new_value, &changed);
+    error = sysctl_io_number(req, vc_progressmeter_enable, sizeof(int), &new_value, &changed);
 
-    if (changed)
-       vc_enable_progressmeter(new_value);
+    if (changed) vc_enable_progressmeter(new_value);
 
     return (error);
 }
@@ -773,64 +813,150 @@ sysctl_progressmeter
     int error;
     int new_value, changed;
 
-    error = sysctl_io_number(req, vc_progress_meter_value, sizeof(int), &new_value, &changed);
+    error = sysctl_io_number(req, vc_progressmeter_value, sizeof(int), &new_value, &changed);
 
-    if (changed)
-       vc_set_progressmeter(new_value);
+    if (changed) vc_set_progressmeter(new_value);
 
     return (error);
 }
 
 static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
-           CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
-           0, 0, sysctl_progressmeterenable, "I", "");
+        CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+        0, 0, sysctl_progressmeterenable, "I", "");
 
 static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
-           CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
-           0, 0, sysctl_progressmeter, "I", "");
+        CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+        0, 0, sysctl_progressmeter, "I", "");
 
-#endif
+
+
+
+static int
+sysctl_consoleoptions
+(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
+{
+    int error, changed;
+    uint32_t new_value;
+
+    error = sysctl_io_number(req, vc_user_options.options, sizeof(uint32_t), &new_value, &changed);
+
+    if (changed) vc_user_options.options = new_value;
+
+    return (error);
+}
+
+static SYSCTL_PROC(_kern, OID_AUTO, consoleoptions,
+        CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+        0, 0, sysctl_consoleoptions, "I", "");
+
+
+static int
+sysctl_progressoptions SYSCTL_HANDLER_ARGS
+{
+    return sysctl_io_opaque(req, &vc_user_options, sizeof(vc_user_options), NULL);
+}
+
+static SYSCTL_PROC(_kern, OID_AUTO, progressoptions,
+        CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
+        NULL, 0, sysctl_progressoptions, "S,vc_progress_user_options", "");
+
+
+static int
+sysctl_wakereason SYSCTL_HANDLER_ARGS
+{
+    char wr[ sizeof(gWakeReasonString) ];
+
+    wr[0] = '\0';
+    if (gRootDomain)
+        gRootDomain->copyWakeReasonString(wr, sizeof(wr));
+
+    return sysctl_io_string(req, wr, 0, 0, NULL);
+}
+
+SYSCTL_PROC(_kern, OID_AUTO, wakereason,
+    CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    NULL, 0, sysctl_wakereason, "A", "wakereason");
+
+static int
+sysctl_targettype SYSCTL_HANDLER_ARGS
+{
+    IOService * root;
+    OSObject *  obj;
+    OSData *    data;
+    char        tt[32];
+
+    tt[0] = '\0';
+    root = IOService::getServiceRoot();
+    if (root && (obj = root->copyProperty(gIODTTargetTypeKey)))
+    {
+       if ((data = OSDynamicCast(OSData, obj)))
+       {
+           strlcpy(tt, (const char *) data->getBytesNoCopy(), sizeof(tt));
+       }
+       obj->release();
+    }
+    return sysctl_io_string(req, tt, 0, 0, NULL);
+}
+
+SYSCTL_PROC(_hw, OID_AUTO, targettype,
+    CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    NULL, 0, sysctl_targettype, "A", "targettype");
 
 static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
+static SYSCTL_INT(_debug, OID_AUTO, noidle, CTLFLAG_RW, &gNoIdleFlag, 0, "");
 
+static const OSSymbol * gIOPMSettingAutoWakeCalendarKey;
 static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
 static const OSSymbol * gIOPMSettingDebugWakeRelativeKey;
 static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
+static const OSSymbol * gIOPMSettingSleepServiceWakeCalendarKey;
+static const OSSymbol * gIOPMSettingSilentRunningKey;
+static const OSSymbol * gIOPMUserTriggeredFullWakeKey;
+static const OSSymbol * gIOPMUserIsActiveKey;
 
 //******************************************************************************
 // start
 //
 //******************************************************************************
 
-#define kRootDomainSettingsCount        16
+#define kRootDomainSettingsCount        17
 
 bool IOPMrootDomain::start( IOService * nub )
 {
     OSIterator      *psIterator;
     OSDictionary    *tmpDict;
     IORootParent *   patriarch;
+#if defined(__i386__) || defined(__x86_64__)
+    IONotifier   *   notifier;
+#endif
 
     super::start(nub);
 
     gRootDomain = this;
+    gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey);
     gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
     gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
-    gIOPMSettingMaintenanceWakeCalendarKey =
-        OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
+    gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
+    gIOPMSettingSleepServiceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey);
+    gIOPMSettingSilentRunningKey = OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey);
+    gIOPMUserTriggeredFullWakeKey = OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey);
+    gIOPMUserIsActiveKey = OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey);
 
     gIOPMStatsApplicationResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
     gIOPMStatsApplicationResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
     gIOPMStatsApplicationResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
+    gIOPMStatsApplicationResponsePrompt = OSSymbol::withCString(kIOPMStatsResponsePrompt);
+    gIOPMStatsDriverPSChangeSlow = OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow);
 
     sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
     sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage");
 
-    const OSSymbol  *settingsArr[kRootDomainSettingsCount] = 
+    const OSSymbol  *settingsArr[kRootDomainSettingsCount] =
         {
             OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
             gIOPMSettingAutoWakeSecondsKey,
             OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
-            OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey),
+            gIOPMSettingAutoWakeCalendarKey,
             OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
             gIOPMSettingDebugWakeRelativeKey,
             OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
@@ -842,21 +968,12 @@ bool IOPMrootDomain::start( IOService * nub )
             OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
             OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
             OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
-            OSSymbol::withCString(kIOPMStateConsoleShutdown)
+            OSSymbol::withCString(kIOPMStateConsoleShutdown),
+            gIOPMSettingSilentRunningKey
         };
 
     PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
-    
-    IORegistryEntry * chosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
-    if (chosenEntry)
-    {
-        if (chosenEntry->getProperty("boot-ramdmg-size") &&
-            chosenEntry->getProperty("boot-ramdmg-extents"))
-        {
-            gRAMDiskImageBoot = true;
-        }
-        chosenEntry->release();
-    }
+    PE_parse_boot_argn("noidle", &gNoIdleFlag, sizeof(gNoIdleFlag));
 
     queue_init(&aggressivesQueue);
     aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
@@ -865,8 +982,9 @@ bool IOPMrootDomain::start( IOService * nub )
 
     featuresDictLock = IOLockAlloc();
     settingsCtrlLock = IOLockAlloc();
+    wakeEventLock = IOLockAlloc();
     setPMRootDomain(this);
-    
+
     extraSleepTimer = thread_call_allocate(
                         idleSleepTimerExpired,
                         (thread_call_param_t) this);
@@ -874,10 +992,24 @@ bool IOPMrootDomain::start( IOService * nub )
     diskSyncCalloutEntry = thread_call_allocate(
                         &disk_sync_callout,
                         (thread_call_param_t) this);
-    
+    hibDebugSetupEntry = thread_call_allocate(
+                        &hib_debugSetup_callout,
+                        (thread_call_param_t) this);
+
+    updateConsoleUsersEntry = thread_call_allocate(
+                        &updateConsoleUsersCallout,
+                        (thread_call_param_t) this);
+
+#if DARK_TO_FULL_EVALUATE_CLAMSHELL
+    fullWakeThreadCall = thread_call_allocate(
+                            OSMemberFunctionCast(thread_call_func_t, this,
+                                &IOPMrootDomain::fullWakeDelayedWork),
+                            (thread_call_param_t) this);
+#endif
+
     setProperty(kIOSleepSupportedKey, true);
 
-    bzero(&pmStats, sizeof(pmStats));
+    bzero(&gPMStats, sizeof(gPMStats));
 
     pmTracer = PMTraceWorker::tracer(this);
 
@@ -892,6 +1024,14 @@ bool IOPMrootDomain::start( IOService * nub )
     clamshellExists    = false;
     clamshellDisabled  = true;
     acAdaptorConnected = true;
+    clamshellSleepDisabled = false;
+    gWakeReasonString[0] = '\0';
+
+    // Initialize to user active.
+    // Will never transition to user inactive w/o wrangler.
+    fullWakeReason = kFullWakeReasonLocalUser;
+    userIsActive = userWasActive = true;
+    setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
 
     // Set the default system capabilities at boot.
     _currentCapability = kIOPMSystemCapabilityCPU      |
@@ -905,20 +1045,24 @@ bool IOPMrootDomain::start( IOService * nub )
     setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
 
     queuedSleepWakeUUIDString = NULL;
+    initializeBootSessionUUID();
     pmStatsAppResponses     = OSArray::withCapacity(5);
     _statsNameKey           = OSSymbol::withCString(kIOPMStatsNameKey);
     _statsPIDKey            = OSSymbol::withCString(kIOPMStatsPIDKey);
     _statsTimeMSKey         = OSSymbol::withCString(kIOPMStatsTimeMSKey);
     _statsResponseTypeKey   = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
     _statsMessageTypeKey    = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
+    _statsPowerCapsKey      = OSSymbol::withCString(kIOPMStatsPowerCapabilityKey);
+    assertOnWakeSecs        = -1;  // Invalid value to prevent updates
 
+    pmStatsLock = IOLockAlloc();
     idxPMCPUClamshell = kCPUUnknownIndex;
     idxPMCPULimitedPower = kCPUUnknownIndex;
-        
+
     tmpDict = OSDictionary::withCapacity(1);
     setProperty(kRootDomainSupportedFeatures, tmpDict);
     tmpDict->release();
-    
+
     settingsCallbacks = OSDictionary::withCapacity(1);
 
     // Create a list of the valid PM settings that we'll relay to
@@ -927,8 +1071,15 @@ bool IOPMrootDomain::start( IOService * nub )
                     (const OSObject **)settingsArr,
                     kRootDomainSettingsCount,
                     0);
-                    
+
+    // List of PM settings that should not automatically publish itself
+    // as a feature when registered by a listener.
+    noPublishPMSettings = OSArray::withObjects(
+                    (const OSObject **) &gIOPMSettingSilentRunningKey, 1, 0);
+
     fPMSettingsDict = OSDictionary::withCapacity(5);
+    preventIdleSleepList = OSSet::withCapacity(8);
+    preventSystemSleepList = OSSet::withCapacity(2);
 
     PMinit();   // creates gIOPMWorkLoop
 
@@ -952,21 +1103,6 @@ bool IOPMrootDomain::start( IOService * nub )
     registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
     changePowerStateToPriv(ON_STATE);
 
-    if (gIOKitDebug & (kIOLogDriverPower1 | kIOLogDriverPower2))
-    {
-        // Setup our PM logging & recording code
-        timeline = IOPMTimeline::timeline(this);    
-        if (timeline) {
-            OSDictionary *tlInfo = timeline->copyInfoDictionary();
-            
-            if (tlInfo) 
-            {
-                setProperty(kIOPMTimelineDictionaryKey, tlInfo);
-                tlInfo->release();
-            }
-        }
-    }
-
     // install power change handler
     gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
 
@@ -974,14 +1110,38 @@ bool IOPMrootDomain::start( IOService * nub )
     // Register for a notification when IODisplayWrangler is published
     if ((tmpDict = serviceMatching("IODisplayWrangler")))
     {
-        _displayWranglerNotifier = addMatchingNotification( 
-                gIOPublishNotification, tmpDict, 
+        _displayWranglerNotifier = addMatchingNotification(
+                gIOPublishNotification, tmpDict,
                 (IOServiceMatchingNotificationHandler) &displayWranglerMatchPublished,
                 this, 0);
         tmpDict->release();
     }
 #endif
 
+#if defined(__i386__) || defined(__x86_64__)
+
+    if ((tmpDict = serviceMatching("IODTNVRAM")))
+    {
+        notifier = addMatchingNotification(
+                gIOFirstPublishNotification, tmpDict,
+                (IOServiceMatchingNotificationHandler) &IONVRAMMatchPublished,
+                this, 0);
+        tmpDict->release();
+    }
+
+    wranglerIdleSettings = NULL;
+    OSNumber * wranglerIdlePeriod = NULL;
+    wranglerIdleSettings = OSDictionary::withCapacity(1);
+    wranglerIdlePeriod  = OSNumber::withNumber(kDefaultWranglerIdlePeriod, 32);
+
+    if(wranglerIdleSettings && wranglerIdlePeriod)
+        wranglerIdleSettings->setObject(kIORequestWranglerIdleKey,
+                                        wranglerIdlePeriod);
+
+    if(wranglerIdlePeriod)
+        wranglerIdlePeriod->release();
+#endif
+
     const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
     setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
     ucClassName->release();
@@ -989,7 +1149,10 @@ bool IOPMrootDomain::start( IOService * nub )
     // IOBacklightDisplay can take a long time to load at boot, or it may
     // not load at all if you're booting with clamshell closed. We publish
     // 'DisplayDims' here redundantly to get it published early and at all.
-    psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") );
+    OSDictionary * matching;
+    matching = serviceMatching("IOPMPowerSource");
+    psIterator = getMatchingServices( matching );
+    if (matching) matching->release();
     if( psIterator && psIterator->getNextObject() )
     {
         // There's at least one battery on the system, so we publish
@@ -1003,16 +1166,20 @@ bool IOPMrootDomain::start( IOService * nub )
     sysctl_register_oid(&sysctl__kern_sleeptime);
     sysctl_register_oid(&sysctl__kern_waketime);
     sysctl_register_oid(&sysctl__kern_willshutdown);
-#if !CONFIG_EMBEDDED
+    sysctl_register_oid(&sysctl__kern_iokittest);
+    sysctl_register_oid(&sysctl__hw_targettype);
+
     sysctl_register_oid(&sysctl__kern_progressmeterenable);
     sysctl_register_oid(&sysctl__kern_progressmeter);
-#endif /* !CONFIG_EMBEDDED */
+    sysctl_register_oid(&sysctl__kern_wakereason);
+    sysctl_register_oid(&sysctl__kern_consoleoptions);
+    sysctl_register_oid(&sysctl__kern_progressoptions);
 
-#if    HIBERNATION
+#if HIBERNATION
     IOHibernateSystemInit(this);
 #endif
 
-    registerService();                                         // let clients find us
+    registerService();                      // let clients find us
 
     return true;
 }
@@ -1030,10 +1197,9 @@ IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
     OSDictionary    *dict = OSDynamicCast(OSDictionary, props_obj);
     OSBoolean       *b;
     OSNumber        *n;
-    OSDictionary    *d;
-    OSSymbol        *type;
+    const OSSymbol  *key;
     OSObject        *obj;
-    unsigned int    i;
+    OSCollectionIterator * iter = 0;
 
     const OSSymbol *publish_simulated_battery_string    = OSSymbol::withCString("SoftwareSimulatedBatteries");
     const OSSymbol *boot_complete_string                = OSSymbol::withCString("System Boot Complete");
@@ -1044,180 +1210,176 @@ IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
     const OSSymbol *sleepdisabled_string                = OSSymbol::withCString("SleepDisabled");
     const OSSymbol *ondeck_sleepwake_uuid_string        = OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
     const OSSymbol *loginwindow_tracepoint_string       = OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey);
-    const OSSymbol *pmTimelineLogging_string            = OSSymbol::withCString(kIOPMTimelineDictionaryKey);
-#if    HIBERNATION
+#if HIBERNATION
     const OSSymbol *hibernatemode_string                = OSSymbol::withCString(kIOHibernateModeKey);
     const OSSymbol *hibernatefile_string                = OSSymbol::withCString(kIOHibernateFileKey);
+    const OSSymbol *hibernatefilemin_string            = OSSymbol::withCString(kIOHibernateFileMinSizeKey);
+    const OSSymbol *hibernatefilemax_string            = OSSymbol::withCString(kIOHibernateFileMaxSizeKey);
     const OSSymbol *hibernatefreeratio_string           = OSSymbol::withCString(kIOHibernateFreeRatioKey);
     const OSSymbol *hibernatefreetime_string            = OSSymbol::withCString(kIOHibernateFreeTimeKey);
 #endif
 
-    if (!dict) 
+    if (!dict)
     {
         return_value = kIOReturnBadArgument;
         goto exit;
     }
 
-    if ((b = OSDynamicCast(OSBoolean, dict->getObject(publish_simulated_battery_string))))
+    iter = OSCollectionIterator::withCollection(dict);
+    if (!iter)
     {
-        publishResource(publish_simulated_battery_string, kOSBooleanTrue);
-    }
-
-    if ((n = OSDynamicCast(OSNumber, dict->getObject(idle_seconds_string))))
-    {
-        setProperty(idle_seconds_string, n);
-        idleSeconds = n->unsigned32BitValue();
+        return_value = kIOReturnNoMemory;
+        goto exit;
     }
 
-    if (boot_complete_string && dict->getObject(boot_complete_string)) 
-    {
-        pmPowerStateQueue->submitPowerEvent( kPowerEventSystemBootCompleted );
-    }
-    
-    if( battery_warning_disabled_string && dict->getObject(battery_warning_disabled_string))
-    {
-        setProperty( battery_warning_disabled_string, dict->getObject(battery_warning_disabled_string));
-    }
-    
-    if (pmTimelineLogging_string && (d = OSDynamicCast(OSDictionary, dict->getObject(pmTimelineLogging_string))))
+    while ((key = (const OSSymbol *) iter->getNextObject()) &&
+           (obj = dict->getObject(key)))
     {
-        if (timeline && timeline->setProperties(d)) 
+        if (key->isEqualTo(publish_simulated_battery_string))
         {
-            OSDictionary *tlInfo = timeline->copyInfoDictionary();            
-            if (tlInfo) {
-                setProperty(kIOPMTimelineDictionaryKey, tlInfo);
-                tlInfo->release();
+            if (OSDynamicCast(OSBoolean, obj))
+                publishResource(key, kOSBooleanTrue);
+        }
+        else if (key->isEqualTo(idle_seconds_string))
+        {
+            if ((n = OSDynamicCast(OSNumber, obj)))
+            {
+                setProperty(key, n);
+                idleSeconds = n->unsigned32BitValue();
             }
         }
-    }
-
-    if( sys_shutdown_string && (b = OSDynamicCast(OSBoolean, dict->getObject(sys_shutdown_string)))) 
-    {
-        pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
-    }
-    
-    if( stall_halt_string && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) ) 
-    {
-        setProperty(stall_halt_string, b);
-    }
-
-#if    HIBERNATION
-    if ( hibernatemode_string
-        && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
-    {
-       setProperty(hibernatemode_string, n);
-    }
-    if ( hibernatefreeratio_string
-        && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
-    {
-        setProperty(hibernatefreeratio_string, n);
-    }
-    if ( hibernatefreetime_string
-        && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
-    {
-        setProperty(hibernatefreetime_string, n);
-    }    
-    OSString *str;
-    if ( hibernatefile_string
-        && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
-    {
-        setProperty(hibernatefile_string, str);
-    }
+        else if (key->isEqualTo(boot_complete_string))
+        {
+            pmPowerStateQueue->submitPowerEvent(kPowerEventSystemBootCompleted);
+        }
+        else if (key->isEqualTo(sys_shutdown_string))
+        {
+            if ((b = OSDynamicCast(OSBoolean, obj)))
+                pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
+        }
+        else if (key->isEqualTo(battery_warning_disabled_string))
+        {
+            setProperty(key, obj);
+        }
+#if HIBERNATION
+        else if (key->isEqualTo(hibernatemode_string) ||
+                 key->isEqualTo(hibernatefilemin_string) ||
+                 key->isEqualTo(hibernatefilemax_string) ||
+                 key->isEqualTo(hibernatefreeratio_string) ||
+                 key->isEqualTo(hibernatefreetime_string))
+        {
+            if ((n = OSDynamicCast(OSNumber, obj)))
+                setProperty(key, n);
+        }
+        else if (key->isEqualTo(hibernatefile_string))
+        {
+            OSString * str = OSDynamicCast(OSString, obj);
+            if (str) setProperty(key, str);
+        }
 #endif
-    
-    if( sleepdisabled_string
-        && (b = OSDynamicCast(OSBoolean, dict->getObject(sleepdisabled_string))) )
-    {
-        setProperty(sleepdisabled_string, b);
-        pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
-    }
-    if (ondeck_sleepwake_uuid_string
-        && (obj = dict->getObject(ondeck_sleepwake_uuid_string)))
-    {
-        if(pmPowerStateQueue) {
+        else if (key->isEqualTo(sleepdisabled_string))
+        {
+            if ((b = OSDynamicCast(OSBoolean, obj)))
+            {
+                setProperty(key, b);
+                pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
+            }
+        }
+        else if (key->isEqualTo(ondeck_sleepwake_uuid_string))
+        {
             obj->retain();
             pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
         }
-
-    }
-    
-    if (loginwindow_tracepoint_string
-        && (n = OSDynamicCast(OSNumber, dict->getObject(loginwindow_tracepoint_string)))
-        && pmTracer)
-    {
-        pmTracer->traceLoginWindowPhase( n->unsigned8BitValue() );
-    }
-
-    if ((b = OSDynamicCast(OSBoolean, dict->getObject(kIOPMDeepSleepEnabledKey))))
-    {
-        setProperty(kIOPMDeepSleepEnabledKey, b);
-    }
-    if ((n = OSDynamicCast(OSNumber, dict->getObject(kIOPMDeepSleepDelayKey))))
-    {
-        setProperty(kIOPMDeepSleepDelayKey, n);
-    }
-    if ((b = OSDynamicCast(OSBoolean, dict->getObject(kIOPMDestroyFVKeyOnStandbyKey))))
-    {
-        setProperty(kIOPMDestroyFVKeyOnStandbyKey, b);
-    }
-
-    // Relay our allowed PM settings onto our registered PM clients
-    for(i = 0; i < allowedPMSettings->getCount(); i++) {
-
-        type = (OSSymbol *)allowedPMSettings->getObject(i);
-        if(!type) continue;
-
-        obj = dict->getObject(type);
-        if(!obj) continue;
-
-        if ((gIOPMSettingAutoWakeSecondsKey == type) && ((n = OSDynamicCast(OSNumber, obj))))
+        else if (key->isEqualTo(loginwindow_tracepoint_string))
         {
-            UInt32 rsecs = n->unsigned32BitValue();
-            if (!rsecs)
-            autoWakeStart = autoWakeEnd = 0;
-            else
-            {
-            AbsoluteTime deadline;
-            clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline);
-            autoWakeEnd = AbsoluteTime_to_scalar(&deadline);
-            if (rsecs > kAutoWakePreWindow)
-                rsecs -= kAutoWakePreWindow;
-            else
-                rsecs = 0;
-            clock_interval_to_deadline(rsecs, kSecondScale, &deadline);
-            autoWakeStart = AbsoluteTime_to_scalar(&deadline);
-            }
+            if (pmTracer && (n = OSDynamicCast(OSNumber, obj)))
+                pmTracer->traceLoginWindowPhase(n->unsigned8BitValue());
+        }
+        else if (key->isEqualTo(kIOPMDeepSleepEnabledKey)       ||
+                 key->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey)  ||
+                 key->isEqualTo(kIOPMAutoPowerOffEnabledKey)    ||
+                 key->isEqualTo(stall_halt_string))
+        {
+            if ((b = OSDynamicCast(OSBoolean, obj)))
+                setProperty(key, b);
         }
-        if (gIOPMSettingDebugWakeRelativeKey == type)
+        else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
+                 key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
+                 key->isEqualTo(kIOPMAutoPowerOffTimerKey))
         {
             if ((n = OSDynamicCast(OSNumber, obj)))
-                _debugWakeSeconds = n->unsigned32BitValue();
+                setProperty(key, n);
+        }
+        else if (key->isEqualTo(kIOPMUserWakeAlarmScheduledKey))
+        {
+            if (kOSBooleanTrue == obj)
+                OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
             else
-                _debugWakeSeconds = 0;
+                OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
+            DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm);
         }
-        
-        return_value = setPMSetting(type, obj);
-        
-        if(kIOReturnSuccess != return_value) goto exit;
-    }
 
-exit:
-    if(publish_simulated_battery_string) publish_simulated_battery_string->release();
-    if(boot_complete_string) boot_complete_string->release();
-    if(sys_shutdown_string) sys_shutdown_string->release();
-    if(stall_halt_string) stall_halt_string->release();
-    if(battery_warning_disabled_string) battery_warning_disabled_string->release();
-    if(idle_seconds_string) idle_seconds_string->release();
-    if(sleepdisabled_string) sleepdisabled_string->release();
-    if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
-    if(loginwindow_tracepoint_string) loginwindow_tracepoint_string->release();
-    if(pmTimelineLogging_string) pmTimelineLogging_string->release();
-#if    HIBERNATION
-    if(hibernatemode_string) hibernatemode_string->release();
-    if(hibernatefile_string) hibernatefile_string->release();
-    if(hibernatefreeratio_string) hibernatefreeratio_string->release();
-    if(hibernatefreetime_string) hibernatefreetime_string->release();
-#endif
+        // Relay our allowed PM settings onto our registered PM clients
+        else if ((allowedPMSettings->getNextIndexOfObject(key, 0) != (unsigned int) -1))
+        {
+            return_value = setPMSetting(key, obj);
+            if (kIOReturnSuccess != return_value)
+                break;
+
+            if (gIOPMSettingDebugWakeRelativeKey == key)
+            {
+                if ((n = OSDynamicCast(OSNumber, obj)) &&
+                    (_debugWakeSeconds = n->unsigned32BitValue()))
+                {
+                    OSBitOrAtomic(kIOPMAlarmBitDebugWake, &_scheduledAlarms);
+                }
+                else
+                {
+                    _debugWakeSeconds = 0;
+                    OSBitAndAtomic(~kIOPMAlarmBitDebugWake, &_scheduledAlarms);
+                }
+                DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
+            }
+            else if (gIOPMSettingAutoWakeCalendarKey == key)
+            {
+                OSData * data;
+                if ((data = OSDynamicCast(OSData, obj)) &&
+                    (data->getLength() == sizeof(IOPMCalendarStruct)))
+                {
+                    const IOPMCalendarStruct * cs =
+                        (const IOPMCalendarStruct *) data->getBytesNoCopy();
+
+                    if (cs->year)
+                        OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
+                    else
+                        OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
+                    DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
+                }
+            }
+        }
+        else
+        {
+            DLOG("setProperties(%s) not handled\n", key->getCStringNoCopy());
+        }
+    }
+
+exit:
+    if(publish_simulated_battery_string) publish_simulated_battery_string->release();
+    if(boot_complete_string) boot_complete_string->release();
+    if(sys_shutdown_string) sys_shutdown_string->release();
+    if(stall_halt_string) stall_halt_string->release();
+    if(battery_warning_disabled_string) battery_warning_disabled_string->release();
+    if(idle_seconds_string) idle_seconds_string->release();
+    if(sleepdisabled_string) sleepdisabled_string->release();
+    if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
+    if(loginwindow_tracepoint_string) loginwindow_tracepoint_string->release();
+#if HIBERNATION
+    if(hibernatemode_string) hibernatemode_string->release();
+    if(hibernatefile_string) hibernatefile_string->release();
+    if(hibernatefreeratio_string) hibernatefreeratio_string->release();
+    if(hibernatefreetime_string) hibernatefreetime_string->release();
+#endif
+    if (iter) iter->release();
     return return_value;
 }
 
@@ -1406,7 +1568,7 @@ IOReturn IOPMrootDomain::joinAggressiveness(
     if (!service || (service == this))
         return kIOReturnBadArgument;
 
-    DLOG("joinAggressiveness %s %p\n", service->getName(), service);
+    DLOG("joinAggressiveness %s %p\n", service->getName(), OBFUSCATE(service));
 
     request = IONew(AggressivesRequest, 1);
     if (!request)
@@ -1722,13 +1884,21 @@ void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
     AbsoluteTime deadline;
 
     ASSERT_GATED();
+    if (gNoIdleFlag) {
+        DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag);
+        return;
+    }
     if (inSeconds)
     {
-        clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);        
+        clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
         thread_call_enter_delayed(extraSleepTimer, deadline);
         idleSleepTimerPending = true;
-        DLOG("idle timer set for %u seconds\n", inSeconds);
     }
+    else
+    {
+        thread_call_enter(extraSleepTimer);
+    }
+    DLOG("idle timer set for %u seconds\n", inSeconds);
 }
 
 //******************************************************************************
@@ -1744,6 +1914,18 @@ void IOPMrootDomain::cancelIdleSleepTimer( void )
         DLOG("idle timer cancelled\n");
         thread_call_cancel(extraSleepTimer);
         idleSleepTimerPending = false;
+
+        if (!assertOnWakeSecs && systemWakeTime) {
+                AbsoluteTime    now;
+                clock_usec_t    microsecs;
+                clock_get_uptime(&now);
+                SUB_ABSOLUTETIME(&now, &systemWakeTime);
+                absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
+                if (assertOnWakeReport)  {
+                    HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
+                    DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
+                }
+        }
     }
 }
 
@@ -1784,15 +1966,55 @@ void IOPMrootDomain::handleSleepTimerExpiration( void )
     idleSleepTimerPending = false;
 
     clock_get_uptime(&time);
-    if ((AbsoluteTime_to_scalar(&time) > autoWakeStart) &&
-        (AbsoluteTime_to_scalar(&time) < autoWakeEnd))
+    setQuickSpinDownTimeout();
+    adjustPowerState(true);
+}
+
+//******************************************************************************
+// getTimeToIdleSleep
+//
+// Returns number of seconds left before going into idle sleep.
+// Caller has to make sure that idle sleep is allowed at the time of calling
+// this function
+//******************************************************************************
+
+uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
+{
+
+    AbsoluteTime    now, lastActivityTime;
+    uint64_t        nanos;
+    uint32_t        minutesSinceUserInactive = 0;
+    uint32_t         sleepDelay = 0;
+
+    if (sleepSlider == 0)
+        return 0xffffffff;
+
+    if (userActivityTime)
+        lastActivityTime = userActivityTime;
+    else
+        lastActivityTime = userBecameInactiveTime;
+
+    clock_get_uptime(&now);
+    if (CMP_ABSOLUTETIME(&now, &lastActivityTime) > 0)
     {
-        thread_call_enter_delayed(extraSleepTimer, *((AbsoluteTime *) &autoWakeEnd));
-        return;
+        SUB_ABSOLUTETIME(&now, &lastActivityTime);
+        absolutetime_to_nanoseconds(now, &nanos);
+        minutesSinceUserInactive = nanos / (60000000000ULL);
+
+        if (minutesSinceUserInactive >= sleepSlider)
+            sleepDelay = 0;
+        else
+            sleepDelay = sleepSlider - minutesSinceUserInactive;
+    }
+    else
+    {
+        sleepDelay = sleepSlider;
     }
 
-    setQuickSpinDownTimeout();
-    adjustPowerState(true);
+    DLOG("user inactive %u min, time to idle sleep %u min\n",
+        minutesSinceUserInactive, sleepDelay);
+
+    return (sleepDelay * 60);
 }
 
 //******************************************************************************
@@ -1833,126 +2055,48 @@ IOReturn IOPMrootDomain::sleepSystem( void )
 /* private */
 IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
 {
-       /* sleepSystem is a public function, and may be called by any kernel driver.
-     * And that's bad - drivers should sleep the system by calling 
+    OSObject *obj = NULL;
+    OSString *reason = NULL;
+    /* sleepSystem is a public function, and may be called by any kernel driver.
+     * And that's bad - drivers should sleep the system by calling
      * receivePowerNotification() instead. Drivers should not use sleepSystem.
      *
      * Note that user space app calls to IOPMSleepSystem() will also travel
      * this code path and thus be correctly identified as software sleeps.
      */
-          
-    if (options && options->getObject("OSSwitch")) 
+
+    if (options && options->getObject("OSSwitch"))
     {
         // Log specific sleep cause for OS Switch hibernation
         return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate);
-    } else {
-        return privateSleepSystem( kIOPMSleepReasonSoftware);
     }
+
+    if (options && (obj = options->getObject("Sleep Reason")))
+    {
+        reason = OSDynamicCast(OSString, obj);
+        if (reason && reason->isEqualTo(kIOPMDarkWakeThermalEmergencyKey))
+            return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency);
+    }
+
+    return privateSleepSystem( kIOPMSleepReasonSoftware);
 }
 
 /* private */
 IOReturn IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
 {
-    static const char * IOPMSleepReasons[] = {
-        "",
-        kIOPMClamshellSleepKey,
-        kIOPMPowerButtonSleepKey,
-        kIOPMSoftwareSleepKey,
-        kIOPMOSSwitchHibernationKey,
-        kIOPMIdleSleepKey,
-        kIOPMLowPowerSleepKey,
-        kIOPMClamshellSleepKey,
-        kIOPMThermalEmergencySleepKey,
-        kIOPMMaintenanceSleepKey
-    };
+    /* Called from both gated and non-gated context */
 
-    PMEventDetails *details;
-
-    if (!checkSystemCanSleep())
+    if (!checkSystemSleepEnabled() || !pmPowerStateQueue)
     {
-        // Record why the system couldn't sleep        
-        details = PMEventDetails::eventDetails(kIOPMEventTypeSleep, NULL,
-                                        sleepReason, kIOReturnNotPermitted);
-               
-               recordAndReleasePMEvent( details );
         return kIOReturnNotPermitted;
     }
 
-    if (timeline)
-        timeline->setSleepCycleInProgressFlag(true);
-  
-    // Time to publish a UUID for the Sleep --> Wake cycle  
-    if(pmPowerStateQueue) {
-        pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)true);
-    }
-
-  
-    // Log the beginning of system sleep.
-       details = PMEventDetails::eventDetails(kIOPMEventTypeSleep, NULL,
-                                            sleepReason, kIOReturnSuccess);
-       
-       recordAndReleasePMEvent( details );
-       
-    // Record sleep cause in IORegistry
-    lastSleepReason = sleepReason;
-    sleepReason -= (kIOPMSleepReasonClamshell - 1);
-    if (sleepReason && (sleepReason < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0]))) {
-        setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[sleepReason]);
-    }
-
-    if (pmPowerStateQueue)
-        pmPowerStateQueue->submitPowerEvent(
+    pmPowerStateQueue->submitPowerEvent(
                             kPowerEventPolicyStimulus,
-                            (void *) kStimulusDemandSystemSleep );
-
-    return kIOReturnSuccess;
-}
+                            (void *) kStimulusDemandSystemSleep,
+                            sleepReason);
 
-IOReturn IOPMrootDomain::recordPMEventGated(PMEventDetails *record)
-{  
-  // If we don't have a place to log to, we can't actually
-  // log anything. Chances are, the person who is asking us to do    
-  // the PM logging has forgotten to set the right bootflags
-  if(!timeline)
     return kIOReturnSuccess;
-
-  if(gIOPMWorkLoop->inGate() == false) {
-    
-    IOReturn ret = gIOPMWorkLoop->runAction(
-                     OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::recordPMEventGated),
-                     (OSObject *)this,
-                     (void *)record);
-    
-    return ret;
-  }
-  else {
-    // Now that we're guaranteed to be running in gate ...
-
-    // Check the validity of the argument we are given
-    if(!record) 
-      return kIOReturnBadArgument;
-    
-         // Record a driver event, or a system event
-         if(record->eventClassifier == kIOPMEventClassDriverEvent
-            || record->eventClassifier == kIOPMEventClassSystemEvent)
-                 return this->recordPMEvent(record);
-       
-         else
-                 return kIOReturnBadArgument;
-  }
-}
-
-IOReturn IOPMrootDomain::recordAndReleasePMEventGated(PMEventDetails *record)
-{
-    IOReturn ret = kIOReturnBadArgument;
-
-    if (record)
-    {
-        ret = recordPMEventGated(record);
-        record->release();
-    }
-    
-    return ret;
 }
 
 //******************************************************************************
@@ -1963,39 +2107,46 @@ IOReturn IOPMrootDomain::recordAndReleasePMEventGated(PMEventDetails *record)
 
 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
 {
-    PMEventDetails *details;
-
+    uint64_t    now;
     ASSERT_GATED();
     DLOG("PowerChangeDone: %u->%u\n",
         (uint32_t) previousPowerState, (uint32_t) getPowerState());
-       
+
     switch ( getPowerState() )
     {
         case SLEEP_STATE: {
             if (previousPowerState != ON_STATE)
                 break;
-                       
-            details = PMEventDetails::eventDetails(
-                            kIOPMEventTypeSleepDone,
-                            NULL, 
-                            NULL, 
-                            kIOReturnSuccess);
-                       
-            recordAndReleasePMEvent( details );
+
+            acceptSystemWakeEvents(true);
 
             // re-enable this timer for next sleep
             cancelIdleSleepTimer();
 
-            clock_sec_t                secs;
-            clock_usec_t       microsecs;
-            clock_get_calendar_microtime(&secs, &microsecs);
+            clock_sec_t     secs;
+            clock_usec_t    microsecs;
+            clock_get_calendar_absolute_and_microtime(&secs, &microsecs, &now);
             logtime(secs);
             gIOLastSleepTime.tv_sec  = secs;
             gIOLastSleepTime.tv_usec = microsecs;
             gIOLastWakeTime.tv_sec = 0;
             gIOLastWakeTime.tv_usec = 0;
 
-#if    HIBERNATION
+            if (wake2DarkwakeDelay && sleepDelaysReport) {
+                clock_usec_t    microsecs;
+                clock_sec_t     wake2DarkwakeSecs, darkwake2SleepSecs;
+                // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
+
+                SUB_ABSOLUTETIME(&now, &ts_sleepStart);
+                absolutetime_to_microtime(now, &darkwake2SleepSecs, &microsecs);
+                absolutetime_to_microtime(wake2DarkwakeDelay, &wake2DarkwakeSecs, &microsecs);
+                HISTREPORT_TALLYVALUE(sleepDelaysReport, 
+                                           (int64_t)(wake2DarkwakeSecs+darkwake2SleepSecs));
+
+                DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs, (unsigned long)darkwake2SleepSecs);
+                wake2DarkwakeDelay = 0;
+            }
+#if HIBERNATION
             LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
 
             IOHibernateSystemHasSlept();
@@ -2004,81 +2155,127 @@ void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
 #else
             LOG("System Sleep\n");
 #endif
-
+            if (thermalWarningState) {
+                const OSSymbol *event = OSSymbol::withCString(kIOPMThermalLevelWarningKey);
+                if (event) {
+                    systemPowerEventOccurred(event, kIOPMThermalLevelUnknown);
+                    event->release();
+                }
+            }
+            assertOnWakeSecs = 0;
+            ((IOService *)this)->stop_watchdog_timer(); //14456299
             getPlatform()->sleepKernel();
 
             // The CPU(s) are off at this point,
             // Code will resume execution here upon wake.
 
             clock_get_uptime(&systemWakeTime);
+            _highestCapability = 0;
 
-#if    HIBERNATION
+            ((IOService *)this)->start_watchdog_timer(); //14456299
+#if HIBERNATION
             IOHibernateSystemWake();
 #endif
 
             // sleep transition complete
             gSleepOrShutdownPending = 0;
 
-            // trip the reset of the calendar clock
-            clock_wakeup_calendar();
+                       // trip the reset of the calendar clock
+                       {
+                               clock_sec_t  wakeSecs;
+                               clock_usec_t wakeMicrosecs;
 
-#if    HIBERNATION
+                               clock_initialize_calendar();
+
+                               clock_get_calendar_microtime(&wakeSecs, &wakeMicrosecs);
+                               gIOLastWakeTime.tv_sec  = wakeSecs;
+                               gIOLastWakeTime.tv_usec = wakeMicrosecs;
+                       }
+
+#if HIBERNATION
             LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
 #endif
 
             // log system wake
-            getPlatform()->PMLog(kIOPMrootDomainClass, kPMLogSystemWake, 0, 0);
+            PMDebug(kPMLogSystemWake, 0, 0);
             lowBatteryCondition = false;
             lastSleepReason = 0;
 
-            // And start logging the wake event here
-            // TODO: Publish the wakeReason string as an integer
-            details = PMEventDetails::eventDetails(
-                            kIOPMEventTypeWake,
-                            NULL, 
-                            0, 
-                            kIOReturnSuccess);
-                       
-            recordAndReleasePMEvent( details );
-                       
+            _lastDebugWakeSeconds = _debugWakeSeconds;
+            _debugWakeSeconds = 0;
+            _scheduledAlarms = 0;
 
 #ifndef __LP64__
             systemWake();
 #endif
 
 #if defined(__i386__) || defined(__x86_64__)
-            wranglerTickled    = false;
-            graphicsSuppressed = false;
-            darkWakePostTickle = false;
-            logGraphicsClamp   = true;
-            logWranglerTickle  = true;
-            sleepTimerMaintenance = false;
+            wranglerTickled         = false;
+            graphicsSuppressed      = false;
+            darkWakePostTickle      = false;
+            darkWakeHibernateError  = false;
+            darkWakeToSleepASAP     = true;
+            logGraphicsClamp        = true;
+            sleepTimerMaintenance   = false;
+            sleepToStandby          = false;
+            wranglerTickleLatched   = false;
+            userWasActive           = false;
+            fullWakeReason = kFullWakeReasonNone;
 
             OSString * wakeType = OSDynamicCast(
                 OSString, getProperty(kIOPMRootDomainWakeTypeKey));
             OSString * wakeReason = OSDynamicCast(
                 OSString, getProperty(kIOPMRootDomainWakeReasonKey));
 
+            if (wakeReason && (wakeReason->getLength() >= 2) &&
+                gWakeReasonString[0] == '\0')
+            {
+                // Until the platform driver can claim its wake reasons
+                strlcat(gWakeReasonString, wakeReason->getCStringNoCopy(),
+                        sizeof(gWakeReasonString));
+            }
+
             if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery))
             {
                 lowBatteryCondition = true;
                 darkWakeMaintenance = true;
-                darkWakeToSleepASAP = true;
             }
             else if ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0)
             {
+#if HIBERNATION
                 OSNumber * hibOptions = OSDynamicCast(
                     OSNumber, getProperty(kIOHibernateOptionsKey));
-
-                if (hibernateAborted ||
-                    ((hibOptions &&
-                     !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))) ||
-                    ((_debugWakeSeconds != 0) &&
-                      ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0)) ||
-                    (wakeType && (
-                     wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
-                     wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm))))
+                if (hibernateAborted || ((hibOptions &&
+                    !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))))
                 {
+                    // Hibernate aborted, or EFI brought up graphics
+                    wranglerTickled = true;
+                    DLOG("hibernation aborted %d, options 0x%x\n",
+                        hibernateAborted,
+                        hibOptions ? hibOptions->unsigned32BitValue() : 0);
+                }
+                else
+#endif
+                if (wakeType && (
+                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
+                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)))
+                {
+                    // User wake or RTC alarm
+                    wranglerTickled = true;
+                }
+                else
+                if (wakeType &&
+                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
+                {
+                    // SMC standby timer trumps SleepX
+                    darkWakeMaintenance = true;
+                    sleepTimerMaintenance = true;
+                }
+                else
+                if ((_lastDebugWakeSeconds != 0) &&
+                    ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0))
+                {
+                    // SleepX before maintenance
                     wranglerTickled = true;
                 }
                 else
@@ -2086,51 +2283,73 @@ void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
                     wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
                 {
                     darkWakeMaintenance = true;
-                    darkWakeToSleepASAP = true;
                 }
                 else
                 if (wakeType &&
-                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
+                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepService))
                 {
                     darkWakeMaintenance = true;
-                    darkWakeToSleepASAP = true;
-                    sleepTimerMaintenance = true;
+                    darkWakeSleepService = true;
+#if HIBERNATION
+                    if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
+                        sleepToStandby = true;
+                    }
+#endif
+                }
+                else
+                if (wakeType &&
+                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeHibernateError))
+                {
+                    darkWakeMaintenance = true;
+                    darkWakeHibernateError = true;
                 }
                 else
                 {
                     // Unidentified wake source, resume to full wake if debug
                     // alarm is pending.
 
-                    if (_debugWakeSeconds && (!wakeReason || wakeReason->isEqualTo("")))
+                    if (_lastDebugWakeSeconds &&
+                        (!wakeReason || wakeReason->isEqualTo("")))
                         wranglerTickled = true;
-                    else
-                        darkWakeToSleepASAP = true;
                 }
             }
             else
             {
-                // Post a HID tickle immediately - except for maintenance wake.
-
-                if (hibernateAborted || !wakeType ||
-                    !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
+                if (wakeType &&
+                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
+                {
+                    darkWakeMaintenance = true;
+                    sleepTimerMaintenance = true;
+                }
+                else if (hibernateAborted || !wakeType ||
+                    !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance) ||
+                    !wakeReason || !wakeReason->isEqualTo("RTC"))
                 {
+                    // Post a HID tickle immediately - except for RTC maintenance wake.
                     wranglerTickled = true;
                 }
                 else
                 {
                     darkWakeMaintenance = true;
-                    darkWakeToSleepASAP = true;
                 }
             }
 
             if (wranglerTickled)
+            {
+                darkWakeToSleepASAP = false;
+                fullWakeReason = kFullWakeReasonLocalUser;
                 reportUserInput();
+            }
+            else if (displayPowerOnRequested && checkSystemCanSustainFullWake())
+            {
+                handleDisplayPowerOn();
+            }
             else if (!darkWakeMaintenance)
             {
                 // Early/late tickle for non-maintenance wake.
-                if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) == 
+                if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
                      kDarkWakeFlagHIDTickleEarly) ||
-                    ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) == 
+                    ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
                      kDarkWakeFlagHIDTickleLate))
                 {
                     darkWakePostTickle = true;
@@ -2139,37 +2358,30 @@ void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
 #else   /* !__i386__ && !__x86_64__ */
             // stay awake for at least 30 seconds
             wranglerTickled = true;
+            fullWakeReason = kFullWakeReasonLocalUser;
             startIdleSleepTimer(30);
 #endif
+            sleepCnt++;
+
+           thread_call_enter(updateConsoleUsersEntry);
 
             changePowerStateToPriv(ON_STATE);
         }   break;
-    
+#if !__i386__ && !__x86_64__
         case ON_STATE: {
-            bool wasPrevented = childPreventSystemSleep;
-
-            details = PMEventDetails::eventDetails(
-                            kIOPMEventTypeWakeDone,
-                            NULL, 
-                            0, 
-                            kIOReturnSuccess);
-                       
-            recordAndReleasePMEvent( details );
-
             if (previousPowerState != ON_STATE)
-                _debugWakeSeconds = 0;
-
-            // Update childPreventSystemSleep flag using the capability computed
-            // by IOSevice::rebuildChildClampBits().
+            {
+                DLOG("Force re-evaluating aggressiveness\n");
+                /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
+                pmPowerStateQueue->submitPowerEvent(
+                    kPowerEventPolicyStimulus,
+                    (void *) kStimulusNoIdleSleepPreventers );
+          }
+          break;
+        }
 
-            childPreventSystemSleep =
-                ((currentCapability() & kIOPMChildClamp2) != 0);
+#endif
 
-            if (wasPrevented && !childPreventSystemSleep)
-            {
-                evaluatePolicy( kStimulusDarkWakeEvaluate );
-            }
-        }   break;
     }
 }
 
@@ -2177,9 +2389,6 @@ void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
 // requestPowerDomainState
 //
 // Extend implementation in IOService. Running on PM work loop thread.
-//
-// Examine children desires and initiate idle-sleep if all children are idle,
-// prevent idle and system sleep flags are not set.
 //******************************************************************************
 
 IOReturn IOPMrootDomain::requestPowerDomainState (
@@ -2187,148 +2396,216 @@ IOReturn IOPMrootDomain::requestPowerDomainState (
     IOPowerConnection * childConnection,
     unsigned long       specification )
 {
-    OSIterator          *iter;
-    OSObject            *next;
-    IOPowerConnection   *connection;
-    IOPMPowerFlags      mergedChildDesire = 0;
-    IOPMPowerFlags      editedChildDesire;
-    IOPMPowerFlags      thisDesire;
-    bool                sleepASAP = false;
+    // Idle and system sleep prevention flags affects driver desire.
+    // Children desire are irrelevant so they are cleared.
 
-    ASSERT_GATED();
+    return super::requestPowerDomainState(0, childConnection, specification);
+}
 
-    // Disregard disk I/O (anything besides the display wrangler) as a
-    // factor in preventing idle sleep - based on a runtime setting.
 
-    if ((gDarkWakeFlags & kDarkWakeFlagIgnoreDiskIOAlways) &&
-        (kIOPMPreventIdleSleep & childDesire) &&
-        (childConnection != wranglerConnection))
-    {
-        childDesire &= ~kIOPMPreventIdleSleep;
-    }
+//******************************************************************************
+// updatePreventIdleSleepList
+//
+// Called by IOService on PM work loop.
+// Returns true if PM policy recognized the driver's desire to prevent idle
+// sleep and updated the list of idle sleep preventers. Returns false otherwise
+//******************************************************************************
 
-    // Force the child's input power requirement to 0 unless the prevent
-    // idle-sleep flag is set. Nil input power flags maps to our state 0.
-    // Our power clamp (deviceDesire) clamps the lowest power state at 2.
+bool IOPMrootDomain::updatePreventIdleSleepList(
+        IOService * service, bool addNotRemove )
+{
+    unsigned int oldCount, newCount;
 
-    editedChildDesire = 0;
-    if (childDesire & kIOPMPreventIdleSleep)
-        editedChildDesire |= (kIOPMPowerOn | kIOPMPreventIdleSleep);
-    if (childDesire & kIOPMPreventSystemSleep)
-        editedChildDesire |= (kIOPMPowerOn | kIOPMPreventSystemSleep);
+    ASSERT_GATED();
 
-    iter = getChildIterator(gIOPowerPlane);
-    if ( iter )
+#if defined(__i386__) || defined(__x86_64__)
+    // Disregard disk I/O (besides the display wrangler) as a factor preventing
+    // idle sleep, except in the case of legacy disk I/O
+    if ((service != wrangler) && (service != this))
     {
-        while ( (next = iter->getNextObject()) )
-        {
-            if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
-            {
-                // Ignore child that are in the process of joining.
-                               if (connection->getReadyFlag() == false)
-                                       continue;
+        return false;
+    }
+#endif
 
-                // OR in the child's input power requirements.
-                // Is this connection attached to the child that called
-                // requestPowerDomainState()?
+    oldCount = preventIdleSleepList->getCount();
+    if (addNotRemove)
+    {
+        preventIdleSleepList->setObject(service);
+        DLOG("prevent idle sleep list: %s+ (%u)\n",
+            service->getName(), preventIdleSleepList->getCount());
+    }
+    else if (preventIdleSleepList->member(service))
+    {
+        preventIdleSleepList->removeObject(service);
+        DLOG("prevent idle sleep list: %s- (%u)\n",
+            service->getName(), preventIdleSleepList->getCount());
+    }
+    newCount = preventIdleSleepList->getCount();
 
-                if (connection == childConnection)
-                {
-                    thisDesire = editedChildDesire;
-                }
-                else
-                {
-                    thisDesire = 0;
-                    if (connection->getPreventIdleSleepFlag())
-                        thisDesire |= (kIOPMPowerOn | kIOPMPreventIdleSleep);
-                    if (connection->getPreventSystemSleepFlag())
-                        thisDesire |= (kIOPMPowerOn | kIOPMPreventSystemSleep);
-                }
+    if ((oldCount == 0) && (newCount != 0))
+    {
+        // Driver added to empty prevent list.
+        // Update the driver desire to prevent idle sleep.
+        // Driver desire does not prevent demand sleep.
 
-                mergedChildDesire |= thisDesire;
-                if (thisDesire && (kIOLogPMRootDomain & gIOKitDebug))
-                {
-                    IOService * child =
-                        (IOService *) connection->getChildEntry(gIOPowerPlane);
-                    LOG("child %p, noIdle %d, noSleep %d - %s\n",
-                        child,
-                        ((thisDesire & kIOPMPreventIdleSleep) != 0),
-                        ((thisDesire & kIOPMPreventSystemSleep) != 0),
-                        child ? child->getName() : "?");
-                }
-            }
-        }
-        iter->release();
+        changePowerStateTo(ON_STATE);
     }
+    else if ((oldCount != 0) && (newCount == 0))
+    {
+        // Last driver removed from prevent list.
+        // Drop the driver clamp to allow idle sleep.
 
-    DLOG("mergedChildDesire 0x%lx, extraSleepDelay %ld\n",
-        mergedChildDesire, extraSleepDelay);
+        changePowerStateTo(SLEEP_STATE);
+        evaluatePolicy( kStimulusNoIdleSleepPreventers );
+    }
+    messageClient(kIOPMMessageIdleSleepPreventers, systemCapabilityNotifier,
+        &newCount, sizeof(newCount));
 
-    if ( !mergedChildDesire && !systemBooting )
+#if defined(__i386__) || defined(__x86_64__)
+    if (addNotRemove && (service == wrangler) && !checkSystemCanSustainFullWake())
     {
-        if (!wrangler)
-        {
-            changePowerStateToPriv(ON_STATE);
-            if (idleSeconds)
-            {
-                // stay awake for at least idleSeconds
-                startIdleSleepTimer(idleSeconds);
-            }
-        }
-        else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
-        {
-            sleepASAP = true;
-        }
+        return false;   // do not idle-cancel
     }
+#endif
 
-    // Drop our power clamp to SLEEP_STATE when all children became idle,
-    // and system sleep and display sleep slider values are equal.
-
-    adjustPowerState(sleepASAP);
-
-    // If our power clamp has already dropped to SLEEP_STATE, and no child
-    // is keeping us at ON_STATE, then the following will trigger idle sleep.
-
-    return super::requestPowerDomainState(
-        editedChildDesire, childConnection, specification);
+    return true;
 }
 
 //******************************************************************************
-// tellChangeDown
+// preventSystemSleepListUpdate
 //
-// Override the superclass implementation to send a different message type.
+// Called by IOService on PM work loop.
 //******************************************************************************
 
-bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
+void IOPMrootDomain::updatePreventSystemSleepList(
+        IOService * service, bool addNotRemove )
 {
-    DLOG("tellChangeDown %u->%u\n",
-        (uint32_t) getPowerState(), (uint32_t) stateNum);
+    unsigned int oldCount, newCount;
 
-    if (SLEEP_STATE == stateNum)
+    ASSERT_GATED();
+    if (this == service)
+        return;
+
+    oldCount = preventSystemSleepList->getCount();
+    if (addNotRemove)
     {
-        if (!ignoreTellChangeDown)
-            tracePoint( kIOPMTracePointSleepApplications );
-        else
-            tracePoint( kIOPMTracePointSleepPriorityClients );   
+        preventSystemSleepList->setObject(service);
+        DLOG("prevent system sleep list: %s+ (%u)\n",
+            service->getName(), preventSystemSleepList->getCount());
+        if (!assertOnWakeSecs && systemWakeTime) {
+                AbsoluteTime    now;
+                clock_usec_t    microsecs;
+                clock_get_uptime(&now);
+                SUB_ABSOLUTETIME(&now, &systemWakeTime);
+                absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
+                if (assertOnWakeReport)  {
+                    HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
+                    DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
+                }
+        }
     }
-
-    if ((SLEEP_STATE == stateNum) && !ignoreTellChangeDown)
+    else if (preventSystemSleepList->member(service))
     {
-        userActivityAtSleep = userActivityCount;
-        hibernateAborted = false;
-        DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
+        preventSystemSleepList->removeObject(service);
+        DLOG("prevent system sleep list: %s- (%u)\n",
+            service->getName(), preventSystemSleepList->getCount());
 
-        // Direct callout into OSKext so it can disable kext unloads
-        // during sleep/wake to prevent deadlocks.
-        OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
+        if ((oldCount != 0) && (preventSystemSleepList->getCount() == 0))
+        {
+            // Lost all system sleep preventers.
+            // Send stimulus if system sleep was blocked, and is in dark wake.
+            evaluatePolicy( kStimulusDarkWakeEvaluate );
+        }
+    }
+    newCount = preventSystemSleepList->getCount();
+    messageClient(kIOPMMessageSystemSleepPreventers, systemCapabilityNotifier,
+        &newCount, sizeof(newCount));
+}
 
-        IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
+void IOPMrootDomain::copySleepPreventersList(OSArray **idleSleepList, OSArray **systemSleepList)
+{
 
-        // Notify platform that sleep has begun
-        getPlatform()->callPlatformFunction(
-                        sleepMessagePEFunction, false,
-                        (void *)(uintptr_t) kIOMessageSystemWillSleep,
-                        NULL, NULL, NULL);
+    OSCollectionIterator *iterator = NULL;
+    OSObject    *object = NULL;
+    OSArray     *array = NULL;
+
+    if (!getPMworkloop()->inGate())
+    {
+        getPMworkloop()->runAction(
+            OSMemberFunctionCast(IOWorkLoop::Action, this,
+                &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList),
+            this, (void *)idleSleepList, (void *)systemSleepList);
+        return;
+    }
+
+    if (idleSleepList && preventIdleSleepList && (preventIdleSleepList->getCount() != 0))
+    {
+        iterator = OSCollectionIterator::withCollection(preventIdleSleepList);
+        array = OSArray::withCapacity(5);
+
+        while ((object = iterator->getNextObject()))
+        {
+            IOService *service = OSDynamicCast(IOService, object);
+            if (object)
+            {
+                array->setObject(OSSymbol::withCString(service->getName()));
+            }
+        }
+
+        iterator->release();
+        *idleSleepList = array;
+    }
+
+    if (systemSleepList && preventSystemSleepList && (preventSystemSleepList->getCount() != 0))
+    {
+        iterator = OSCollectionIterator::withCollection(preventSystemSleepList);
+        array = OSArray::withCapacity(5);
+
+        while ((object = iterator->getNextObject()))
+        {
+            IOService *service = OSDynamicCast(IOService, object);
+            if (object)
+            {
+                array->setObject(OSSymbol::withCString(service->getName()));
+            }
+        }
+
+        iterator->release();
+        *systemSleepList = array;
+    }
+}
+
+//******************************************************************************
+// tellChangeDown
+//
+// Override the superclass implementation to send a different message type.
+//******************************************************************************
+
+bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
+{
+    DLOG("tellChangeDown %u->%u\n",
+        (uint32_t) getPowerState(), (uint32_t) stateNum);
+
+    if (SLEEP_STATE == stateNum)
+    {
+        // Legacy apps were already told in the full->dark transition
+        if (!ignoreTellChangeDown)
+            tracePoint( kIOPMTracePointSleepApplications );
+        else
+            tracePoint( kIOPMTracePointSleepPriorityClients );
+    }
+
+    if ((SLEEP_STATE == stateNum) && !ignoreTellChangeDown)
+    {
+        userActivityAtSleep = userActivityCount;
+        hibernateAborted = false;
+        DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
+
+        // Direct callout into OSKext so it can disable kext unloads
+        // during sleep/wake to prevent deadlocks.
+        OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
+
+        IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
 
         // Two change downs are sent by IOServicePM. Ignore the 2nd.
         // But tellClientsWithResponse() must be called for both.
@@ -2360,8 +2637,25 @@ bool IOPMrootDomain::askChangeDown( unsigned long stateNum )
 //******************************************************************************
 // askChangeDownDone
 //
-// Called by PM after all apps have responded to kIOMessageCanSystemSleep.
-// pmconfigd may create a deny sleep assertion before ack'ing.
+// An opportunity for root domain to cancel the power transition,
+// possibily due to an assertion created by powerd in response to
+// kIOMessageCanSystemSleep.
+//
+// Idle sleep:
+//   full -> dark wake transition
+//     1. Notify apps and powerd with kIOMessageCanSystemSleep
+//     2. askChangeDownDone()
+//   dark -> sleep transition
+//     1. Notify powerd with kIOMessageCanSystemSleep
+//     2. askChangeDownDone()
+//
+// Demand sleep:
+//   full -> dark wake transition
+//     1. Notify powerd with kIOMessageCanSystemSleep
+//     2. askChangeDownDone()
+//   dark -> sleep transition
+//     1. Notify powerd with kIOMessageCanSystemSleep
+//     2. askChangeDownDone()
 //******************************************************************************
 
 void IOPMrootDomain::askChangeDownDone(
@@ -2376,9 +2670,9 @@ void IOPMrootDomain::askChangeDownDone(
     {
         // Dark->Sleep transition.
         // Check if there are any deny sleep assertions.
-        // Full->Dark transition is never cancelled.
+        // lastSleepReason already set by handleOurPowerChangeStart()
 
-        if (!checkSystemCanSleep(true))
+        if (!checkSystemCanSleep(lastSleepReason))
         {
             // Cancel dark wake to sleep transition.
             // Must re-scan assertions upon entering dark wake.
@@ -2389,6 +2683,63 @@ void IOPMrootDomain::askChangeDownDone(
     }
 }
 
+//******************************************************************************
+// systemDidNotSleep
+//
+// Work common to both canceled or aborted sleep.
+//******************************************************************************
+
+void IOPMrootDomain::systemDidNotSleep( void )
+{
+    // reset console lock state
+    thread_call_enter(updateConsoleUsersEntry);
+
+    if (!wrangler)
+    {
+        if (idleSeconds)
+        {
+            // stay awake for at least idleSeconds
+            startIdleSleepTimer(idleSeconds);
+        }
+    }
+    else
+    {
+        if (sleepSlider && !userIsActive)
+        {
+            // Manually start the idle sleep timer besides waiting for
+            // the user to become inactive.
+            startIdleSleepTimer( kIdleSleepRetryInterval );
+        }
+    }
+
+    preventTransitionToUserActive(false);
+    IOService::setAdvisoryTickleEnable( true );
+
+    // After idle revert and cancel, send a did-change message to powerd
+    // to balance the previous will-change message. Kernel clients do not
+    // need this since sleep cannot be canceled once they are notified.
+
+    if (toldPowerdCapWillChange && systemCapabilityNotifier &&
+        (_pendingCapability != _currentCapability) &&
+        ((_systemMessageClientMask & kSystemMessageClientPowerd) != 0))
+    {
+        // Differs from a real capability gain change where notifyRef != 0,
+        // but it is zero here since no response is expected.
+
+        IOPMSystemCapabilityChangeParameters params;
+
+        bzero(&params, sizeof(params));
+        params.fromCapabilities = _pendingCapability;
+        params.toCapabilities = _currentCapability;
+        params.changeFlags = kIOPMSystemCapabilityDidChange;
+
+        DLOG("MESG cap %x->%x did change\n",
+            params.fromCapabilities, params.toCapabilities);
+        messageClient(kIOMessageSystemCapabilityChange, systemCapabilityNotifier,
+            &params, sizeof(params));
+    }
+}
+
 //******************************************************************************
 // tellNoChangeDown
 //
@@ -2406,11 +2757,10 @@ void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
     DLOG("tellNoChangeDown %u->%u\n",
         (uint32_t) getPowerState(), (uint32_t) stateNum);
 
-    if (idleSeconds && !wrangler)
-    {
-        // stay awake for at least idleSeconds
-        startIdleSleepTimer(idleSeconds);
-    }
+    // Sleep canceled, clear the sleep trace point.
+    tracePoint(kIOPMTracePointSystemUp);
+
+    systemDidNotSleep();
     return tellClients( kIOMessageSystemWillNotSleep );
 }
 
@@ -2425,8 +2775,6 @@ void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
 
 void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
 {
-    OSData *publishPMStats = NULL;
-
     DLOG("tellChangeUp %u->%u\n",
         (uint32_t) getPowerState(), (uint32_t) stateNum);
 
@@ -2447,27 +2795,11 @@ void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
         if (getPowerState() == ON_STATE)
         {
             // this is a quick wake from aborted sleep
-            if (idleSeconds && !wrangler)
-            {
-                // stay awake for at least idleSeconds
-                startIdleSleepTimer(idleSeconds);
-            }
+            systemDidNotSleep();
             tellClients( kIOMessageSystemWillPowerOn );
         }
 
         tracePoint( kIOPMTracePointWakeApplications );
-        publishPMStats = OSData::withBytes(&pmStats, sizeof(pmStats));
-        setProperty(kIOPMSleepStatisticsKey, publishPMStats);
-        publishPMStats->release();
-        bzero(&pmStats, sizeof(pmStats));
-
-        if (pmStatsAppResponses) 
-        {
-            setProperty(kIOPMSleepStatisticsAppsKey, pmStatsAppResponses);
-            pmStatsAppResponses->release();
-            pmStatsAppResponses = OSArray::withCapacity(5);
-        }
-
         tellClients( kIOMessageSystemHasPoweredOn );
     }
 }
@@ -2483,14 +2815,34 @@ IOReturn IOPMrootDomain::sysPowerDownHandler(
     UInt32 messageType, IOService * service,
     void * messageArgs, vm_size_t argSize )
 {
-    IOReturn    ret;
+    IOReturn    ret = 0;
 
     DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
 
     if (!gRootDomain)
         return kIOReturnUnsupported;
 
-    if (messageType == kIOMessageSystemCapabilityChange)
+    if (messageType == kIOMessageSystemWillSleep)
+    {
+#if HIBERNATION
+        static int32_t mem_only = -1;
+        IOPowerStateChangeNotification *notify =
+                    (IOPowerStateChangeNotification *)messageArgs;
+
+       if ((mem_only == -1) &&
+           (PE_parse_boot_argn("swd_mem_only", &mem_only, sizeof(mem_only)) == false)) {
+           mem_only = 0;
+       }
+       if ((mem_only != 1) && (gRootDomain->sleepWakeDebugIsWdogEnabled()))
+       {
+           notify->returnValue = 30 * 1000 * 1000;
+           thread_call_enter1(
+                              gRootDomain->hibDebugSetupEntry,
+                              (thread_call_param_t)(uintptr_t) notify->powerRef);
+       }
+#endif
+    }
+    else if (messageType == kIOMessageSystemCapabilityChange)
     {
         IOPMSystemCapabilityChangeParameters * params =
             (IOPMSystemCapabilityChangeParameters *) messageArgs;
@@ -2512,7 +2864,7 @@ IOReturn IOPMrootDomain::sysPowerDownHandler(
         {
             // We will ack within 20 seconds
             params->maxWaitForReply = 20 * 1000 * 1000;
-#if    HIBERNATION
+#if HIBERNATION
             gRootDomain->evaluateSystemSleepPolicyEarly();
 
             // add in time we could spend freeing pages
@@ -2520,9 +2872,17 @@ IOReturn IOPMrootDomain::sysPowerDownHandler(
             {
                 params->maxWaitForReply = kCapabilityClientMaxWait;
             }
-            DLOG("sysPowerDownHandler timeout %d s\n", (int) (params->maxWaitForReply / 1000 / 1000));
+            DLOG("sysPowerDownHandler max wait %d s\n",
+                (int) (params->maxWaitForReply / 1000 / 1000));
 #endif
 
+            // Notify platform that sleep has begun, after the early
+            // sleep policy evaluation.
+            getPlatform()->callPlatformFunction(
+                            sleepMessagePEFunction, false,
+                            (void *)(uintptr_t) kIOMessageSystemWillSleep,
+                            NULL, NULL, NULL);
+
             if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
             {
                 // Purposely delay the ack and hope that shutdown occurs quickly.
@@ -2531,29 +2891,29 @@ IOReturn IOPMrootDomain::sysPowerDownHandler(
                 AbsoluteTime deadline;
                 clock_interval_to_deadline( 30, kSecondScale, &deadline );
                 thread_call_enter1_delayed(
-                    gRootDomain->diskSyncCalloutEntry, 
-                    (thread_call_param_t) params->notifyRef,
+                    gRootDomain->diskSyncCalloutEntry,
+                    (thread_call_param_t)(uintptr_t) params->notifyRef,
                     deadline );
             }
             else
                 thread_call_enter1(
                     gRootDomain->diskSyncCalloutEntry,
-                    (thread_call_param_t) params->notifyRef);
+                    (thread_call_param_t)(uintptr_t) params->notifyRef);
         }
-#if    HIBERNATION
         else
         if ((params->changeFlags & kIOPMSystemCapabilityDidChange) &&
             (params->toCapabilities & kIOPMSystemCapabilityCPU) &&
             (params->fromCapabilities & kIOPMSystemCapabilityCPU) == 0)
         {
+#if HIBERNATION
             // We will ack within 110 seconds
             params->maxWaitForReply = 110 * 1000 * 1000;
 
             thread_call_enter1(
                 gRootDomain->diskSyncCalloutEntry,
-                (thread_call_param_t) params->notifyRef);
-        }
+                (thread_call_param_t)(uintptr_t) params->notifyRef);
 #endif
+        }
         ret = kIOReturnSuccess;
     }
 
@@ -2573,16 +2933,16 @@ IOReturn IOPMrootDomain::sysPowerDownHandler(
 //******************************************************************************
 
 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj)
-{        
+{
     OSString    *str = NULL;
 
-    if (kOSBooleanFalse == obj) 
+    if (kOSBooleanFalse == obj)
     {
         handlePublishSleepWakeUUID(NULL);
     }
-    else if ((str = OSDynamicCast(OSString, obj))) 
+    else if ((str = OSDynamicCast(OSString, obj)))
     {
-        // This branch caches the UUID for an upcoming sleep/wake        
+        // This branch caches the UUID for an upcoming sleep/wake
         if (queuedSleepWakeUUIDString) {
             queuedSleepWakeUUIDString->release();
             queuedSleepWakeUUIDString = NULL;
@@ -2613,27 +2973,13 @@ void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
 {
    ASSERT_GATED();
 
-   /* 
+   /*
     * Clear the current UUID
     */
    if (gSleepWakeUUIDIsSet)
    {
         DLOG("SleepWake UUID cleared\n");
 
-        OSString *UUIDstring = NULL;
-        
-        if (timeline && 
-            (UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey)))) 
-        {
-            PMEventDetails *details = PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear, 
-                            UUIDstring->getCStringNoCopy(), NULL, 0);
-            if (details) {
-                timeline->recordSystemPowerEvent( details );
-                details->release();
-            }
-            timeline->setNumEventsLoggedThisPeriod(0); 
-        }
-
         gSleepWakeUUIDIsSet = false;
 
         removeProperty(kIOPMSleepWakeUUIDKey);
@@ -2650,22 +2996,12 @@ void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
         publishThisUUID = queuedSleepWakeUUIDString;
         publishThisUUID->retain();
 
-        if (timeline) {
-            PMEventDetails  *details;
-            details = PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet,
-                              publishThisUUID->getCStringNoCopy(), NULL, 0);
-            if (details) {
-                timeline->recordSystemPowerEvent( details );
-                details->release();
-            }
-        }
-        
         if (publishThisUUID)
         {
             setProperty(kIOPMSleepWakeUUIDKey, publishThisUUID);
             publishThisUUID->release();
         }
-        
+
         gSleepWakeUUIDIsSet = true;
         messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet);
 
@@ -2674,6 +3010,24 @@ void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
     }
 }
 
+//******************************************************************************
+// initializeBootSessionUUID
+//
+// Initialize the boot session uuid at boot up and sets it into registry.
+//******************************************************************************
+
+void IOPMrootDomain::initializeBootSessionUUID(void)
+{
+    uuid_t          new_uuid;
+    uuid_string_t   new_uuid_string;
+
+    uuid_generate(new_uuid);
+    uuid_unparse_upper(new_uuid, new_uuid_string);
+    memcpy(bootsessionuuid_string, new_uuid_string, sizeof(uuid_string_t));
+
+    setProperty(kIOPMBootSessionUUIDKey, new_uuid_string);
+}
+
 //******************************************************************************
 // changePowerStateTo & changePowerStateToPriv
 //
@@ -2682,7 +3036,12 @@ void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
 
 IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
 {
-    return kIOReturnUnsupported;    // ignored
+    DLOG("changePowerStateTo(%lu)\n", ordinal);
+
+    if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
+        return kIOReturnUnsupported;
+
+    return super::changePowerStateTo(ordinal);
 }
 
 IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
@@ -2709,7 +3068,7 @@ bool IOPMrootDomain::abortHibernation(void)
 {
     bool ret = activitySinceSleep();
 
-    if (ret && !hibernateAborted)
+    if (ret && !hibernateAborted && checkSystemCanSustainFullWake())
     {
         DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
         hibernateAborted = true;
@@ -2726,6 +3085,52 @@ hibernate_should_abort(void)
         return (0);
 }
 
+//******************************************************************************
+// willNotifyPowerChildren
+//
+// Called after all interested drivers have all acknowledged the power change,
+// but before any power children is informed. Dispatched though a thread call,
+// so it is safe to perform work that might block on a sleeping disk. PM state
+// machine (not thread) will block w/o timeout until this function returns.
+//******************************************************************************
+
+void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState )
+{
+    OSDictionary *dict;
+    OSNumber *secs;
+
+    if (SLEEP_STATE == newPowerState)
+    {
+        if (!tasksSuspended)
+        {
+           AbsoluteTime deadline;
+           tasksSuspended = TRUE;
+           tasks_system_suspend(tasksSuspended);
+
+           clock_interval_to_deadline(10, kSecondScale, &deadline);
+           vm_pageout_wait(AbsoluteTime_to_scalar(&deadline));
+        }
+
+#if HIBERNATION
+        IOHibernateSystemSleep();
+        IOHibernateIOKitSleep();
+#endif
+        if (gRootDomain->activitySinceSleep()) {
+            dict = OSDictionary::withCapacity(1);
+            secs = OSNumber::withNumber(1, 32);
+
+            if (dict && secs) {
+                dict->setObject(gIOPMSettingDebugWakeRelativeKey, secs);
+                gRootDomain->setProperties(dict);
+                MSG("Reverting sleep with relative wake\n");
+            }
+            if (dict) dict->release();
+            if (secs) secs->release();
+        }
+
+    }
+}
+
 //******************************************************************************
 // sleepOnClamshellClosed
 //
@@ -2738,10 +3143,10 @@ bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
     if (!clamshellExists)
         return false;
 
-    DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d\n",
-        clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected);
+    DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
+        clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected, clamshellSleepDisabled);
 
-    return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) );
+    return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) && !clamshellSleepDisabled );
 }
 
 void IOPMrootDomain::sendClientClamshellNotification( void )
@@ -2750,17 +3155,17 @@ void IOPMrootDomain::sendClientClamshellNotification( void )
     if (!clamshellExists)
         return;
 
-    setProperty(kAppleClamshellStateKey, 
+    setProperty(kAppleClamshellStateKey,
         clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
 
-    setProperty(kAppleClamshellCausesSleepKey, 
+    setProperty(kAppleClamshellCausesSleepKey,
         shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
 
-    /* Argument to message is a bitfiel of 
+    /* Argument to message is a bitfiel of
      *      ( kClamshellStateBit | kClamshellSleepBit )
      */
     messageClients(kIOPMMessageClamshellStateChange,
-        (void *) ( (clamshellClosed ? kClamshellStateBit : 0)
+        (void *)(uintptr_t) ( (clamshellClosed ? kClamshellStateBit : 0)
              | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
 }
 
@@ -2787,6 +3192,35 @@ void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
     OSBitOrAtomic(flags, &platformSleepSupport);
 }
 
+//******************************************************************************
+// setDisableClamShellSleep
+//
+//******************************************************************************
+
+void IOPMrootDomain::setDisableClamShellSleep( bool val )
+{
+    if (gIOPMWorkLoop->inGate() == false) {
+
+       gIOPMWorkLoop->runAction(
+               OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setDisableClamShellSleep),
+               (OSObject *)this,
+               (void *)val);
+
+       return;
+    }
+    else {
+       DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val);
+       if ( clamshellSleepDisabled != val )
+       {
+           clamshellSleepDisabled = val;
+           // If clamshellSleepDisabled is reset to 0, reevaluate if
+           // system need to go to sleep due to clamshell state
+           if ( !clamshellSleepDisabled && clamshellClosed)
+              handlePowerNotification(kLocalEvalClamshellCommand);
+       }
+    }
+}
+
 //******************************************************************************
 // wakeFromDoze
 //
@@ -2819,7 +3253,7 @@ void IOPMrootDomain::publishFeature( const char * feature )
 //******************************************************************************
 
 void IOPMrootDomain::publishFeature(
-    const char *feature, 
+    const char *feature,
     uint32_t supportedWhere,
     uint32_t *uniqueFeatureID)
 {
@@ -2837,7 +3271,7 @@ void IOPMrootDomain::publishFeature(
         // Feature isn't supported anywhere!
         return;
     }
-    
+
     if(next_feature_id > 5000) {
         // Far, far too many features!
         return;
@@ -2847,16 +3281,16 @@ void IOPMrootDomain::publishFeature(
 
     OSDictionary *features =
         (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
-    
+
     // Create new features dict if necessary
     if ( features && OSDynamicCast(OSDictionary, features)) {
         features = OSDictionary::withDictionary(features);
     } else {
         features = OSDictionary::withCapacity(1);
     }
-    
+
     // Create OSNumber to track new feature
-    
+
     next_feature_id += 1;
     if( uniqueFeatureID ) {
         // We don't really mind if the calling kext didn't give us a place
@@ -2882,7 +3316,7 @@ void IOPMrootDomain::publishFeature(
                             (const OSObject **)&existing_feature, 1, 2);
         } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
         {
-            // Add object to existing array        
+            // Add object to existing array
             existing_feature_arr = OSArray::withArray(
                             existing_feature_arr,
                             existing_feature_arr->getCount() + 1);
@@ -2898,19 +3332,19 @@ void IOPMrootDomain::publishFeature(
     } else {
         // The easy case: no previously existing features listed. We simply
         // set the OSNumber at key 'feature' and we're on our way.
-        features->setObject(feature, new_feature_data);        
+        features->setObject(feature, new_feature_data);
     }
-    
+
     new_feature_data->release();
 
     setProperty(kRootDomainSupportedFeatures, features);
 
     features->release();
 
-    if(featuresDictLock) IOLockUnlock(featuresDictLock);    
+    if(featuresDictLock) IOLockUnlock(featuresDictLock);
 
     // Notify EnergySaver and all those in user space so they might
-    // re-populate their feature specific UI    
+    // re-populate their feature specific UI
     if(pmPowerStateQueue) {
         pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
     }
@@ -2928,7 +3362,7 @@ IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
     uint32_t                feature_value = 0;
     uint16_t                feature_id = 0;
     bool                    madeAChange = false;
-    
+
     OSSymbol                *dictKey = NULL;
     OSCollectionIterator    *dictIterator = NULL;
     OSArray                 *arrayMember  = NULL;
@@ -2937,11 +3371,14 @@ IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
     OSNumber                *osNum        = NULL;
     OSArray                 *arrayMemberCopy;
 
+    if (kBadPMFeatureID == removeFeatureID)
+        return kIOReturnNotFound;
+
     if(featuresDictLock) IOLockLock(featuresDictLock);
 
     OSDictionary *features =
         (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
-    
+
     if ( features && OSDynamicCast(OSDictionary, features) )
     {
         // Any modifications to the dictionary are made to the copy to prevent
@@ -2953,20 +3390,20 @@ IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
         ret = kIOReturnNotFound;
         goto exit;
     }
-    
+
     // We iterate 'features' dictionary looking for an entry tagged
     // with 'removeFeatureID'. If found, we remove it from our tracking
     // structures and notify the OS via a general interest message.
-    
+
     dictIterator = OSCollectionIterator::withCollection(features);
     if(!dictIterator) {
         goto exit;
     }
-    
+
     while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
     {
         osObj = features->getObject(dictKey);
-        
+
         // Each Feature is either tracked by an OSNumber
         if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
         {
@@ -2980,19 +3417,19 @@ IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
                 madeAChange = true;
                 break;
             }
-        
+
         // Or tracked by an OSArray of OSNumbers
         } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
         {
             unsigned int arrayCount = arrayMember->getCount();
-            
+
             for(unsigned int i=0; i<arrayCount; i++)
             {
                 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
                 if(!osNum) {
                     continue;
                 }
-                
+
                 feature_value = osNum->unsigned32BitValue();
                 feature_id = (uint16_t)(feature_value >> 16);
 
@@ -3018,32 +3455,54 @@ IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
                     break;
                 }
             }
-        }    
+        }
     }
-    
+
     dictIterator->release();
-    
+
     if( madeAChange )
     {
-        ret = kIOReturnSuccess;    
+        ret = kIOReturnSuccess;
 
         setProperty(kRootDomainSupportedFeatures, features);
-    
+
         // Notify EnergySaver and all those in user space so they might
-        // re-populate their feature specific UI    
+        // re-populate their feature specific UI
         if(pmPowerStateQueue) {
             pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
         }
     } else {
         ret = kIOReturnNotFound;
     }
-    
+
 exit:
     if(features)    features->release();
-    if(featuresDictLock) IOLockUnlock(featuresDictLock);    
+    if(featuresDictLock) IOLockUnlock(featuresDictLock);
     return ret;
 }
 
+//******************************************************************************
+// publishPMSetting (private)
+//
+// Should only be called by PMSettingObject to publish a PM Setting as a
+// supported feature.
+//******************************************************************************
+
+void IOPMrootDomain::publishPMSetting(
+    const OSSymbol * feature, uint32_t where, uint32_t * featureID )
+{
+    if (noPublishPMSettings &&
+        (noPublishPMSettings->getNextIndexOfObject(feature, 0) != (unsigned int)-1))
+    {
+        // Setting found in noPublishPMSettings array
+        *featureID = kBadPMFeatureID;
+        return;
+    }
+
+    publishFeature(
+        feature->getCStringNoCopy(), where, featureID);
+}
+
 //******************************************************************************
 // setPMSetting (private)
 //
@@ -3067,7 +3526,7 @@ IOReturn IOPMrootDomain::setPMSetting(
 
     PMSETTING_LOCK();
 
-    // Update settings dict so changes are visible from copyPMSetting().    
+    // Update settings dict so changes are visible from copyPMSetting().
     fPMSettingsDict->setObject(type, object);
 
     // Prep all PMSetting objects with the given 'type' for callout.
@@ -3092,14 +3551,14 @@ IOReturn IOPMrootDomain::setPMSetting(
         pmso = (PMSettingObject *) array->getObject(i);
         if (pmso->disabled)
             continue;
-        entries[j].thread = thisThread;        
+        entries[j].thread = thisThread;
         queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link);
         chosen->setObject(pmso);
         j++;
     }
     count = j;
     if (!count)
-        goto unlock_exit; 
+        goto unlock_exit;
 
     PMSETTING_UNLOCK();
 
@@ -3149,7 +3608,7 @@ OSObject * IOPMrootDomain::copyPMSetting(
         obj->retain();
     }
     PMSETTING_UNLOCK();
-    
+
     return obj;
 }
 
@@ -3166,7 +3625,7 @@ IOReturn IOPMrootDomain::registerPMSettingController(
     uintptr_t                       refcon,
     OSObject                        **handle)
 {
-    return registerPMSettingController( 
+    return registerPMSettingController(
             settings,
             (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
             func, target, refcon, handle);
@@ -3181,9 +3640,9 @@ IOReturn IOPMrootDomain::registerPMSettingController(
 //  * settings - An OSArray containing OSSymbols. Caller should populate this
 //          array with a list of settings caller wants notifications from.
 //  * func - A C function callback of the type IOPMSettingControllerCallback
-//  * target - caller may provide an OSObject *, which PM will pass as an 
+//  * target - caller may provide an OSObject *, which PM will pass as an
 //          target to calls to "func"
-//  * refcon - caller may provide an void *, which PM will pass as an 
+//  * refcon - caller may provide an void *, which PM will pass as an
 //          argument to calls to "func"
 //  * handle - This is a return argument. We will populate this pointer upon
 //          call success. Hold onto this and pass this argument to
@@ -3213,7 +3672,7 @@ IOReturn IOPMrootDomain::registerPMSettingController(
     }
 
     pmso = PMSettingObject::pmSettingObject(
-                (IOPMrootDomain *) this, func, target, 
+                (IOPMrootDomain *) this, func, target,
                 refcon, supportedPowerSources, settings, &pmsh);
 
     if (!pmso) {
@@ -3285,7 +3744,7 @@ void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
 
     // Search each PM settings array in the kernel.
     iter = OSCollectionIterator::withCollection(settingsCallbacks);
-    if (iter) 
+    if (iter)
     {
         while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject())))
         {
@@ -3314,12 +3773,12 @@ void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
 //******************************************************************************
 
 void IOPMrootDomain::informCPUStateChange(
-    uint32_t type, 
+    uint32_t type,
     uint32_t value )
 {
 #if defined(__i386__) || defined(__x86_64__)
 
-    pmioctlVariableInfo_t varInfoStruct;                            
+    pmioctlVariableInfo_t varInfoStruct;
     int                 pmCPUret = 0;
     const char          *varNameStr = NULL;
     int32_t             *varIndex   = NULL;
@@ -3333,7 +3792,7 @@ void IOPMrootDomain::informCPUStateChange(
     } else {
         return;
     }
-    
+
     // Set the new value!
     // pmCPUControl will assign us a new ID if one doesn't exist yet
     bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
@@ -3343,8 +3802,8 @@ void IOPMrootDomain::informCPUStateChange(
     varInfoStruct.varCurValue   = value;
     strncpy( (char *)varInfoStruct.varName,
              (const char *)varNameStr,
-             strlen(varNameStr) + 1 );                 
-    
+             strlen(varNameStr) + 1 );
+
     // Set!
     pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
 
@@ -3352,19 +3811,19 @@ void IOPMrootDomain::informCPUStateChange(
     if ((0 == pmCPUret)
         && (*varIndex == kCPUUnknownIndex))
     {
-        // pmCPUControl has assigned us a new variable ID. 
+        // pmCPUControl has assigned us a new variable ID.
         // Let's re-read the structure we just SET to learn that ID.
         pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
 
-        if (0 == pmCPUret) 
-        {        
+        if (0 == pmCPUret)
+        {
             // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
             *varIndex = varInfoStruct.varID;
         }
-    } 
-    
+    }
+
     return;
-    
+
 #endif /* __i386__ || __x86_64__ */
 }
 
@@ -3377,81 +3836,127 @@ void IOPMrootDomain::informCPUStateChange(
 // evaluateSystemSleepPolicy
 //******************************************************************************
 
+#define kIOPlatformSystemSleepPolicyKey     "IOPlatformSystemSleepPolicy"
+
+// Sleep flags
+enum {
+    kIOPMSleepFlagHibernate         = 0x00000001,
+    kIOPMSleepFlagSleepTimerEnable  = 0x00000002
+};
+
 struct IOPMSystemSleepPolicyEntry
 {
     uint32_t    factorMask;
     uint32_t    factorBits;
     uint32_t    sleepFlags;
     uint32_t    wakeEvents;
-};
+} __attribute__((packed));
 
 struct IOPMSystemSleepPolicyTable
 {
-    uint8_t     signature[4];
+    uint32_t    signature;
     uint16_t    version;
     uint16_t    entryCount;
     IOPMSystemSleepPolicyEntry  entries[];
-};
+} __attribute__((packed));
 
 enum {
-    kIOPMSleepFactorSleepTimerWake          = 0x00000001,
-    kIOPMSleepFactorLidOpen                 = 0x00000002,
-    kIOPMSleepFactorACPower                 = 0x00000004,
-    kIOPMSleepFactorLowBattery              = 0x00000008,
-    kIOPMSleepFactorDeepSleepNoDelay        = 0x00000010,
-    kIOPMSleepFactorDeepSleepDemand         = 0x00000020,
-    kIOPMSleepFactorDeepSleepDisable        = 0x00000040,
-    kIOPMSleepFactorUSBExternalDevice       = 0x00000080,
-    kIOPMSleepFactorBluetoothHIDDevice      = 0x00000100,
-    kIOPMSleepFactorExternalMediaMounted    = 0x00000200,
-    kIOPMSleepFactorDriverAssertBit5        = 0x00000400,   /* Reserved for ThunderBolt */
-    kIOPMSleepFactorDriverAssertBit6        = 0x00000800,
-    kIOPMSleepFactorDriverAssertBit7        = 0x00001000
+    kIOPMSleepAttributeHibernateSetup   = 0x00000001,
+    kIOPMSleepAttributeHibernateSleep   = 0x00000002
 };
 
-bool IOPMrootDomain::evaluateSystemSleepPolicy( IOPMSystemSleepParameters * p )
+static uint32_t
+getSleepTypeAttributes( uint32_t sleepType )
 {
-    const IOPMSystemSleepPolicyTable * pt;
-    OSObject *  prop = 0;
-    OSData *    policyData;
-    uint32_t    currentFactors;
-    uint32_t    deepSleepDelay = 0;
-    bool        success = false;
-
-    if (getProperty(kIOPMDeepSleepEnabledKey) != kOSBooleanTrue)
-        return false;
-
-    getSleepOption(kIOPMDeepSleepDelayKey, &deepSleepDelay);
+    static const uint32_t sleepTypeAttributes[ kIOPMSleepTypeLast ] =
+    {
+    /* invalid   */ 0,
+    /* abort     */ 0,
+    /* normal    */ 0,
+    /* safesleep */ kIOPMSleepAttributeHibernateSetup,
+    /* hibernate */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
+    /* standby   */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
+    /* poweroff  */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
+    /* deepidle  */ 0
+    };
 
-    prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
-    if (!prop)
-        return false;
+    if (sleepType >= kIOPMSleepTypeLast)
+        return 0;
 
-    policyData = OSDynamicCast(OSData, prop);
-    if (!policyData ||
-        (policyData->getLength() < sizeof(IOPMSystemSleepPolicyTable)))
-    {
-        goto done;
-    }
+    return sleepTypeAttributes[sleepType];
+}
 
-    pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
-    if ((pt->signature[0] != 'S') ||
-        (pt->signature[1] != 'L') ||
-        (pt->signature[2] != 'P') ||
-        (pt->signature[3] != 'T') ||
-        (pt->version      != 1)   ||
-        (pt->entryCount   == 0))
-    {
-        goto done;
+bool IOPMrootDomain::evaluateSystemSleepPolicy(
+    IOPMSystemSleepParameters * params, int sleepPhase, uint32_t * hibMode )
+{
+    const IOPMSystemSleepPolicyTable * pt;
+    OSObject *  prop = 0;
+    OSData *    policyData;
+    uint64_t    currentFactors = 0;
+    uint32_t    standbyDelay   = 0;
+    uint32_t    powerOffDelay  = 0;
+    uint32_t    powerOffTimer  = 0;
+    uint32_t    mismatch;
+    bool        standbyEnabled;
+    bool        powerOffEnabled;
+    bool        found = false;
+
+    // Get platform's sleep policy table
+    if (!gSleepPolicyHandler)
+    {
+        prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
+        if (!prop) goto done;
+    }
+
+    // Fetch additional settings
+    standbyEnabled = (getSleepOption(kIOPMDeepSleepDelayKey, &standbyDelay)
+        && (getProperty(kIOPMDeepSleepEnabledKey) == kOSBooleanTrue));
+    powerOffEnabled = (getSleepOption(kIOPMAutoPowerOffDelayKey, &powerOffDelay)
+        && (getProperty(kIOPMAutoPowerOffEnabledKey) == kOSBooleanTrue));
+    if (!getSleepOption(kIOPMAutoPowerOffTimerKey, &powerOffTimer))
+        powerOffTimer = powerOffDelay;
+
+    DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
+        sleepPhase, standbyEnabled, standbyDelay,
+        powerOffEnabled, powerOffDelay, powerOffTimer, *hibMode);
+
+    // pmset level overrides
+    if ((*hibMode & kIOHibernateModeOn) == 0)
+    {
+        if (!gSleepPolicyHandler)
+        {
+            standbyEnabled  = false;
+            powerOffEnabled = false;
+        }
     }
-
-    if ((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
-        (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount))
+    else if (!(*hibMode & kIOHibernateModeSleep))
     {
-        goto done;
+        // Force hibernate (i.e. mode 25)
+        // If standby is enabled, force standy.
+        // If poweroff is enabled, force poweroff.
+        if (standbyEnabled)
+            currentFactors |= kIOPMSleepFactorStandbyForced;
+        else if (powerOffEnabled)
+            currentFactors |= kIOPMSleepFactorAutoPowerOffForced;
+        else
+            currentFactors |= kIOPMSleepFactorHibernateForced;
     }
 
-    currentFactors = 0;
+    // Current factors based on environment and assertions
+    if (sleepTimerMaintenance)
+        currentFactors |= kIOPMSleepFactorSleepTimerWake;
+    if (standbyEnabled && sleepToStandby && !gSleepPolicyHandler)
+        currentFactors |= kIOPMSleepFactorSleepTimerWake;
+    if (!clamshellClosed)
+        currentFactors |= kIOPMSleepFactorLidOpen;
+    if (acAdaptorConnected)
+        currentFactors |= kIOPMSleepFactorACPower;
+    if (lowBatteryCondition)
+        currentFactors |= kIOPMSleepFactorBatteryLow;
+    if (!standbyDelay)
+        currentFactors |= kIOPMSleepFactorStandbyNoDelay;
+    if (!standbyEnabled)
+        currentFactors |= kIOPMSleepFactorStandbyDisabled;
     if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
         kIOPMDriverAssertionLevelOff)
         currentFactors |= kIOPMSleepFactorUSBExternalDevice;
@@ -3461,57 +3966,175 @@ bool IOPMrootDomain::evaluateSystemSleepPolicy( IOPMSystemSleepParameters * p )
     if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
         kIOPMDriverAssertionLevelOff)
         currentFactors |= kIOPMSleepFactorExternalMediaMounted;
-    if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=    /* AssertionBit5 = Thunderbolt */
+    if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
         kIOPMDriverAssertionLevelOff)
-        currentFactors |= kIOPMSleepFactorDriverAssertBit5;
-    if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit7) !=
+        currentFactors |= kIOPMSleepFactorThunderboltDevice;
+    if (_scheduledAlarms != 0)
+        currentFactors |= kIOPMSleepFactorRTCAlarmScheduled;
+    if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) !=
         kIOPMDriverAssertionLevelOff)
-        currentFactors |= kIOPMSleepFactorDriverAssertBit7;
-    if (0 == deepSleepDelay)
-        currentFactors |= kIOPMSleepFactorDeepSleepNoDelay;
-    if (!clamshellClosed)
-        currentFactors |= kIOPMSleepFactorLidOpen;
-    if (acAdaptorConnected)
-        currentFactors |= kIOPMSleepFactorACPower;
-    if (lowBatteryCondition)
-        currentFactors |= kIOPMSleepFactorLowBattery;
-    if (sleepTimerMaintenance)
-        currentFactors |= kIOPMSleepFactorSleepTimerWake;
+        currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled;
+#define TCPKEEPALIVE 1
+#if TCPKEEPALIVE
+    if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit) !=
+        kIOPMDriverAssertionLevelOff)
+        currentFactors |= kIOPMSleepFactorNetworkKeepAliveActive;
+#endif
+    if (!powerOffEnabled)
+        currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled;
+    if (desktopMode)
+        currentFactors |= kIOPMSleepFactorExternalDisplay;
+    if (userWasActive)
+        currentFactors |= kIOPMSleepFactorLocalUserActivity;
+    if (darkWakeHibernateError && !CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
+        currentFactors |= kIOPMSleepFactorHibernateFailed;
+    if (thermalWarningState)
+        currentFactors |= kIOPMSleepFactorThermalWarning;
+
+    DLOG("sleep factors 0x%llx\n", currentFactors);
+
+    if (gSleepPolicyHandler)
+    {
+        uint32_t    savedHibernateMode;
+        IOReturn    result;
+
+        if (!gSleepPolicyVars)
+        {
+            gSleepPolicyVars = IONew(IOPMSystemSleepPolicyVariables, 1);
+            if (!gSleepPolicyVars)
+                goto done;
+            bzero(gSleepPolicyVars, sizeof(*gSleepPolicyVars));
+        }
+        gSleepPolicyVars->signature = kIOPMSystemSleepPolicySignature;
+        gSleepPolicyVars->version   = kIOPMSystemSleepPolicyVersion;
+        gSleepPolicyVars->currentCapability = _currentCapability;
+        gSleepPolicyVars->highestCapability = _highestCapability;
+        gSleepPolicyVars->sleepFactors      = currentFactors;
+        gSleepPolicyVars->sleepReason       = lastSleepReason;
+        gSleepPolicyVars->sleepPhase        = sleepPhase;
+        gSleepPolicyVars->standbyDelay      = standbyDelay;
+        gSleepPolicyVars->poweroffDelay     = powerOffDelay;
+        gSleepPolicyVars->scheduledAlarms   = _scheduledAlarms | _userScheduledAlarm;
+        gSleepPolicyVars->poweroffTimer     = powerOffTimer;
+
+        if (kIOPMSleepPhase0 == sleepPhase)
+        {
+            // preserve hibernateMode
+            savedHibernateMode = gSleepPolicyVars->hibernateMode;
+            gSleepPolicyVars->hibernateMode = *hibMode;
+        }
+        else if (kIOPMSleepPhase1 == sleepPhase)
+        {
+            // use original hibernateMode for phase2
+            gSleepPolicyVars->hibernateMode = *hibMode;
+        }
+
+        result = gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params);
+
+        if (kIOPMSleepPhase0 == sleepPhase)
+        {
+            // restore hibernateMode
+            gSleepPolicyVars->hibernateMode = savedHibernateMode;
+        }
+
+        if ((result != kIOReturnSuccess) ||
+             (kIOPMSleepTypeInvalid == params->sleepType) ||
+             (params->sleepType >= kIOPMSleepTypeLast) ||
+             (kIOPMSystemSleepParametersVersion != params->version))
+        {
+            MSG("sleep policy handler error\n");
+            goto done;
+        }
+
+        if ((getSleepTypeAttributes(params->sleepType) &
+             kIOPMSleepAttributeHibernateSetup) &&
+            ((*hibMode & kIOHibernateModeOn) == 0))
+        {
+            *hibMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
+        }
+
+        DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
+            params->version, params->sleepType, params->sleepFlags,
+            params->ecWakeEvents, params->ecWakeTimer, params->ecPoweroffTimer);
+        found = true;
+        goto done;
+    }
+
+    // Policy table is meaningless without standby enabled
+    if (!standbyEnabled)
+        goto done;
+
+    // Validate the sleep policy table
+    policyData = OSDynamicCast(OSData, prop);
+    if (!policyData || (policyData->getLength() <= sizeof(IOPMSystemSleepPolicyTable)))
+        goto done;
+
+    pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
+    if ((pt->signature != kIOPMSystemSleepPolicySignature) ||
+        (pt->version != 1) || (0 == pt->entryCount))
+        goto done;
 
-    // pmset overrides
-    if ((hibernateMode & kIOHibernateModeOn) == 0)
-        currentFactors |= kIOPMSleepFactorDeepSleepDisable;
-    else if ((hibernateMode & kIOHibernateModeSleep) == 0)
-        currentFactors |= kIOPMSleepFactorDeepSleepDemand;
-    
-    DLOG("Sleep policy %u entries, current factors 0x%x\n",
-        pt->entryCount, currentFactors);
+    if (((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
+         (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount)))
+        goto done;
 
     for (uint32_t i = 0; i < pt->entryCount; i++)
     {
-        const IOPMSystemSleepPolicyEntry * policyEntry = &pt->entries[i];
+        const IOPMSystemSleepPolicyEntry * entry = &pt->entries[i];
+        mismatch = (((uint32_t)currentFactors ^ entry->factorBits) & entry->factorMask);
+
+        DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
+            entry->factorMask, entry->factorBits,
+            entry->sleepFlags, entry->wakeEvents, mismatch);
+        if (mismatch)
+            continue;
 
-        DLOG("factor mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x\n",
-            policyEntry->factorMask, policyEntry->factorBits,
-            policyEntry->sleepFlags, policyEntry->wakeEvents);
+        DLOG("^ found match\n");
+        found = true;
 
-        if ((currentFactors ^ policyEntry->factorBits) & policyEntry->factorMask)
-            continue;   // mismatch, try next
+        params->version = kIOPMSystemSleepParametersVersion;
+        params->reserved1 = 1;
+        if (entry->sleepFlags & kIOPMSleepFlagHibernate)
+            params->sleepType = kIOPMSleepTypeStandby;
+        else
+            params->sleepType = kIOPMSleepTypeNormalSleep;
 
-        if (p)
+        params->ecWakeEvents = entry->wakeEvents;
+        if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
         {
-            p->version    = 1;
-            p->sleepFlags = policyEntry->sleepFlags;
-            p->sleepTimer = 0;
-            p->wakeEvents = policyEntry->wakeEvents;
-            if (p->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
+            if (kIOPMSleepPhase2 == sleepPhase)
             {
-                p->sleepTimer = deepSleepDelay;
+                clock_sec_t now_secs = gIOLastSleepTime.tv_sec;
+
+                if (!_standbyTimerResetSeconds ||
+                    (now_secs <= _standbyTimerResetSeconds))
+                {
+                    // Reset standby timer adjustment
+                    _standbyTimerResetSeconds = now_secs;
+                    DLOG("standby delay %u, reset %u\n",
+                        standbyDelay, (uint32_t) _standbyTimerResetSeconds);
+                }
+                else if (standbyDelay)
+                {
+                    // Shorten the standby delay timer
+                    clock_sec_t elapsed = now_secs - _standbyTimerResetSeconds;
+                    if (standbyDelay > elapsed)
+                        standbyDelay -= elapsed;
+                    else
+                        standbyDelay = 1; // must be > 0
+
+                    DLOG("standby delay %u, elapsed %u\n",
+                        standbyDelay, (uint32_t) elapsed);
+                }
             }
+            params->ecWakeTimer = standbyDelay;
+        }
+        else if (kIOPMSleepPhase2 == sleepPhase)
+        {
+            // A sleep that does not enable the sleep timer will reset
+            // the standby delay adjustment.
+            _standbyTimerResetSeconds = 0;
         }
-
-        DLOG("matched policy entry %u\n", i);
-        success = true;
         break;
     }
 
@@ -3519,28 +4142,59 @@ done:
     if (prop)
         prop->release();
 
-    return success;
+    return found;
 }
 
+static IOPMSystemSleepParameters gEarlySystemSleepParams;
+
 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
 {
-    IOPMSystemSleepParameters   params;
-
-    // Evaluate sleep policy before driver sleep phase.
+    // Evaluate early (priority interest phase), before drivers sleep.
 
     DLOG("%s\n", __FUNCTION__);
     removeProperty(kIOPMSystemSleepParametersKey);
 
+    // Full wake resets the standby timer delay adjustment
+    if (_highestCapability & kIOPMSystemCapabilityGraphics)
+        _standbyTimerResetSeconds = 0;
+
     hibernateDisabled = false;
     hibernateMode = 0;
     getSleepOption(kIOHibernateModeKey, &hibernateMode);
 
-    if (!hibernateNoDefeat &&
-        evaluateSystemSleepPolicy(&params) &&
-        ((params.sleepFlags & kIOPMSleepFlagHibernate) == 0))
+    // Save for late evaluation if sleep is aborted
+    bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams));
+
+    if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1,
+                                  &hibernateMode))
+    {
+        if (!hibernateRetry &&
+            ((getSleepTypeAttributes(gEarlySystemSleepParams.sleepType) &
+              kIOPMSleepAttributeHibernateSetup) == 0))
+        {
+            // skip hibernate setup
+            hibernateDisabled = true;
+        }
+    }
+
+    // Publish IOPMSystemSleepType
+    uint32_t sleepType = gEarlySystemSleepParams.sleepType;
+    if (sleepType == kIOPMSleepTypeInvalid)
+    {
+        // no sleep policy
+        sleepType = kIOPMSleepTypeNormalSleep;
+        if (hibernateMode & kIOHibernateModeOn)
+            sleepType = (hibernateMode & kIOHibernateModeSleep) ?
+                        kIOPMSleepTypeSafeSleep : kIOPMSleepTypeHibernate;
+    }
+    else if ((sleepType == kIOPMSleepTypeStandby) &&
+             (gEarlySystemSleepParams.ecPoweroffTimer))
     {
-        hibernateDisabled = true;
+        // report the lowest possible sleep state
+        sleepType = kIOPMSleepTypePowerOff;
     }
+
+    setProperty(kIOPMSystemSleepTypeKey, sleepType, 32);
 }
 
 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
@@ -3548,27 +4202,34 @@ void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
     IOPMSystemSleepParameters   params;
     OSData *                    paramsData;
 
-    // Evaluate sleep policy after drivers but before platform sleep.
+    // Evaluate sleep policy after sleeping drivers but before platform sleep.
 
     DLOG("%s\n", __FUNCTION__);
 
-    if (evaluateSystemSleepPolicy(&params))
+    bzero(&params, sizeof(params));
+    if (evaluateSystemSleepPolicy(&params, kIOPMSleepPhase2, &hibernateMode))
     {
         if ((hibernateDisabled || hibernateAborted) &&
-            (params.sleepFlags & kIOPMSleepFlagHibernate))
+            (getSleepTypeAttributes(params.sleepType) &
+             kIOPMSleepAttributeHibernateSetup))
         {
-            // Should hibernate but unable to or aborted.
-            // Arm timer for a short sleep and retry or wake fully.
-
-            params.sleepFlags &= ~kIOPMSleepFlagHibernate;
-            params.sleepFlags |= kIOPMSleepFlagSleepTimerEnable;
-            params.sleepTimer = 1;
-            hibernateNoDefeat = true;
+            // Final evaluation picked a state requiring hibernation,
+            // but hibernate setup was skipped. Arm a short sleep using
+            // the early non-hibernate sleep parameters.
+            // Set hibernateRetry flag to force hibernate setup on the
+            // next sleep.
+
+            bcopy(&gEarlySystemSleepParams, &params, sizeof(params));
+            params.sleepType = kIOPMSleepTypeAbortedSleep;
+            params.ecWakeTimer = 1;
+            hibernateRetry = true;
             DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
-                        params.sleepTimer, hibernateDisabled, hibernateAborted);
+                params.ecWakeTimer, hibernateDisabled, hibernateAborted);
         }
         else
-            hibernateNoDefeat = false;
+        {
+            hibernateRetry = false;
+        }
 
         paramsData = OSData::withBytes(&params, sizeof(params));
         if (paramsData)
@@ -3577,25 +4238,31 @@ void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
             paramsData->release();
         }
 
-        if (params.sleepFlags & kIOPMSleepFlagHibernate)
+        if (getSleepTypeAttributes(params.sleepType) &
+            kIOPMSleepAttributeHibernateSleep)
         {
-            // Force hibernate
+            // Disable sleep to force hibernation
             gIOHibernateMode &= ~kIOHibernateModeSleep;
         }
     }
 }
 
 bool IOPMrootDomain::getHibernateSettings(
-    uint32_t *  hibernateMode,
+    uint32_t *  hibernateModePtr,
     uint32_t *  hibernateFreeRatio,
     uint32_t *  hibernateFreeTime )
 {
-    bool ok = getSleepOption(kIOHibernateModeKey, hibernateMode);
+    // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
+    // has updated the hibernateDisabled flag.
+
+    bool ok = getSleepOption(kIOHibernateModeKey, hibernateModePtr);
     getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
     getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
     if (hibernateDisabled)
-        *hibernateMode = 0;
-    DLOG("hibernateMode 0x%x\n", *hibernateMode);
+        *hibernateModePtr = 0;
+    else if (gSleepPolicyHandler)
+        *hibernateModePtr = hibernateMode;
+    DLOG("hibernateMode 0x%x\n", *hibernateModePtr);
     return ok;
 }
 
@@ -3609,7 +4276,7 @@ bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
 
     optionsProp = copyProperty(kRootDomainSleepOptionsKey);
     optionsDict = OSDynamicCast(OSDictionary, optionsProp);
-    
+
     if (optionsDict)
     {
         obj = optionsDict->getObject(key);
@@ -3619,10 +4286,18 @@ bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
     {
         obj = copyProperty(key);
     }
-    if (obj && (num = OSDynamicCast(OSNumber, obj)))
+    if (obj
     {
-        *option = num->unsigned32BitValue();
-        ok = true;
+        if ((num = OSDynamicCast(OSNumber, obj)))
+        {
+            *option = num->unsigned32BitValue();
+            ok = true;
+        }
+        else if (OSDynamicCast(OSBoolean, obj))
+        {
+            *option = (obj == kOSBooleanTrue) ? 1 : 0;
+            ok = true;
+        }
     }
 
     if (obj)
@@ -3634,6 +4309,37 @@ bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
 }
 #endif /* HIBERNATION */
 
+IOReturn IOPMrootDomain::getSystemSleepType( uint32_t * sleepType )
+{
+#if HIBERNATION
+    IOPMSystemSleepParameters   params;
+    uint32_t                    hibMode = 0;
+    bool                        ok;
+
+    if (gIOPMWorkLoop->inGate() == false)
+    {
+        IOReturn ret = gIOPMWorkLoop->runAction(
+                        OSMemberFunctionCast(IOWorkLoop::Action, this,
+                            &IOPMrootDomain::getSystemSleepType),
+                        (OSObject *) this,
+                        (void *) sleepType);
+        return ret;
+    }
+
+    getSleepOption(kIOHibernateModeKey, &hibMode);
+    bzero(&params, sizeof(params));
+
+    ok = evaluateSystemSleepPolicy(&params, kIOPMSleepPhase0, &hibMode);
+    if (ok)
+    {
+        *sleepType = params.sleepType;
+        return kIOReturnSuccess;
+    }
+#endif
+
+    return kIOReturnUnsupported;
+}
+
 // MARK: -
 // MARK: Shutdown and Restart
 
@@ -3643,89 +4349,102 @@ bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
 //******************************************************************************
 
 struct HaltRestartApplierContext {
-       IOPMrootDomain *        RootDomain;
-       unsigned long           PowerState;
-       IOPMPowerFlags          PowerFlags;
-       UInt32                          MessageType;
-       UInt32                          Counter;
+    IOPMrootDomain *    RootDomain;
+    unsigned long       PowerState;
+    IOPMPowerFlags      PowerFlags;
+    UInt32              MessageType;
+    UInt32              Counter;
+    const char *        LogString;
 };
 
 static void
 platformHaltRestartApplier( OSObject * object, void * context )
 {
-       IOPowerStateChangeNotification  notify;
-       HaltRestartApplierContext *             ctx;
-       AbsoluteTime                                    startTime;
-       UInt32                                                  deltaTime;
+    IOPowerStateChangeNotification  notify;
+    HaltRestartApplierContext *     ctx;
+    AbsoluteTime                    startTime;
+    uint32_t                        deltaTime;
+
+    ctx = (HaltRestartApplierContext *) context;
 
-       ctx = (HaltRestartApplierContext *) context;
-       
-       memset(&notify, 0, sizeof(notify));
-    notify.powerRef    = (void *)ctx->Counter;
+    memset(&notify, 0, sizeof(notify));
+    notify.powerRef    = (void *)(uintptr_t)ctx->Counter;
     notify.returnValue = 0;
     notify.stateNumber = ctx->PowerState;
     notify.stateFlags  = ctx->PowerFlags;
 
-       clock_get_uptime(&startTime);
+    clock_get_uptime(&startTime);
     ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
-       deltaTime = computeDeltaTimeMS(&startTime);
+    deltaTime = computeDeltaTimeMS(&startTime);
 
-       if ((deltaTime > kPMHaltTimeoutMS) ||
+    if ((deltaTime > kPMHaltTimeoutMS) ||
         (gIOKitDebug & kIOLogPMRootDomain))
-       {
-               _IOServiceInterestNotifier * notifier;
-               notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
-
-               // IOService children of IOPMrootDomain are not instrumented.
-               // Only IORootParent currently falls under that group.
-
-               if (notifier)
-               {
-                       LOG("%s handler %p took %u ms\n",
-                               (ctx->MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" :
-                                        (ctx->MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart",
-                               notifier->handler, (uint32_t) deltaTime );
-               }
-       }
+    {
+        _IOServiceInterestNotifier * notifier;
+        notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
+
+        // IOService children of IOPMrootDomain are not instrumented.
+        // Only IORootParent currently falls under that group.
+
+        if (notifier)
+        {
+            LOG("%s handler %p took %u ms\n",
+                ctx->LogString, OBFUSCATE(notifier->handler), deltaTime);
+        }
+    }
+
+    ctx->Counter++;
+}
 
-       ctx->Counter++;
+static void quiescePowerTreeCallback( void * target, void * param )
+{
+    IOLockLock(gPMHaltLock);
+    gPMQuiesced = true;
+    thread_wakeup(param);
+    IOLockUnlock(gPMHaltLock);
 }
 
 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
 {
-       HaltRestartApplierContext       ctx;
-       AbsoluteTime                            startTime;
-       UInt32                                          deltaTime;
+    HaltRestartApplierContext   ctx;
+    AbsoluteTime                startTime;
+    uint32_t                    deltaTime;
 
-       memset(&ctx, 0, sizeof(ctx));
-       ctx.RootDomain = this;
+    memset(&ctx, 0, sizeof(ctx));
+    ctx.RootDomain = this;
 
-       clock_get_uptime(&startTime);
-       switch (pe_type)
-       {
-               case kPEHaltCPU:
+    clock_get_uptime(&startTime);
+    switch (pe_type)
+    {
+        case kPEHaltCPU:
         case kPEUPSDelayHaltCPU:
-                       ctx.PowerState  = OFF_STATE;
-                       ctx.MessageType = kIOMessageSystemWillPowerOff;
-                       break;
-
-               case kPERestartCPU:
-                       ctx.PowerState  = RESTART_STATE;
-                       ctx.MessageType = kIOMessageSystemWillRestart;
-                       break;
-
-               case kPEPagingOff:
-                       ctx.PowerState  = ON_STATE;
-                       ctx.MessageType = kIOMessageSystemPagingOff;
-                       IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
-                       break;
-
-               default:
-                       return;
-       }
+            ctx.PowerState  = OFF_STATE;
+            ctx.MessageType = kIOMessageSystemWillPowerOff;
+            ctx.LogString   = "PowerOff";
+            break;
+
+        case kPERestartCPU:
+            ctx.PowerState  = RESTART_STATE;
+            ctx.MessageType = kIOMessageSystemWillRestart;
+            ctx.LogString   = "Restart";
+            break;
+
+        case kPEPagingOff:
+            ctx.PowerState  = ON_STATE;
+            ctx.MessageType = kIOMessageSystemPagingOff;
+            ctx.LogString   = "PagingOff";
+            IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
+#if HIBERNATION
+            IOHibernateSystemRestart();
+#endif
+            break;
+
+        default:
+            return;
+    }
 
-       // Notify legacy clients
-       applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
+    // Notify legacy clients
+    applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
 
     // For normal shutdown, turn off File Server Mode.
     if (kPEHaltCPU == pe_type)
@@ -3740,17 +4459,37 @@ void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
         }
     }
 
-       if (kPEPagingOff != pe_type)
-       {
-               // Notify in power tree order
-               notifySystemShutdown(this, ctx.MessageType);
-       }
+    if (kPEPagingOff != pe_type)
+    {
+        // Notify in power tree order
+        notifySystemShutdown(this, ctx.MessageType);
+    }
+
+    IOCPURunPlatformHaltRestartActions(pe_type);
+
+    // Wait for PM to quiesce
+    if ((kPEPagingOff != pe_type) && gPMHaltLock)
+    {
+        AbsoluteTime quiesceTime = mach_absolute_time();
+
+        IOLockLock(gPMHaltLock);
+        gPMQuiesced = false;
+        if (quiescePowerTree(this, &quiescePowerTreeCallback, &gPMQuiesced) ==
+            kIOReturnSuccess)
+        {
+            while (!gPMQuiesced)
+            {
+                IOLockSleep(gPMHaltLock, &gPMQuiesced, THREAD_UNINT);
+            }
+        }
+        IOLockUnlock(gPMHaltLock);
+
+        deltaTime = computeDeltaTimeMS(&quiesceTime);
+        DLOG("PM quiesce took %u ms\n", deltaTime);
+    }
 
-       deltaTime = computeDeltaTimeMS(&startTime);
-       LOG("%s all drivers took %u ms\n",
-               (ctx.MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" :
-                        (ctx.MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart",
-               (uint32_t) deltaTime );
+    deltaTime = computeDeltaTimeMS(&startTime);
+    LOG("%s all drivers took %u ms\n", ctx.LogString, deltaTime);
 }
 
 //******************************************************************************
@@ -3816,7 +4555,6 @@ void IOPMrootDomain::tagPowerPlaneService(
     if (isDisplayWrangler)
     {
         wrangler = service;
-        wranglerConnection = (IOService *) service->getParentEntry(gIOPowerPlane);
     }
 #else
     isDisplayWrangler = false;
@@ -3872,6 +4610,11 @@ void IOPMrootDomain::tagPowerPlaneService(
                 OSMemberFunctionCast(
                     IOPMActionActivityTickle, this,
                     &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
+
+            actions->actionUpdatePowerClient =
+                OSMemberFunctionCast(
+                    IOPMActionUpdatePowerClient, this,
+                    &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler);
         }
         return;
     }
@@ -3891,7 +4634,7 @@ void IOPMrootDomain::tagPowerPlaneService(
     }
 
     // Tag top-level PCI devices. The order of PMinit() call does not
-       // change across boots and is used as the PCI bit number.
+    // change across boots and is used as the PCI bit number.
     if (pciHostBridgeDevice && service->metaCast("IOPCIDevice"))
     {
         // Would prefer to check built-in property, but tagPowerPlaneService()
@@ -3902,7 +4645,7 @@ void IOPMrootDomain::tagPowerPlaneService(
             int bit = pmTracer->recordTopLevelPCIDevice( service );
             if (bit >= 0)
             {
-                               // Save the assigned bit for fast lookup.
+                // Save the assigned bit for fast lookup.
                 actions->parameter |= (bit & kPMActionsPCIBitNumberMask);
 
                 actions->actionPowerChangeStart =
@@ -3924,73 +4667,89 @@ void IOPMrootDomain::tagPowerPlaneService(
 //******************************************************************************
 
 void IOPMrootDomain::overrideOurPowerChange(
-    IOService *     service,
-    IOPMActions *   actions,
-    unsigned long * inOutPowerState,
-    uint32_t *      inOutChangeFlags )
+    IOService *             service,
+    IOPMActions *           actions,
+    IOPMPowerStateIndex *   inOutPowerState,
+    IOPMPowerChangeFlags *  inOutChangeFlags,
+    IOPMRequestTag          requestTag )
 {
-    uint32_t    powerState  = (uint32_t) *inOutPowerState;
-    uint32_t    changeFlags = *inOutChangeFlags;
-    uint32_t    currentPowerState = (uint32_t) getPowerState();
+    uint32_t powerState  = (uint32_t) *inOutPowerState;
+    uint32_t changeFlags = *inOutChangeFlags;
+    uint32_t currentPowerState = (uint32_t) getPowerState();
 
-    if ((currentPowerState == powerState) ||
-        (changeFlags & kIOPMParentInitiated))
+    if (changeFlags & kIOPMParentInitiated)
     {
-        // FIXME: cancel any parent change (unexpected)
         // Root parent is permanently pegged at max power,
-        // kIOPMParentInitiated is unexpected.
+        // a parent initiated power change is unexpected.
+        *inOutChangeFlags |= kIOPMNotDone;
         return;
     }
 
     if (powerState < currentPowerState)
     {
-        if ((changeFlags & kIOPMSkipAskPowerDown) == 0)
-        {
-            /* Convenient place to run any code at idle sleep time
-             * IOPMrootDomain initiates an idle sleep here
-             *
-             * Set last sleep cause accordingly.
-             */
-            pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)true);
-
-            lastSleepReason = kIOPMSleepReasonIdle;
-            setProperty(kRootDomainSleepReasonKey, kIOPMIdleSleepKey);
-        }
         if (CAP_CURRENT(kIOPMSystemCapabilityGraphics))
         {
             // Root domain is dropping power state ON->SLEEP.
-            // If system is in full wake, first drop to dark wake.
+            // If system is in full wake, first enter dark wake by
+            // converting the power drop to a capability change.
+            // Once in dark wake, transition to sleep state ASAP.
 
             darkWakeToSleepASAP = true;
 
-            // Drop graphics capability.
-            // No transition if system is already in dark wake.
-
+            // Drop graphics and audio capability
             _desiredCapability &= ~(
                 kIOPMSystemCapabilityGraphics |
                 kIOPMSystemCapabilityAudio    );
 
+            // Convert to capability change (ON->ON)
             *inOutPowerState = ON_STATE;
             *inOutChangeFlags |= kIOPMSynchronize;
 
-            // Revert device desire from SLEEP->ON.
+            // Revert device desire from SLEEP to ON
             changePowerStateToPriv(ON_STATE);
         }
+        else
+        {
+            // System is in dark wake, ok to drop power state.
+            // Broadcast root powering down to entire tree.
+            *inOutChangeFlags |= kIOPMRootChangeDown;
+        }
+    }
+    else if (powerState > currentPowerState)
+    {
+        if ((_currentCapability & kIOPMSystemCapabilityCPU) == 0)
+        {
+            // Broadcast power up when waking from sleep, but not for the
+            // initial power change at boot by checking for cpu capability.
+            *inOutChangeFlags |= kIOPMRootChangeUp;
+        }
     }
 }
 
 void IOPMrootDomain::handleOurPowerChangeStart(
-    IOService *     service,
-    IOPMActions *   actions,
-    uint32_t        powerState,
-    uint32_t *      inOutChangeFlags )
+    IOService *             service,
+    IOPMActions *           actions,
+    IOPMPowerStateIndex     powerState,
+    IOPMPowerChangeFlags *  inOutChangeFlags,
+    IOPMRequestTag          requestTag )
 {
-    uint32_t changeFlags = *inOutChangeFlags;
-    uint32_t currentPowerState = (uint32_t) getPowerState();
+    uint32_t changeFlags        = *inOutChangeFlags;
+    uint32_t currentPowerState  = (uint32_t) getPowerState();
+    uint32_t sleepReason        = requestTag ? requestTag : kIOPMSleepReasonIdle;
+    bool     publishSleepReason = false;
 
     _systemTransitionType    = kSystemTransitionNone;
     _systemMessageClientMask = 0;
     capabilityLoss           = false;
+    toldPowerdCapWillChange  = false;
+
+    if (lowBatteryCondition)
+    {
+        // Low battery notification may arrive after the initial sleep request
+        // has been queued. Override the sleep reason so powerd and others can
+        // treat this as an emergency sleep.
+        sleepReason = kIOPMSleepReasonLowPower;
+    }
 
     // 1. Explicit capability change.
 
@@ -4020,13 +4779,16 @@ void IOPMrootDomain::handleOurPowerChangeStart(
         _desiredCapability = kIOPMSystemCapabilityCPU |
                              kIOPMSystemCapabilityNetwork;
 
-        // Check for early HID events (e.g. LID open)
-        if (wranglerTickled)
+        // Early exit from dark wake to full (e.g. LID open)
+        if (kFullWakeReasonNone != fullWakeReason)
         {
             _desiredCapability |= (
                 kIOPMSystemCapabilityGraphics |
                 kIOPMSystemCapabilityAudio );
         }
+#if HIBERNATION
+    IOHibernateSetWakeCapabilities(_desiredCapability);
+#endif
     }
 
     // Update pending wake capability at the beginning of every
@@ -4037,6 +4799,16 @@ void IOPMrootDomain::handleOurPowerChangeStart(
     {
         _pendingCapability = 0;
         capabilityLoss = true;
+
+        // Clear previous stats
+        IOLockLock(pmStatsLock);
+        if (pmStatsAppResponses)
+        {
+            pmStatsAppResponses->release();
+            pmStatsAppResponses = OSArray::withCapacity(5);
+        }
+        IOLockUnlock(pmStatsLock);
+
     }
     else if (kSystemTransitionNewCapClient != _systemTransitionType)
     {
@@ -4057,8 +4829,6 @@ void IOPMrootDomain::handleOurPowerChangeStart(
         if (__builtin_popcount(_pendingCapability) <
             __builtin_popcount(_currentCapability))
             capabilityLoss = true;
-        if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
-            rejectWranglerTickle = true;
     }
 
     // 1. Capability change.
@@ -4069,14 +4839,8 @@ void IOPMrootDomain::handleOurPowerChangeStart(
         if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
         {
             tracePoint( kIOPMTracePointDarkWakeExit );
-            wranglerSleepIgnored = false;
-            sleepTimerMaintenance = false;
-            hibernateNoDefeat = false;
-            _systemMessageClientMask = kSystemMessageClientUser;
-            if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
-                _systemMessageClientMask |= kSystemMessageClientKernel;
 
-            tellClients(kIOMessageSystemWillPowerOn);
+            willEnterFullWake();
         }
 
         // Full to Dark transition.
@@ -4084,7 +4848,27 @@ void IOPMrootDomain::handleOurPowerChangeStart(
         {
             tracePoint( kIOPMTracePointDarkWakeEntry );
             *inOutChangeFlags |= kIOPMSyncTellPowerDown;
-            _systemMessageClientMask = kSystemMessageClientUser;
+            _systemMessageClientMask = kSystemMessageClientPowerd |
+                                       kSystemMessageClientLegacyApp;
+
+
+            // rdar://15971327
+            // Prevent user active transitions before notifying clients
+            // that system will sleep.
+            preventTransitionToUserActive(true);
+
+            IOService::setAdvisoryTickleEnable( false );
+
+            // Publish the sleep reason for full to dark wake
+            publishSleepReason = true;
+            lastSleepReason = fullToDarkReason = sleepReason;
+
+            // Publish a UUID for the Sleep --> Wake cycle
+            handlePublishSleepWakeUUID(true);
+            if (sleepDelaysReport) {
+                clock_get_uptime(&ts_sleepStart);
+                DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart);
+            }
         }
     }
 
@@ -4094,42 +4878,70 @@ void IOPMrootDomain::handleOurPowerChangeStart(
     {
         // Beginning of a system sleep transition.
         // Cancellation is still possible.
-        tracePoint( kIOPMTracePointSleepStarted, lastSleepReason );
+        tracePoint( kIOPMTracePointSleepStarted, sleepReason );
 
         _systemMessageClientMask = kSystemMessageClientAll;
         if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0)
-            _systemMessageClientMask &= ~kSystemMessageClientApp;
+            _systemMessageClientMask &= ~kSystemMessageClientLegacyApp;
         if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
             _systemMessageClientMask &= ~kSystemMessageClientKernel;
 
-        // Optimization to ignore wrangler power down thus skipping
-        // the disk spindown and arming the idle timer for demand sleep.
+        // Record the reason for dark wake back to sleep
+        // System may not have ever achieved full wake
 
-        if (changeFlags & kIOPMIgnoreChildren)
-        {
-            wranglerSleepIgnored = true;
+        publishSleepReason = true;
+        lastSleepReason = sleepReason;
+        if (sleepDelaysReport) {
+            clock_get_uptime(&ts_sleepStart);
+                DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart);
         }
-
-        logWranglerTickle = false;
     }
 
     // 3. System wake.
 
     else if (kSystemTransitionWake == _systemTransitionType)
     {
-        wranglerSleepIgnored = false;
+        tracePoint( kIOPMTracePointWakeWillPowerOnClients );
+        // Clear stats about sleep 
 
         if (_pendingCapability & kIOPMSystemCapabilityGraphics)
         {
-            _systemMessageClientMask = kSystemMessageClientAll;
+            willEnterFullWake();
         }
         else
         {
-            _systemMessageClientMask = kSystemMessageClientConfigd;
+            // Message powerd only
+            _systemMessageClientMask = kSystemMessageClientPowerd;
+            tellClients(kIOMessageSystemWillPowerOn);
         }
+    }
 
-        tracePoint( kIOPMTracePointWakeWillPowerOnClients );
-        tellClients(kIOMessageSystemWillPowerOn);
+    // The only location where the sleep reason is published. At this point
+    // sleep can still be cancelled, but sleep reason should be published
+    // early for logging purposes.
+
+    if (publishSleepReason)
+    {
+        static const char * IOPMSleepReasons[] =
+        {
+            kIOPMClamshellSleepKey,
+            kIOPMPowerButtonSleepKey,
+            kIOPMSoftwareSleepKey,
+            kIOPMOSSwitchHibernationKey,
+            kIOPMIdleSleepKey,
+            kIOPMLowPowerSleepKey,
+            kIOPMThermalEmergencySleepKey,
+            kIOPMMaintenanceSleepKey,
+            kIOPMSleepServiceExitKey,
+            kIOPMDarkWakeThermalEmergencyKey
+        };
+
+        // Record sleep cause in IORegistry
+        uint32_t reasonIndex = sleepReason - kIOPMSleepReasonClamshell;
+        if (reasonIndex < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0])) {
+            DLOG("sleep reason %s\n", IOPMSleepReasons[reasonIndex]);
+            setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[reasonIndex]);
+        }
     }
 
     if ((kSystemTransitionNone != _systemTransitionType) &&
@@ -4140,7 +4952,7 @@ void IOPMrootDomain::handleOurPowerChangeStart(
 
         DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
              "dcp %x:%x:%x\n",
-            currentPowerState, powerState, *inOutChangeFlags,
+            currentPowerState, (uint32_t) powerState, *inOutChangeFlags,
             _systemTransitionType, _systemStateGeneration,
             _systemMessageClientMask,
             _desiredCapability, _currentCapability, _pendingCapability);
@@ -4148,10 +4960,11 @@ void IOPMrootDomain::handleOurPowerChangeStart(
 }
 
 void IOPMrootDomain::handleOurPowerChangeDone(
-    IOService *     service,
-    IOPMActions *   actions,
-    uint32_t        powerState,
-    uint32_t        changeFlags )
+    IOService *             service,
+    IOPMActions *           actions,
+    IOPMPowerStateIndex     powerState,
+    IOPMPowerChangeFlags    changeFlags,
+    IOPMRequestTag          requestTag __unused )
 {
     if (kSystemTransitionNewCapClient == _systemTransitionType)
     {
@@ -4169,15 +4982,15 @@ void IOPMrootDomain::handleOurPowerChangeDone(
             _pendingCapability = _currentCapability;
             lastSleepReason = 0;
 
-            if (((_currentCapability & kIOPMSystemCapabilityGraphics) == 0) &&
-                (_currentCapability & kIOPMSystemCapabilityCPU))
+            if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
+                 CAP_CURRENT(kIOPMSystemCapabilityCPU))
             {
                 pmPowerStateQueue->submitPowerEvent(
                     kPowerEventPolicyStimulus,
                     (void *) kStimulusDarkWakeReentry,
-                    _systemStateGeneration );                
+                    _systemStateGeneration );
             }
-            
+
             // Revert device desire to max.
             changePowerStateToPriv(ON_STATE);
         }
@@ -4190,20 +5003,23 @@ void IOPMrootDomain::handleOurPowerChangeDone(
             {
                 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
                 {
+                    lastSleepReason = 0; // stop logging wrangler tickles
                     tellClients(kIOMessageSystemHasPoweredOn);
-#if DARK_TO_FULL_EVALUATE_CLAMSHELL
-                    // Re-evaluate clamshell state ourselves when graphics
-                    // will not get kIOMessageSystemHasPoweredOn.
-
-                    if (clamshellClosed &&
-                        ((_systemMessageClientMask & kSystemMessageClientKernel) == 0))
-                    {
-                        receivePowerNotification( kLocalEvalClamshellCommand );
-                    }
-#endif
                 }
                 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
+                {
+                    // Going dark, reset full wake state
+                    // userIsActive will be cleared by wrangler powering down
                     wranglerTickled = false;
+                    fullWakeReason = kFullWakeReasonNone;
+
+                    if (ts_sleepStart) {
+                        clock_get_uptime(&wake2DarkwakeDelay);
+                        SUB_ABSOLUTETIME(&wake2DarkwakeDelay, &ts_sleepStart);
+                        DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay);
+                        ts_sleepStart = 0;
+                    }
+                }
             }
 
             // Reset state after exiting from dark wake.
@@ -4214,7 +5030,16 @@ void IOPMrootDomain::handleOurPowerChangeDone(
                 darkWakeMaintenance = false;
                 darkWakeToSleepASAP = false;
                 pciCantSleepValid   = false;
-                rejectWranglerTickle = false;
+                darkWakeSleepService = false;
+
+                if (CAP_LOSS(kIOPMSystemCapabilityCPU))
+                {
+                    // Remove the influence of display power assertion
+                    // before next system wake.
+                    if (wrangler) wrangler->changePowerStateForRootDomain(
+                                                kWranglerPowerStateMin );
+                    removeProperty(gIOPMUserTriggeredFullWakeKey);
+                }
             }
 
             // Entered dark mode.
@@ -4222,28 +5047,6 @@ void IOPMrootDomain::handleOurPowerChangeDone(
             if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
                  (_pendingCapability & kIOPMSystemCapabilityCPU))
             {
-                if (((gDarkWakeFlags & kDarkWakeFlagIgnoreDiskIOInDark) == 0) &&
-                    (kSystemTransitionWake == _systemTransitionType) &&
-                    (_debugWakeSeconds == 0))
-                {
-                    OSObject * prop = copyProperty(kIOPMRootDomainWakeTypeKey);
-                    if (prop)
-                    {
-                        OSString * wakeType = OSDynamicCast(OSString, prop);
-                        if (wakeType &&
-                            wakeType->isEqualTo(kIOPMRootDomainWakeTypeNetwork))
-                        {
-                            // Woke from network and entered dark wake.                    
-                            if (darkWakeToSleepASAP)
-                            {
-                                DLOG("cleared darkWakeToSleepASAP\n");
-                                darkWakeToSleepASAP = false;
-                            }
-                        }
-                        prop->release();
-                    }
-                }
-
                 // Queue an evaluation of whether to remain in dark wake,
                 // and for how long. This serves the purpose of draining
                 // any assertions from the queue.
@@ -4257,23 +5060,39 @@ void IOPMrootDomain::handleOurPowerChangeDone(
 
         DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
              "dcp %x:%x:%x, dbgtimer %u\n",
-            currentPowerState, powerState, changeFlags,
+            currentPowerState, (uint32_t) powerState, changeFlags,
             _systemTransitionType, _systemStateGeneration,
             _systemMessageClientMask,
             _desiredCapability, _currentCapability, _pendingCapability,
-            _debugWakeSeconds);
+            _lastDebugWakeSeconds);
 
-        // Update current system capability.
+        if (_pendingCapability & kIOPMSystemCapabilityGraphics)
+        {
+            displayWakeCnt++;
+#if DARK_TO_FULL_EVALUATE_CLAMSHELL
+            if (clamshellExists && fullWakeThreadCall &&
+                CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
+            {
+                // Not the initial graphics full power, graphics won't
+                // send a power notification to trigger a lid state
+                // evaluation.
+
+                AbsoluteTime deadline;
+                clock_interval_to_deadline(45, kSecondScale, &deadline);
+                thread_call_enter_delayed(fullWakeThreadCall, deadline);
+            }
+#endif
+        }
+        else if (CAP_GAIN(kIOPMSystemCapabilityCPU))
+            darkWakeCnt++;
 
+        // Update current system capability.
         if (_currentCapability != _pendingCapability)
             _currentCapability = _pendingCapability;
 
         // Update highest system capability.
 
-        if (!CAP_CURRENT(kIOPMSystemCapabilityCPU))
-            _highestCapability = 0;     // reset at sleep state
-        else
-            _highestCapability |= _currentCapability;
+        _highestCapability |= _currentCapability;
 
         if (darkWakePostTickle &&
             (kSystemTransitionWake == _systemTransitionType) &&
@@ -4298,6 +5117,7 @@ void IOPMrootDomain::handleOurPowerChangeDone(
 
         _systemTransitionType = kSystemTransitionNone;
         _systemMessageClientMask = 0;
+        toldPowerdCapWillChange  = false;
 
         logGraphicsClamp = false;
     }
@@ -4308,10 +5128,10 @@ void IOPMrootDomain::handleOurPowerChangeDone(
 //******************************************************************************
 
 void IOPMrootDomain::overridePowerChangeForUIService(
-    IOService *     service,
-    IOPMActions *   actions,
-    unsigned long * inOutPowerState,
-    uint32_t *      inOutChangeFlags )
+    IOService *             service,
+    IOPMActions *           actions,
+    IOPMPowerStateIndex *   inOutPowerState,
+    IOPMPowerChangeFlags *  inOutChangeFlags )
 {
     uint32_t powerState  = (uint32_t) *inOutPowerState;
     uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
@@ -4326,12 +5146,15 @@ void IOPMrootDomain::overridePowerChangeForUIService(
         // Activate power limiter.
 
         if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
-            ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
+            ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
+            (changeFlags & kIOPMSynchronize))
         {
             actions->parameter |= kPMActionsFlagLimitPower;
         }
         else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
-                 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0))
+                 ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) &&
+                 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
+                 (changeFlags & kIOPMSynchronize))
         {
             actions->parameter |= kPMActionsFlagLimitPower;
         }
@@ -4340,13 +5163,13 @@ void IOPMrootDomain::overridePowerChangeForUIService(
         {
             // For graphics devices, arm the limiter when entering
             // system sleep. Not when dropping to dark wake.
-            actions->parameter |= kPMActionsFlagLimitPower; 
+            actions->parameter |= kPMActionsFlagLimitPower;
         }
 
         if (actions->parameter & kPMActionsFlagLimitPower)
         {
             DLOG("+ plimit %s %p\n",
-                service->getName(), service);
+                service->getName(), OBFUSCATE(service));
         }
     }
     else
@@ -4369,17 +5192,10 @@ void IOPMrootDomain::overridePowerChangeForUIService(
         if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
         {
             DLOG("- plimit %s %p\n",
-                service->getName(), service);
+                service->getName(), OBFUSCATE(service));
         }
     }
 
-    if (gRAMDiskImageBoot &&
-        (actions->parameter & kPMActionsFlagIsDisplayWrangler))
-    {
-        // Tag devices subject to power suppression.
-        *inOutChangeFlags |= kIOPMPowerSuppressed;
-    }
-
     if (actions->parameter & kPMActionsFlagLimitPower)
     {
         uint32_t maxPowerState = (uint32_t)(-1);
@@ -4389,14 +5205,21 @@ void IOPMrootDomain::overridePowerChangeForUIService(
             // Enforce limit for system power/cap transitions.
 
             maxPowerState = 0;
-            if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
-                (!gRAMDiskImageBoot || (service->getPowerState() > 0)))
+            if ((service->getPowerState() > maxPowerState) &&
+                (actions->parameter & kPMActionsFlagIsDisplayWrangler))
             {
-                // Forces a 3->1 transition sequence
-                if (changeFlags & kIOPMDomainWillChange)
-                    maxPowerState = 3;
-                else
-                    maxPowerState = 1;
+                maxPowerState++;
+
+                // Remove lingering effects of any tickle before entering
+                // dark wake. It will take a new tickle to return to full
+                // wake, so the existing tickle state is useless.
+
+                if (changeFlags & kIOPMDomainDidChange)
+                    *inOutChangeFlags |= kIOPMExpireIdleTimer;
+            }
+            else if (actions->parameter & kPMActionsFlagIsGraphicsDevice)
+            {
+                maxPowerState++;
             }
         }
         else
@@ -4410,7 +5233,7 @@ void IOPMrootDomain::overridePowerChangeForUIService(
         if (powerState > maxPowerState)
         {
             DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
-                service->getName(), service, powerState, maxPowerState,
+                service->getName(), OBFUSCATE(service), powerState, maxPowerState,
                 changeFlags);
             *inOutPowerState = maxPowerState;
 
@@ -4435,8 +5258,9 @@ void IOPMrootDomain::overridePowerChangeForUIService(
                 clock_get_uptime(&now);
                 SUB_ABSOLUTETIME(&now, &systemWakeTime);
                 absolutetime_to_nanoseconds(now, &nsec);
-                MSG("Graphics suppressed %u ms\n",
-                    ((int)((nsec) / 1000000ULL)));
+                if (kIOLogPMRootDomain & gIOKitDebug)
+                    MSG("Graphics suppressed %u ms\n",
+                        ((int)((nsec) / 1000000ULL)));
             }
             graphicsSuppressed = true;
         }
@@ -4447,23 +5271,24 @@ void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
     IOService *     service,
     IOPMActions *   actions )
 {
+#if !NO_KERNEL_HID
     // Warning: Not running in PM work loop context - don't modify state !!!
     // Trap tickle directed to IODisplayWrangler while running with graphics
     // capability suppressed.
 
     assert(service == wrangler);
 
-    if (service == wrangler)
-    {
-        bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle) 
-                       || (lastSleepReason == kIOPMSleepReasonMaintenance));
-        if (aborting) {
-            userActivityCount++;
-            DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
-        }
+    clock_get_uptime(&userActivityTime);
+    bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
+                  || (lastSleepReason == kIOPMSleepReasonMaintenance)
+                  || (lastSleepReason == kIOPMSleepReasonSoftware));
+    if (aborting) {
+        userActivityCount++;
+        DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
+            userActivityCount, lastSleepReason);
     }
 
-    if (!wranglerTickled && !lowBatteryCondition &&
+    if (!wranglerTickled &&
         ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
     {
         DLOG("display wrangler tickled\n");
@@ -4473,9 +5298,83 @@ void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
         {
             pmPowerStateQueue->submitPowerEvent(
                 kPowerEventPolicyStimulus,
-                (void *) kStimulusDarkWakeActivityTickle );
+                (void *) kStimulusDarkWakeActivityTickle,
+                true /* set wake type */ );
+        }
+    }
+#endif
+}
+
+void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
+    IOService *             service,
+    IOPMActions *           actions,
+    const OSSymbol *        powerClient,
+    IOPMPowerStateIndex     oldPowerState,
+    IOPMPowerStateIndex     newPowerState )
+{
+#if !NO_KERNEL_HID
+    assert(service == wrangler);
+
+    // This function implements half of the user active detection
+    // by monitoring changes to the display wrangler's device desire.
+    //
+    // User becomes active when either:
+    // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
+    //    in max power state. This desire change in absence of a power state
+    //    change is detected within. This handles the case when user becomes
+    //    active while the display is already lit by setDisplayPowerOn().
+    //
+    // 2. Power state change to max, and DeviceDesire is also at max.
+    //    Handled by displayWranglerNotification().
+    //
+    // User becomes inactive when DeviceDesire drops to sleep state or below.
+
+    DLOG("wrangler %s (ps %u, %u->%u)\n",
+        powerClient->getCStringNoCopy(),
+        (uint32_t) service->getPowerState(),
+        (uint32_t) oldPowerState, (uint32_t) newPowerState);
+
+    if (powerClient == gIOPMPowerClientDevice)
+    {
+        if ((newPowerState > oldPowerState) &&
+            (newPowerState == kWranglerPowerStateMax) &&
+            (service->getPowerState() == kWranglerPowerStateMax))
+        {
+            evaluatePolicy( kStimulusEnterUserActiveState );
+        }
+        else
+        if ((newPowerState < oldPowerState) &&
+            (newPowerState <= kWranglerPowerStateSleep))
+        {
+            evaluatePolicy( kStimulusLeaveUserActiveState );
+        }
+    }
+#endif
+}
+
+//******************************************************************************
+// User active state management
+//******************************************************************************
+
+void IOPMrootDomain::preventTransitionToUserActive( bool prevent )
+{
+#if !NO_KERNEL_HID
+    _preventUserActive = prevent;
+    if (wrangler && !_preventUserActive)
+    {
+        // Allowing transition to user active, but the wrangler may have
+        // already powered ON in case of sleep cancel/revert. Poll the
+        // same conditions checked for in displayWranglerNotification()
+        // to bring the user active state up to date.
+
+        if ((wrangler->getPowerState() == kWranglerPowerStateMax) &&
+            (wrangler->getPowerStateForClient(gIOPMPowerClientDevice) ==
+             kWranglerPowerStateMax))
+        {
+            evaluatePolicy( kStimulusEnterUserActiveState );
         }
     }
+#endif
 }
 
 //******************************************************************************
@@ -4486,7 +5385,7 @@ bool IOPMrootDomain::shouldDelayChildNotification(
     IOService * service )
 {
     if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) &&
-        !wranglerTickled &&
+        (kFullWakeReasonNone == fullWakeReason) &&
         (kSystemTransitionWake == _systemTransitionType))
     {
         DLOG("%s: delay child notify\n", service->getName());
@@ -4500,10 +5399,10 @@ bool IOPMrootDomain::shouldDelayChildNotification(
 //******************************************************************************
 
 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
-    IOService *     service,
-    IOPMActions *   actions, 
-    uint32_t        powerState,
-    uint32_t *      inOutChangeFlags )
+    IOService *             service,
+    IOPMActions *           actions,
+    IOPMPowerStateIndex     powerState,
+    IOPMPowerChangeFlags *  inOutChangeFlags )
 {
     pmTracer->tracePCIPowerChange(
         PMTraceWorker::kPowerChangeStart,
@@ -4512,10 +5411,10 @@ void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
 }
 
 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
-    IOService *     service,
-    IOPMActions *   actions, 
-    uint32_t        powerState,
-    uint32_t        changeFlags )
+    IOService *             service,
+    IOPMActions *           actions,
+    IOPMPowerStateIndex     powerState,
+    IOPMPowerChangeFlags    changeFlags )
 {
     pmTracer->tracePCIPowerChange(
         PMTraceWorker::kPowerChangeCompleted,
@@ -4529,14 +5428,28 @@ void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
 // Override IOService::registerInterest() to intercept special clients.
 //******************************************************************************
 
+class IOPMServiceInterestNotifier: public _IOServiceInterestNotifier
+{
+
+    friend class IOPMrootDomain;
+    OSDeclareDefaultStructors(IOPMServiceInterestNotifier)
+
+protected:
+    uint32_t    ackTimeoutCnt;
+
+};
+
+OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier)
+
 IONotifier * IOPMrootDomain::registerInterest(
                 const OSSymbol * typeOfInterest,
                 IOServiceInterestHandler handler,
                 void * target, void * ref )
 {
-    IONotifier *    notifier;
+    IOPMServiceInterestNotifier *notifier = 0;
     bool            isSystemCapabilityClient;
     bool            isKernelCapabilityClient;
+    IOReturn        rc = kIOReturnError;;
 
     isSystemCapabilityClient =
         typeOfInterest &&
@@ -4549,9 +5462,21 @@ IONotifier * IOPMrootDomain::registerInterest(
     if (isSystemCapabilityClient)
         typeOfInterest = gIOAppPowerStateInterest;
 
-    notifier = super::registerInterest(typeOfInterest, handler, target, ref);
-    if (notifier && pmPowerStateQueue)
+    notifier = new IOPMServiceInterestNotifier;
+    if (!notifier) return NULL;
+
+    if (notifier->init()) {
+        rc  = super::registerInterestForNotifer(notifier, typeOfInterest, handler, target, ref);
+    }
+    if (rc != kIOReturnSuccess) {
+        notifier->release();
+        notifier = 0;
+
+        return NULL;
+    }
+    if (pmPowerStateQueue)
     {
+        notifier->ackTimeoutCnt = 0;
         if (isSystemCapabilityClient)
         {
             notifier->retain();
@@ -4624,9 +5549,15 @@ bool IOPMrootDomain::systemMessageFilter(
                     capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
                 else
                     capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
+
+                if ((object == (void *) systemCapabilityNotifier) &&
+                    context->isPreChange)
+                {
+                    toldPowerdCapWillChange = true;
+                }
             }
 
-            // Capability change messages only go to the PM configd plugin. 
+            // Capability change messages only go to the PM configd plugin.
             // Wait for response post-change if capabilitiy is increasing.
             // Wait for response pre-change if capability is decreasing.
 
@@ -4643,7 +5574,9 @@ bool IOPMrootDomain::systemMessageFilter(
         }
 
         // Capability client will always see kIOMessageCanSystemSleep,
-        // even for demand sleep.
+        // even for demand sleep. It will also have a chance to veto
+        // sleep one last time after all clients have responded to
+        // kIOMessageSystemWillSleep
 
         if ((kIOMessageCanSystemSleep == context->messageType) ||
             (kIOMessageSystemWillNotSleep == context->messageType))
@@ -4653,7 +5586,7 @@ bool IOPMrootDomain::systemMessageFilter(
                 allow = true;
                 break;
             }
-            
+
             // Not idle sleep, don't ask apps.
             if (context->changeFlags & kIOPMSkipAskPowerDown)
             {
@@ -4661,6 +5594,15 @@ bool IOPMrootDomain::systemMessageFilter(
             }
         }
 
+        if (kIOPMMessageLastCallBeforeSleep == context->messageType)
+        {
+            if ((object == (OSObject *) systemCapabilityNotifier) &&
+                CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
+                (fullToDarkReason == kIOPMSleepReasonIdle))
+                allow = true;
+            break;
+        }
+
         // Reject capability change messages for legacy clients.
         // Reject legacy system sleep messages for capability client.
 
@@ -4672,9 +5614,19 @@ bool IOPMrootDomain::systemMessageFilter(
         // Filter system sleep messages.
 
         if ((context->notifyType == kNotifyApps) &&
-            (_systemMessageClientMask & kSystemMessageClientApp))
+            (_systemMessageClientMask & kSystemMessageClientLegacyApp))
         {
+            IOPMServiceInterestNotifier *notify;
             allow = true;
+
+            if ((notify = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object))
+                && arg3) {
+
+                if (notify->ackTimeoutCnt >= 3)
+                    *((OSObject **) arg3) = kOSBooleanFalse;
+                else
+                    *((OSObject **) arg3) = kOSBooleanTrue;
+            }
         }
         else if ((context->notifyType == kNotifyPriority) &&
                  (_systemMessageClientMask & kSystemMessageClientKernel))
@@ -4690,7 +5642,7 @@ bool IOPMrootDomain::systemMessageFilter(
         if (_joinedCapabilityClients->getCount() == 0)
         {
             DLOG("destroyed capability client set %p\n",
-                _joinedCapabilityClients);
+                OBFUSCATE(_joinedCapabilityClients));
             _joinedCapabilityClients->release();
             _joinedCapabilityClients = 0;
         }
@@ -4708,16 +5660,27 @@ IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
     const IOPMCalendarStruct * calendar )
 {
     OSData * data;
-    IOReturn ret;
+    IOReturn ret = 0;
 
     if (!calendar)
         return kIOReturnBadArgument;
-    
+
     data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
     if (!data)
         return kIOReturnNoMemory;
-    
-    ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
+
+    if (kPMCalendarTypeMaintenance == calendar->selector) {
+        ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
+        if (kIOReturnSuccess == ret)
+            OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarms);
+    } else
+    if (kPMCalendarTypeSleepService == calendar->selector)
+    {
+        ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey, data);
+        if (kIOReturnSuccess == ret)
+            OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarms);
+    }
+    DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
 
     data->release();
     return ret;
@@ -4751,59 +5714,62 @@ IOReturn IOPMrootDomain::displayWranglerNotification(
         return kIOReturnUnsupported;
 
     displayPowerState = params->stateNumber;
-    DLOG("DisplayWrangler message 0x%x, power state %d\n",
-              (uint32_t) messageType, displayPowerState);
+    DLOG("wrangler %s ps %d\n",
+         getIOMessageString(messageType), displayPowerState);
 
     switch (messageType) {
        case kIOMessageDeviceWillPowerOff:
-
             // Display wrangler has dropped power due to display idle
             // or force system sleep.
             //
-            // 4 Display ON
-            // 3 Display Dim
-            // 2 Display Sleep
+            // 4 Display ON             kWranglerPowerStateMax
+            // 3 Display Dim            kWranglerPowerStateDim
+            // 2 Display Sleep          kWranglerPowerStateSleep
             // 1 Not visible to user
-            // 0 Not visible to user
-
-            if (displayPowerState > 2)
-                break;
+            // 0 Not visible to user    kWranglerPowerStateMin
 
-            gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
+            if (displayPowerState <= kWranglerPowerStateSleep)
+                gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
             break;
 
         case kIOMessageDeviceHasPoweredOn:
-
-            // Display wrangler has powered on due to user activity 
+            // Display wrangler has powered on due to user activity
             // or wake from sleep.
 
-            if ( 4 != displayPowerState )
-                break;
+            if (kWranglerPowerStateMax == displayPowerState)
+            {
+                gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
 
-            gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
+                // See comment in handleUpdatePowerClientForDisplayWrangler
+                if (service->getPowerStateForClient(gIOPMPowerClientDevice) ==
+                    kWranglerPowerStateMax)
+                {
+                    gRootDomain->evaluatePolicy( kStimulusEnterUserActiveState );
+                }
+            }
             break;
     }
 #endif
     return kIOReturnUnsupported;
 }
 
-//*********************************************************************************
+//******************************************************************************
 // displayWranglerMatchPublished
 //
 // Receives a notification when the IODisplayWrangler is published.
 // When it's published we install a power state change handler.
 //******************************************************************************
 
-bool IOPMrootDomain::displayWranglerMatchPublished( 
-    void * target, 
+bool IOPMrootDomain::displayWranglerMatchPublished(
+    void * target,
     void * refCon,
     IOService * newService,
     IONotifier * notifier __unused)
 {
 #if !NO_KERNEL_HID
     // found the display wrangler, now install a handler
-    if( !newService->registerInterest( gIOGeneralInterest, 
-                            &displayWranglerNotification, target, 0) ) 
+    if( !newService->registerInterest( gIOGeneralInterest,
+                            &displayWranglerNotification, target, 0) )
     {
         return false;
     }
@@ -4811,6 +5777,50 @@ bool IOPMrootDomain::displayWranglerMatchPublished(
     return true;
 }
 
+#if defined(__i386__) || defined(__x86_64__)
+
+bool IOPMrootDomain::IONVRAMMatchPublished(
+    void * target,
+    void * refCon,
+    IOService * newService,
+    IONotifier * notifier)
+{
+    unsigned int     len = 0;
+    IOPMrootDomain *rd = (IOPMrootDomain *)target;
+    OSNumber    *statusCode = NULL;
+
+    if (PEReadNVRAMProperty(kIOSleepWakeDebugKey, NULL, &len))
+    {
+        statusCode = OSDynamicCast(OSNumber, rd->getProperty(kIOPMSleepWakeFailureCodeKey));
+        if (statusCode != NULL) {
+            if (statusCode->unsigned64BitValue() != 0) {
+                rd->swd_flags |= SWD_BOOT_BY_SW_WDOG;
+                MSG("System was rebooted due to Sleep/Wake failure\n");
+            }
+            else {
+                rd->swd_flags |= SWD_BOOT_BY_OSX_WDOG;
+                MSG("System was non-responsive and was rebooted by watchdog\n");
+            }
+        }
+
+        rd->swd_logBufMap = rd->sleepWakeDebugRetrieve();
+    }
+    if (notifier) notifier->remove();
+    return true;
+}
+
+#else
+bool IOPMrootDomain::IONVRAMMatchPublished(
+    void * target,
+    void * refCon,
+    IOService * newService,
+    IONotifier * notifier __unused)
+{
+    return false;
+}
+
+#endif
+
 //******************************************************************************
 // reportUserInput
 //
@@ -4820,11 +5830,14 @@ void IOPMrootDomain::reportUserInput( void )
 {
 #if !NO_KERNEL_HID
     OSIterator * iter;
+    OSDictionary * matching;
 
-    if(!wrangler) 
+    if(!wrangler)
     {
-        iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
-        if(iter) 
+        matching = serviceMatching("IODisplayWrangler");
+        iter = getMatchingServices(matching);
+        if (matching) matching->release();
+        if(iter)
         {
             wrangler = (IOService *) iter->getNextObject();
             iter->release();
@@ -4836,6 +5849,56 @@ void IOPMrootDomain::reportUserInput( void )
 #endif
 }
 
+//******************************************************************************
+// latchDisplayWranglerTickle
+//******************************************************************************
+
+bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
+{
+#if !NO_KERNEL_HID
+    if (latch)
+    {
+        if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
+            !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
+            !checkSystemCanSustainFullWake())
+        {
+            // Currently in dark wake, and not transitioning to full wake.
+            // Full wake is unsustainable, so latch the tickle to prevent
+            // the display from lighting up momentarily.
+            wranglerTickleLatched = true;
+        }
+        else
+        {
+            wranglerTickleLatched = false;
+        }
+    }
+    else if (wranglerTickleLatched && checkSystemCanSustainFullWake())
+    {
+        wranglerTickleLatched = false;
+
+        pmPowerStateQueue->submitPowerEvent(
+            kPowerEventPolicyStimulus,
+            (void *) kStimulusDarkWakeActivityTickle );
+    }
+
+    return wranglerTickleLatched;
+#else
+    return false;
+#endif
+}
+
+//******************************************************************************
+// setDisplayPowerOn
+//
+// For root domain user client
+//******************************************************************************
+
+void IOPMrootDomain::setDisplayPowerOn( uint32_t options )
+{
+    pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
+                                         (void *) 0, options );
+}
+
 // MARK: -
 // MARK: Battery
 
@@ -4845,13 +5908,13 @@ void IOPMrootDomain::reportUserInput( void )
 // Notification on battery class IOPowerSource appearance
 //******************************************************************************
 
-bool IOPMrootDomain::batteryPublished( 
-    void * target, 
+bool IOPMrootDomain::batteryPublished(
+    void * target,
     void * root_domain,
     IOService * resourceService,
     IONotifier * notifier __unused )
-{    
-    // rdar://2936060&4435589    
+{
+    // rdar://2936060&4435589
     // All laptops have dimmable LCD displays
     // All laptops have batteries
     // So if this machine has a battery, publish the fact that the backlight
@@ -4865,11 +5928,12 @@ bool IOPMrootDomain::batteryPublished(
 // MARK: System PM Policy
 
 //******************************************************************************
-// checkSystemCanSleep
+// checkSystemSleepAllowed
 //
 //******************************************************************************
 
-bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options )
+bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options,
+                                              uint32_t     sleepReason )
 {
     int err = 0;
 
@@ -4882,7 +5946,7 @@ bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options )
             break;
         }
 
-        if (systemBooting || systemShutdown)
+        if (systemBooting || systemShutdown || gWillShutdown)
         {
             err = 2;        // 2. restart or shutdown in progress
             break;
@@ -4900,12 +5964,17 @@ bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options )
         break;
 #endif
 
-        if (lowBatteryCondition)
+        if (lowBatteryCondition || thermalWarningState)
         {
-            break;          // always sleep on low battery
+            break;          // always sleep on low battery or when in thermal warning state
         }
 
-        if (childPreventSystemSleep)
+        if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency)
+        {
+            break;          // always sleep on dark wake thermal emergencies
+        }
+
+        if (preventSystemSleepList->getCount() != 0)
         {
             err = 4;        // 4. child prevent system sleep clamp
             break;
@@ -4926,7 +5995,7 @@ bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options )
         }
         else if (sleepSupportedPEFunction &&
                  CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
-        {            
+        {
             IOReturn ret;
             OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
             ret = getPlatform()->callPlatformFunction(
@@ -4953,6 +6022,48 @@ bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options )
     return true;
 }
 
+bool IOPMrootDomain::checkSystemSleepEnabled( void )
+{
+    return checkSystemSleepAllowed(0, 0);
+}
+
+bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason )
+{
+    ASSERT_GATED();
+    return checkSystemSleepAllowed(1, sleepReason);
+}
+
+//******************************************************************************
+// checkSystemCanSustainFullWake
+//******************************************************************************
+
+bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
+{
+#if !NO_KERNEL_HID
+    if (lowBatteryCondition || thermalWarningState)
+    {
+        // Low battery wake, or received a low battery notification
+        // while system is awake. This condition will persist until
+        // the following wake.
+        return false;
+    }
+
+    if (clamshellExists && clamshellClosed && !clamshellSleepDisabled)
+    {
+        // Graphics state is unknown and external display might not be probed.
+        // Do not incorporate state that requires graphics to be in max power
+        // such as desktopMode or clamshellDisabled.
+
+        if (!acAdaptorConnected)
+        {
+            DLOG("full wake check: no AC\n");
+            return false;
+        }
+    }
+#endif
+    return true;
+}
+
 //******************************************************************************
 // adjustPowerState
 //
@@ -4970,7 +6081,7 @@ void IOPMrootDomain::adjustPowerState( bool sleepASAP )
 
     ASSERT_GATED();
 
-    if ((sleepSlider == 0) || !checkSystemCanSleep())
+    if ((sleepSlider == 0) || !checkSystemSleepEnabled())
     {
         changePowerStateToPriv(ON_STATE);
     }
@@ -4980,6 +6091,41 @@ void IOPMrootDomain::adjustPowerState( bool sleepASAP )
     }
 }
 
+void IOPMrootDomain::handleDisplayPowerOn( )
+{
+    if (!wrangler) return;
+    if (displayPowerOnRequested)
+    {
+        if (!checkSystemCanSustainFullWake()) return;
+
+        // Force wrangler to max power state. If system is in dark wake
+        // this alone won't raise the wrangler's power state.
+
+        wrangler->changePowerStateForRootDomain(kWranglerPowerStateMax);
+
+        // System in dark wake, always requesting full wake should
+        // not have any bad side-effects, even if the request fails.
+
+        if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics))
+        {
+            setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification);
+            requestFullWake( kFullWakeReasonDisplayOn );
+        }
+    }
+    else
+    {
+        // Relenquish desire to power up display.
+        // Must first transition to state 1 since wrangler doesn't
+        // power off the displays at state 0. At state 0 the root
+        // domain is removed from the wrangler's power client list.
+
+        wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin + 1);
+        wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin);
+
+    }
+
+}
+
 //******************************************************************************
 // dispatchPowerEvent
 //
@@ -4989,7 +6135,7 @@ void IOPMrootDomain::adjustPowerState( bool sleepASAP )
 void IOPMrootDomain::dispatchPowerEvent(
     uint32_t event, void * arg0, uint64_t arg1 )
 {
-    DLOG("power event %u args %p 0x%llx\n", event, arg0, arg1);
+    DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
     ASSERT_GATED();
 
     switch (event)
@@ -5001,12 +6147,35 @@ void IOPMrootDomain::dispatchPowerEvent(
         case kPowerEventReceivedPowerNotification:
             handlePowerNotification( (UInt32)(uintptr_t) arg0 );
             break;
-        
+
         case kPowerEventSystemBootCompleted:
             if (systemBooting)
             {
                 systemBooting = false;
 
+                if (lowBatteryCondition)
+                {
+                    privateSleepSystem (kIOPMSleepReasonLowPower);
+
+                    // The rest is unnecessary since the system is expected
+                    // to sleep immediately. The following wake will update
+                    // everything.
+                    break;
+                }
+
+                if (swd_flags & SWD_VALID_LOGS) {
+                    if (swd_flags & SWD_LOGS_IN_MEM) {
+                        sleepWakeDebugDumpFromMem(swd_logBufMap);
+                        swd_logBufMap->release();
+                        swd_logBufMap = 0;
+                    }
+                    else if (swd_flags & SWD_LOGS_IN_FILE) 
+                        sleepWakeDebugDumpFromFile();
+                }
+                else if (swd_flags & (SWD_BOOT_BY_SW_WDOG|SWD_BOOT_BY_OSX_WDOG)) {
+                    // If logs are invalid, write the failure code
+                    sleepWakeDebugDumpFromMem(NULL);
+                }
                 // If lid is closed, re-send lid closed notification
                 // now that booting is complete.
                 if ( clamshellClosed )
@@ -5014,6 +6183,7 @@ void IOPMrootDomain::dispatchPowerEvent(
                     handlePowerNotification(kLocalEvalClamshellCommand);
                 }
                 evaluatePolicy( kStimulusAllowSystemSleepChanged );
+
             }
             break;
 
@@ -5024,7 +6194,7 @@ void IOPMrootDomain::dispatchPowerEvent(
                    to prevent sleep at unexpected times while loginwindow is trying
                    to shutdown apps and while the OS is trying to transition to
                    complete power of.
-                   
+
                    Set to true during shutdown, as soon as loginwindow shows
                    the "shutdown countdown dialog", through individual app
                    termination, and through black screen kernel shutdown.
@@ -5035,7 +6205,7 @@ void IOPMrootDomain::dispatchPowerEvent(
                  A shutdown was initiated, but then the shutdown
                  was cancelled, clearing systemShutdown to false here.
                 */
-                systemShutdown = false;            
+                systemShutdown = false;
             }
             break;
 
@@ -5097,13 +6267,26 @@ void IOPMrootDomain::dispatchPowerEvent(
                 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
             }
             break;
-            
+
         case kPowerEventQueueSleepWakeUUID:
             handleQueueSleepWakeUUID((OSObject *)arg0);
             break;
         case kPowerEventPublishSleepWakeUUID:
             handlePublishSleepWakeUUID((bool)arg0);
             break;
+
+        case kPowerEventSetDisplayPowerOn:
+            if (!wrangler) break;
+            if (arg1 != 0)
+            {
+                displayPowerOnRequested = true;
+            }
+            else
+            {
+                displayPowerOnRequested = false;
+            }
+            handleDisplayPowerOn();
+            break;
     }
 }
 
@@ -5111,7 +6294,7 @@ void IOPMrootDomain::dispatchPowerEvent(
 // systemPowerEventOccurred
 //
 // The power controller is notifying us of a hardware-related power management
-// event that we must handle. 
+// event that we must handle.
 //
 // systemPowerEventOccurred covers the same functionality that
 // receivePowerNotification does; it simply provides a richer API for conveying
@@ -5125,9 +6308,9 @@ IOReturn IOPMrootDomain::systemPowerEventOccurred(
     IOReturn        attempt = kIOReturnSuccess;
     OSNumber        *newNumber = NULL;
 
-    if (!event) 
+    if (!event)
         return kIOReturnBadArgument;
-        
+
     newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
     if (!newNumber)
         return kIOReturnInternalError;
@@ -5139,14 +6322,32 @@ IOReturn IOPMrootDomain::systemPowerEventOccurred(
     return attempt;
 }
 
+void IOPMrootDomain::setThermalState(OSObject *value)
+{
+   OSNumber * num;
+
+   if (gIOPMWorkLoop->inGate() == false) {
+       gIOPMWorkLoop->runAction(
+               OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setThermalState),
+               (OSObject *)this,
+               (void *)value);
+
+       return;
+    }
+    if (value && (num = OSDynamicCast(OSNumber, value))) {
+        thermalWarningState = ((num->unsigned32BitValue() == kIOPMThermalLevelWarning) || 
+                               (num->unsigned32BitValue() == kIOPMThermalLevelTrap)) ? 1 : 0; 
+    }
+}
+
 IOReturn IOPMrootDomain::systemPowerEventOccurred(
     const OSSymbol *event,
     OSObject *value)
 {
     OSDictionary *thermalsDict = NULL;
     bool shouldUpdate = true;
-    
-    if (!event || !value) 
+
+    if (!event || !value)
         return kIOReturnBadArgument;
 
     // LOCK
@@ -5156,9 +6357,9 @@ IOReturn IOPMrootDomain::systemPowerEventOccurred(
     if (featuresDictLock) IOLockLock(featuresDictLock);
 
     thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
-                   
+
     if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
-        thermalsDict = OSDictionary::withDictionary(thermalsDict);                        
+        thermalsDict = OSDictionary::withDictionary(thermalsDict);
     } else {
         thermalsDict = OSDictionary::withCapacity(1);
     }
@@ -5178,8 +6379,13 @@ exit:
     // UNLOCK
     if (featuresDictLock) IOLockUnlock(featuresDictLock);
 
-    if (shouldUpdate)
+    if (shouldUpdate) {
+        if (event && 
+             event->isEqualTo(kIOPMThermalLevelWarningKey)) {
+             setThermalState(value);
+        }
         messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
+    }
 
     return kIOReturnSuccess;
 }
@@ -5195,7 +6401,7 @@ exit:
 IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
 {
     pmPowerStateQueue->submitPowerEvent(
-        kPowerEventReceivedPowerNotification, (void *) msg );
+        kPowerEventReceivedPowerNotification, (void *)(uintptr_t) msg );
     return kIOReturnSuccess;
 }
 
@@ -5222,18 +6428,28 @@ void IOPMrootDomain::handlePowerNotification( UInt32 msg )
         privateSleepSystem (kIOPMSleepReasonThermalEmergency);
     }
 
+    /*
+     * Forward DW thermal notification to client, if system is not going to sleep
+     */
+    if ((msg & kIOPMDWOverTemp) && (_systemTransitionType != kSystemTransitionSleep))
+    {
+        DLOG("DarkWake thermal limits message received!\n");
+
+        messageClients(kIOPMMessageDarkWakeThermalEmergency);
+    }
+
     /*
      * Sleep Now!
      */
-    if (msg & kIOPMSleepNow) 
+    if (msg & kIOPMSleepNow)
     {
         privateSleepSystem (kIOPMSleepReasonSoftware);
     }
-    
+
     /*
      * Power Emergency
      */
-    if (msg & kIOPMPowerEmergency) 
+    if (msg & kIOPMPowerEmergency)
     {
         lowBatteryCondition = true;
         privateSleepSystem (kIOPMSleepReasonLowPower);
@@ -5242,34 +6458,36 @@ void IOPMrootDomain::handlePowerNotification( UInt32 msg )
     /*
      * Clamshell OPEN
      */
-    if (msg & kIOPMClamshellOpened) 
+    if (msg & kIOPMClamshellOpened)
     {
         // Received clamshel open message from clamshell controlling driver
         // Update our internal state and tell general interest clients
         clamshellClosed = false;
         clamshellExists = true;
 
+        // Don't issue a hid tickle when lid is open and polled on wake
         if (msg & kIOPMSetValue)
         {
+            setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open");
             reportUserInput();
         }
 
         // Tell PMCPU
         informCPUStateChange(kInformLid, 0);
 
-        // Tell general interest clients        
+        // Tell general interest clients
         sendClientClamshellNotification();
 
         bool aborting =  ((lastSleepReason == kIOPMSleepReasonClamshell)
-                       || (lastSleepReason == kIOPMSleepReasonIdle) 
+                       || (lastSleepReason == kIOPMSleepReasonIdle)
                        || (lastSleepReason == kIOPMSleepReasonMaintenance));
         if (aborting) userActivityCount++;
         DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
-    } 
+    }
 
-    /* 
+    /*
      * Clamshell CLOSED
-     * Send the clamshell interest notification since the lid is closing. 
+     * Send the clamshell interest notification since the lid is closing.
      */
     if (msg & kIOPMClamshellClosed)
     {
@@ -5283,8 +6501,8 @@ void IOPMrootDomain::handlePowerNotification( UInt32 msg )
 
         // Tell general interest clients
         sendClientClamshellNotification();
-        
-        // And set eval_clamshell = so we can attempt 
+
+        // And set eval_clamshell = so we can attempt
         eval_clamshell = true;
     }
 
@@ -5293,7 +6511,7 @@ void IOPMrootDomain::handlePowerNotification( UInt32 msg )
      *
      *  -> reevaluate lid state
      */
-    if (msg & kIOPMSetDesktopMode) 
+    if (msg & kIOPMSetDesktopMode)
     {
         desktopMode = (0 != (msg & kIOPMSetValue));
         msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
@@ -5301,18 +6519,15 @@ void IOPMrootDomain::handlePowerNotification( UInt32 msg )
         sendClientClamshellNotification();
 
         // Re-evaluate the lid state
-        if( clamshellClosed )
-        {
-            eval_clamshell = true;
-        }
+        eval_clamshell = true;
     }
-    
+
     /*
      * AC Adaptor connected
      *
      *  -> reevaluate lid state
      */
-    if (msg & kIOPMSetACAdaptorConnected) 
+    if (msg & kIOPMSetACAdaptorConnected)
     {
         acAdaptorConnected = (0 != (msg & kIOPMSetValue));
         msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
@@ -5327,63 +6542,68 @@ void IOPMrootDomain::handlePowerNotification( UInt32 msg )
         sendClientClamshellNotification();
 
         // Re-evaluate the lid state
-        if( clamshellClosed )
-        {
-            eval_clamshell = true;
+        eval_clamshell = true;
+
+        // Lack of AC may have latched a display wrangler tickle.
+        // This mirrors the hardware's USB wake event latch, where a latched
+        // USB wake event followed by an AC attach will trigger a full wake.
+        latchDisplayWranglerTickle( false );
+
+#if HIBERNATION
+        // AC presence will reset the standy timer delay adjustment.
+        _standbyTimerResetSeconds = 0;
+#endif
+        if (!userIsActive) {
+            // Reset userActivityTime when power supply is changed(rdr 13789330)
+            clock_get_uptime(&userActivityTime);
         }
     }
-    
+
     /*
      * Enable Clamshell (external display disappear)
      *
      *  -> reevaluate lid state
      */
-    if (msg & kIOPMEnableClamshell) 
+    if (msg & kIOPMEnableClamshell)
     {
         // Re-evaluate the lid state
         // System should sleep on external display disappearance
         // in lid closed operation.
-        if( clamshellClosed && (true == clamshellDisabled) )        
+        if (true == clamshellDisabled)
         {
             eval_clamshell = true;
         }
 
         clamshellDisabled = false;
-
         sendClientClamshellNotification();
     }
-    
+
     /*
      * Disable Clamshell (external display appeared)
      * We don't bother re-evaluating clamshell state. If the system is awake,
-     * the lid is probably open. 
+     * the lid is probably open.
      */
-    if (msg & kIOPMDisableClamshell) 
+    if (msg & kIOPMDisableClamshell)
     {
         clamshellDisabled = true;
-
         sendClientClamshellNotification();
     }
 
     /*
      * Evaluate clamshell and SLEEP if appropiate
      */
-    if ( eval_clamshell && shouldSleepOnClamshellClosed() ) 
-    {
-
-
-        // SLEEP!
-        privateSleepSystem (kIOPMSleepReasonClamshell);
-    }
-    else if ( eval_clamshell )
+    if (eval_clamshell && clamshellClosed)
     {
-        evaluatePolicy(kStimulusDarkWakeEvaluate);
+        if (shouldSleepOnClamshellClosed())
+            privateSleepSystem (kIOPMSleepReasonClamshell);
+        else
+            evaluatePolicy( kStimulusDarkWakeEvaluate );
     }
 
     /*
      * Power Button
      */
-    if (msg & kIOPMPowerButton) 
+    if (msg & kIOPMPowerButton)
     {
         if (!wranglerAsleep)
         {
@@ -5414,6 +6634,8 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
             int displaySleep        : 1;
             int sleepDelayChanged   : 1;
             int evaluateDarkWake    : 1;
+            int adjustPowerState    : 1;
+            int userBecameInactive  : 1;
         } bit;
         uint32_t u32;
     } flags;
@@ -5428,17 +6650,50 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
         case kStimulusDisplayWranglerSleep:
             if (!wranglerAsleep)
             {
+                // first transition to wrangler sleep or lower
                 wranglerAsleep = true;
-                clock_get_uptime(&wranglerSleepTime);
                 flags.bit.displaySleep = true;
             }
             break;
 
         case kStimulusDisplayWranglerWake:
+            displayIdleForDemandSleep = false;
             wranglerAsleep = false;
+            break;
+
+        case kStimulusEnterUserActiveState:
+            if (_preventUserActive)
+            {
+                DLOG("user active dropped\n");
+                break;
+            }
+            if (!userIsActive)
+            {
+                userIsActive = true;
+                userWasActive = true;
+
+                // Stay awake after dropping demand for display power on
+                if (kFullWakeReasonDisplayOn == fullWakeReason)
+                    fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser;
+
+                setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
+                messageClients(kIOPMMessageUserIsActiveChanged);
+            }
             flags.bit.idleSleepDisabled = true;
             break;
 
+        case kStimulusLeaveUserActiveState:
+            if (userIsActive)
+            {
+                userIsActive = false;
+                clock_get_uptime(&userBecameInactiveTime);
+                flags.bit.userBecameInactive = true;
+
+                setProperty(gIOPMUserIsActiveKey, kOSBooleanFalse);
+                messageClients(kIOPMMessageUserIsActiveChanged);
+            }
+            break;
+
         case kStimulusAggressivenessChanged:
         {
             unsigned long   minutesToIdleSleep  = 0;
@@ -5464,6 +6719,8 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
 
             if ( minutesToIdleSleep > minutesToDisplayDim )
                 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
+            else if ( minutesToIdleSleep == minutesToDisplayDim )
+                minutesDelta = 1;
 
             if ((sleepSlider == 0) && (minutesToIdleSleep != 0))
                 flags.bit.idleSleepEnabled = true;
@@ -5471,7 +6728,8 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
             if ((sleepSlider != 0) && (minutesToIdleSleep == 0))
                 flags.bit.idleSleepDisabled = true;
 
-            if ((minutesDelta != extraSleepDelay) &&
+            if (((minutesDelta != extraSleepDelay) ||
+                        (userActivityTime != userActivityTime_prev)) &&
                 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled)
                 flags.bit.sleepDelayChanged = true;
 
@@ -5484,92 +6742,48 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
 
             sleepSlider = minutesToIdleSleep;
             extraSleepDelay = minutesDelta;
+            userActivityTime_prev = userActivityTime;
         }   break;
 
         case kStimulusDemandSystemSleep:
-            changePowerStateWithOverrideTo( SLEEP_STATE );
+            displayIdleForDemandSleep = true;
+            if (wrangler && wranglerIdleSettings)
+            {
+                // Request wrangler idle only when demand sleep is triggered
+                // from full wake.
+                if(CAP_CURRENT(kIOPMSystemCapabilityGraphics))
+                {
+                    wrangler->setProperties(wranglerIdleSettings);
+                    DLOG("Requested wrangler idle\n");
+                }
+            }
+            // arg = sleepReason
+            changePowerStateWithOverrideTo( SLEEP_STATE, arg );
             break;
 
         case kStimulusAllowSystemSleepChanged:
-            // FIXME: de-compose to change flags.
-            adjustPowerState();
+            flags.bit.adjustPowerState = true;
             break;
 
         case kStimulusDarkWakeActivityTickle:
+            // arg == true implies real and not self generated wrangler tickle.
+            // Update wake type on PM work loop instead of the tickle thread to
+            // eliminate the possibility of an early tickle clobbering the wake
+            // type set by the platform driver.
+            if (arg == true)
+                setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity);
+            
             if (false == wranglerTickled)
             {
-                uint32_t    options = 0;
-                IOService * pciRoot = 0;
-
-                if (rejectWranglerTickle)
+                if (latchDisplayWranglerTickle(true))
                 {
-                    DLOG("rejected tickle, type %u capability %x:%x\n",
-                        _systemTransitionType,
-                        _currentCapability, _pendingCapability);
+                    DLOG("latched tickle\n");
                     break;
                 }
 
-                _desiredCapability |=
-                    (kIOPMSystemCapabilityGraphics |
-                     kIOPMSystemCapabilityAudio);
-                
-                if ((kSystemTransitionWake == _systemTransitionType) &&
-                    !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
-                    !graphicsSuppressed)
-                {
-                    DLOG("Promoting to full wake\n");
-
-                    // Elevate to full wake while waking up to dark wake.
-                    // PM will hold off notifying the graphics subsystem about
-                    // system wake as late as possible, so if a HID event does
-                    // arrive, we can turn on graphics on this wake cycle, and
-                    // not have to wait till the following cycle. That latency
-                    // can be huge on some systems. However, once any graphics
-                    // suppression has taken effect, it is too late. All other
-                    // graphics devices must be similarly suppressed. But the
-                    // delay till the following cycle should be very short.
-
-                    _pendingCapability |=
-                        (kIOPMSystemCapabilityGraphics |
-                         kIOPMSystemCapabilityAudio);
-
-                    // Immediately bring up audio and graphics.
-                    pciRoot = pciHostBridgeDriver;
-
-                    // Notify clients about full wake.
-                    _systemMessageClientMask = kSystemMessageClientAll;
-                    tellClients(kIOMessageSystemWillPowerOn);
-                }
-
-                // Unsafe to cancel once graphics was powered.
-                // If system woke from dark wake, the return to sleep can
-                // be cancelled. But "awake -> dark -> sleep" transition
-                // cannot be cancelled.
-                
-                if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
-                    options |= kIOPMSyncCancelPowerDown;                    
-                }
-
-                synchronizePowerTree( options, pciRoot );
                 wranglerTickled = true;
-                // IOGraphics doesn't lit the display even though graphics
-                // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
-                // So, do an explicit activity tickle
-                if(wrangler)
-                    wrangler->activityTickle(0,0);
-
-                if (logWranglerTickle)
-                {
-                    AbsoluteTime    now;
-                    uint64_t        nsec;
-
-                    clock_get_uptime(&now);
-                    SUB_ABSOLUTETIME(&now, &systemWakeTime);
-                    absolutetime_to_nanoseconds(now, &nsec);
-                    MSG("HID tickle %u ms\n",
-                        ((int)((nsec) / 1000000ULL)));
-                    logWranglerTickle = false;
-                }
+                DLOG("Requesting full wake after dark wake activity tickle\n");
+                requestFullWake( kFullWakeReasonLocalUser );
             }
             break;
 
@@ -5582,15 +6796,22 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
             {
                 DLOG("dark wake entry\n");
                 systemDarkWake = true;
-                wranglerAsleep = true;
-                clock_get_uptime(&wranglerSleepTime);
+
+                // Keep wranglerAsleep an invariant when wrangler is absent
+                if (wrangler)
+                    wranglerAsleep = true;
+
+                if (kStimulusDarkWakeEntry == stimulus)
+                {
+                    clock_get_uptime(&userBecameInactiveTime);
+                    flags.bit.evaluateDarkWake = true;
+                }
 
                 // Always accelerate disk spindown while in dark wake,
                 // even if system does not support/allow sleep.
 
                 cancelIdleSleepTimer();
                 setQuickSpinDownTimeout();
-                flags.bit.evaluateDarkWake = true;
             }
             break;
 
@@ -5599,51 +6820,49 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
             {
                 flags.bit.evaluateDarkWake = true;
             }
-#if !DARK_TO_FULL_EVALUATE_CLAMSHELL
-            else
-            {
-                // Not through kLocalEvalClamshellCommand to avoid loop.
-                if (clamshellClosed && shouldSleepOnClamshellClosed() &&
-                    checkSystemCanSleep(true))
-                {
-                    privateSleepSystem( kIOPMSleepReasonClamshell );
-                }
-            }
-#endif
+            break;
+
+        case kStimulusNoIdleSleepPreventers:
+            flags.bit.adjustPowerState = true;
             break;
 
     } /* switch(stimulus) */
 
-    if (flags.bit.evaluateDarkWake && !wranglerTickled)
+    if (flags.bit.evaluateDarkWake && (kFullWakeReasonNone == fullWakeReason))
     {
         if (darkWakeToSleepASAP ||
             (clamshellClosed && !(desktopMode && acAdaptorConnected)))
         {
-            // System currently in dark wake, and no children and
-            // assertion prevent system sleep.
+            uint32_t newSleepReason;
 
-            if (checkSystemCanSleep(true))
+            if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
             {
+                // System was previously in full wake. Sleep reason from
+                // full to dark already recorded in fullToDarkReason.
+
                 if (lowBatteryCondition)
-                {
-                    lastSleepReason = kIOPMSleepReasonLowPower;
-                    setProperty(kRootDomainSleepReasonKey, kIOPMLowPowerSleepKey);
-                }
-                else  if (darkWakeMaintenance)
-                {
-                    lastSleepReason = kIOPMSleepReasonMaintenance;
-                    setProperty(kRootDomainSleepReasonKey, kIOPMMaintenanceSleepKey);
-                }
-                changePowerStateWithOverrideTo( SLEEP_STATE );
+                    newSleepReason = kIOPMSleepReasonLowPower;
+                else
+                    newSleepReason = fullToDarkReason;
             }
             else
             {
-                // Parked in dark wake, a tickle will return to full wake
-                rejectWranglerTickle = false;
+                // In dark wake from system sleep.
+
+                if (darkWakeSleepService)
+                    newSleepReason = kIOPMSleepReasonSleepServiceExit;
+                else
+                    newSleepReason = kIOPMSleepReasonMaintenance;
+            }
+
+            if (checkSystemCanSleep(newSleepReason))
+            {
+                privateSleepSystem(newSleepReason);
             }
-        } else // non-maintenance (network) dark wake
+        }
+        else // non-maintenance (network) dark wake
         {
-            if (checkSystemCanSleep(true))
+            if (checkSystemCanSleep(kIOPMSleepReasonIdle))
             {
                 // Release power clamp, and wait for children idle.
                 adjustPowerState(true);
@@ -5652,7 +6871,6 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
             {
                 changePowerStateToPriv(ON_STATE);
             }
-            rejectWranglerTickle = false;
         }
     }
 
@@ -5662,42 +6880,37 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
         flags.u32 = 0;
     }
 
-    if (flags.bit.displaySleep || flags.bit.sleepDelayChanged)
+    if ((flags.bit.displaySleep) &&
+        (kFullWakeReasonDisplayOn == fullWakeReason))
+    {
+        // kIOPMSleepReasonMaintenance?
+        changePowerStateWithOverrideTo( SLEEP_STATE, kIOPMSleepReasonMaintenance );
+    }
+
+    if (flags.bit.userBecameInactive || flags.bit.sleepDelayChanged)
     {
         bool cancelQuickSpindown = false;
 
         if (flags.bit.sleepDelayChanged)
         {
+            // Cancel existing idle sleep timer and quick disk spindown.
+            // New settings will be applied by the idleSleepEnabled flag
+            // handler below if idle sleep is enabled.
+
             DLOG("extra sleep timer changed\n");
             cancelIdleSleepTimer();
             cancelQuickSpindown = true;
         }
         else
         {
-            DLOG("display sleep\n");        
+            DLOG("user inactive\n");
         }
 
-        if (wranglerAsleep && !wranglerSleepIgnored)
+        if (!userIsActive && sleepSlider)
         {
-            if ( extraSleepDelay )
-            {
-                // Start a timer here if the System Sleep timer is greater
-                // than the Display Sleep timer.
-
-                startIdleSleepTimer(gRootDomain->extraSleepDelay * 60);            
-            }
-            else if ( sleepSlider )
-            {
-                // Accelerate disk spindown if system sleep and display sleep
-                // sliders are set to the same value (e.g. both set to 5 min),
-                // and display is about to go dark. Check the system sleep is
-                // not set to never sleep. Disk sleep setting is ignored.
-
-                setQuickSpinDownTimeout();
-                cancelQuickSpindown = false;
-            }
+            startIdleSleepTimer(getTimeToIdleSleep());
         }
-        
+
         if (cancelQuickSpindown)
             restoreUserSpinDownTimeout();
     }
@@ -5715,37 +6928,13 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
         }
         else
         {
-            // Start idle sleep timer if wrangler went to sleep
-            // while system sleep was disabled. Disk spindown is
+            // Start idle timer if prefs now allow system sleep
+            // and user is already inactive. Disk spindown is
             // accelerated upon timer expiration.
 
-            if (wranglerAsleep)
+            if (!userIsActive)
             {
-                AbsoluteTime    now;
-                uint64_t        nanos;
-                uint32_t        minutesSinceDisplaySleep = 0;
-                uint32_t        sleepDelay;
-
-                clock_get_uptime(&now);
-                if (CMP_ABSOLUTETIME(&now, &wranglerSleepTime) > 0)
-                {
-                    SUB_ABSOLUTETIME(&now, &wranglerSleepTime);
-                    absolutetime_to_nanoseconds(now, &nanos);
-                    minutesSinceDisplaySleep = nanos / (60000000000ULL);
-                }
-
-                if (extraSleepDelay > minutesSinceDisplaySleep)
-                {
-                    sleepDelay = extraSleepDelay - minutesSinceDisplaySleep;
-                }
-                else
-                {
-                    sleepDelay = 1; // 1 min
-                }
-
-                startIdleSleepTimer(sleepDelay * 60);
-                DLOG("display slept %u min, set idle timer to %u min\n",
-                    minutesSinceDisplaySleep, sleepDelay);
+                startIdleSleepTimer(getTimeToIdleSleep());
             }
         }
     }
@@ -5757,6 +6946,218 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
         restoreUserSpinDownTimeout();
         adjustPowerState();
     }
+
+    if (flags.bit.adjustPowerState)
+    {
+        bool sleepASAP = false;
+
+        if (!systemBooting && (preventIdleSleepList->getCount() == 0))
+        {
+            if (!wrangler)
+            {
+                changePowerStateToPriv(ON_STATE);
+                if (idleSeconds)
+                {
+                    // stay awake for at least idleSeconds
+                    startIdleSleepTimer(idleSeconds);
+                }
+            }
+            else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
+            {
+                sleepASAP = true;
+            }
+        }
+
+        adjustPowerState(sleepASAP);
+    }
+}
+
+//******************************************************************************
+// requestFullWake
+//
+// Request transition from dark wake to full wake
+//******************************************************************************
+
+void IOPMrootDomain::requestFullWake( FullWakeReason reason )
+{
+    uint32_t        options = 0;
+    IOService *     pciRoot = 0;
+    bool            promotion = false;
+
+    // System must be in dark wake and a valid reason for entering full wake
+    if ((kFullWakeReasonNone == reason) ||
+        (kFullWakeReasonNone != fullWakeReason) ||
+        (CAP_CURRENT(kIOPMSystemCapabilityGraphics)))
+    {
+        return;
+    }
+
+    // Will clear reason upon exit from full wake
+    fullWakeReason = reason;
+
+    _desiredCapability |= (kIOPMSystemCapabilityGraphics |
+                           kIOPMSystemCapabilityAudio);
+
+    if ((kSystemTransitionWake == _systemTransitionType) &&
+        !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
+        !graphicsSuppressed)
+    {
+        // Promote to full wake while waking up to dark wake due to tickle.
+        // PM will hold off notifying the graphics subsystem about system wake
+        // as late as possible, so if a HID tickle does arrive, graphics can
+        // power up on this same wake cycle. The latency to power up graphics
+        // on the next cycle can be huge on some systems. However, once any
+        // graphics suppression has taken effect, it is too late. All other
+        // graphics devices must be similarly suppressed. But the delay till
+        // the following cycle should be short.
+
+        _pendingCapability |= (kIOPMSystemCapabilityGraphics |
+                               kIOPMSystemCapabilityAudio);
+
+        // Immediately bring up audio and graphics
+        pciRoot = pciHostBridgeDriver;
+        willEnterFullWake();
+        promotion = true;
+    }
+
+    // Unsafe to cancel once graphics was powered.
+    // If system woke from dark wake, the return to sleep can
+    // be cancelled. "awake -> dark -> sleep" transition
+    // can be canceled also, during the "dark --> sleep" phase
+    // *prior* to driver power down.
+    if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics) ||
+        _pendingCapability == 0) {
+        options |= kIOPMSyncCancelPowerDown;
+    }
+
+    synchronizePowerTree(options, pciRoot);
+    if (kFullWakeReasonLocalUser == fullWakeReason)
+    {
+        // IOGraphics doesn't light the display even though graphics is
+        // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
+        // So, do an explicit activity tickle
+        if (wrangler)
+            wrangler->activityTickle(0,0);
+    }
+
+    // Log a timestamp for the initial full wake request.
+    // System may not always honor this full wake request.
+    if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
+    {
+        AbsoluteTime    now;
+        uint64_t        nsec;
+
+        clock_get_uptime(&now);
+        SUB_ABSOLUTETIME(&now, &systemWakeTime);
+        absolutetime_to_nanoseconds(now, &nsec);
+        MSG("full wake %s (reason %u) %u ms\n",
+            promotion ? "promotion" : "request",
+            fullWakeReason, ((int)((nsec) / 1000000ULL)));
+    }
+}
+
+//******************************************************************************
+// willEnterFullWake
+//
+// System will enter full wake from sleep, from dark wake, or from dark
+// wake promotion. This function aggregate things that are in common to
+// all three full wake transitions.
+//
+// Assumptions: fullWakeReason was updated
+//******************************************************************************
+
+void IOPMrootDomain::willEnterFullWake( void )
+{
+    hibernateRetry = false;
+    sleepToStandby = false;
+    sleepTimerMaintenance = false;
+
+    _systemMessageClientMask = kSystemMessageClientPowerd |
+                               kSystemMessageClientLegacyApp;
+
+    if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
+    {
+        // Initial graphics full power
+        _systemMessageClientMask |= kSystemMessageClientKernel;
+
+        // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
+        setProperty(gIOPMUserTriggeredFullWakeKey,
+            (kFullWakeReasonLocalUser == fullWakeReason) ?
+                kOSBooleanTrue : kOSBooleanFalse);
+    }
+#if HIBERNATION
+    IOHibernateSetWakeCapabilities(_pendingCapability);
+#endif
+
+    IOService::setAdvisoryTickleEnable( true );
+    tellClients(kIOMessageSystemWillPowerOn);
+    preventTransitionToUserActive(false);
+}
+
+//******************************************************************************
+// fullWakeDelayedWork
+//
+// System has already entered full wake. Invoked by a delayed thread call.
+//******************************************************************************
+
+void IOPMrootDomain::fullWakeDelayedWork( void )
+{
+#if DARK_TO_FULL_EVALUATE_CLAMSHELL
+    // Not gated, don't modify state
+    if ((kSystemTransitionNone == _systemTransitionType) &&
+        CAP_CURRENT(kIOPMSystemCapabilityGraphics))
+    {
+        receivePowerNotification( kLocalEvalClamshellCommand );
+    }
+#endif
+}
+
+//******************************************************************************
+// evaluateAssertions
+//
+//******************************************************************************
+void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
+{
+    IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
+
+    messageClients(kIOPMMessageDriverAssertionsChanged);
+
+    if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
+
+        if (wrangler) {
+            bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
+
+            DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
+            wrangler->setIgnoreIdleTimer( value );
+        }
+    }
+
+    if (changedBits & kIOPMDriverAssertionCPUBit) {
+        evaluatePolicy(kStimulusDarkWakeEvaluate);
+        if (!assertOnWakeSecs && systemWakeTime) {
+                AbsoluteTime    now;
+                clock_usec_t    microsecs;
+                clock_get_uptime(&now);
+                SUB_ABSOLUTETIME(&now, &systemWakeTime);
+                absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
+                if (assertOnWakeReport)  {
+                    HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
+                    DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
+                }
+        }
+    }
+
+    if (changedBits & kIOPMDriverAssertionReservedBit7) {
+        bool value = (newAssertions & kIOPMDriverAssertionReservedBit7) ? true : false;
+        if (value) {
+            DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
+            updatePreventIdleSleepList(this, true);
+        }
+        else {
+            DLOG("Driver assertion ReservedBit7 dropped\n");
+            updatePreventIdleSleepList(this, false);
+        }
+    }
 }
 
 // MARK: -
@@ -5775,6 +7176,7 @@ void IOPMrootDomain::pmStatsRecordEvent(
     bool        stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
     uint64_t    delta;
     uint64_t    nsec;
+    OSData *publishPMStats = NULL;
 
     eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
 
@@ -5783,24 +7185,29 @@ void IOPMrootDomain::pmStatsRecordEvent(
     switch (eventIndex) {
         case kIOPMStatsHibernateImageWrite:
             if (starting)
-                pmStats.hibWrite.start = nsec;
+                gPMStats.hibWrite.start = nsec;
             else if (stopping)
-                pmStats.hibWrite.stop = nsec;
+                gPMStats.hibWrite.stop = nsec;
 
             if (stopping) {
-                delta = pmStats.hibWrite.stop - pmStats.hibWrite.start;
+                delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
                 IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
             }
             break;
         case kIOPMStatsHibernateImageRead:
             if (starting)
-                pmStats.hibRead.start = nsec;
+                gPMStats.hibRead.start = nsec;
             else if (stopping)
-                pmStats.hibRead.stop = nsec;
+                gPMStats.hibRead.stop = nsec;
 
             if (stopping) {
-                delta = pmStats.hibRead.stop - pmStats.hibRead.start;
+                delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
                 IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
+
+                publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats));
+                setProperty(kIOPMSleepStatisticsKey, publishPMStats);
+                publishPMStats->release();
+                bzero(&gPMStats, sizeof(gPMStats));
             }
             break;
     }
@@ -5811,52 +7218,48 @@ void IOPMrootDomain::pmStatsRecordEvent(
  * IOPMrootDomain::pmStatsAppResponses
  */
 void IOPMrootDomain::pmStatsRecordApplicationResponse(
-       const OSSymbol          *response,
-       const char          *name,
-       int                 messageType,
+    const OSSymbol      *response,
+    const char          *name,
+    int                 messageType,
     uint32_t            delay_ms,
-    int                 app_pid)
+    int                 app_pid,
+    OSObject            *object,
+    IOPMPowerStateIndex powerState)
 {
     OSDictionary    *responseDescription    = NULL;
     OSNumber        *delayNum               = NULL;
+    OSNumber        *powerCaps              = NULL;
     OSNumber        *pidNum                 = NULL;
     OSNumber        *msgNum                 = NULL;
     const OSSymbol  *appname;
-    const OSSymbol  *entryName;
-    OSObject        *entryType;
-    int             i;
-
-    if (!pmStatsAppResponses || pmStatsAppResponses->getCount() > 50)
-        return;
+    const OSSymbol  *sleep = NULL, *wake = NULL;
+    IOPMServiceInterestNotifier *notify = 0;
 
-    i = 0;
-    while ((responseDescription = (OSDictionary *) pmStatsAppResponses->getObject(i++)))
+    if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object)))
     {
-        entryType = responseDescription->getObject(_statsResponseTypeKey);
-        entryName = (OSSymbol *) responseDescription->getObject(_statsNameKey);
-        if (entryName && (entryType == response) && entryName->isEqualTo(name))
-        {
-            OSNumber * entryValue;
-            entryValue = (OSNumber *) responseDescription->getObject(_statsTimeMSKey);
-            if (entryValue && (entryValue->unsigned32BitValue() < delay_ms))
-                entryValue->setValue(delay_ms);
-            return;
-        }
+        if (response->isEqualTo(gIOPMStatsApplicationResponseTimedOut)) 
+            notify->ackTimeoutCnt++;
+        else
+            notify->ackTimeoutCnt = 0;
+
     }
 
+    if (response->isEqualTo(gIOPMStatsApplicationResponsePrompt) || 
+         (_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient))
+        return;
+
+
     responseDescription = OSDictionary::withCapacity(5);
-    if (responseDescription) 
+    if (responseDescription)
     {
         if (response) {
             responseDescription->setObject(_statsResponseTypeKey, response);
         }
-        
-        if (messageType != 0) {
-            msgNum = OSNumber::withNumber(messageType, 32);
-            if (msgNum) {
-                responseDescription->setObject(_statsMessageTypeKey, msgNum);
-                msgNum->release();
-            }
+
+        msgNum = OSNumber::withNumber(messageType, 32);
+        if (msgNum) {
+            responseDescription->setObject(_statsMessageTypeKey, msgNum);
+            msgNum->release();
         }
 
         if (name && (strlen(name) > 0))
@@ -5882,12 +7285,52 @@ void IOPMrootDomain::pmStatsRecordApplicationResponse(
             delayNum->release();
         }
 
-        if (pmStatsAppResponses) {
+        if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
+            powerCaps = OSNumber::withNumber(powerState, 32);
+
+#if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
+            IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
+                  name, messageType,
+                  powerState, delay_ms);
+#endif
+
+        }
+        else {
+            powerCaps = OSNumber::withNumber(_pendingCapability, 32);
+        }
+        if (powerCaps) {
+            responseDescription->setObject(_statsPowerCapsKey, powerCaps);
+            powerCaps->release();
+        }
+
+        sleep = OSSymbol::withCString("Sleep");
+        wake = OSSymbol::withCString("Wake");
+        if (_systemTransitionType == kSystemTransitionSleep)  {
+            responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
+        }
+        else if (_systemTransitionType == kSystemTransitionWake) {
+            responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
+        }
+        else if (_systemTransitionType == kSystemTransitionCapability) {
+            if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
+                responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
+            else if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
+                responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
+        }
+        if (sleep) sleep->release();
+        if (wake) wake->release();
+
+
+
+        IOLockLock(pmStatsLock);
+        if (pmStatsAppResponses && pmStatsAppResponses->getCount() < 50) {
             pmStatsAppResponses->setObject(responseDescription);
         }
+        IOLockUnlock(pmStatsLock);
 
         responseDescription->release();
     }
+
     return;
 }
 
@@ -5899,8 +7342,8 @@ void IOPMrootDomain::pmStatsRecordApplicationResponse(
 //
 //******************************************************************************
 
-#define kIOPMRegisterNVRAMTracePointHandlerKey \
-               "IOPMRegisterNVRAMTracePointHandler"
+#define kIOPMRegisterNVRAMTracePointHandlerKey  \
+        "IOPMRegisterNVRAMTracePointHandler"
 
 IOReturn IOPMrootDomain::callPlatformFunction(
     const OSSymbol * functionName,
@@ -5913,23 +7356,37 @@ IOReturn IOPMrootDomain::callPlatformFunction(
         !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
     {
         uint32_t    tracePointPhases, tracePointPCI;
-               uint64_t        statusCode;
+        uint64_t    statusCode;
 
         pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
         pmTracer->tracePointTarget  = (void *) param2;
-        tracePointPCI                          = (uint32_t)(uintptr_t) param3;
-        tracePointPhases                       = (uint32_t)(uintptr_t) param4;
+        tracePointPCI               = (uint32_t)(uintptr_t) param3;
+        tracePointPhases            = (uint32_t)(uintptr_t) param4;
         statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
-               if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp)
+        if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp)
         {
             MSG("Sleep failure code 0x%08x 0x%08x\n",
                 tracePointPCI, tracePointPhases);
         }
-               setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
+        setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
         pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
 
         return kIOReturnSuccess;
     }
+#if HIBERNATION
+    else if (functionName &&
+             functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey))
+    {
+        if (gSleepPolicyHandler)
+            return kIOReturnExclusiveAccess;
+        if (!param1)
+            return kIOReturnBadArgument;
+        gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
+        gSleepPolicyTarget  = (void *) param2;
+        setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
+        return kIOReturnSuccess;
+    }
+#endif
 
     return super::callPlatformFunction(
         functionName, waitForFunction, param1, param2, param3, param4);
@@ -5937,14 +7394,21 @@ IOReturn IOPMrootDomain::callPlatformFunction(
 
 void IOPMrootDomain::tracePoint( uint8_t point )
 {
-    if (!systemBooting)
-        pmTracer->tracePoint(point);
+    if (systemBooting) return;
+
+    if (kIOPMTracePointWakeCapabilityClients == point)
+        acceptSystemWakeEvents(false);
+
+    PMDebug(kPMLogSleepWakeTracePoint, point, 0);
+    pmTracer->tracePoint(point);
 }
 
 void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data )
 {
-    if (!systemBooting)
-        pmTracer->tracePoint(point, data);
+    if (systemBooting) return;
+
+    PMDebug(kPMLogSleepWakeTracePoint, point, data);
+    pmTracer->tracePoint(point, data);
 }
 
 void IOPMrootDomain::traceDetail( uint32_t detail )
@@ -5953,6 +7417,187 @@ void IOPMrootDomain::traceDetail( uint32_t detail )
         pmTracer->traceDetail( detail );
 }
 
+
+void IOPMrootDomain::configureReportGated(uint64_t channel_id, uint64_t action, void *result)
+{
+    size_t      reportSize;
+    void        **report = NULL;
+    uint32_t    bktCnt;
+    uint32_t    bktSize;
+    uint32_t    *clientCnt;
+
+    ASSERT_GATED();
+
+    report = NULL;
+    if (channel_id == kAssertDelayChID) {
+        report = &assertOnWakeReport;
+        bktCnt = kAssertDelayBcktCnt;
+        bktSize = kAssertDelayBcktSize;
+        clientCnt = &assertOnWakeClientCnt;
+    }
+    else if (channel_id == kSleepDelaysChID) {
+        report = &sleepDelaysReport;
+        bktCnt = kSleepDelaysBcktCnt;
+        bktSize = kSleepDelaysBcktSize;
+        clientCnt = &sleepDelaysClientCnt;
+    }
+
+    switch (action)
+    {
+        case kIOReportEnable:
+
+            if (*report) {
+                (*clientCnt)++;
+                break;
+            }
+
+            reportSize = HISTREPORT_BUFSIZE(bktCnt);
+            *report = IOMalloc(reportSize);
+            if (*report == NULL) {
+                break;
+            }
+            bzero(*report, reportSize);
+            HISTREPORT_INIT(bktCnt, bktSize, *report, reportSize,
+                                 getRegistryEntryID(), channel_id,  kIOReportCategoryPower);
+
+            if (channel_id == kAssertDelayChID)
+                assertOnWakeSecs = 0;
+
+            break;
+
+        case kIOReportDisable:
+            if (*clientCnt == 0) {
+                break;
+            }
+            if (*clientCnt == 1)
+            {
+                IOFree(*report, HISTREPORT_BUFSIZE(bktCnt));
+                *report = NULL;
+            }
+            (*clientCnt)--;
+
+            if (channel_id == kAssertDelayChID)
+                assertOnWakeSecs = -1;  // Invalid value to prevent updates
+
+            break;
+
+        case kIOReportGetDimensions:
+            if (*report) {
+                HISTREPORT_UPDATERES(*report, kIOReportGetDimensions, result);
+            }
+            break;
+    }
+
+    return;
+}
+
+IOReturn IOPMrootDomain::configureReport(IOReportChannelList    *channelList,
+                                    IOReportConfigureAction action,
+                                    void                   *result,
+                                    void                   *destination)
+{
+    unsigned cnt;
+    uint64_t configAction = (uint64_t)action;
+
+    for (cnt = 0; cnt < channelList->nchannels; cnt++) {
+        if ( (channelList->channels[cnt].channel_id == kSleepCntChID) ||
+               (channelList->channels[cnt].channel_id == kDarkWkCntChID) ||
+               (channelList->channels[cnt].channel_id == kUserWkCntChID) ) {
+            if (action != kIOReportGetDimensions) continue;
+            SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
+        }
+        else if ((channelList->channels[cnt].channel_id == kAssertDelayChID) ||
+                 (channelList->channels[cnt].channel_id == kSleepDelaysChID)) {
+            gIOPMWorkLoop->runAction(
+                     OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::configureReportGated),
+                     (OSObject *)this, (void *)channelList->channels[cnt].channel_id,
+                     (void *)configAction, (void *)result);
+        }
+    }
+
+    return super::configureReport(channelList, action, result, destination);
+}
+
+IOReturn IOPMrootDomain::updateReportGated(uint64_t ch_id, void *result, IOBufferMemoryDescriptor *dest)
+{
+
+    uint32_t    size2cpy;
+    void        *data2cpy;
+    void        **report;
+
+    ASSERT_GATED();
+
+    report = NULL;
+    if (ch_id == kAssertDelayChID) {
+        report = &assertOnWakeReport;
+    }
+    else if (ch_id == kSleepDelaysChID) {
+        report = &sleepDelaysReport;
+    }
+
+    if (*report == NULL) {
+        return kIOReturnNotOpen;
+    }
+
+    HISTREPORT_UPDATEPREP(*report, data2cpy, size2cpy);
+    if (size2cpy > (dest->getCapacity() - dest->getLength()) ) {
+        return kIOReturnOverrun;
+    }
+
+    HISTREPORT_UPDATERES(*report, kIOReportCopyChannelData, result);
+    dest->appendBytes(data2cpy, size2cpy);
+
+    return kIOReturnSuccess;
+}
+
+IOReturn IOPMrootDomain::updateReport(IOReportChannelList      *channelList,
+                                 IOReportUpdateAction      action,
+                                 void                     *result,
+                                 void                     *destination)
+{
+    uint32_t size2cpy;
+    void *data2cpy;
+    uint8_t buf[SIMPLEREPORT_BUFSIZE];
+    IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
+    unsigned cnt;
+    uint64_t ch_id;
+
+    if (action != kIOReportCopyChannelData) goto exit;
+
+    for (cnt = 0; cnt < channelList->nchannels; cnt++) {
+        ch_id = channelList->channels[cnt].channel_id ;
+
+        if ((ch_id == kAssertDelayChID) || (ch_id == kSleepDelaysChID)) {
+            gIOPMWorkLoop->runAction(
+                     OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::updateReportGated),
+                     (OSObject *)this, (void *)ch_id,
+                     (void *)result, (void *)dest);
+            continue;
+
+        }
+        else if ((ch_id == kSleepCntChID) ||
+                (ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) {
+            SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower);
+        }
+        else continue;
+
+        if (ch_id == kSleepCntChID)
+            SIMPLEREPORT_SETVALUE(buf, sleepCnt);
+        else if (ch_id == kDarkWkCntChID)
+            SIMPLEREPORT_SETVALUE(buf, darkWakeCnt);
+        else if (ch_id == kUserWkCntChID)
+            SIMPLEREPORT_SETVALUE(buf, displayWakeCnt);
+
+        SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
+        SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
+        dest->appendBytes(data2cpy, size2cpy);
+    }
+
+exit:
+    return super::updateReport(channelList, action, result, destination);
+}
+
+
 //******************************************************************************
 // PMTraceWorker Class
 //
@@ -5968,14 +7613,14 @@ OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
 PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
 {
     PMTraceWorker           *me;
-    
+
     me = OSTypeAlloc( PMTraceWorker );
     if (!me || !me->init())
     {
         return NULL;
     }
 
-    DLOG("PMTraceWorker %p\n", me);
+    DLOG("PMTraceWorker %p\n", OBFUSCATE(me));
 
     // Note that we cannot instantiate the PCI device -> bit mappings here, since
     // the IODeviceTree has not yet been created by IOPlatformExpert. We create
@@ -5991,16 +7636,16 @@ PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
 
 void PMTraceWorker::RTC_TRACE(void)
 {
-       if (tracePointHandler && tracePointTarget)
-       {
-               uint32_t    wordA;
+    if (tracePointHandler && tracePointTarget)
+    {
+        uint32_t    wordA;
 
         wordA = (tracePhase << 24) | (loginWindowPhase << 16) |
                 (traceData8 << 8);
 
         tracePointHandler( tracePointTarget, traceData32, wordA );
-               _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
-       }
+        _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
+    }
 }
 
 int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
@@ -6096,23 +7741,23 @@ void PMTraceWorker::traceLoginWindowPhase(uint8_t phase)
 }
 
 void PMTraceWorker::tracePCIPowerChange(
-       change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
+    change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
 {
-    uint32_t   bitMask;
-       uint32_t        expectedFlag;
+    uint32_t    bitMask;
+    uint32_t    expectedFlag;
 
-       // Ignore PCI changes outside of system sleep/wake.
+    // Ignore PCI changes outside of system sleep/wake.
     if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
         (kIOPMTracePointWakePowerPlaneDrivers  != tracePhase))
         return;
 
-       // Only record the WillChange transition when going to sleep,
-       // and the DidChange on the way up.
-       changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
-       expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
-                                       kIOPMDomainWillChange : kIOPMDomainDidChange;
-       if (changeFlags != expectedFlag)
-               return;
+    // Only record the WillChange transition when going to sleep,
+    // and the DidChange on the way up.
+    changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
+    expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
+                    kIOPMDomainWillChange : kIOPMDomainDidChange;
+    if (changeFlags != expectedFlag)
+        return;
 
     // Mark this device off in our bitfield
     if (bitNum < kPMMaxRTCBitfieldSize)
@@ -6132,10 +7777,18 @@ void PMTraceWorker::tracePCIPowerChange(
                 service->getName(), bitNum, bitMask, traceData32);
         }
 
+        DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
         RTC_TRACE();
     }
 }
 
+uint64_t  PMTraceWorker::getPMStatusCode( )
+{
+    return (((uint64_t)traceData32 << 32) | ((uint64_t)tracePhase << 24) |
+            (loginWindowPhase << 16) | (traceData8 << 8));
+
+}
+
 // MARK: -
 // MARK: PMHaltWorker
 
@@ -6144,196 +7797,187 @@ void PMTraceWorker::tracePCIPowerChange(
 //
 //******************************************************************************
 
-static unsigned int            gPMHaltBusyCount;
-static unsigned int            gPMHaltIdleCount;
-static int                             gPMHaltDepth;
-static unsigned long    gPMHaltEvent;
-static IOLock *                        gPMHaltLock  = 0;
-static OSArray *               gPMHaltArray = 0;
-static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
-
 PMHaltWorker * PMHaltWorker::worker( void )
 {
-       PMHaltWorker *  me;
-       IOThread                thread;
+    PMHaltWorker *  me;
+    IOThread        thread;
 
-       do {
-               me = OSTypeAlloc( PMHaltWorker );
-               if (!me || !me->init())
-                       break;
-
-               me->lock = IOLockAlloc();
-               if (!me->lock)
-                       break;
+    do {
+        me = OSTypeAlloc( PMHaltWorker );
+        if (!me || !me->init())
+            break;
 
-               DLOG("PMHaltWorker %p\n", me);
-               me->retain();   // thread holds extra retain
-               if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
-               {
-                       me->release();
-                       break;
-               }
-               thread_deallocate(thread);
-               return me;
+        me->lock = IOLockAlloc();
+        if (!me->lock)
+            break;
 
-       } while (false);
+        DLOG("PMHaltWorker %p\n", OBFUSCATE(me));
+        me->retain();   // thread holds extra retain
+        if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
+        {
+            me->release();
+            break;
+        }
+        thread_deallocate(thread);
+        return me;
 
-       if (me) me->release();
-       return 0;
+    } while (false);
+
+    if (me) me->release();
+    return 0;
 }
 
 void PMHaltWorker::free( void )
 {
-       DLOG("PMHaltWorker free %p\n", this);
-       if (lock)
-       {
-               IOLockFree(lock);
-               lock = 0;
-       }
-       return OSObject::free();
+    DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
+    if (lock)
+    {
+        IOLockFree(lock);
+        lock = 0;
+    }
+    return OSObject::free();
 }
 
 void PMHaltWorker::main( void * arg, wait_result_t waitResult )
 {
-       PMHaltWorker * me = (PMHaltWorker *) arg;
+    PMHaltWorker * me = (PMHaltWorker *) arg;
 
-       IOLockLock( gPMHaltLock );
-       gPMHaltBusyCount++;
-       me->depth = gPMHaltDepth;
-       IOLockUnlock( gPMHaltLock );
+    IOLockLock( gPMHaltLock );
+    gPMHaltBusyCount++;
+    me->depth = gPMHaltDepth;
+    IOLockUnlock( gPMHaltLock );
 
-       while (me->depth >= 0)
-       {
-               PMHaltWorker::work( me );
-
-               IOLockLock( gPMHaltLock );
-               if (++gPMHaltIdleCount >= gPMHaltBusyCount)
-               {
-                       // This is the last thread to finish work on this level,
-                       // inform everyone to start working on next lower level.
-                       gPMHaltDepth--;
-                       me->depth = gPMHaltDepth;
-                       gPMHaltIdleCount = 0;
-                       thread_wakeup((event_t) &gPMHaltIdleCount);
-               }
-               else
-               {
-                       // One or more threads are still working on this level,
-                       // this thread must wait.
-                       me->depth = gPMHaltDepth - 1;
-                       do {
-                               IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
-                       } while (me->depth != gPMHaltDepth);
-               }
-               IOLockUnlock( gPMHaltLock );
-       }
+    while (me->depth >= 0)
+    {
+        PMHaltWorker::work( me );
+
+        IOLockLock( gPMHaltLock );
+        if (++gPMHaltIdleCount >= gPMHaltBusyCount)
+        {
+            // This is the last thread to finish work on this level,
+            // inform everyone to start working on next lower level.
+            gPMHaltDepth--;
+            me->depth = gPMHaltDepth;
+            gPMHaltIdleCount = 0;
+            thread_wakeup((event_t) &gPMHaltIdleCount);
+        }
+        else
+        {
+            // One or more threads are still working on this level,
+            // this thread must wait.
+            me->depth = gPMHaltDepth - 1;
+            do {
+                IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
+            } while (me->depth != gPMHaltDepth);
+        }
+        IOLockUnlock( gPMHaltLock );
+    }
 
-       // No more work to do, terminate thread
-       DLOG("All done for worker: %p (visits = %u)\n", me, me->visits);
-       thread_wakeup( &gPMHaltDepth );
-       me->release();
+    // No more work to do, terminate thread
+    DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me), me->visits);
+    thread_wakeup( &gPMHaltDepth );
+    me->release();
 }
 
 void PMHaltWorker::work( PMHaltWorker * me )
 {
-       IOService *             service;
-       OSSet *                 inner;
-       AbsoluteTime    startTime;
-       UInt32                  deltaTime;
-       bool                    timeout;
+    IOService *     service;
+    OSSet *         inner;
+    AbsoluteTime    startTime;
+    UInt32          deltaTime;
+    bool            timeout;
 
-       while (true)
-       {
-               service = 0;
-               timeout = false;
-
-               // Claim an unit of work from the shared pool
-               IOLockLock( gPMHaltLock );
-               inner = (OSSet *)gPMHaltArray->getObject(me->depth);
-               if (inner)
-               {
-                       service = (IOService *)inner->getAnyObject();
-                       if (service)
-                       {
-                               service->retain();
-                               inner->removeObject(service);
-                       }
-               }
-               IOLockUnlock( gPMHaltLock );    
-               if (!service)
-                       break;  // no more work at this depth
-
-               clock_get_uptime(&startTime);
-
-               if (!service->isInactive() &&
-                       service->setProperty(gPMHaltClientAcknowledgeKey, me))
-               {
-                       IOLockLock(me->lock);
-                       me->startTime = startTime;
-                       me->service   = service;
-                       me->timeout   = false;
-                       IOLockUnlock(me->lock);
-
-                       service->systemWillShutdown( gPMHaltEvent );
-
-                       // Wait for driver acknowledgement
-                       IOLockLock(me->lock);
-                       while (service->getProperty(gPMHaltClientAcknowledgeKey))
-                       {
-                               IOLockSleep(me->lock, me, THREAD_UNINT);                        
-                       }
-                       me->service = 0;
-                       timeout = me->timeout;
-                       IOLockUnlock(me->lock);
-               }
-
-               deltaTime = computeDeltaTimeMS(&startTime);
-               if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
-                       (gIOKitDebug & kIOLogPMRootDomain))
-               {
-                       LOG("%s driver %s (%p) took %u ms\n",
-                               (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
-                                       "PowerOff" : "Restart",
-                               service->getName(), service,
-                               (uint32_t) deltaTime );
-               }
-
-               service->release();
-               me->visits++;
-       }
+    while (true)
+    {
+        service = 0;
+        timeout = false;
+
+        // Claim an unit of work from the shared pool
+        IOLockLock( gPMHaltLock );
+        inner = (OSSet *)gPMHaltArray->getObject(me->depth);
+        if (inner)
+        {
+            service = (IOService *)inner->getAnyObject();
+            if (service)
+            {
+                service->retain();
+                inner->removeObject(service);
+            }
+        }
+        IOLockUnlock( gPMHaltLock );
+        if (!service)
+            break;  // no more work at this depth
+
+        clock_get_uptime(&startTime);
+
+        if (!service->isInactive() &&
+            service->setProperty(gPMHaltClientAcknowledgeKey, me))
+        {
+            IOLockLock(me->lock);
+            me->startTime = startTime;
+            me->service   = service;
+            me->timeout   = false;
+            IOLockUnlock(me->lock);
+
+            service->systemWillShutdown( gPMHaltMessageType );
+
+            // Wait for driver acknowledgement
+            IOLockLock(me->lock);
+            while (service->getProperty(gPMHaltClientAcknowledgeKey))
+            {
+                IOLockSleep(me->lock, me, THREAD_UNINT);
+            }
+            me->service = 0;
+            timeout = me->timeout;
+            IOLockUnlock(me->lock);
+        }
+
+        deltaTime = computeDeltaTimeMS(&startTime);
+        if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
+            (gIOKitDebug & kIOLogPMRootDomain))
+        {
+            LOG("%s driver %s (0x%llx) took %u ms\n",
+                (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
+                    "PowerOff" : "Restart",
+                service->getName(), service->getRegistryEntryID(),
+                (uint32_t) deltaTime );
+        }
+
+        service->release();
+        me->visits++;
+    }
 }
 
 void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
 {
-       UInt64                  nano;
-       AbsoluteTime    startTime;
-       AbsoluteTime    endTime;
+    UInt64          nano;
+    AbsoluteTime    startTime;
+    AbsoluteTime    endTime;
 
-       endTime = *now;
+    endTime = *now;
 
-       IOLockLock(me->lock);
-       if (me->service && !me->timeout)
-       {
-               startTime = me->startTime;
-               nano = 0;
-           if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
-           {
-                       SUB_ABSOLUTETIME(&endTime, &startTime);
-                       absolutetime_to_nanoseconds(endTime, &nano);
-           }
-               if (nano > 3000000000ULL)
-               {
-                       me->timeout = true;
-                       MSG("%s still waiting on %s\n",
-                               (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
-                                       "PowerOff" : "Restart",
-                               me->service->getName());
-               }
-       }
-       IOLockUnlock(me->lock);
+    IOLockLock(me->lock);
+    if (me->service && !me->timeout)
+    {
+        startTime = me->startTime;
+        nano = 0;
+        if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
+        {
+            SUB_ABSOLUTETIME(&endTime, &startTime);
+            absolutetime_to_nanoseconds(endTime, &nano);
+        }
+        if (nano > 3000000000ULL)
+        {
+            me->timeout = true;
+            MSG("%s still waiting on %s\n",
+                (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
+                    "PowerOff" : "Restart",
+                me->service->getName());
+        }
+    }
+    IOLockUnlock(me->lock);
 }
 
-
 //******************************************************************************
 // acknowledgeSystemWillShutdown
 //
@@ -6342,28 +7986,28 @@ void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
 
 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
 {
-       PMHaltWorker *  worker;
-       OSObject *              prop;
+    PMHaltWorker *  worker;
+    OSObject *      prop;
 
-       if (!from)
-               return;
+    if (!from)
+        return;
 
-       //DLOG("%s acknowledged\n", from->getName());
-       prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
-       if (prop)
-       {
-               worker = (PMHaltWorker *) prop;
-               IOLockLock(worker->lock);
-               from->removeProperty( gPMHaltClientAcknowledgeKey );
-               thread_wakeup((event_t) worker);
-               IOLockUnlock(worker->lock);
-               worker->release();
-       }
-       else
-       {
-               DLOG("%s acknowledged without worker property\n",
-                       from->getName());
-       }
+    //DLOG("%s acknowledged\n", from->getName());
+    prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
+    if (prop)
+    {
+        worker = (PMHaltWorker *) prop;
+        IOLockLock(worker->lock);
+        from->removeProperty( gPMHaltClientAcknowledgeKey );
+        thread_wakeup((event_t) worker);
+        IOLockUnlock(worker->lock);
+        worker->release();
+    }
+    else
+    {
+        DLOG("%s acknowledged without worker property\n",
+            from->getName());
+    }
 }
 
 
@@ -6374,275 +8018,206 @@ void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
 //******************************************************************************
 
 static void
-notifySystemShutdown( IOService * root, unsigned long event )
+notifySystemShutdown( IOService * root, uint32_t messageType )
 {
 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
-       IORegistryIterator *    iter;
-       IORegistryEntry *               entry;
-       IOService *                             node;
-       OSSet *                                 inner;
-       PMHaltWorker *                  workers[kPMHaltMaxWorkers];
-       AbsoluteTime                    deadline;
-       unsigned int                    totalNodes = 0;
-       unsigned int                    depth;
-       unsigned int                    rootDepth;
-       unsigned int                    numWorkers;
-       unsigned int                    count;
-       int                                             waitResult;
-       void *                                  baseFunc;
-       bool                                    ok;
-
-       DLOG("%s event = %lx\n", __FUNCTION__, event);
-
-       baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
-
-       // Iterate the entire PM tree starting from root
-
-       rootDepth = root->getDepth( gIOPowerPlane );
-       if (!rootDepth) goto done;
-
-       // debug - for repeated test runs
-       while (PMHaltWorker::metaClass->getInstanceCount())
-               IOSleep(1);
-
-       if (!gPMHaltArray)
-       {
-               gPMHaltArray = OSArray::withCapacity(40);
-               if (!gPMHaltArray) goto done;
-       }
-       else // debug
-               gPMHaltArray->flushCollection();
+    IORegistryIterator *    iter;
+    IORegistryEntry *       entry;
+    IOService *             node;
+    OSSet *                 inner;
+    PMHaltWorker *          workers[kPMHaltMaxWorkers];
+    AbsoluteTime            deadline;
+    unsigned int            totalNodes = 0;
+    unsigned int            depth;
+    unsigned int            rootDepth;
+    unsigned int            numWorkers;
+    unsigned int            count;
+    int                     waitResult;
+    void *                  baseFunc;
+    bool                    ok;
 
-       if (!gPMHaltLock)
-       {
-               gPMHaltLock = IOLockAlloc();
-               if (!gPMHaltLock) goto done;
-       }
+    DLOG("%s msgType = 0x%x\n", __FUNCTION__, messageType);
 
-       if (!gPMHaltClientAcknowledgeKey)
-       {
-               gPMHaltClientAcknowledgeKey =
-                       OSSymbol::withCStringNoCopy("PMShutdown");
-               if (!gPMHaltClientAcknowledgeKey) goto done;
-       }
+    baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
 
-       gPMHaltEvent = event;
+    // Iterate the entire PM tree starting from root
 
-       // Depth-first walk of PM plane
+    rootDepth = root->getDepth( gIOPowerPlane );
+    if (!rootDepth) goto done;
 
-       iter = IORegistryIterator::iterateOver(
-               root, gIOPowerPlane, kIORegistryIterateRecursively);
+    // debug - for repeated test runs
+    while (PMHaltWorker::metaClass->getInstanceCount())
+        IOSleep(1);
 
-       if (iter)
-       {
-               while ((entry = iter->getNextObject()))
-               {
-                       node = OSDynamicCast(IOService, entry);
-                       if (!node)
-                               continue;
+    if (!gPMHaltArray)
+    {
+        gPMHaltArray = OSArray::withCapacity(40);
+        if (!gPMHaltArray) goto done;
+    }
+    else // debug
+        gPMHaltArray->flushCollection();
 
-                       if (baseFunc == 
-                               OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
-                               continue;
+    if (!gPMHaltLock)
+    {
+        gPMHaltLock = IOLockAlloc();
+        if (!gPMHaltLock) goto done;
+    }
 
-                       depth = node->getDepth( gIOPowerPlane );
-                       if (depth <= rootDepth)
-                               continue;
+    if (!gPMHaltClientAcknowledgeKey)
+    {
+        gPMHaltClientAcknowledgeKey =
+            OSSymbol::withCStringNoCopy("PMShutdown");
+        if (!gPMHaltClientAcknowledgeKey) goto done;
+    }
 
-                       ok = false;
+    gPMHaltMessageType = messageType;
 
-                       // adjust to zero based depth
-                       depth -= (rootDepth + 1);
+    // Depth-first walk of PM plane
 
-                       // gPMHaltArray is an array of containers, each container
-                       // refers to nodes with the same depth.
+    iter = IORegistryIterator::iterateOver(
+        root, gIOPowerPlane, kIORegistryIterateRecursively);
 
-                       count = gPMHaltArray->getCount();
-                       while (depth >= count)
-                       {
-                               // expand array and insert placeholders
-                               gPMHaltArray->setObject(PLACEHOLDER);
-                               count++;
-                       }
-                       count = gPMHaltArray->getCount();
-                       if (depth < count)
-                       {
-                               inner = (OSSet *)gPMHaltArray->getObject(depth);
-                               if (inner == PLACEHOLDER)
-                               {
-                                       inner = OSSet::withCapacity(40);
-                                       if (inner)
-                                       {
-                                               gPMHaltArray->replaceObject(depth, inner);
-                                               inner->release();
-                                       }
-                               }
-
-                               // PM nodes that appear more than once in the tree will have
-                               // the same depth, OSSet will refuse to add the node twice.
-                               if (inner)
-                                       ok = inner->setObject(node);
-                       }
-                       if (!ok)
-                               DLOG("Skipped PM node %s\n", node->getName());
-               }
-               iter->release();
-       }
+    if (iter)
+    {
+        while ((entry = iter->getNextObject()))
+        {
+            node = OSDynamicCast(IOService, entry);
+            if (!node)
+                continue;
 
-       // debug only
-       for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
-       {
-               count = 0;
-               if (inner != PLACEHOLDER)
-                       count = inner->getCount();
-               DLOG("Nodes at depth %u = %u\n", i, count);
-       }
+            if (baseFunc ==
+                OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
+                continue;
 
-       // strip placeholders (not all depths are populated)
-       numWorkers = 0;
-       for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
-       {
-               if (inner == PLACEHOLDER)
-               {
-                       gPMHaltArray->removeObject(i);
-                       continue;
-               }
-               count = inner->getCount();
-               if (count > numWorkers)
-                       numWorkers = count;
-               totalNodes += count;
-               i++;
-       }
+            depth = node->getDepth( gIOPowerPlane );
+            if (depth <= rootDepth)
+                continue;
 
-       if (gPMHaltArray->getCount() == 0 || !numWorkers)
-               goto done;
+            ok = false;
 
-       gPMHaltBusyCount = 0;
-       gPMHaltIdleCount = 0;
-       gPMHaltDepth = gPMHaltArray->getCount() - 1;
+            // adjust to zero based depth
+            depth -= (rootDepth + 1);
 
-       // Create multiple workers (and threads)
+            // gPMHaltArray is an array of containers, each container
+            // refers to nodes with the same depth.
 
-       if (numWorkers > kPMHaltMaxWorkers)
-               numWorkers = kPMHaltMaxWorkers;
+            count = gPMHaltArray->getCount();
+            while (depth >= count)
+            {
+                // expand array and insert placeholders
+                gPMHaltArray->setObject(PLACEHOLDER);
+                count++;
+            }
+            count = gPMHaltArray->getCount();
+            if (depth < count)
+            {
+                inner = (OSSet *)gPMHaltArray->getObject(depth);
+                if (inner == PLACEHOLDER)
+                {
+                    inner = OSSet::withCapacity(40);
+                    if (inner)
+                    {
+                        gPMHaltArray->replaceObject(depth, inner);
+                        inner->release();
+                    }
+                }
 
-       DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
-               totalNodes, gPMHaltArray->getCount(), numWorkers);
+                // PM nodes that appear more than once in the tree will have
+                // the same depth, OSSet will refuse to add the node twice.
+                if (inner)
+                    ok = inner->setObject(node);
+            }
+            if (!ok)
+                DLOG("Skipped PM node %s\n", node->getName());
+        }
+        iter->release();
+    }
 
-       for (unsigned int i = 0; i < numWorkers; i++)
-               workers[i] = PMHaltWorker::worker();
+    // debug only
+    for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
+    {
+        count = 0;
+        if (inner != PLACEHOLDER)
+            count = inner->getCount();
+        DLOG("Nodes at depth %u = %u\n", i, count);
+    }
 
-       // Wait for workers to exhaust all available work
+    // strip placeholders (not all depths are populated)
+    numWorkers = 0;
+    for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
+    {
+        if (inner == PLACEHOLDER)
+        {
+            gPMHaltArray->removeObject(i);
+            continue;
+        }
+        count = inner->getCount();
+        if (count > numWorkers)
+            numWorkers = count;
+        totalNodes += count;
+        i++;
+    }
 
-       IOLockLock(gPMHaltLock);
-       while (gPMHaltDepth >= 0)
-       {
-               clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
+    if (gPMHaltArray->getCount() == 0 || !numWorkers)
+        goto done;
 
-               waitResult = IOLockSleepDeadline(
-                       gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
-               if (THREAD_TIMED_OUT == waitResult)
-               {
-                       AbsoluteTime now;
-                       clock_get_uptime(&now);
+    gPMHaltBusyCount = 0;
+    gPMHaltIdleCount = 0;
+    gPMHaltDepth = gPMHaltArray->getCount() - 1;
 
-                       IOLockUnlock(gPMHaltLock);
-                       for (unsigned int i = 0 ; i < numWorkers; i++)
-                       {
-                               if (workers[i])
-                                       PMHaltWorker::checkTimeout(workers[i], &now);
-                       }
-                       IOLockLock(gPMHaltLock);
-               }
-       }
-       IOLockUnlock(gPMHaltLock);
+    // Create multiple workers (and threads)
 
-       // Release all workers
+    if (numWorkers > kPMHaltMaxWorkers)
+        numWorkers = kPMHaltMaxWorkers;
 
-       for (unsigned int i = 0; i < numWorkers; i++)
-       {
-               if (workers[i])
-                       workers[i]->release();
-               // worker also retained by it's own thread
-       }
+    DLOG("PM nodes %u, maxDepth %u, workers %u\n",
+        totalNodes, gPMHaltArray->getCount(), numWorkers);
 
-done:
-       DLOG("%s done\n", __FUNCTION__);
-       return;
-}
+    for (unsigned int i = 0; i < numWorkers; i++)
+        workers[i] = PMHaltWorker::worker();
 
-//*********************************************************************************
-// Sleep/Wake logging
-//
-//*********************************************************************************
+    // Wait for workers to exhaust all available work
 
-IOMemoryDescriptor *IOPMrootDomain::getPMTraceMemoryDescriptor(void)
-{
-    if (timeline)
-        return timeline->getPMTraceMemoryDescriptor();
-    else
-        return NULL;
-}
+    IOLockLock(gPMHaltLock);
+    while (gPMHaltDepth >= 0)
+    {
+        clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
 
-// Forwards external reports of detailed events to IOPMTimeline
-IOReturn IOPMrootDomain::recordPMEvent(PMEventDetails *details)
-{
-    if (timeline && details) {
-        
-                 IOReturn rc;
-               
-                 // Record a detailed driver power change event, or... 
-                 if(details->eventClassifier == kIOPMEventClassDriverEvent) {
-                         rc = timeline->recordDetailedPowerEvent( details );
-                 }
-               
-                 // Record a system power management event
-                 else if(details->eventClassifier == kIOPMEventClassSystemEvent) {
-                         rc = timeline->recordSystemPowerEvent( details );
-                 }
-                 else {
-                         return kIOReturnBadArgument;
-                 }
-      
-      // If we get to record this message, then we've reached the 
-      // end of another successful Sleep --> Wake cycle
-      // At this point, we pat ourselves in the back and allow
-      // our Sleep --> Wake UUID to be published
-      if(details->eventType == kIOPMEventTypeWakeDone) {
-        timeline->setSleepCycleInProgressFlag(false);
-      }
+        waitResult = IOLockSleepDeadline(
+            gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
+        if (THREAD_TIMED_OUT == waitResult)
+        {
+            AbsoluteTime now;
+            clock_get_uptime(&now);
 
-/*
-      // Check if its time to clear the timeline buffer
-      if(getProperty(kIOPMSleepWakeUUIDKey) 
-         && timeline->isSleepCycleInProgress() == false
-         && timeline->getNumEventsLoggedThisPeriod() > 500) {
-            
-        // Clear the old UUID
-        if(pmPowerStateQueue) {
-            pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
+            IOLockUnlock(gPMHaltLock);
+            for (unsigned int i = 0 ; i < numWorkers; i++)
+            {
+                if (workers[i])
+                    PMHaltWorker::checkTimeout(workers[i], &now);
+            }
+            IOLockLock(gPMHaltLock);
         }
-      }
-*/
-      return rc;
     }
-    else
-        return kIOReturnNotReady;
-}
+    IOLockUnlock(gPMHaltLock);
 
-IOReturn IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails *details)
-{
-    IOReturn ret = kIOReturnBadArgument;
+    // Release all workers
 
-    if (details)
+    for (unsigned int i = 0; i < numWorkers; i++)
     {
-        ret = recordPMEvent(details);
-        details->release();
+        if (workers[i])
+            workers[i]->release();
+        // worker also retained by it's own thread
     }
 
-    return ret;
+done:
+    DLOG("%s done\n", __FUNCTION__);
+    return;
 }
 
+// MARK: -
+// MARK: Kernel Assertion
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
@@ -6653,10 +8228,10 @@ IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
 {
     IOReturn            ret;
     IOPMDriverAssertionID     newAssertion;
+
     if (!pmAssertions)
         return 0;
+
     ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
 
     if (kIOReturnSuccess == ret)
@@ -6669,12 +8244,13 @@ IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAsserti
 {
     if (!pmAssertions)
         return kIOReturnInternalError;
-    
+
     return pmAssertions->releaseAssertion(releaseAssertion);
 }
 
+
 IOReturn IOPMrootDomain::setPMAssertionLevel(
-    IOPMDriverAssertionID assertionID, 
+    IOPMDriverAssertionID assertionID,
     IOPMDriverAssertionLevel assertionLevel)
 {
     return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
@@ -6684,11 +8260,11 @@ IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertion
 {
     IOPMDriverAssertionType       sysLevels;
 
-    if (!pmAssertions || whichAssertion == 0) 
+    if (!pmAssertions || whichAssertion == 0)
         return kIOPMDriverAssertionLevelOff;
 
     sysLevels = pmAssertions->getActivatedAssertions();
-    
+
     // Check that every bit set in argument 'whichAssertion' is asserted
     // in the aggregate bits.
     if ((sysLevels & whichAssertion) == whichAssertion)
@@ -6714,6 +8290,203 @@ bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
     return( IOService::serializeProperties(s) );
 }
 
+OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
+{
+    OSObject *obj = NULL;
+    obj = IOService::copyProperty(aKey);
+
+    if (obj)  return obj;
+
+    if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey,
+                        sizeof(kIOPMSleepWakeWdogRebootKey))) {
+        if (swd_flags & SWD_BOOT_BY_SW_WDOG)
+            return kOSBooleanTrue;
+        else
+            return kOSBooleanFalse;
+
+    }
+
+    if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey,
+                        sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
+        if (swd_flags & SWD_VALID_LOGS)
+            return kOSBooleanTrue;
+        else
+            return kOSBooleanFalse;
+
+    }
+
+    /*
+     * XXX: We should get rid of "DesktopMode" property  when 'kAppleClamshellCausesSleepKey'
+     * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
+     * issued by DisplayWrangler on darkwake.
+     */
+    if (!strcmp(aKey, "DesktopMode")) {
+        if (desktopMode)
+            return kOSBooleanTrue;
+        else
+            return kOSBooleanFalse;
+    }
+    if (!strcmp(aKey, "DisplayIdleForDemandSleep")) {
+        if (displayIdleForDemandSleep) {
+            return kOSBooleanTrue;
+        }
+        else  {
+            return kOSBooleanFalse;
+        }
+    }
+
+    if (!strcmp(aKey, kIOPMDriverWakeEventsKey))
+    {
+        OSArray * array = 0;
+        WAKEEVENT_LOCK();
+        if (_systemWakeEventsArray && _systemWakeEventsArray->getCount()) {
+            OSCollection *collection = _systemWakeEventsArray->copyCollection();
+            if (collection && !(array = OSDynamicCast(OSArray, collection))) {
+                collection->release();
+            }
+        }
+        WAKEEVENT_UNLOCK();
+        return array;
+    }
+
+    if (!strcmp(aKey, kIOPMSleepStatisticsAppsKey))
+    {
+        OSArray * array = 0;
+        IOLockLock(pmStatsLock);
+        if (pmStatsAppResponses && pmStatsAppResponses->getCount()) {
+            OSCollection *collection = pmStatsAppResponses->copyCollection();
+            if (collection && !(array = OSDynamicCast(OSArray, collection))) {
+                collection->release();
+            }
+            pmStatsAppResponses->flushCollection();
+        }
+        IOLockUnlock(pmStatsLock);
+        return array;
+    }
+
+    if (!strcmp(aKey, kIOPMIdleSleepPreventersKey))
+    {
+        OSArray *idleSleepList = NULL;
+        gRootDomain->copySleepPreventersList(&idleSleepList, NULL);
+        return idleSleepList;
+    }
+
+    if (!strcmp(aKey, kIOPMSystemSleepPreventersKey))
+    {
+        OSArray *systemSleepList = NULL;
+        gRootDomain->copySleepPreventersList(NULL, &systemSleepList);
+        return systemSleepList;
+    }
+
+    return NULL;
+}
+
+// MARK: -
+// MARK: Wake Event Reporting
+
+void IOPMrootDomain::copyWakeReasonString( char * outBuf, size_t bufSize )
+{
+    WAKEEVENT_LOCK();
+    strlcpy(outBuf, gWakeReasonString, bufSize);
+    WAKEEVENT_UNLOCK();
+}
+
+//******************************************************************************
+// acceptSystemWakeEvents
+//
+// Private control for the acceptance of driver wake event claims.
+//******************************************************************************
+
+void IOPMrootDomain::acceptSystemWakeEvents( bool accept )
+{
+    bool logWakeReason = false;
+
+    WAKEEVENT_LOCK();
+    if (accept)
+    {
+        gWakeReasonString[0] = '\0';
+        if (!_systemWakeEventsArray)
+            _systemWakeEventsArray = OSArray::withCapacity(4);
+        if ((_acceptSystemWakeEvents = (_systemWakeEventsArray != 0)))
+            _systemWakeEventsArray->flushCollection();
+    }
+    else
+    {
+        _acceptSystemWakeEvents = false;
+    }
+    WAKEEVENT_UNLOCK();
+
+    if (logWakeReason)
+        MSG("system wake events:%s\n", gWakeReasonString);
+}
+
+//******************************************************************************
+// claimSystemWakeEvent
+//
+// For a driver to claim a device is the source/conduit of a system wake event.
+//******************************************************************************
+
+void IOPMrootDomain::claimSystemWakeEvent(
+    IOService *     device,
+    IOOptionBits    flags,
+    const char *    reason,
+    OSObject *      details )
+{
+    const OSSymbol *    deviceName   = 0;
+    OSNumber *          deviceRegId  = 0;
+    OSNumber *          claimTime    = 0;
+    OSData *            flagsData    = 0;
+    OSString *          reasonString = 0;
+    OSDictionary *      d = 0;
+    uint64_t            timestamp;
+    bool                ok = false;
+
+    pmEventTimeStamp(&timestamp);
+
+    if (!device || !reason) return;
+
+    deviceName   = device->copyName(gIOServicePlane);
+    deviceRegId  = OSNumber::withNumber(device->getRegistryEntryID(), 64);
+    claimTime    = OSNumber::withNumber(timestamp, 64);
+    flagsData    = OSData::withBytes(&flags, sizeof(flags));
+    reasonString = OSString::withCString(reason);
+    d = OSDictionary::withCapacity(5 + (details ? 1 : 0));
+    if (!deviceName || !deviceRegId || !claimTime || !flagsData || !reasonString)
+        goto done;
+
+    d->setObject(gIONameKey, deviceName);
+    d->setObject(gIORegistryEntryIDKey, deviceRegId);
+    d->setObject(kIOPMWakeEventTimeKey, claimTime);
+    d->setObject(kIOPMWakeEventFlagsKey, flagsData);
+    d->setObject(kIOPMWakeEventReasonKey, reasonString);
+    if (details)
+        d->setObject(kIOPMWakeEventDetailsKey, details);
+
+    WAKEEVENT_LOCK();
+    if (!gWakeReasonSysctlRegistered)
+    {
+        // Lazy registration until the platform driver stops registering
+        // the same name.
+        gWakeReasonSysctlRegistered = true;
+    }
+    if (_acceptSystemWakeEvents)
+    {
+        ok = _systemWakeEventsArray->setObject(d);
+        if (gWakeReasonString[0] != '\0')
+            strlcat(gWakeReasonString, " ", sizeof(gWakeReasonString));
+        strlcat(gWakeReasonString, reason, sizeof(gWakeReasonString));
+    }
+    WAKEEVENT_UNLOCK();
+
+done:
+    if (deviceName)   deviceName->release();
+    if (deviceRegId)  deviceRegId->release();
+    if (claimTime)    claimTime->release();
+    if (flagsData)    flagsData->release();
+    if (reasonString) reasonString->release();
+    if (d) d->release();
+}
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 // MARK: -
@@ -6740,7 +8513,7 @@ void PMSettingHandle::free( void )
 #define super OSObject
 OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
 
-/* 
+/*
  * Static constructor/initializer for PMSettingObject
  */
 PMSettingObject *PMSettingObject::pmSettingObject(
@@ -6790,7 +8563,7 @@ PMSettingObject *PMSettingObject::pmSettingObject(
         for (unsigned int i=0; i<settingCount; i++) {
             // Since there is now at least one listener to this setting, publish
             // PM root domain support for it.
-            parent_arg->publishFeature( settings[i]->getCStringNoCopy(),
+            parent_arg->publishPMSetting( settings[i],
                     supportedPowerSources, &pmso->publishedFeatureID[i] );
         }
     }
@@ -6821,373 +8594,12 @@ void PMSettingObject::free( void )
 
 void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
 {
-    (*func)(target, type, object, refcon);
-}
-
-void PMSettingObject::clientHandleFreed( void )
-{
-    parent->deregisterPMSettingObject(this);
-}
-
-// MARK: -
-// MARK: IOPMTimeline
-
-#undef super
-#define super OSObject
-
-//*********************************************************************************
-//*********************************************************************************
-//*********************************************************************************
-
-IOPMTimeline *IOPMTimeline::timeline(IOPMrootDomain *root_domain)
-{
-    IOPMTimeline    *myself;
-    
-    if (!root_domain)
-        return NULL;
-    
-    myself = new IOPMTimeline;
-    if (myself) {
-        myself->owner = root_domain;
-        myself->init();
-    }
-    return myself;
-}
-
-bool IOPMTimeline::init(void)
-{
-    if (!super::init()) {
-        return false;
-    }
-
-    logLock = IOLockAlloc();
-    
-    // Fresh timeline, no events logged yet
-    this->numEventsLoggedThisPeriod = 0;
-    this->sleepCycleInProgress = false;
-
-    //this->setEventsRecordingLevel(1);   // TODO
-    this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked);
-
-    return true;
-}
-
-void IOPMTimeline::free(void)
-{
-    if (pmTraceMemoryDescriptor) {
-        pmTraceMemoryDescriptor->release();
-        pmTraceMemoryDescriptor = NULL;
-    }
-    
-    IOLockFree(logLock);
-
-    super::free();
-}
-
-IOMemoryDescriptor *IOPMTimeline::getPMTraceMemoryDescriptor()
-{
-    return pmTraceMemoryDescriptor;
-}
-
-//*********************************************************************************
-//*********************************************************************************
-//*********************************************************************************
-
-bool IOPMTimeline::setProperties(OSDictionary *d)
-{
-    OSNumber    *n = NULL;
-    OSBoolean   *b = NULL;
-    bool        changed = false;
-
-    /* Changes size of detailed events buffer */
-    n = (OSNumber *)d->getObject(kIOPMTimelineSystemNumberTrackedKey);
-    if (OSDynamicCast(OSNumber, n))
-    {
-        changed = true;
-        this->setEventsTrackedCount(n->unsigned32BitValue());        
-    }
-
-
-    /* enables or disables system events */
-    b = (OSBoolean *)d->getObject(kIOPMTimelineEnabledKey);
-    if (b)
-    {
-        changed = true;
-        this->setEventsRecordingLevel((int)(kOSBooleanTrue == b));        
-    }
-
-    return changed;
-}
-
-//*********************************************************************************
-//*********************************************************************************
-//*********************************************************************************
-
-OSDictionary *IOPMTimeline::copyInfoDictionary(void)
-{
-    OSDictionary *out = OSDictionary::withCapacity(3);
-    OSNumber    *n = NULL;
-
-    if (!out || !hdr)
-        return NULL;
-
-    n = OSNumber::withNumber(hdr->sizeEntries, 32);
-    out->setObject(kIOPMTimelineSystemNumberTrackedKey, n);
-    n->release();
-    
-    n = OSNumber::withNumber(hdr->sizeBytes, 32);
-    out->setObject(kIOPMTimelineSystemBufferSizeKey, n);
-    n->release();
-
-    // bool
-    out->setObject(kIOPMTimelineEnabledKey, eventsRecordingLevel ? kOSBooleanTrue : kOSBooleanFalse);
-
-    return out;
-}
-
-//*********************************************************************************
-//*********************************************************************************
-//*********************************************************************************
-
-/* IOPMTimeline::recordSystemPowerEvent()
- *
- * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
- * Type arguments include "system events", and "Intermediate events"
- *
- * - System Events have paired "start" and "stop" events.
- * - A start event shall be followed by a stop event.
- * - Any number of Intermediate Events may fall between the 
- *   start and stop events.
- * - Intermediate events are meaningless outside the bounds of a system event's
- *   start & stoup routines.
- * - It's invalid to record a Start event without a following Stop event; e.g. two
- *   Start events without an intervenining Stop event is invalid.
- *
- * Buffer invariants
- * - The first recorded system event shall be preceded by an entry with type == 0
- * - IOPMTimeline may choose not to record intermediate events while there's not
- *   a system event in process.
- */
-IOReturn IOPMTimeline::recordSystemPowerEvent( PMEventDetails *details )
-{
-    static bool                 wakeDonePending = true;
-    IOPMSystemEventRecord       *record_to = NULL;
-    OSString                    *swUUIDKey = NULL;
-    uint32_t                    useIndex = 0;
-
-    if (!details)
-        return kIOReturnBadArgument;
-
-    if (!traceBuffer) 
-        return kIOReturnNotReady;
-    
-    if (details->eventType == kIOPMEventTypeWakeDone)
-    {
-      if(!wakeDonePending)  
-        return kIOReturnBadArgument;
-    }
-
-    IOLockLock(logLock);
-    
-    if (details->eventType == kIOPMEventTypeWake) {
-        wakeDonePending = true;
-    } else if (details->eventType == kIOPMEventTypeWakeDone) {
-        wakeDonePending = false;
-    }
-
-    systemState = details->eventType;
-   
-    useIndex = _atomicIndexIncrement(&hdr->index, hdr->sizeEntries);
-    
-    // The entry immediately after the latest entry (and thus
-    //  immediately before the first entry) shall have a type 0.
-    if (useIndex + 1 >= hdr->sizeEntries) {
-        traceBuffer[useIndex + 1].eventType = 0;
-    } else {
-        traceBuffer[0].eventType = 0;
-    }
-    
-    record_to = &traceBuffer[useIndex];
-    bzero(record_to, sizeof(IOPMSystemEventRecord));
-
-    /*****/
-    record_to->eventType    = details->eventType;
-    record_to->eventReason  = details->reason;
-    record_to->eventResult  = details->result;
-    pmEventTimeStamp(&record_to->timestamp);
-
-    // If caller doesn't provide a UUID, we'll use the UUID that's posted
-    // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
-    if (!details->uuid)  {
-        swUUIDKey = OSDynamicCast(OSString, owner->copyProperty(kIOPMSleepWakeUUIDKey));
-
-        if (swUUIDKey)
-            details->uuid = swUUIDKey->getCStringNoCopy();
-    }
-
-    if (details->uuid)
-        strncpy(record_to->uuid, details->uuid, kMaxPMStringLength);
-
-    if (swUUIDKey) 
-        swUUIDKey->release();
-
-    numEventsLoggedThisPeriod++;
-    /*****/
-
-    IOLockUnlock(logLock);
-    
-    return kIOReturnSuccess;
-
-}
-
-//*********************************************************************************
-//*********************************************************************************
-//*********************************************************************************
-
-IOReturn IOPMTimeline::recordDetailedPowerEvent( PMEventDetails *details )
-{
-    IOPMSystemEventRecord *record_to = NULL;
-    uint32_t                useIndex;
-
-    if (!details->eventType || !details->ownerName) 
-        return kIOReturnBadArgument;
-        
-    IOLockLock(logLock);
-
-    useIndex = _atomicIndexIncrement(&hdr->index, hdr->sizeEntries);
-    
-    record_to = (IOPMSystemEventRecord *)&traceBuffer[useIndex];
-    bzero(record_to, sizeof(IOPMSystemEventRecord));
-
-    /*****/
-    record_to->eventType = details->eventType;
-    if (details->ownerName && (strlen(details->ownerName) > 1)) {
-        strlcpy( record_to->ownerName, 
-                 details->ownerName, 
-                 sizeof(record_to->ownerName));
-    }
-    
-    record_to->ownerDisambiguateID = details->ownerUnique;
-    
-    if (details->interestName && (strlen(details->interestName) > 1)) {
-        strlcpy(record_to->interestName, 
-                details->interestName, 
-                sizeof(record_to->interestName));
-    }
-
-    record_to->oldState      = details->oldState;
-    record_to->newState      = details->newState;
-    record_to->eventResult   = details->result;
-    record_to->elapsedTimeUS = details->elapsedTimeUS;
-    pmEventTimeStamp(&record_to->timestamp);
-
-    numEventsLoggedThisPeriod++;
-    /*****/
-
-    IOLockUnlock(logLock);
-    return kIOReturnSuccess;
-}
-
-uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
-  return this->numEventsLoggedThisPeriod;
-}
-
-void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount) {
-  this->numEventsLoggedThisPeriod = newCount;
-}
-
-bool IOPMTimeline::isSleepCycleInProgress() {
-  return this->sleepCycleInProgress;
-}
-
-void IOPMTimeline::setSleepCycleInProgressFlag(bool flag) {
-  this->sleepCycleInProgress = flag;
-}
-//*********************************************************************************
-//*********************************************************************************
-//*********************************************************************************
-    
-void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked)
-{
-    size_t      make_buf_size = 0;
-    
-    make_buf_size = sizeof(IOPMTraceBufferHeader) + (newTracked * sizeof(IOPMSystemEventRecord));
-
-    IOLockLock(logLock);
-
-    if (pmTraceMemoryDescriptor) {
-        pmTraceMemoryDescriptor->release();
-        pmTraceMemoryDescriptor = NULL;
-    }
-
-    hdr = NULL;
-    traceBuffer = NULL;
-
-    if (0 == newTracked)
-    {
-        IOLog("IOPMrootDomain -> erased buffer.\n");
-        goto exit;
-    }
-
-    pmTraceMemoryDescriptor = IOBufferMemoryDescriptor::withOptions(
-                    kIOMemoryKernelUserShared | kIODirectionIn, make_buf_size);
-
-    if (!pmTraceMemoryDescriptor)
-    {
-        IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size);
-        goto exit;
-    }    
-
-    pmTraceMemoryDescriptor->prepare(kIODirectionIn);
-    
-    // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
-    hdr = (IOPMTraceBufferHeader *)pmTraceMemoryDescriptor->getBytesNoCopy();
-
-    // Recorded events occupy the remaining bulk of the buffer
-    traceBuffer = (IOPMSystemEventRecord *)((uint8_t *)hdr + sizeof(IOPMTraceBufferHeader));
-
-    bzero(hdr, make_buf_size);
-
-    hdr->sizeBytes = make_buf_size;
-    hdr->sizeEntries = newTracked;
-
-    IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size, (unsigned int)(uintptr_t)traceBuffer);
-
-exit:
-    IOLockUnlock(logLock);
-}
-
-//*********************************************************************************
-//*********************************************************************************
-//*********************************************************************************
-
-void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits)
-{
-
-    // TODO
-
-    return;
-
-}
-
-/* static helper to IOPMTimeline 
- */
-uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index, uint32_t limit)
-{
-    uint32_t    was_index;
-    uint32_t    inc_index;
-    
-    if(!index)
-        return NULL;
-    
-    do {
-        was_index = *index;
-        inc_index = (was_index+1)%limit;
-    } while (!OSCompareAndSwap(was_index, inc_index, index));
+    (*func)(target, type, object, refcon);
+}
 
-    return inc_index;
+void PMSettingObject::clientHandleFreed( void )
+{
+    parent->deregisterPMSettingObject(this);
 }
 
 // MARK: -
@@ -7203,20 +8615,20 @@ uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index, uint32_t limit)
 PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
 {
     PMAssertionsTracker    *myself;
-    
+
     myself = new PMAssertionsTracker;
+
     if (myself) {
         myself->init();
         myself->owner = rootDomain;
-        myself->issuingUniqueID = kAssertUniqueIDStart; 
+        myself->issuingUniqueID = kAssertUniqueIDStart;
         myself->assertionsArray = OSArray::withCapacity(5);
         myself->assertionsKernel = 0;
         myself->assertionsUser = 0;
         myself->assertionsCombined = 0;
         myself->assertionsArrayLock = IOLockAlloc();
         myself->tabulateProducerCount = myself->tabulateConsumerCount = 0;
-    
+
         if (!myself->assertionsArray || !myself->assertionsArrayLock)
             myself = NULL;
     }
@@ -7266,19 +8678,8 @@ void PMAssertionsTracker::tabulate(void)
 
     if ((assertionsKernel != oldKernel) ||
         (assertionsCombined != oldCombined))
-    {    
-        owner->messageClients(kIOPMMessageDriverAssertionsChanged);        
-        
-        if (((assertionsCombined & kIOPMDriverAssertionPreventDisplaySleepBit) != 0) 
-                && ((oldCombined & kIOPMDriverAssertionPreventDisplaySleepBit) == 0))
-        {
-            /* We react to a new PreventDisplaySleep assertion by waking the display
-             * with an activityTickle
-             */
-            owner->evaluatePolicy(kStimulusDarkWakeActivityTickle);
-        } else {
-            owner->evaluatePolicy(kStimulusDarkWakeEvaluate);
-        }
+    {
+        owner->evaluateAssertions(assertionsCombined, oldCombined);
     }
 }
 
@@ -7367,14 +8768,14 @@ IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
 }
 
 /* PMAssertionsTracker::createAssertion
- * createAssertion allocates memory for a new PM assertion, and affects system behavior, if 
+ * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
  * appropiate.
  */
 IOReturn PMAssertionsTracker::createAssertion(
     IOPMDriverAssertionType which,
     IOPMDriverAssertionLevel level,
-    IOService *serviceID, 
-    const char *whoItIs, 
+    IOService *serviceID,
+    const char *whoItIs,
     IOPMDriverAssertionID *outID)
 {
     OSData          *dataStore = NULL;
@@ -7384,11 +8785,12 @@ IOReturn PMAssertionsTracker::createAssertion(
     track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
     track.level = level;
     track.assertionBits = which;
-    track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs) : 0;
+    track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs):0;
     track.ownerService = serviceID;
+    track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0;
     track.modifiedTime = 0;
     pmEventTimeStamp(&track.createdTime);
-    
+
     dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
     if (!dataStore)
     {
@@ -7398,11 +8800,11 @@ IOReturn PMAssertionsTracker::createAssertion(
     }
 
     *outID = track.id;
-    
+
     if (owner && owner->pmPowerStateQueue) {
         owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
     }
-    
+
     return kIOReturnSuccess;
 }
 
@@ -7416,17 +8818,17 @@ IOReturn PMAssertionsTracker::handleReleaseAssertion(
 
     int             index;
     PMAssertStruct  *assertStruct = detailsForID(_id, &index);
-    
+
     if (!assertStruct)
         return kIOReturnNotFound;
 
     IOLockLock(assertionsArrayLock);
-    if (assertStruct->ownerString) 
+    if (assertStruct->ownerString)
         assertStruct->ownerString->release();
 
     assertionsArray->removeObject(index);
     IOLockUnlock(assertionsArrayLock);
-    
+
     tabulate();
     return kIOReturnSuccess;
 }
@@ -7448,7 +8850,7 @@ IOReturn PMAssertionsTracker::releaseAssertion(
  * Runs in PM workloop. Do not call directly.
  */
 IOReturn PMAssertionsTracker::handleSetAssertionLevel(
-    IOPMDriverAssertionID    _id, 
+    IOPMDriverAssertionID    _id,
     IOPMDriverAssertionLevel _level)
 {
     PMAssertStruct      *assertStruct = detailsForID(_id, NULL);
@@ -7471,15 +8873,15 @@ IOReturn PMAssertionsTracker::handleSetAssertionLevel(
 /* PMAssertionsTracker::setAssertionLevel
  */
 IOReturn PMAssertionsTracker::setAssertionLevel(
-    IOPMDriverAssertionID    _id, 
+    IOPMDriverAssertionID    _id,
     IOPMDriverAssertionLevel _level)
 {
     if (owner && owner->pmPowerStateQueue) {
         owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
-                (void *)_level, _id);
+                (void *)(uintptr_t)_level, _id);
     }
 
-    return kIOReturnSuccess;    
+    return kIOReturnSuccess;
 }
 
 IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
@@ -7545,38 +8947,38 @@ OSArray *PMAssertionsTracker::copyAssertionsArray(void)
 
             outArray->setObject(details);
             details->release();
-            
+
             _n = OSNumber::withNumber(_a->id, 64);
-            if (_n) {            
+            if (_n) {
                 details->setObject(kIOPMDriverAssertionIDKey, _n);
                 _n->release();
             }
             _n = OSNumber::withNumber(_a->createdTime, 64);
-            if (_n) {            
+            if (_n) {
                 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
                 _n->release();
             }
             _n = OSNumber::withNumber(_a->modifiedTime, 64);
-            if (_n) {            
+            if (_n) {
                 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
                 _n->release();
             }
-            _n = OSNumber::withNumber((uintptr_t)_a->ownerService, 64);
-            if (_n) {            
-                details->setObject(kIOPMDriverAssertionOwnerServiceKey, _n);
+            _n = OSNumber::withNumber((uintptr_t)_a->registryEntryID, 64);
+            if (_n) {
+                details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, _n);
                 _n->release();
             }
             _n = OSNumber::withNumber(_a->level, 64);
-            if (_n) {            
+            if (_n) {
                 details->setObject(kIOPMDriverAssertionLevelKey, _n);
                 _n->release();
             }
             _n = OSNumber::withNumber(_a->assertionBits, 64);
-            if (_n) {            
+            if (_n) {
                 details->setObject(kIOPMDriverAssertionAssertedKey, _n);
                 _n->release();
             }
-            
+
             if (_a->ownerString) {
                 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
             }
@@ -7615,7 +9017,7 @@ static void pmEventTimeStamp(uint64_t *recordTS)
 
     if (!recordTS)
         return;
-    
+
     // We assume tsec fits into 32 bits; 32 bits holds enough
     // seconds for 136 years since the epoch in 1970.
     clock_get_calendar_microtime(&tsec, &tusec);
@@ -7693,3 +9095,906 @@ OSObject * IORootParent::copyProperty( const char * aKey) const
     return (IOService::copyProperty(aKey));
 }
 
+
+#if defined(__i386__) || defined(__x86_64__)
+IOReturn IOPMrootDomain::restartWithStackshot()
+{
+    if ((swd_flags & SWD_WDOG_ENABLED) == 0)
+        return kIOReturnError;
+
+    takeStackshot(true, true, false);
+
+    return kIOReturnSuccess;
+}
+
+void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
+{
+    takeStackshot(wdogTrigger, false, false);
+}
+
+void IOPMrootDomain::takeStackshot(bool wdogTrigger, bool isOSXWatchdog, bool isSpinDump)
+{
+   swd_hdr *         hdr = NULL;
+   addr64_t          data[3];
+   uint32_t          wdog_panic = 0;
+   int               cnt = 0;
+   pid_t             pid = 0;
+   uint32_t          flags;
+
+   char *            dstAddr;
+   uint32_t          size;
+   uint32_t          bytesRemaining;
+   unsigned int      len;
+   OSString *        UUIDstring = NULL;
+   uint64_t          code;
+   IOMemoryMap *     logBufMap = NULL;
+
+   swd_stackshot_hdr *stackshotHdr = NULL;
+
+   uint32_t          bufSize;
+   uint32_t          initialStackSize;
+
+   if (isSpinDump) {
+       if (_systemTransitionType != kSystemTransitionSleep &&
+           _systemTransitionType != kSystemTransitionWake)
+           return;
+   } else {
+       if ( kIOSleepWakeWdogOff & gIOKitDebug )
+           return;
+   }
+
+   if (wdogTrigger) {
+       if (PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic)) &&
+                  (wdog_panic == 1)) {
+           // If boot-arg is set to panic on sleep/wake hang, call panic
+           panic("Sleep/Wake hang detected\n");
+           return;
+       }
+       else if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
+           // If current boot is due to this watch dog trigger restart in previous boot,
+           // then don't trigger again until at least 1 successful sleep & wake.
+           if (!(sleepCnt && (displayWakeCnt || darkWakeCnt))) {
+               IOLog("Shutting down due to repeated Sleep/Wake failures\n");
+               PEHaltRestart(kPEHaltCPU);
+               return;
+           }
+       }
+
+   }
+
+   if (isSpinDump) {
+      if (gSpinDumpBufferFull)
+         return;
+      if (swd_spindump_buffer == NULL) {
+         sleepWakeDebugSpinDumpMemAlloc();
+         if (swd_spindump_buffer == NULL) return;
+      }
+
+      bufSize = SWD_SPINDUMP_SIZE;
+      initialStackSize = SWD_INITIAL_SPINDUMP_SIZE;
+   } else {
+      if (sleepWakeDebugIsWdogEnabled() == false)
+         return;
+
+      if (swd_buffer == NULL) {
+         sleepWakeDebugMemAlloc();
+         if (swd_buffer == NULL) return;
+      }
+
+      bufSize = SWD_BUF_SIZE;
+      initialStackSize = SWD_INITIAL_STACK_SIZE;
+   }
+
+   if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
+       return;
+
+   if (isSpinDump)
+      hdr = (swd_hdr *)swd_spindump_buffer;
+   else
+      hdr = (swd_hdr *)swd_buffer;
+   memset(hdr->UUID, 0x20, sizeof(hdr->UUID));
+   if ((UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))) != NULL ) {
+
+      if (wdogTrigger || (!UUIDstring->isEqualTo(hdr->UUID))) {
+         const char *str = UUIDstring->getCStringNoCopy();
+         snprintf(hdr->UUID, sizeof(hdr->UUID), "UUID: %s", str);
+      }
+      else {
+         DLOG("Data for current UUID already exists\n");
+         goto exit;
+      }
+   }
+
+   dstAddr = (char*)hdr + hdr->spindump_offset;
+   bytesRemaining = bufSize - hdr->spindump_offset;
+
+   /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
+   hdr->is_osx_watchdog = isOSXWatchdog;
+
+   DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining);
+
+   while (bytesRemaining > sizeof(swd_stackshot_hdr)) {
+
+       stackshotHdr = (swd_stackshot_hdr *)dstAddr;
+       stackshotHdr->magic = SWD_STACKSHOTHDR_MAGIC;
+       stackshotHdr->size = 0;
+       bytesRemaining -= sizeof(swd_stackshot_hdr);
+       dstAddr += sizeof(swd_stackshot_hdr);
+
+       if (isOSXWatchdog) {
+           pid = -1;
+           size = bytesRemaining;
+           flags = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO;
+       }
+       else if (cnt == 0) {
+           /* 
+            * Take stackshot of all process on first sample. Size is restricted
+            * to SWD_INITIAL_STACK_SIZE
+            */
+           pid = -1;
+           size = (bytesRemaining > initialStackSize) ? initialStackSize : bytesRemaining;
+           flags = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY;
+       }
+       else {
+           /* Take sample of kernel threads only */
+           pid = 0;
+           size = bytesRemaining;
+           flags = 0;
+       }
+
+       stack_snapshot_from_kernel(pid, dstAddr, size, flags, &stackshotHdr->size);
+
+       dstAddr += stackshotHdr->size;
+       bytesRemaining -= stackshotHdr->size;
+
+       DLOG("Sample: %d size: %d bytesRemaining: %d\n", cnt, stackshotHdr->size, bytesRemaining);
+       if ((stackshotHdr->size == 0) || (++cnt == 10))
+           break;
+       IOSleep(10); // 10 ms
+   }
+
+   hdr->spindump_size = (bufSize - bytesRemaining - hdr->spindump_offset);
+
+
+   memset(hdr->cps, 0x20, sizeof(hdr->cps));
+   snprintf(hdr->cps, sizeof(hdr->cps), "\ncps: %d", ((IOService*)this)->getPowerState());
+   code = pmTracer->getPMStatusCode();
+   memset(hdr->PMStatusCode, 0x20, sizeof(hdr->PMStatusCode));
+   snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: %08x %08x",
+           (uint32_t)((code >> 32) & 0xffffffff), (uint32_t)(code & 0xffffffff));
+   memset(hdr->reason, 0x20, sizeof(hdr->reason));
+   if (isSpinDump) {
+      snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: PSC Delay\n\n");
+      gRootDomain->swd_lock = 0;
+      gSpinDumpBufferFull = true;
+      return;
+   }
+   snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n");
+
+
+   data[0] = round_page(sizeof(swd_hdr) + hdr->spindump_size);
+   /* Header & rootdomain log is constantly changing and  is not covered by CRC */
+   data[1] = hdr->crc = crc32(0, ((char*)swd_buffer+hdr->spindump_offset), hdr->spindump_size);
+   data[2] = kvtophys((vm_offset_t)swd_buffer);
+   len = sizeof(addr64_t)*3;
+   DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
+         data[0], data[1], data[2]);
+
+   if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey, data, len) == false)
+   {
+      DLOG("Failed to update nvram boot-args\n");
+      goto exit;
+   }
+
+exit:
+
+   gRootDomain->swd_lock = 0;
+
+   if (wdogTrigger) {
+      IOLog("Restarting to collect Sleep wake debug logs\n");
+      PEHaltRestart(kPERestartCPU);
+   }
+   else {
+     logBufMap = sleepWakeDebugRetrieve();
+      if (logBufMap) {
+          sleepWakeDebugDumpFromMem(logBufMap);
+          logBufMap->release();
+          logBufMap = 0;
+      }
+   }
+}
+
+void IOPMrootDomain::sleepWakeDebugMemAlloc( )
+{
+    vm_size_t    size = SWD_BUF_SIZE;
+
+    swd_hdr      *hdr = NULL;
+
+    IOBufferMemoryDescriptor  *memDesc = NULL;
+
+
+    if ( kIOSleepWakeWdogOff & gIOKitDebug )
+      return;
+
+    if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
+       return;
+
+    // Try allocating above 4GB. If that fails, try at 2GB
+    memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
+                            kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
+                            size, 0xFFFFFFFF00000000ULL);
+    if (!memDesc) {
+       memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
+                            kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
+                            size, 0xFFFFFFFF10000000ULL);
+    }
+
+    if (memDesc == NULL)
+    {
+      DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
+      goto exit;
+    }
+
+
+    hdr = (swd_hdr *)memDesc->getBytesNoCopy();
+    memset(hdr, 0, sizeof(swd_hdr));
+
+    hdr->signature = SWD_HDR_SIGNATURE;
+    hdr->alloc_size = size;
+
+    hdr->spindump_offset = sizeof(swd_hdr);
+    swd_buffer = (void *)hdr;
+    DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset);
+
+exit:
+    gRootDomain->swd_lock = 0;
+}
+
+void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
+{
+    vm_size_t    size = SWD_SPINDUMP_SIZE;
+
+    swd_hdr      *hdr = NULL;
+
+    IOBufferMemoryDescriptor  *memDesc = NULL;
+
+    if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
+        return;
+
+    memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
+                            kernel_task, kIODirectionIn|kIOMemoryMapperNone,
+                            SWD_SPINDUMP_SIZE);
+
+    if (memDesc == NULL)
+    {
+        DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
+        goto exit;
+    }
+
+
+    hdr = (swd_hdr *)memDesc->getBytesNoCopy();
+    memset(hdr, 0, sizeof(swd_hdr));
+
+    hdr->signature = SWD_HDR_SIGNATURE;
+    hdr->alloc_size = size;
+
+    hdr->spindump_offset = sizeof(swd_hdr);
+    swd_spindump_buffer = (void *)hdr;
+
+exit:
+    gRootDomain->swd_lock = 0;
+}
+
+void IOPMrootDomain::sleepWakeDebugEnableWdog()
+{
+    swd_flags |= SWD_WDOG_ENABLED;
+    if (!swd_buffer)
+        sleepWakeDebugMemAlloc();
+}
+
+bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
+{
+    return ((swd_flags & SWD_WDOG_ENABLED) &&
+            !systemBooting && !systemShutdown && !gWillShutdown);
+}
+
+void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
+{
+    swd_hdr *hdr = NULL;
+    errno_t error = EIO;
+
+    if (swd_spindump_buffer && gSpinDumpBufferFull) {
+        hdr = (swd_hdr *)swd_spindump_buffer;
+
+        error = sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
+                        (char*)hdr+hdr->spindump_offset, hdr->spindump_size);
+
+        if (error) return;
+
+        sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
+                         (char*)hdr+offsetof(swd_hdr, UUID),
+                         sizeof(swd_hdr)-offsetof(swd_hdr, UUID));
+
+        gSpinDumpBufferFull = false;
+    }
+}
+
+errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
+{
+   struct vnode         *vp = NULL;
+   vfs_context_t        ctx = vfs_context_create(vfs_context_current());
+   kauth_cred_t         cred = vfs_context_ucred(ctx);
+   struct vnode_attr    va;
+   errno_t      error = EIO;
+
+   if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW),
+                        S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
+   {
+      IOLog("Failed to open the file %s\n", name);
+      goto exit;
+   }
+   VATTR_INIT(&va);
+   VATTR_WANTED(&va, va_nlink);
+   /* Don't dump to non-regular files or files with links. */
+   if (vp->v_type != VREG ||
+        vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
+        IOLog("Bailing as this is not a regular file\n");
+        goto exit;
+    }
+    VATTR_INIT(&va);
+    VATTR_SET(&va, va_data_size, 0);
+    vnode_setattr(vp, &va, ctx);
+
+
+    error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
+        UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0,  vfs_context_proc(ctx));
+    if (error != 0)
+       IOLog("Failed to save sleep wake log. err 0x%x\n", error);
+    else
+       DLOG("Saved %d bytes to file %s\n",len, name);
+
+exit:
+    if (vp) vnode_close(vp, FWRITE, ctx);
+    if (ctx) vfs_context_rele(ctx);
+
+    return error;
+
+}
+
+errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
+                               struct vnode *srcVp, 
+                               vfs_context_t srcCtx,
+                               char *tmpBuf, uint64_t tmpBufSize,
+                               uint64_t srcOffset, 
+                               const char *dstFname, 
+                               uint64_t numBytes,
+                               uint32_t crc)
+{
+   struct vnode         *vp = NULL;
+   vfs_context_t        ctx = vfs_context_create(vfs_context_current());
+   struct vnode_attr    va;
+   errno_t      error = EIO;
+   uint64_t bytesToRead, bytesToWrite;
+   uint64_t readFileOffset, writeFileOffset, srcDataOffset; 
+   uint32_t newcrc = 0;
+
+   if (vnode_open(dstFname, (O_CREAT | FWRITE | O_NOFOLLOW), 
+                        S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0) 
+   {
+      DLOG("Failed to open the file %s\n", dstFname);
+      goto exit;
+   }
+   VATTR_INIT(&va);
+   VATTR_WANTED(&va, va_nlink);
+   /* Don't dump to non-regular files or files with links. */
+   if (vp->v_type != VREG ||
+        vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
+        DLOG("Bailing as this is not a regular file\n");
+        goto exit;
+       }
+    VATTR_INIT(&va);   
+    VATTR_SET(&va, va_data_size, 0);
+    vnode_setattr(vp, &va, ctx);
+   
+    writeFileOffset = 0;
+    while(numBytes) {
+        bytesToRead = (round_page(numBytes) > tmpBufSize) ? tmpBufSize : round_page(numBytes);
+        readFileOffset = trunc_page(srcOffset);
+
+       DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead, readFileOffset);
+       error = vn_rdwr(UIO_READ, srcVp, tmpBuf, bytesToRead, readFileOffset,
+               UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE, 
+               vfs_context_ucred(srcCtx), (int *) 0,
+               vfs_context_proc(srcCtx));
+       if (error) {
+           DLOG("Failed to read file(numBytes:0x%llx)\n", bytesToRead);
+           break;
+       }
+
+       srcDataOffset = (uint64_t)tmpBuf + (srcOffset - readFileOffset);
+       bytesToWrite = bytesToRead - (srcOffset - readFileOffset);
+       if (bytesToWrite > numBytes) bytesToWrite = numBytes;
+
+       if (crc) {
+           newcrc = crc32(newcrc, (void *)srcDataOffset, bytesToWrite);
+       }
+       DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite, writeFileOffset);
+       error = vn_rdwr(UIO_WRITE, vp, (char *)srcDataOffset, bytesToWrite, writeFileOffset,
+               UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT, 
+               vfs_context_ucred(ctx), (int *) 0,
+               vfs_context_proc(ctx));
+       if (error) {
+           DLOG("Failed to write file(numBytes:0x%llx)\n", bytesToWrite);
+           break;
+       }
+
+       writeFileOffset += bytesToWrite;
+       numBytes -= bytesToWrite;
+       srcOffset += bytesToWrite;
+
+    }
+    if (crc != newcrc) {
+        swd_stackshot_hdr *shdr = (swd_stackshot_hdr *)tmpBuf;;
+
+        /* Set statckshot size to 0 if crc doesn't match */
+        shdr->magic = SWD_STACKSHOTHDR_MAGIC;
+        shdr->size = 0;
+
+        assert(tmpBufSize > sizeof(swd_stackshot_hdr));
+        bytesToWrite = round_page(sizeof(swd_stackshot_hdr));
+        vn_rdwr(UIO_WRITE, vp, (char *)tmpBuf, bytesToWrite, 0,
+               UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT, 
+               vfs_context_ucred(ctx), (int *) 0,
+               vfs_context_proc(ctx));
+
+        DLOG("CRC check failed. expected:0x%x actual:0x%x\n", crc, newcrc);
+        error = EFAULT;
+    }
+exit:
+    if (vp) { 
+        error = vnode_close(vp, FWRITE, ctx);
+        DLOG("vnode_close returned 0x%x\n", error);
+    }
+    if (ctx) vfs_context_rele(ctx);
+
+    return error;
+
+
+
+}
+void IOPMrootDomain::checkForValidDebugData(const char *fname, vfs_context_t *ctx, 
+                                            void *tmpBuf, struct vnode **vp)
+{
+    int             rc;
+    uint64_t        hdrOffset;
+
+    struct vnode_attr           va;
+    IOHibernateImageHeader      *imageHdr;
+
+    *vp = NULL;
+    if (vnode_open(fname, (FREAD | O_NOFOLLOW), 0,
+                   VNODE_LOOKUP_NOFOLLOW, vp, *ctx) != 0) 
+    {
+        DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname);
+        goto err;
+    }
+    VATTR_INIT(&va);
+    VATTR_WANTED(&va, va_nlink);
+    VATTR_WANTED(&va, va_data_alloc);
+    if ((*vp)->v_type != VREG ||
+        vnode_getattr((*vp), &va, *ctx) || va.va_nlink != 1) {
+        DMSG("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname);
+        goto err;
+    }
+
+    /* Read the sleepimage file header */
+    rc = vn_rdwr(UIO_READ, *vp, (char *)tmpBuf, round_page(sizeof(IOHibernateImageHeader)), 0,
+                UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE, 
+                vfs_context_ucred(*ctx), (int *) 0,
+                vfs_context_proc(*ctx));
+    if (rc != 0) {
+        DMSG("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n", 
+             round_page(sizeof(IOHibernateImageHeader)), rc, fname);
+        goto err;
+    }
+
+    imageHdr = ((IOHibernateImageHeader *)tmpBuf);
+    if (imageHdr->signature != kIOHibernateHeaderDebugDataSignature) {
+        DMSG("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n", 
+             fname, imageHdr->signature);
+        goto err;
+    }
+
+    /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
+    hdrOffset = imageHdr->deviceBlockSize;
+    if (hdrOffset + sizeof(swd_hdr) >= va.va_data_alloc) {
+        DMSG("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",  
+             va.va_data_alloc, fname);
+        goto err;
+    }
+
+    return; 
+
+err:
+    if (*vp) vnode_close(*vp, FREAD, *ctx);
+    *vp = NULL;
+
+    return;
+}
+
+void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
+{
+#if HIBERNATION
+    int             rc;
+    char                       hibernateFilename[MAXPATHLEN+1];
+    char            PMStatusCode[100];
+    void            *tmpBuf;
+    swd_hdr         *hdr = NULL;
+    uint32_t        stacksSize, logSize;
+    uint64_t        tmpBufSize;
+    uint64_t        hdrOffset, stacksOffset, logOffset;
+    errno_t         error = EIO;
+    OSObject        *obj = NULL;
+    OSString        *str = NULL;
+    OSNumber        *failStat = NULL;
+    struct vnode    *vp = NULL;
+    vfs_context_t   ctx = NULL;
+
+    IOBufferMemoryDescriptor    *tmpBufDesc = NULL;
+
+    DLOG("sleepWakeDebugDumpFromFile\n");
+    if ((swd_flags & SWD_LOGS_IN_FILE) == 0)
+        return;
+
+   if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
+       return;
+
+
+    /* Allocate a temp buffer to copy data between files */
+    tmpBufSize = 2*4096;
+    tmpBufDesc = IOBufferMemoryDescriptor::
+        inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryMapperNone, 
+                          tmpBufSize, PAGE_SIZE);
+
+    if (!tmpBufDesc) {
+        DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
+        goto exit;
+    }
+
+    tmpBuf = tmpBufDesc->getBytesNoCopy();
+
+   ctx = vfs_context_create(vfs_context_current());
+
+    /* First check if 'kSleepWakeStackBinFilename' has valid data */
+    checkForValidDebugData(kSleepWakeStackBinFilename, &ctx, tmpBuf, &vp);
+    if (vp == NULL) {
+        /* Check if the debug data is saved to hibernation file */
+        hibernateFilename[0] = 0;
+        if ((obj = copyProperty(kIOHibernateFileKey)))
+        {
+            if ((str = OSDynamicCast(OSString, obj)))
+                strlcpy(hibernateFilename, str->getCStringNoCopy(),
+                        sizeof(hibernateFilename));
+            obj->release();
+        }
+        if (!hibernateFilename[0]) {
+            DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
+            goto exit;
+        }
+
+        checkForValidDebugData(hibernateFilename, &ctx, tmpBuf, &vp);
+        if (vp == NULL) {
+            DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
+            goto exit;
+        }
+        DLOG("Getting SW Stacks image from file %s\n", hibernateFilename);
+    }
+    else {
+        DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename);
+    }
+
+    hdrOffset = ((IOHibernateImageHeader *)tmpBuf)->deviceBlockSize;
+
+    DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr)), trunc_page(hdrOffset));
+    /* Read the sleep/wake debug header(swd_hdr) */
+    rc = vn_rdwr(UIO_READ, vp, (char *)tmpBuf, round_page(sizeof(swd_hdr)), trunc_page(hdrOffset),
+                UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE, 
+                vfs_context_ucred(ctx), (int *) 0,
+                vfs_context_proc(ctx));
+    if (rc != 0) {
+        DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
+             round_page(sizeof(swd_hdr)), rc);
+        goto exit;
+    }
+
+    hdr = (swd_hdr *)((char *)tmpBuf + (hdrOffset - trunc_page(hdrOffset)));
+    if ((hdr->signature != SWD_HDR_SIGNATURE) || (hdr->alloc_size > SWD_BUF_SIZE) ||
+        (hdr->spindump_offset > SWD_BUF_SIZE) || (hdr->spindump_size > SWD_BUF_SIZE)) {
+        DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
+             hdr->signature, hdr->alloc_size, hdr->spindump_offset, hdr->spindump_size);
+        goto exit;
+    }
+    stacksSize = hdr->spindump_size;
+
+    /* Get stacks & log offsets in the image file */
+    stacksOffset = hdrOffset + hdr->spindump_offset;
+    logOffset = hdrOffset + offsetof(swd_hdr, UUID);
+    logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID); 
+
+    error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, stacksOffset,
+                                   getDumpStackFilename(hdr), stacksSize, hdr->crc);
+    if (error == EFAULT) {
+        DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
+        goto exit;
+    }
+    error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, logOffset, 
+                                   getDumpLogFilename(hdr), logSize, 0);
+    if (error) {
+        DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error);
+        goto exit;
+    }
+exit:
+    if (error) {
+      // Write just the SleepWakeLog.dump with failure code
+      uint64_t fcode = 0;
+      const char *fname;
+      if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
+          failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
+          fcode = failStat->unsigned64BitValue();
+          fname = kSleepWakeLogFilename;
+      }
+      else {
+          fname = kAppleOSXWatchdogLogFilename;
+      }
+      memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces
+      PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end
+      snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode);
+      sleepWakeDebugSaveFile(fname, PMStatusCode, sizeof(PMStatusCode));
+    }
+    gRootDomain->swd_lock = 0;
+
+    if (vp) vnode_close(vp, FREAD, ctx);
+    if (ctx) vfs_context_rele(ctx);
+    if (tmpBufDesc) tmpBufDesc->release();
+#endif /* HIBERNATION */
+}
+
+void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *logBufMap)
+{
+   IOVirtualAddress     srcBuf = NULL;
+   char                 *stackBuf = NULL, *logOffset = NULL;
+   int                  logSize = 0;
+
+   errno_t      error = EIO;
+   uint64_t     bufSize = 0;
+   swd_hdr      *hdr = NULL;
+   char PMStatusCode[100];
+   OSNumber  *failStat = NULL;
+
+   if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
+       return;
+
+   if ((logBufMap == 0) || ( (srcBuf = logBufMap->getVirtualAddress()) == 0) )
+   {
+      DLOG("Nothing saved to dump to file\n");
+      goto exit;
+   }
+
+   hdr = (swd_hdr *)srcBuf;
+   bufSize = logBufMap->getLength();
+   if (bufSize <= sizeof(swd_hdr))
+   {
+      IOLog("SleepWake log buffer contents are invalid\n");
+      goto exit;
+   }
+
+   stackBuf = (char*)hdr+hdr->spindump_offset;
+
+   error = sleepWakeDebugSaveFile(getDumpStackFilename(hdr), stackBuf, hdr->spindump_size);
+   if (error) goto exit;
+
+   logOffset = (char*)hdr+offsetof(swd_hdr, UUID);
+   logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
+
+   error = sleepWakeDebugSaveFile(getDumpLogFilename(hdr), logOffset, logSize);
+   if (error) goto exit;
+
+    hdr->spindump_size = 0;
+    error = 0;
+
+exit:
+    if (error) {
+      // Write just the SleepWakeLog.dump with failure code
+      uint64_t fcode = 0;
+      const char *sname, *lname;
+      swd_stackshot_hdr shdr;
+
+        /* Try writing an empty stacks file */
+        shdr.magic = SWD_STACKSHOTHDR_MAGIC;
+        shdr.size = 0;
+
+
+      if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
+          failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
+          fcode = failStat->unsigned64BitValue();
+          lname = kSleepWakeLogFilename;
+          sname = kSleepWakeStackFilename;
+      }
+      else {
+          lname = kAppleOSXWatchdogLogFilename;
+          sname= kAppleOSXWatchdogStackFilename;
+      }
+
+      sleepWakeDebugSaveFile(sname, (char*)(&shdr), sizeof(shdr));
+      memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces
+      PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end
+      snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode);
+      sleepWakeDebugSaveFile(lname, PMStatusCode, sizeof(PMStatusCode));
+    }
+    gRootDomain->swd_lock = 0;
+}
+
+IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
+{
+   IOVirtualAddress     vaddr = NULL;
+   IOMemoryDescriptor * desc = NULL;
+   IOMemoryMap *        logBufMap = NULL;
+
+   uint32_t          len;
+   addr64_t          data[3];
+   uint64_t          bufSize = 0;
+   uint64_t          crc = 0;
+   uint64_t          newcrc = 0;
+   uint64_t          paddr = 0;
+   swd_hdr           *hdr = NULL;
+   bool              ret = false;
+   char              str[20];
+
+
+   if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
+       return NULL;
+
+   if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey, 0, &len)) {
+      DLOG("No sleepWakeDebug note to read\n");
+      goto exit;
+   }
+
+   if (len == strlen("sleepimage")) {
+       str[0] = 0;
+       PEReadNVRAMProperty(kIOSleepWakeDebugKey, str, &len);
+
+       if (!strncmp((char*)str, "sleepimage", strlen("sleepimage"))) {
+           DLOG("sleepWakeDebugRetrieve: in file logs\n");
+           swd_flags |= SWD_LOGS_IN_FILE|SWD_VALID_LOGS;
+           goto exit;
+       }
+   }
+   else if (len == sizeof(addr64_t)*3)
+       PEReadNVRAMProperty(kIOSleepWakeDebugKey, data, &len);
+   else {
+      DLOG("Invalid sleepWakeDebug note length(%d)\n", len);
+      goto exit;
+   }
+
+
+
+   DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
+        data[0], data[1], data[2]);
+   DLOG("sleepWakeDebugRetrieve: in mem logs\n");
+   bufSize = data[0];
+   crc = data[1];
+   paddr = data[2];
+   if ( (bufSize <= sizeof(swd_hdr)) ||(bufSize > SWD_BUF_SIZE) || (crc == 0) )
+   {
+      IOLog("SleepWake log buffer contents are invalid\n");
+      return NULL;
+   }
+
+   DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
+         bufSize, crc, paddr);
+
+
+   desc = IOMemoryDescriptor::withAddressRange( paddr, bufSize,
+                          kIODirectionOutIn | kIOMemoryMapperNone, NULL);
+   if (desc == NULL)
+   {
+      IOLog("Fail to map SleepWake log buffer\n");
+      goto exit;
+   }
+
+   logBufMap = desc->map();
+
+   vaddr = logBufMap->getVirtualAddress();
+
+
+   if ( (logBufMap->getLength() <= sizeof(swd_hdr)) || (vaddr == NULL) ) {
+      IOLog("Fail to map SleepWake log buffer\n");
+      goto exit;
+   }
+
+   hdr = (swd_hdr *)vaddr;
+   if (hdr->spindump_offset+hdr->spindump_size > bufSize)
+   {
+      IOLog("SleepWake log buffer contents are invalid\n");
+      goto exit;
+   }
+
+   hdr->crc = crc;
+   newcrc = crc32(0, (void *)((char*)vaddr+hdr->spindump_offset),
+            hdr->spindump_size);
+   if (newcrc != crc) {
+      IOLog("SleepWake log buffer contents are invalid\n");
+      goto exit;
+   }
+
+   ret = true;
+   swd_flags |= SWD_LOGS_IN_MEM | SWD_VALID_LOGS;
+
+
+exit:
+   PERemoveNVRAMProperty(kIOSleepWakeDebugKey);
+   if (!ret) {
+      if (logBufMap) logBufMap->release();
+      logBufMap = 0;
+   }
+   if (desc) desc->release();
+    gRootDomain->swd_lock = 0;
+
+   return logBufMap;
+}
+
+#else
+
+void IOPMrootDomain::sleepWakeDebugTrig(bool restart)
+{
+}
+
+void IOPMrootDomain::takeStackshot(bool restart, bool isOSXWatchdog, bool isSpinDump)
+{
+#pragma unused(restart)
+#pragma unused(isOSXWatchdog)
+}
+
+void IOPMrootDomain::sleepWakeDebugMemAlloc( )
+{
+}
+void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *map)
+{
+}
+errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
+                               struct vnode *srcVp, 
+                               vfs_context_t srcCtx,
+                               char *tmpBuf, uint64_t tmpBufSize,
+                               uint64_t srcOffset, 
+                               const char *dstFname, 
+                               uint64_t numBytes,
+                               uint32_t crc)
+{
+    return EIO;
+}
+
+void IOPMrootDomain::sleepWakeDebugDumpFromFile()
+{
+}
+
+IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
+{
+   return NULL;
+}
+
+void IOPMrootDomain::sleepWakeDebugEnableWdog()
+{
+}
+
+bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
+{
+    return false;
+}
+
+errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
+{
+    return 0;
+}
+
+#endif
+