+#if HIBERNATION
+
+//******************************************************************************
+// evaluateSystemSleepPolicy
+//******************************************************************************
+
+struct IOPMSystemSleepPolicyEntry
+{
+ uint32_t factorMask;
+ uint32_t factorBits;
+ uint32_t sleepFlags;
+ uint32_t wakeEvents;
+};
+
+struct IOPMSystemSleepPolicyTable
+{
+ uint8_t signature[4];
+ uint16_t version;
+ uint16_t entryCount;
+ IOPMSystemSleepPolicyEntry entries[];
+};
+
+enum {
+ kIOPMSleepFactorSleepTimerWake = 0x00000001,
+ kIOPMSleepFactorLidOpen = 0x00000002,
+ kIOPMSleepFactorACPower = 0x00000004,
+ kIOPMSleepFactorLowBattery = 0x00000008,
+ kIOPMSleepFactorDeepSleepNoDelay = 0x00000010,
+ kIOPMSleepFactorDeepSleepDemand = 0x00000020,
+ kIOPMSleepFactorDeepSleepDisable = 0x00000040,
+ kIOPMSleepFactorUSBExternalDevice = 0x00000080,
+ kIOPMSleepFactorBluetoothHIDDevice = 0x00000100,
+ kIOPMSleepFactorExternalMediaMounted = 0x00000200,
+ kIOPMSleepFactorDriverAssertBit5 = 0x00000400,
+ kIOPMSleepFactorDriverAssertBit6 = 0x00000800,
+ kIOPMSleepFactorDriverAssertBit7 = 0x00001000
+};
+
+bool IOPMrootDomain::evaluateSystemSleepPolicy( IOPMSystemSleepParameters * p )
+{
+ 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);
+
+ prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
+ if (!prop)
+ return false;
+
+ policyData = OSDynamicCast(OSData, prop);
+ if (!policyData ||
+ (policyData->getLength() < sizeof(IOPMSystemSleepPolicyTable)))
+ {
+ goto done;
+ }
+
+ 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;
+ }
+
+ if ((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
+ (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount))
+ {
+ goto done;
+ }
+
+ currentFactors = 0;
+ if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
+ kIOPMDriverAssertionLevelOff)
+ currentFactors |= kIOPMSleepFactorUSBExternalDevice;
+ if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit) !=
+ kIOPMDriverAssertionLevelOff)
+ currentFactors |= kIOPMSleepFactorBluetoothHIDDevice;
+ if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
+ kIOPMDriverAssertionLevelOff)
+ currentFactors |= kIOPMSleepFactorExternalMediaMounted;
+ if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
+ kIOPMDriverAssertionLevelOff)
+ currentFactors |= kIOPMSleepFactorDriverAssertBit5;
+ if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit6) !=
+ kIOPMDriverAssertionLevelOff)
+ currentFactors |= kIOPMSleepFactorDriverAssertBit6;
+ if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit7) !=
+ kIOPMDriverAssertionLevelOff)
+ currentFactors |= kIOPMSleepFactorDriverAssertBit7;
+ if (0 == deepSleepDelay)
+ currentFactors |= kIOPMSleepFactorDeepSleepNoDelay;
+ if (!clamshellIsClosed)
+ currentFactors |= kIOPMSleepFactorLidOpen;
+ if (acAdaptorConnected)
+ currentFactors |= kIOPMSleepFactorACPower;
+ if (lowBatteryCondition)
+ currentFactors |= kIOPMSleepFactorLowBattery;
+ if (sleepTimerMaintenance)
+ currentFactors |= kIOPMSleepFactorSleepTimerWake;
+
+ // 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);
+
+ for (uint32_t i = 0; i < pt->entryCount; i++)
+ {
+ const IOPMSystemSleepPolicyEntry * policyEntry = &pt->entries[i];
+
+ DLOG("factor mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x\n",
+ policyEntry->factorMask, policyEntry->factorBits,
+ policyEntry->sleepFlags, policyEntry->wakeEvents);
+
+ if ((currentFactors ^ policyEntry->factorBits) & policyEntry->factorMask)
+ continue; // mismatch, try next
+
+ if (p)
+ {
+ p->version = 1;
+ p->sleepFlags = policyEntry->sleepFlags;
+ p->sleepTimer = 0;
+ p->wakeEvents = policyEntry->wakeEvents;
+ if (p->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
+ {
+ p->sleepTimer = deepSleepDelay;
+ }
+ }
+
+ DLOG("matched policy entry %u\n", i);
+ success = true;
+ break;
+ }
+
+done:
+ if (prop)
+ prop->release();
+
+ return success;
+}
+
+void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
+{
+ IOPMSystemSleepParameters params;
+
+ // Evaluate sleep policy before driver sleep phase.
+
+ DLOG("%s\n", __FUNCTION__);
+ removeProperty(kIOPMSystemSleepParametersKey);
+
+ hibernateDisabled = false;
+ hibernateMode = 0;
+ getSleepOption(kIOHibernateModeKey, &hibernateMode);
+
+ if (!hibernateNoDefeat &&
+ evaluateSystemSleepPolicy(¶ms) &&
+ ((params.sleepFlags & kIOPMSleepFlagHibernate) == 0))
+ {
+ hibernateDisabled = true;
+ }
+}
+
+void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
+{
+ IOPMSystemSleepParameters params;
+ OSData * paramsData;
+
+ // Evaluate sleep policy after drivers but before platform sleep.
+
+ DLOG("%s\n", __FUNCTION__);
+
+ if (evaluateSystemSleepPolicy(¶ms))
+ {
+ if ((hibernateDisabled || hibernateAborted) &&
+ (params.sleepFlags & kIOPMSleepFlagHibernate))
+ {
+ // 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;
+ DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
+ params.sleepTimer, hibernateDisabled, hibernateAborted);
+ }
+ else
+ hibernateNoDefeat = false;
+
+ paramsData = OSData::withBytes(¶ms, sizeof(params));
+ if (paramsData)
+ {
+ setProperty(kIOPMSystemSleepParametersKey, paramsData);
+ paramsData->release();
+ }
+
+ if (params.sleepFlags & kIOPMSleepFlagHibernate)
+ {
+ // Force hibernate
+ gIOHibernateMode &= ~kIOHibernateModeSleep;
+ }
+ }
+}
+
+bool IOPMrootDomain::getHibernateSettings(
+ uint32_t * hibernateMode,
+ uint32_t * hibernateFreeRatio,
+ uint32_t * hibernateFreeTime )
+{
+ bool ok = getSleepOption(kIOHibernateModeKey, hibernateMode);
+ getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
+ getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
+ if (hibernateDisabled)
+ *hibernateMode = 0;
+ DLOG("hibernateMode 0x%x\n", *hibernateMode);
+ return ok;
+}
+
+bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
+{
+ OSObject * optionsProp;
+ OSDictionary * optionsDict;
+ OSObject * obj = 0;
+ OSNumber * num;
+ bool ok = false;
+
+ optionsProp = copyProperty(kRootDomainSleepOptionsKey);
+ optionsDict = OSDynamicCast(OSDictionary, optionsProp);
+
+ if (optionsDict)
+ {
+ obj = optionsDict->getObject(key);
+ if (obj) obj->retain();
+ }
+ if (!obj)
+ {
+ obj = copyProperty(key);
+ }
+ if (obj && (num = OSDynamicCast(OSNumber, obj)))
+ {
+ *option = num->unsigned32BitValue();
+ ok = true;
+ }
+
+ if (obj)
+ obj->release();
+ if (optionsProp)
+ optionsProp->release();
+
+ return true;
+}
+#endif /* HIBERNATION */
+
+