/* * Copyright (c) 2001 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. * * 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@ */ #include #include #include #include #include #include #include #include #include #include #include #include #include "IOPMLib.h" #include "IOPMLibPrivate.h" #include "powermanagement.h" #include #include #include #include #include #include #include #include #include #include #define kIOPMPrefsPath CFSTR("com.apple.PowerManagement.xml") #define kIOPMAppName CFSTR("PowerManagement configd") // 2936060 #ifndef kIODisplayDimAggressiveness #define kIODisplayDimAggressiveness iokit_family_err(sub_iokit_graphics, 3) #endif #define kIOPMNumPMProfiles 5 /* Default Energy Saver settings for IOPMCopyPMPreferences * * AC */ #define kACMinutesToDim 5 #define kACMinutesToSpin 10 #define kACMinutesToSleep 10 #define kACWakeOnRing 0 #define kACAutomaticRestart 0 #define kACWakeOnLAN 1 #define kACReduceProcessorSpeed 0 #define kACDynamicPowerStep 1 #define kACSleepOnPowerButton 1 #define kACWakeOnClamshell 1 #define kACWakeOnACChange 0 #define kACReduceBrightness 0 #define kACDisplaySleepUsesDim 1 #define kACMobileMotionModule 1 /* * Battery */ #define kBatteryMinutesToDim 5 #define kBatteryMinutesToSpin 5 #define kBatteryMinutesToSleep 5 #define kBatteryWakeOnRing 0 #define kBatteryAutomaticRestart 0 #define kBatteryWakeOnLAN 0 #define kBatteryReduceProcessorSpeed 0 #define kBatteryDynamicPowerStep 1 #define kBatterySleepOnPowerButton 0 #define kBatteryWakeOnClamshell 1 #define kBatteryWakeOnACChange 0 #define kBatteryReduceBrightness 1 #define kBatteryDisplaySleepUsesDim 1 #define kBatteryMobileMotionModule 1 /* * UPS */ #define kUPSMinutesToDim kACMinutesToDim #define kUPSMinutesToSpin kACMinutesToSpin #define kUPSMinutesToSleep kACMinutesToSleep #define kUPSWakeOnRing kACWakeOnRing #define kUPSAutomaticRestart kACAutomaticRestart #define kUPSWakeOnLAN kACWakeOnLAN #define kUPSReduceProcessorSpeed kACReduceProcessorSpeed #define kUPSDynamicPowerStep kACDynamicPowerStep #define kUPSSleepOnPowerButton kACSleepOnPowerButton #define kUPSWakeOnClamshell kACWakeOnClamshell #define kUPSWakeOnACChange kACWakeOnACChange #define kUPSReduceBrightness kACReduceBrightness #define kUPSDisplaySleepUsesDim kACDisplaySleepUsesDim #define kUPSMobileMotionModule kACMobileMotionModule #define kIOHibernateDefaultFile "/var/vm/sleepimage" enum { kIOHibernateMinFreeSpace = 750*1024ULL*1024ULL }; /* 750Mb */ #define kIOPMNumPMFeatures 15 static char *energy_features_array[kIOPMNumPMFeatures] = { kIOPMDisplaySleepKey, kIOPMDiskSleepKey, kIOPMSystemSleepKey, kIOPMWakeOnRingKey, kIOPMRestartOnPowerLossKey, kIOPMWakeOnLANKey, kIOPMReduceSpeedKey, kIOPMDynamicPowerStepKey, kIOPMSleepOnPowerButtonKey, kIOPMWakeOnClamshellKey, kIOPMWakeOnACChangeKey, kIOPMReduceBrightnessKey, kIOPMDisplaySleepUsesDimKey, kIOPMMobileMotionModuleKey, kIOHibernateModeKey }; static const unsigned int battery_defaults_array[] = { kBatteryMinutesToDim, kBatteryMinutesToSpin, kBatteryMinutesToSleep, kBatteryWakeOnRing, kBatteryAutomaticRestart, kBatteryWakeOnLAN, kBatteryReduceProcessorSpeed, kBatteryDynamicPowerStep, kBatterySleepOnPowerButton, kBatteryWakeOnClamshell, kBatteryWakeOnACChange, kBatteryReduceBrightness, kBatteryDisplaySleepUsesDim, kBatteryMobileMotionModule, kIOHibernateModeOn | kIOHibernateModeSleep /* safe sleep mode */ }; static const unsigned int ac_defaults_array[] = { kACMinutesToDim, kACMinutesToSpin, kACMinutesToSleep, kACWakeOnRing, kACAutomaticRestart, kACWakeOnLAN, kACReduceProcessorSpeed, kACDynamicPowerStep, kACSleepOnPowerButton, kACWakeOnClamshell, kACWakeOnACChange, kACReduceBrightness, kACDisplaySleepUsesDim, kACMobileMotionModule, kIOHibernateModeOn | kIOHibernateModeSleep /* safe sleep mode */ }; static const unsigned int ups_defaults_array[] = { kUPSMinutesToDim, kUPSMinutesToSpin, kUPSMinutesToSleep, kUPSWakeOnRing, kUPSAutomaticRestart, kUPSWakeOnLAN, kUPSReduceProcessorSpeed, kUPSDynamicPowerStep, kUPSSleepOnPowerButton, kUPSWakeOnClamshell, kUPSWakeOnACChange, kUPSReduceBrightness, kUPSDisplaySleepUsesDim, kUPSMobileMotionModule, kIOHibernateModeOn | kIOHibernateModeSleep /* safe sleep mode */ }; /* IOPMRootDomain property keys for default settings */ #define kIOPMSystemDefaultProfilesKey "SystemPowerProfiles" #define kIOPMSystemDefaultOverrideKey "SystemPowerProfileOverrideDict" /* Keys for Cheetah Energy Settings shim */ #define kCheetahDimKey CFSTR("MinutesUntilDisplaySleeps") #define kCheetahDiskKey CFSTR("MinutesUntilHardDiskSleeps") #define kCheetahSleepKey CFSTR("MinutesUntilSystemSleeps") #define kCheetahRestartOnPowerLossKey CFSTR("RestartOnPowerLoss") #define kCheetahWakeForNetworkAccessKey CFSTR("WakeForNetworkAdministrativeAccess") #define kCheetahWakeOnRingKey CFSTR("WakeOnRing") // Supported Feature bitfields for IOPMrootDomain Supported Features enum { kIOPMSupportedOnAC = 1<<0, kIOPMSupportedOnBatt = 1<<1, kIOPMSupportedOnUPS = 1<<2 }; // Forwards static CFArrayRef _createDefaultSystemProfiles(); /* IOPMAggressivenessFactors * * The form of data that the kernel understands. */ typedef struct { unsigned int fMinutesToDim; unsigned int fMinutesToSpin; unsigned int fMinutesToSleep; unsigned int fWakeOnLAN; unsigned int fWakeOnRing; unsigned int fAutomaticRestart; unsigned int fSleepOnPowerButton; unsigned int fWakeOnClamshell; unsigned int fWakeOnACChange; unsigned int fDisplaySleepUsesDimming; unsigned int fMobileMotionModule; } IOPMAggressivenessFactors; Boolean _IOReadBytesFromFile(CFAllocatorRef alloc, const char *path, void **bytes, CFIndex *length, CFIndex maxLength); static int getDefaultEnergySettings(CFMutableDictionaryRef sys) { CFMutableDictionaryRef batt = NULL; CFMutableDictionaryRef ac = NULL; CFMutableDictionaryRef ups = NULL; int i; CFNumberRef val; CFStringRef key; batt=(CFMutableDictionaryRef)CFDictionaryGetValue(sys, CFSTR(kIOPMBatteryPowerKey)); ac=(CFMutableDictionaryRef)CFDictionaryGetValue(sys, CFSTR(kIOPMACPowerKey)); ups=(CFMutableDictionaryRef)CFDictionaryGetValue(sys, CFSTR(kIOPMUPSPowerKey)); /* * Note that in the following "poplulation" loops, we're using CFDictionaryAddValue rather * than CFDictionarySetValue. If a value is already present AddValue will not replace it. */ /* * Populate default battery dictionary */ if(batt) { for(i=0; i= filesize) haveFile = true; else createFile = true; } else break; } else createFile = true; if (createFile) { do { char * patchpath, save = 0; struct statfs sfs; u_int64_t fsfree; fd = -1; /* * get rid of the filename at the end of the file specification * we only want the portion of the pathname that should already exist */ if ((patchpath = strrchr(path, '/'))) { save = *patchpath; *patchpath = 0; } if (-1 == statfs(path, &sfs)) break; fsfree = ((u_int64_t)sfs.f_bfree * (u_int64_t)sfs.f_bsize); if ((fsfree - filesize) < kIOHibernateMinFreeSpace) break; if (patchpath) *patchpath = save; fd = open(path, O_CREAT | O_TRUNC | O_RDWR); if (-1 == fd) break; if (-1 == fchmod(fd, 01600)) break; prealloc.fst_flags = F_ALLOCATEALL; // F_ALLOCATECONTIG prealloc.fst_posmode = F_PEOFPOSMODE; prealloc.fst_offset = 0; prealloc.fst_length = filesize; if (((-1 == fcntl(fd, F_PREALLOCATE, (int) &prealloc)) || (-1 == fcntl(fd, F_SETSIZE, &prealloc.fst_length))) && (-1 == ftruncate(fd, prealloc.fst_length))) break; haveFile = true; } while (false); if (-1 != fd) { close(fd); if (!haveFile) unlink(path); } } if (!haveFile) break; #ifdef __i386__ #define kBootXPath "/System/Library/CoreServices/boot.efi" #define kBootXSignaturePath "/System/Library/Caches/com.apple.bootefisignature" #else #define kBootXPath "/System/Library/CoreServices/BootX" #define kBootXSignaturePath "/System/Library/Caches/com.apple.bootxsignature" #endif #define kCachesPath "/System/Library/Caches" #define kGenSignatureCommand "/bin/cat " kBootXPath " | /usr/bin/openssl dgst -sha1 -hex -out " kBootXSignaturePath struct stat bootx_stat_buf; struct stat bootsignature_stat_buf; if (0 != stat(kBootXPath, &bootx_stat_buf)) break; if ((0 != stat(kBootXSignaturePath, &bootsignature_stat_buf)) || (bootsignature_stat_buf.st_mtime != bootx_stat_buf.st_mtime)) { if (-1 == stat(kCachesPath, &bootsignature_stat_buf)) { mkdir(kCachesPath, 0777); chmod(kCachesPath, 0777); } // generate signature file if (0 != system(kGenSignatureCommand)) break; // set mod time to that of source struct timeval fileTimes[2]; TIMESPEC_TO_TIMEVAL(&fileTimes[0], &bootx_stat_buf.st_atimespec); TIMESPEC_TO_TIMEVAL(&fileTimes[1], &bootx_stat_buf.st_mtimespec); if ((0 != utimes(kBootXSignaturePath, fileTimes))) break; } // send signature to kernel CFAllocatorRef alloc; void * sigBytes; CFIndex sigLen; alloc = CFRetain(CFAllocatorGetDefault()); if (_IOReadBytesFromFile(alloc, kBootXSignaturePath, &sigBytes, &sigLen, 0)) ret = sysctlbyname("kern.bootsignature", NULL, NULL, sigBytes, sigLen); else ret = -1; CFAllocatorDeallocate(alloc, sigBytes); CFRelease(alloc); if (0 != ret) break; ret = IORegistryEntrySetCFProperty(rootDomain, CFSTR(kIOHibernateFileKey), obj); } while (false); if (modeNum) ret = IORegistryEntrySetCFProperty(rootDomain, CFSTR(kIOHibernateModeKey), modeNum); if ((obj = CFDictionaryGetValue(dict, CFSTR(kIOHibernateFreeRatioKey))) && isA_CFNumber(obj)) { ret = IORegistryEntrySetCFProperty(rootDomain, CFSTR(kIOHibernateFreeRatioKey), obj); } if ((obj = CFDictionaryGetValue(dict, CFSTR(kIOHibernateFreeTimeKey))) && isA_CFNumber(obj)) { ret = IORegistryEntrySetCFProperty(rootDomain, CFSTR(kIOHibernateFreeTimeKey), obj); } if (url) CFRelease(url); return 0; } static int sendEnergySettingsToKernel( CFDictionaryRef System, CFStringRef prof, IOPMAggressivenessFactors *p) { io_registry_entry_t PMRootDomain = MACH_PORT_NULL; io_connect_t PM_connection = MACH_PORT_NULL; CFTypeRef power_source_info = NULL; CFStringRef providing_power = NULL; IOReturn err; IOReturn ret; CFNumberRef number1; CFNumberRef number0; int type; UInt32 i; i = 1; number1 = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &i); i = 0; number0 = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &i); if(!number0 || !number1) return -1; PMRootDomain = getPMRootDomainRef(); if(!PMRootDomain) return -1; PM_connection = IOPMFindPowerManagement(0); if ( !PM_connection ) return -1; // Determine type of power source power_source_info = IOPSCopyPowerSourcesInfo(); if(power_source_info) { providing_power = IOPSGetProvidingPowerSourceType(power_source_info); } type = kPMMinutesToDim; err = IOPMSetAggressiveness(PM_connection, type, p->fMinutesToDim); type = kPMMinutesToSpinDown; err = IOPMSetAggressiveness(PM_connection, type, p->fMinutesToSpin); type = kPMMinutesToSleep; err = IOPMSetAggressiveness(PM_connection, type, p->fMinutesToSleep); // Wake on LAN if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMWakeOnLANKey), providing_power)) { type = kPMEthernetWakeOnLANSettings; err = IOPMSetAggressiveness(PM_connection, type, p->fWakeOnLAN); } else { // Even if WakeOnLAN is reported as not supported, broadcast 0 as // value. We may be on a supported machine, just on battery power. // Wake on LAN is not supported on battery power on PPC hardware. type = kPMEthernetWakeOnLANSettings; err = IOPMSetAggressiveness(PM_connection, type, 0); } // Display Sleep Uses Dim if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMDisplaySleepUsesDimKey), providing_power)) { type = kIODisplayDimAggressiveness; err = IOPMSetAggressiveness(PM_connection, type, p->fDisplaySleepUsesDimming); } // Wake On Ring if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMWakeOnRingKey), providing_power)) { ret = IORegistryEntrySetCFProperty(PMRootDomain, CFSTR(kIOPMSettingWakeOnRingKey), (p->fWakeOnRing?number1:number0)); } // Automatic Restart On Power Loss, aka FileServer mode if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMRestartOnPowerLossKey), providing_power)) { ret = IORegistryEntrySetCFProperty(PMRootDomain, CFSTR(kIOPMSettingRestartOnPowerLossKey), (p->fAutomaticRestart?number1:number0)); } // Wake on change of AC state -- battery to AC or vice versa if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMWakeOnACChangeKey), providing_power)) { ret = IORegistryEntrySetCFProperty(PMRootDomain, CFSTR(kIOPMSettingWakeOnACChangeKey), (p->fWakeOnACChange?number1:number0)); } // Disable power button sleep on PowerMacs, Cubes, and iMacs // Default is false == power button causes sleep if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMSleepOnPowerButtonKey), providing_power)) { ret = IORegistryEntrySetCFProperty(PMRootDomain, CFSTR(kIOPMSettingSleepOnPowerButtonKey), (p->fSleepOnPowerButton?kCFBooleanFalse:kCFBooleanTrue)); } // Wakeup on clamshell open // Default is true == wakeup when the clamshell opens if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMWakeOnClamshellKey), providing_power)) { ret = IORegistryEntrySetCFProperty(PMRootDomain, CFSTR(kIOPMSettingWakeOnClamshellKey), (p->fWakeOnClamshell?number1:number0)); } // Mobile Motion Module // Defaults to on if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMMobileMotionModuleKey), providing_power)) { type = 7; // kPMMotionSensor defined in Tiger IOPMSetAggressiveness(PM_connection, type, p->fMobileMotionModule); } CFDictionaryRef dict = NULL; if((dict = CFDictionaryGetValue(System, prof)) ) { ProcessHibernateSettings(dict, PMRootDomain); } /* PowerStep and Reduce Processor Speed are handled by a separate configd plugin that's watching the SCDynamicStore key State:/IOKit/PowerManagement/CurrentSettings. Changes to the settings notify the configd plugin, which then activates th processor speed settings. Note that IOPMActivatePMPreference updates that key in the SCDynamicStore when we activate new settings. See DynamicPowerStep configd plugin. A separate display manager process handles activating the Reduce Brightness key through the same mechanism desribed above for Reduce Process & Dynamic Power Step. */ CFRelease(number0); CFRelease(number1); if(power_source_info) CFRelease(power_source_info); IOServiceClose(PM_connection); IOObjectRelease(PMRootDomain); return 0; } static void GetAggressivenessValue( CFTypeRef obj, CFNumberType type, unsigned int *ret) { *ret = 0; if (isA_CFNumber(obj)) { CFNumberGetValue(obj, type, ret); return; } else if (isA_CFBoolean(obj)) { *ret = CFBooleanGetValue(obj); return; } } /* For internal use only */ static int getAggressivenessFactorsFromProfile( CFDictionaryRef System, CFStringRef prof, IOPMAggressivenessFactors *agg) { CFDictionaryRef p = NULL; if( !(p = CFDictionaryGetValue(System, prof)) ) { return -1; } if(!agg) return -1; /* * Extract battery settings into s->battery */ // dim GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMDisplaySleepKey)), kCFNumberSInt32Type, &agg->fMinutesToDim); // spin down GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMDiskSleepKey)), kCFNumberSInt32Type, &agg->fMinutesToSpin); // sleep GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMSystemSleepKey)), kCFNumberSInt32Type, &agg->fMinutesToSleep); // Wake On Magic Packet GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMWakeOnLANKey)), kCFNumberSInt32Type, &agg->fWakeOnLAN); // Wake On Ring GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMWakeOnRingKey)), kCFNumberSInt32Type, &agg->fWakeOnRing); // AutomaticRestartOnPowerLoss GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMRestartOnPowerLossKey)), kCFNumberSInt32Type, &agg->fAutomaticRestart); // Disable Power Button Sleep GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMSleepOnPowerButtonKey)), kCFNumberSInt32Type, &agg->fSleepOnPowerButton); // Disable Clamshell Wakeup GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMWakeOnClamshellKey)), kCFNumberSInt32Type, &agg->fWakeOnClamshell); // Wake on AC Change GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMWakeOnACChangeKey)), kCFNumberSInt32Type, &agg->fWakeOnACChange); // Disable intermediate dimming stage for display sleep GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMDisplaySleepUsesDimKey)), kCFNumberSInt32Type, &agg->fDisplaySleepUsesDimming); // MMM GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMMobileMotionModuleKey)), kCFNumberSInt32Type, &agg->fMobileMotionModule); return 0; } /* Maps a PowerManagement string constant * -> to its corresponding Supported Feature in IOPMrootDomain */ static CFStringRef supportedNameForPMName( CFStringRef pm_name ) { if(CFEqual(pm_name, CFSTR(kIOPMDisplaySleepUsesDimKey))) { return CFSTR("DisplayDims"); } if(CFEqual(pm_name, CFSTR(kIOPMWakeOnLANKey))) { return CFSTR("WakeOnMagicPacket"); } if(CFEqual(pm_name, CFSTR(kIOPMMobileMotionModuleKey))) { return CFSTR("MobileMotionModule"); } if( CFEqual(pm_name, CFSTR(kIOHibernateModeKey)) || CFEqual(pm_name, CFSTR(kIOHibernateFreeRatioKey)) || CFEqual(pm_name, CFSTR(kIOHibernateFreeTimeKey)) || CFEqual(pm_name, CFSTR(kIOHibernateFileKey))) { return CFSTR(kIOHibernateFeatureKey); } if( CFEqual(pm_name, CFSTR(kIOPMReduceSpeedKey)) || CFEqual(pm_name, CFSTR(kIOPMDynamicPowerStepKey)) || CFEqual(pm_name, CFSTR(kIOPMWakeOnRingKey)) || CFEqual(pm_name, CFSTR(kIOPMRestartOnPowerLossKey)) || CFEqual(pm_name, CFSTR(kIOPMWakeOnACChangeKey)) || CFEqual(pm_name, CFSTR(kIOPMWakeOnClamshellKey)) || CFEqual(pm_name, CFSTR(kIOPMReduceBrightnessKey)) ) { return pm_name; } return NULL; } // Helper for IOPMFeatureIsAvailable static bool featureSupportsPowerSource(CFTypeRef featureDetails, CFStringRef power_source) { CFNumberRef featureNum = NULL; CFNumberRef tempNum = NULL; CFArrayRef featureArr = NULL; uint32_t ps_support = 0; uint32_t tmp; unsigned int i; if(!power_source) { // Lack of a defined power source just gets a "true" return // if the setting is supported on ANY power source. return true; } if( (featureNum = isA_CFNumber(featureDetails)) ) { CFNumberGetValue(featureNum, kCFNumberSInt32Type, &ps_support); } else if( (featureArr = isA_CFArray(featureDetails)) ) { // If several entitites are asserting a given feature, we OR // together their supported power sources. unsigned int arrayCount = CFArrayGetCount(featureArr); for(i = 0; i= 0) { if(kCFBooleanTrue != IOPSPowerSourceSupported(ps_snapshot, profile_keys[profile_count])) { // Remove dictionary if the whole power source isn't supported on this machine. CFDictionaryRemoveValue(energyPrefs, profile_keys[profile_count]); } else { // Make a mutable copy of the prefs dictionary this_profile = (CFMutableDictionaryRef)isA_CFDictionary( CFDictionaryGetValue(energyPrefs, profile_keys[profile_count])); if(!this_profile) continue; this_profile = CFDictionaryCreateMutableCopy(NULL, 0, this_profile); if(!this_profile) continue; CFDictionarySetValue(energyPrefs, profile_keys[profile_count], this_profile); CFRelease(this_profile); // And prune unneeded settings from our new mutable property dict_count = CFDictionaryGetCount(this_profile); dict_keys = (CFStringRef *)malloc(sizeof(CFStringRef) * dict_count); dict_vals = (CFDictionaryRef *)malloc(sizeof(CFDictionaryRef) * dict_count); if(!dict_keys || !dict_vals) continue; CFDictionaryGetKeysAndValues(this_profile, (const void **)dict_keys, (const void **)dict_vals); // For each specific property within each dictionary while(--dict_count >= 0) { if( !IOPMFeatureIsAvailable((CFStringRef)dict_keys[dict_count], (CFStringRef)profile_keys[profile_count]) ) { // If the property isn't supported, remove it CFDictionaryRemoveValue(this_profile, (CFStringRef)dict_keys[dict_count]); } } free(dict_keys); free(dict_vals); } } free(profile_keys); free(profile_vals); if(ps_snapshot) CFRelease(ps_snapshot); return; } /*** * getCheetahPumaEnergySettings * * Reads the old Energy Saver preferences file from /Library/Preferences/com.apple.PowerManagement.xml * ***/ static int getCheetahPumaEnergySettings(CFMutableDictionaryRef energyPrefs) { SCPreferencesRef CheetahPrefs = NULL; CFMutableDictionaryRef s = NULL; CFNumberRef n; CFBooleanRef b; if(!energyPrefs) return 0; CheetahPrefs = SCPreferencesCreate (kCFAllocatorDefault, CFSTR("I/O Kit PM Library"), CFSTR("/Library/Preferences/com.apple.PowerManagement.plist")); if(!CheetahPrefs) return 0; s = (CFMutableDictionaryRef)CFDictionaryGetValue(energyPrefs, CFSTR(kIOPMBatteryPowerKey)); if(!s) { CFRelease(CheetahPrefs); return 0; } n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahDimKey); if(n) CFDictionaryAddValue(s, CFSTR(kIOPMDisplaySleepKey), n); n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahDiskKey); if(n) CFDictionaryAddValue(s, CFSTR(kIOPMDiskSleepKey), n); n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahSleepKey); if(n) CFDictionaryAddValue(s, CFSTR(kIOPMSystemSleepKey), n); b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahRestartOnPowerLossKey); if(b) CFDictionaryAddValue(s, CFSTR(kIOPMRestartOnPowerLossKey), b); b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahWakeForNetworkAccessKey); if(b) CFDictionaryAddValue(s, CFSTR(kIOPMWakeOnLANKey), b); b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahWakeOnRingKey); if(b) CFDictionaryAddValue(s, CFSTR(kIOPMWakeOnRingKey), b); s = (CFMutableDictionaryRef)CFDictionaryGetValue(energyPrefs, CFSTR(kIOPMACPowerKey)); if(!s) { CFRelease(CheetahPrefs); return 0; } n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahDimKey); if(n) CFDictionaryAddValue(s, CFSTR(kIOPMDisplaySleepKey), n); n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahDiskKey); if(n) CFDictionaryAddValue(s, CFSTR(kIOPMDiskSleepKey), n); n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahSleepKey); if(n) CFDictionaryAddValue(s, CFSTR(kIOPMSystemSleepKey), n); b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahRestartOnPowerLossKey); if(b) CFDictionaryAddValue(s, CFSTR(kIOPMRestartOnPowerLossKey), b); b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahWakeForNetworkAccessKey); if(b) CFDictionaryAddValue(s, CFSTR(kIOPMWakeOnLANKey), b); b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahWakeOnRingKey); if(b) CFDictionaryAddValue(s, CFSTR(kIOPMWakeOnRingKey), b); CFRelease(CheetahPrefs); return 1; // success } /************************************************** * * Energy Saver Preferences * **************************************************/ CFMutableDictionaryRef IOPMCopyPMPreferences(void) { CFMutableDictionaryRef energyDict = NULL; CFDictionaryRef tmp_dict = NULL; SCPreferencesRef energyPrefs = NULL; CFDictionaryRef tmp = NULL; CFMutableDictionaryRef batterySettings = NULL; CFMutableDictionaryRef ACSettings = NULL; CFMutableDictionaryRef UPSSettings = NULL; bool usingDefaults = true; energyPrefs = SCPreferencesCreate( kCFAllocatorDefault, kIOPMAppName, kIOPMPrefsPath ); if(!energyPrefs) { return NULL; } // Attempt to read battery & AC settings tmp_dict = isA_CFDictionary(SCPreferencesGetValue(energyPrefs, CFSTR("Custom Profile"))); // If com.apple.PowerManagement.xml opened correctly, read data from it if(tmp_dict) { usingDefaults = false; // Tiger preferences file format energyDict = CFDictionaryCreateMutableCopy( kCFAllocatorDefault, 0, tmp_dict); if(!energyDict) goto failure_exit; } else { // Try Panther/Jaguar prefs formats batterySettings = (CFMutableDictionaryRef)isA_CFDictionary( SCPreferencesGetValue(energyPrefs, CFSTR(kIOPMBatteryPowerKey))); ACSettings = (CFMutableDictionaryRef)isA_CFDictionary( SCPreferencesGetValue(energyPrefs, CFSTR(kIOPMACPowerKey))); UPSSettings = (CFMutableDictionaryRef)isA_CFDictionary( SCPreferencesGetValue(energyPrefs, CFSTR(kIOPMUPSPowerKey))); if(batterySettings || ACSettings || UPSSettings) usingDefaults = false; energyDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if(!energyDict) goto failure_exit; if(batterySettings) CFDictionaryAddValue(energyDict, CFSTR(kIOPMBatteryPowerKey), batterySettings); if(ACSettings) CFDictionaryAddValue(energyDict, CFSTR(kIOPMACPowerKey), ACSettings); if(UPSSettings) CFDictionaryAddValue(energyDict, CFSTR(kIOPMUPSPowerKey), UPSSettings); } // Make sure that the enclosed dictionaries are all mutable tmp = isA_CFDictionary(CFDictionaryGetValue(energyDict, CFSTR(kIOPMBatteryPowerKey))); if(tmp) batterySettings = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, tmp); else batterySettings = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if(batterySettings) { CFDictionarySetValue(energyDict, CFSTR(kIOPMBatteryPowerKey), batterySettings); CFRelease(batterySettings); } else goto failure_exit; tmp = isA_CFDictionary(CFDictionaryGetValue(energyDict, CFSTR(kIOPMACPowerKey))); if(tmp) ACSettings = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, tmp); else ACSettings = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if(ACSettings) { CFDictionarySetValue(energyDict, CFSTR(kIOPMACPowerKey), ACSettings); CFRelease(ACSettings); } else goto failure_exit; tmp = isA_CFDictionary(CFDictionaryGetValue(energyDict, CFSTR(kIOPMUPSPowerKey))); if(tmp) UPSSettings = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, tmp); else UPSSettings = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if(UPSSettings) { CFDictionarySetValue(energyDict, CFSTR(kIOPMUPSPowerKey), UPSSettings); CFRelease(UPSSettings); } else goto failure_exit; // INVARIANT: At this point we want a mutable dictionary energyDict // containing 3 mutable preferences dictionaries that are either empty or contain some settings. // Check for existence of Puma/Cheetah prefs format // And add settings defined there if present getCheetahPumaEnergySettings(energyDict); // Fill in any undefined settings with our defaults // i.e. if no current or legacy prefs files exist, getDefaultEnergySettings() // completely populates the default EnergySaver preferences. getDefaultEnergySettings(energyDict); // Remove any unsupported key/value pairs (including some of // those we just added in getDefaultEnergySettings) IOPMRemoveIrrelevantProperties(energyDict); if(usingDefaults) { // If we couldn't find any user-specified settings on disk, tag this dictionary as // "Defaults" so that BatteryMonitor and EnergySaver can tell these are user-selected // values or just the system defaults. CFDictionarySetValue(energyDict, CFSTR(kIOPMDefaultPreferencesKey), kCFBooleanTrue); } //normal_exit: if(energyPrefs) CFRelease(energyPrefs); return energyDict; failure_exit: if(energyPrefs) CFRelease(energyPrefs); if(energyDict) CFRelease(energyDict); return 0; } // TODO: Migrate this into PM daemon IOReturn IOPMActivatePMPreference(CFDictionaryRef SystemProfiles, CFStringRef profile) { IOPMAggressivenessFactors *agg = NULL; CFDictionaryRef activePMPrefs = NULL; CFDictionaryRef newPMPrefs = NULL; SCDynamicStoreRef dynamic_store = NULL; if(0 == isA_CFDictionary(SystemProfiles) || 0 == isA_CFString(profile)) { return kIOReturnBadArgument; } // Activate settings by sending them to the kernel agg = (IOPMAggressivenessFactors *)malloc(sizeof(IOPMAggressivenessFactors)); getAggressivenessFactorsFromProfile(SystemProfiles, profile, agg); sendEnergySettingsToKernel(SystemProfiles, profile, agg); free(agg); // Put the new settings in the SCDynamicStore for interested apps dynamic_store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("IOKit User Library"), NULL, NULL); if(dynamic_store == NULL) return kIOReturnError; activePMPrefs = isA_CFDictionary(SCDynamicStoreCopyValue(dynamic_store, CFSTR(kIOPMDynamicStoreSettingsKey))); newPMPrefs = isA_CFDictionary(CFDictionaryGetValue(SystemProfiles, profile)); // If there isn't currently a value for kIOPMDynamicStoreSettingsKey // or the current value is different than the new value if( !activePMPrefs || (newPMPrefs && !CFEqual(activePMPrefs, newPMPrefs)) ) { // Then set the kIOPMDynamicStoreSettingsKey to the new value SCDynamicStoreSetValue(dynamic_store, CFSTR(kIOPMDynamicStoreSettingsKey), newPMPrefs); } if(activePMPrefs) CFRelease(activePMPrefs); CFRelease(dynamic_store); return kIOReturnSuccess; } // Sets (and activates) Custom power profile IOReturn IOPMSetPMPreferences(CFDictionaryRef ESPrefs) { IOReturn ret = kIOReturnError; SCPreferencesRef energyPrefs = NULL; energyPrefs = SCPreferencesCreate( kCFAllocatorDefault, kIOPMAppName, kIOPMPrefsPath ); if(!energyPrefs) return kIOReturnError; if(!SCPreferencesLock(energyPrefs, true)) { // handle error if(kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged; else ret = kIOReturnError; goto exit; } if(!SCPreferencesSetValue(energyPrefs, CFSTR("Custom Profile"), ESPrefs)) { ret = kIOReturnError; goto exit; } // If older profiles exist, remove them in favor of the new format SCPreferencesRemoveValue(energyPrefs, CFSTR(kIOPMACPowerKey)); SCPreferencesRemoveValue(energyPrefs, CFSTR(kIOPMBatteryPowerKey)); SCPreferencesRemoveValue(energyPrefs, CFSTR(kIOPMUPSPowerKey)); if(!SCPreferencesCommitChanges(energyPrefs)) { // handle error if(kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged; else ret = kIOReturnError; goto exit; } if(!SCPreferencesApplyChanges(energyPrefs)) { // handle error if(kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged; else ret = kIOReturnError; goto exit; } ret = kIOReturnSuccess; exit: if(energyPrefs) { SCPreferencesUnlock(energyPrefs); CFRelease(energyPrefs); } return ret; } /************************************************** * * Power Profiles * * **************************************************/ static void mergeDictIntoMutable( CFMutableDictionaryRef target, CFDictionaryRef overrides) { const CFStringRef *keys; const CFTypeRef *objs; int count; int i; count = CFDictionaryGetCount(overrides); if(0 == count) return; keys = (CFStringRef *)malloc(sizeof(CFStringRef) * count); objs = (CFTypeRef *)malloc(sizeof(CFTypeRef) * count); if(!keys || !objs) return; CFDictionaryGetKeysAndValues(overrides, (const void **)keys, (const void **)objs); for(i=0; i= kIOPMNumPowerProfiles) return 0; // Battery value optional val = CFDictionaryGetValue(p, CFSTR(kIOPMBatteryPowerKey)); if(val) { CFNumberGetValue(val, kCFNumberIntType, &j); if(j<-1 || j>= kIOPMNumPowerProfiles) return 0; } // UPS value optional val = CFDictionaryGetValue(p, CFSTR(kIOPMUPSPowerKey)); if(val) { CFNumberGetValue(val, kCFNumberIntType, &j); if(j<-1 || j>= kIOPMNumPowerProfiles) return 0; } return 1; } static void _purgeUnsupportedPowerSources(CFMutableDictionaryRef p) { CFStringRef *ps_names = NULL; CFTypeRef ps_snap = NULL; int count; int i; ps_snap = IOPSCopyPowerSourcesInfo(); if(!ps_snap) return; count = CFDictionaryGetCount(p); ps_names = (CFStringRef *)malloc(count*sizeof(CFStringRef)); if(!ps_names) goto exit; CFDictionaryGetKeysAndValues(p, (CFTypeRef *)ps_names, NULL); for(i=0; icallback; if(!cb) return; // Execute callback (*cb)(c->context); } /*** Returns a CFRunLoopSourceRef that notifies the caller when power source information changes. Arguments: IOPowerSourceCallbackType callback - A function to be called whenever ES prefs file on disk changes void *context - Any user-defined pointer, passed to the IOPowerSource callback. Returns NULL if there were any problems. Caller must CFRelease() the returned value. ***/ CFRunLoopSourceRef IOPMPrefsNotificationCreateRunLoopSource(IOPMPrefsCallbackType callback, void *context) { SCDynamicStoreRef store = NULL; CFStringRef EnergyPrefsKey = NULL; CFRunLoopSourceRef SCDrls = NULL; user_callback_context *ioContext = NULL; SCDynamicStoreContext scContext = {0, NULL, CFRetain, CFRelease, NULL}; if(!callback) return NULL; scContext.info = CFDataCreateMutable(NULL, sizeof(user_callback_context)); CFDataSetLength(scContext.info, sizeof(user_callback_context)); ioContext = (user_callback_context *)CFDataGetBytePtr(scContext.info); ioContext->context = context; ioContext->callback = callback; // Open connection to SCDynamicStore. User's callback as context. store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("IOKit Preferences Copy"), ioCallout, (void *)&scContext); if(!store) return NULL; // Setup notification for changes in Energy Saver prefences EnergyPrefsKey = SCDynamicStoreKeyCreatePreferences( NULL, kIOPMPrefsPath, kSCPreferencesKeyApply); if(EnergyPrefsKey) { SCDynamicStoreAddWatchedKey(store, EnergyPrefsKey, FALSE); CFRelease(EnergyPrefsKey); } // Obtain the CFRunLoopSourceRef from this SCDynamicStoreRef session SCDrls = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault, store, 0); CFRelease(store); return SCDrls; }