X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/e5568f75972dfc723778653c11cb6b4dc825716a..8ad349bb6ed4a0be06e34c92be0d98b92e078db4:/iokit/Kernel/IOPMrootDomain.cpp diff --git a/iokit/Kernel/IOPMrootDomain.cpp b/iokit/Kernel/IOPMrootDomain.cpp index 8f15a10b7..a18a256c2 100644 --- a/iokit/Kernel/IOPMrootDomain.cpp +++ b/iokit/Kernel/IOPMrootDomain.cpp @@ -1,23 +1,31 @@ - /* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. +/* + * Copyright (c) 1998-2005 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the + * License may not be used to create, or enable the creation or + * redistribution of, unlawful or unlicensed copies of an Apple operating + * system, or to circumvent, violate, or enable the circumvention or + * violation of, any terms of an Apple operating system software license + * agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ */ #include #include @@ -27,25 +35,22 @@ #include #include #include +#include #include #include "RootDomainUserClient.h" #include "IOKit/pwr_mgt/IOPowerConnection.h" #include "IOPMPowerStateQueue.h" +#include +#include + +#ifdef __ppc__ +#include +#endif extern "C" void kprintf(const char *, ...); extern const IORegistryPlane * gIOPowerPlane; -// debug trace function -static inline void -ioSPMTrace(unsigned int csc, - unsigned int a = 0, unsigned int b = 0, - unsigned int c = 0, unsigned int d = 0) -{ - if (gIOKitDebug & kIOLogTracePower) - IOTimeStampConstant(IODBG_POWER(csc), a, b, c, d); -} - IOReturn broadcast_aggressiveness ( OSObject *, void *, void *, void *, void * ); static void sleepTimerExpired(thread_call_param_t); static void wakeupClamshellTimerExpired ( thread_call_param_t us); @@ -74,6 +79,9 @@ static IOPMPowerState ourPowerStates[number_of_power_states] = { // RESERVED IOPMrootDomain class variables #define diskSyncCalloutEntry _reserved->diskSyncCalloutEntry #define _settingController _reserved->_settingController +#define _batteryLocationNotifier _reserved->_batteryLocationNotifier +#define _displayWranglerNotifier _reserved->_displayWranglerNotifier + static IOPMrootDomain * gRootDomain; static UInt32 gSleepOrShutdownPending = 0; @@ -84,12 +92,12 @@ OSDefineMetaClassAndStructors(IOPMrootDomain,IOService) extern "C" { - IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref = 0) + IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref) { return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref ); } - IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref = 0) + IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref) { return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref ); } @@ -116,6 +124,7 @@ extern "C" void IOSystemShutdownNotification ( void ) { + IOCatalogue::disableExternalLinker(); for ( int i = 0; i < 100; i++ ) { if ( OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) ) break; @@ -187,6 +196,7 @@ static void disk_sync_callout(thread_call_param_t p0, thread_call_param_t p1) IOService *rootDomain = (IOService *) p0; unsigned long pmRef = (unsigned long) p1; + IOHibernateSystemSleep(); sync_internal(); rootDomain->allowPowerChange(pmRef); } @@ -214,6 +224,7 @@ bool IOPMrootDomain::start ( IOService * nub ) PMinit(); setProperty("IOSleepSupported",""); + allowSleep = true; sleepIsSupported = true; systemBooting = true; @@ -229,11 +240,13 @@ bool IOPMrootDomain::start ( IOService * nub ) tmpDict = OSDictionary::withCapacity(1); setProperty(kRootDomainSupportedFeatures, tmpDict); tmpDict->release(); - + pm_vars->PMworkloop = IOWorkLoop::workLoop(); pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(this); pm_vars->PMworkloop->addEventSource(pmPowerStateQueue); + featuresDictLock = IOLockAlloc(); + extraSleepTimer = thread_call_allocate((thread_call_func_t)sleepTimerExpired, (thread_call_param_t) this); clamshellWakeupIgnore = thread_call_allocate((thread_call_func_t)wakeupClamshellTimerExpired, (thread_call_param_t) this); diskSyncCalloutEntry = thread_call_allocate(&disk_sync_callout, (thread_call_param_t) this); @@ -257,12 +270,32 @@ bool IOPMrootDomain::start ( IOService * nub ) registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0); // Register for a notification when IODisplayWrangler is published - addNotification( gIOPublishNotification, serviceMatching("IODisplayWrangler"), &displayWranglerPublished, this, 0); + _displayWranglerNotifier = addNotification( gIOPublishNotification, + serviceMatching("IODisplayWrangler"), + &displayWranglerPublished, this, 0); + + _batteryLocationNotifier = addNotification( gIOPublishNotification, + resourceMatching("battery"), + &batteryLocationPublished, this, this); const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient"); - setProperty(gIOUserClientClassKey, (OSMetaClassBase *) ucClassName); + setProperty(gIOUserClientClassKey, (OSObject *) ucClassName); ucClassName->release(); + IORegistryEntry *temp_entry = NULL; + if( (temp_entry = IORegistryEntry::fromPath("mac-io/battery", gIODTPlane)) || + (temp_entry = IORegistryEntry::fromPath("mac-io/via-pmu/battery", gIODTPlane))) + { + // If this machine has a battery, publish the fact that the backlight + // supports dimming. + // Notice similar call in IOPMrootDomain::batteryLocationPublished() to + // detect batteries on SMU machines. + publishFeature("DisplayDims"); + temp_entry->release(); + } + + IOHibernateSystemInit(this); + registerService(); // let clients find us return true; @@ -291,15 +324,21 @@ IOReturn IOPMrootDomain::setProperties ( OSObject *props_obj) OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj); OSBoolean *b; OSNumber *n; - OSString *boot_complete_string = OSString::withCString("System Boot Complete"); - OSString *power_button_string = OSString::withCString("DisablePowerButtonSleep"); - OSString *stall_halt_string = OSString::withCString("StallSystemAtHalt"); - OSString *auto_wake_string = OSString::withCString("wake"); - OSString *auto_power_string = OSString::withCString("poweron"); - OSString *wakeonring_string = OSString::withCString("WakeOnRing"); - OSString *fileserver_string = OSString::withCString("AutoRestartOnPowerLoss"); - OSString *wakeonlid_string = OSString::withCString("WakeOnLid"); - OSString *wakeonac_string = OSString::withCString("WakeOnACChange"); + OSString *str; + const OSSymbol *boot_complete_string = OSSymbol::withCString("System Boot Complete"); + const OSSymbol *power_button_string = OSSymbol::withCString("DisablePowerButtonSleep"); + const OSSymbol *stall_halt_string = OSSymbol::withCString("StallSystemAtHalt"); + const OSSymbol *auto_wake_string = OSSymbol::withCString("wake"); + const OSSymbol *auto_power_string = OSSymbol::withCString("poweron"); + const OSSymbol *wakeonring_string = OSSymbol::withCString("WakeOnRing"); + const OSSymbol *fileserver_string = OSSymbol::withCString("AutoRestartOnPowerLoss"); + const OSSymbol *wakeonlid_string = OSSymbol::withCString("WakeOnLid"); + const OSSymbol *wakeonac_string = OSSymbol::withCString("WakeOnACChange"); + const OSSymbol *hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey); + const OSSymbol *hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey); + const OSSymbol *hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey); + const OSSymbol *hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey); + const OSSymbol *timezone_string = OSSymbol::withCString("TimeZoneOffsetSeconds"); if(!dict) { @@ -326,7 +365,28 @@ IOReturn IOPMrootDomain::setProperties ( OSObject *props_obj) { setProperty(stall_halt_string, b); } - + + 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); + } + if ( hibernatefile_string + && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string)))) + { + setProperty(hibernatefile_string, str); + } + // Relay AutoWake setting to its controller if( auto_wake_string && (n = OSDynamicCast(OSNumber, dict->getObject(auto_wake_string))) ) @@ -375,6 +435,14 @@ IOReturn IOPMrootDomain::setProperties ( OSObject *props_obj) if(kIOReturnSuccess != return_value) goto exit; } + // Relay timezone offset in seconds to SMU + if( timezone_string + && (n = OSDynamicCast(OSNumber, dict->getObject(timezone_string))) ) + { + return_value = setPMSetting(kIOPMTimeZoneSetting, n); + if(kIOReturnSuccess != return_value) goto exit; + } + exit: if(boot_complete_string) boot_complete_string->release(); @@ -386,6 +454,7 @@ IOReturn IOPMrootDomain::setProperties ( OSObject *props_obj) if(fileserver_string) fileserver_string->release(); if(wakeonlid_string) wakeonlid_string->release(); if(wakeonac_string) wakeonac_string->release(); + if(timezone_string) timezone_string->release(); return return_value; } @@ -518,8 +587,24 @@ void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void) // same thread. //********************************************************************************* +static int pmsallsetup = 0; + IOReturn IOPMrootDomain::setAggressiveness ( unsigned long type, unsigned long newLevel ) { +#ifdef __ppc__ + if(pmsExperimental & 3) kprintf("setAggressiveness: type = %08X, newlevel = %08X\n", type, newLevel); + if(pmsExperimental & 1) { /* Is experimental mode enabled? */ + if(pmsInstalled && (type == kPMSetProcessorSpeed)) { /* We want to look at all processor speed changes if stepper is installed */ + if(pmsallsetup) return kIOReturnSuccess; /* If already running, just eat this */ + kprintf("setAggressiveness: starting stepper...\n"); + pmsallsetup = 1; /* Remember we did this */ + pmsPark(); + pmsStart(); /* Get it all started up... */ + return kIOReturnSuccess; /* Leave now... */ + } + } +#endif + if ( pm_vars->PMcommandGate ) { pm_vars->PMcommandGate->runAction(broadcast_aggressiveness,(void *)type,(void *)newLevel); } @@ -537,6 +622,7 @@ IOReturn IOPMrootDomain::sleepSystem ( void ) //kprintf("sleep demand received\n"); if ( !systemBooting && allowSleep && sleepIsSupported ) { patriarch->sleepSystem(); + return kIOReturnSuccess; } if ( !systemBooting && allowSleep && !sleepIsSupported ) { @@ -593,14 +679,18 @@ void IOPMrootDomain::powerChangeDone ( unsigned long previousState ) { // re-enable this timer for next sleep idleSleepPending = false; - IOLog("System Sleep\n"); + + IOLog("System %sSleep\n", gIOHibernateState ? "Safe" : ""); + + IOHibernateSystemHasSlept(); + pm_vars->thePlatform->sleepKernel(); // The CPU(s) are off at this point. When they're awakened by CPU interrupt, - // code will resume exeuction here. - + // code will resume execution here. + // Now we're waking... - ioSPMTrace(IOPOWER_WAKE, * (int *) this); + IOHibernateSystemWake(); // stay awake for at least 30 seconds clock_interval_to_deadline(30, kSecondScale, &deadline); @@ -625,7 +715,7 @@ void IOPMrootDomain::powerChangeDone ( unsigned long previousState ) tellClients(kIOMessageSystemWillPowerOn); // tell the tree we're waking - IOLog("System Wake\n"); + IOLog("System %sWake\n", gIOHibernateState ? "SafeSleep " : ""); systemWake(); // Allow drivers to request extra processing time before clamshell @@ -721,11 +811,22 @@ void IOPMrootDomain::wakeFromDoze( void ) // ********************************************************************************** void IOPMrootDomain::publishFeature( const char * feature ) { - OSDictionary *features = (OSDictionary *)getProperty(kRootDomainSupportedFeatures); - - features->setObject(feature, kOSBooleanTrue); + if(featuresDictLock) IOLockLock(featuresDictLock); + OSDictionary *features = + (OSDictionary *) getProperty(kRootDomainSupportedFeatures); + + if ( features && OSDynamicCast(OSDictionary, features)) + features = OSDictionary::withDictionary(features); + else + features = OSDictionary::withCapacity(1); + + features->setObject(feature, kOSBooleanTrue); + setProperty(kRootDomainSupportedFeatures, features); + features->release(); + if(featuresDictLock) IOLockUnlock(featuresDictLock); } + void IOPMrootDomain::unIdleDevice( IOService *theDevice, unsigned long theState ) { if(pmPowerStateQueue) @@ -734,6 +835,18 @@ void IOPMrootDomain::unIdleDevice( IOService *theDevice, unsigned long theState void IOPMrootDomain::announcePowerSourceChange( void ) { + IORegistryEntry *_batteryRegEntry = (IORegistryEntry *) getProperty("BatteryEntry"); + + // (if possible) re-publish power source state under IOPMrootDomain + // (only done if the battery controller publishes an IOResource defining battery location) + if(_batteryRegEntry) + { + OSArray *batt_info; + batt_info = (OSArray *) _batteryRegEntry->getProperty(kIOBatteryInfoKey); + if(batt_info) + setProperty(kIOBatteryInfoKey, batt_info); + } + messageClients(kIOPMMessageBatteryStatusHasChanged); } @@ -1030,6 +1143,7 @@ void IOPMrootDomain::tellChangeUp ( unsigned long stateNum) { if ( stateNum == ON_STATE ) { + IOHibernateSystemPostWake(); return tellClients(kIOMessageSystemHasPoweredOn); } } @@ -1085,15 +1199,11 @@ void IOPMrootDomain::restoreUserSpinDownTimeout ( void ) IOReturn IOPMrootDomain::changePowerStateTo ( unsigned long ordinal ) { - ioSPMTrace(IOPOWER_ROOT, * (int *) this, (int) true, (int) ordinal); - return super::changePowerStateTo(ordinal); } IOReturn IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal ) { - ioSPMTrace(IOPOWER_ROOT, * (int *) this, (int) false, (int) ordinal); - return super::changePowerStateToPriv(ordinal); } @@ -1133,6 +1243,8 @@ IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon, // We will ack within 20 seconds params->returnValue = 20 * 1000 * 1000; + if (gIOHibernateState) + params->returnValue += gIOHibernateFreeTime * 1000; //add in time we could spend freeing pages if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) ) { @@ -1270,6 +1382,36 @@ bool IOPMrootDomain::displayWranglerPublished( void * target, void * refCon, return true; } +//********************************************************************************* +// batteryLocationPublished +// +// Notification on AppleSMU publishing location of battery data +// +//********************************************************************************* + +bool IOPMrootDomain::batteryLocationPublished( void * target, void * root_domain, + IOService * resourceService ) +{ + IORegistryEntry *battery_location; + + battery_location = (IORegistryEntry *) resourceService->getProperty("battery"); + if (!battery_location || !OSDynamicCast(IORegistryEntry, battery_location)) + return (true); + + ((IOPMrootDomain *)root_domain)->setProperty("BatteryEntry", battery_location); + + // rdar://2936060 + // All laptops have dimmable LCD displays + // All laptops have batteries + // So if this machine has a battery, publish the fact that the backlight + // supports dimming. + ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims"); + + ((IOPMrootDomain *)root_domain)->announcePowerSourceChange(); + return (true); +} + + //********************************************************************************* // adjustPowerState