#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCValidation.h>
#include <SystemConfiguration/SCPreferencesPrivate.h>
#include <SystemConfiguration/SCDynamicStorePrivate.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/pwr_mgt/IOPM.h>
#include <IOKit/ps/IOPowerSources.h>
#include <IOKit/ps/IOPowerSourcesPrivate.h>
#include <IOKit/IOCFSerialize.h>
#include <IOKit/IOHibernatePrivate.h>
#include <servers/bootstrap.h>
#include <sys/syslog.h>
#include "IOPMLib.h"
#include "IOPMLibPrivate.h"
#include "powermanagement.h"
#include <IOKit/IOKitLib.h>
#include <IOKit/IOBSD.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/mount.h>
#define kIOPMPrefsPath CFSTR("com.apple.PowerManagement.xml")
#define kIOPMAppName CFSTR("PowerManagement configd")
#ifndef kIODisplayDimAggressiveness
#define kIODisplayDimAggressiveness iokit_family_err(sub_iokit_graphics, 3)
#endif
#define kIOPMNumPMProfiles 5
#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
#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
#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 };
#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
};
static const unsigned int ac_defaults_array[] = {
kACMinutesToDim,
kACMinutesToSpin,
kACMinutesToSleep,
kACWakeOnRing,
kACAutomaticRestart,
kACWakeOnLAN,
kACReduceProcessorSpeed,
kACDynamicPowerStep,
kACSleepOnPowerButton,
kACWakeOnClamshell,
kACWakeOnACChange,
kACReduceBrightness,
kACDisplaySleepUsesDim,
kACMobileMotionModule,
kIOHibernateModeOn | kIOHibernateModeSleep
};
static const unsigned int ups_defaults_array[] = {
kUPSMinutesToDim,
kUPSMinutesToSpin,
kUPSMinutesToSleep,
kUPSWakeOnRing,
kUPSAutomaticRestart,
kUPSWakeOnLAN,
kUPSReduceProcessorSpeed,
kUPSDynamicPowerStep,
kUPSSleepOnPowerButton,
kUPSWakeOnClamshell,
kUPSWakeOnACChange,
kUPSReduceBrightness,
kUPSDisplaySleepUsesDim,
kUPSMobileMotionModule,
kIOHibernateModeOn | kIOHibernateModeSleep
};
#define kIOPMSystemDefaultProfilesKey "SystemPowerProfiles"
#define kIOPMSystemDefaultOverrideKey "SystemPowerProfileOverrideDict"
#define kCheetahDimKey CFSTR("MinutesUntilDisplaySleeps")
#define kCheetahDiskKey CFSTR("MinutesUntilHardDiskSleeps")
#define kCheetahSleepKey CFSTR("MinutesUntilSystemSleeps")
#define kCheetahRestartOnPowerLossKey CFSTR("RestartOnPowerLoss")
#define kCheetahWakeForNetworkAccessKey CFSTR("WakeForNetworkAdministrativeAccess")
#define kCheetahWakeOnRingKey CFSTR("WakeOnRing")
static CFArrayRef _createDefaultSystemProfiles();
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));
if(batt) {
for(i=0; i<kIOPMNumPMFeatures; i++)
{
key = CFStringCreateWithCString(kCFAllocatorDefault, energy_features_array[i], kCFStringEncodingMacRoman);
val = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &battery_defaults_array[i]);
CFDictionaryAddValue(batt, key, val);
CFRelease(key);
CFRelease(val);
}
CFDictionaryAddValue(batt, CFSTR(kIOHibernateFileKey), CFSTR(kIOHibernateDefaultFile));
CFDictionarySetValue(sys, CFSTR(kIOPMBatteryPowerKey), batt);
}
if(ac)
{
for(i=0; i<kIOPMNumPMFeatures; i++)
{
key = CFStringCreateWithCString(kCFAllocatorDefault, energy_features_array[i], kCFStringEncodingMacRoman);
val = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ac_defaults_array[i]);
CFDictionaryAddValue(ac, key, val);
CFRelease(key);
CFRelease(val);
}
CFDictionaryAddValue(ac, CFSTR(kIOHibernateFileKey), CFSTR(kIOHibernateDefaultFile));
CFDictionarySetValue(sys, CFSTR(kIOPMACPowerKey), ac);
}
if(ups) {
for(i=0; i<kIOPMNumPMFeatures; i++)
{
key = CFStringCreateWithCString(kCFAllocatorDefault, energy_features_array[i], kCFStringEncodingMacRoman);
val = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ups_defaults_array[i]);
CFDictionaryAddValue(ups, key, val);
CFRelease(key);
CFRelease(val);
}
CFDictionaryAddValue(ups, CFSTR(kIOHibernateFileKey), CFSTR(kIOHibernateDefaultFile));
CFDictionarySetValue(sys, CFSTR(kIOPMUPSPowerKey), ups);
}
return 0;
}
static io_registry_entry_t getPMRootDomainRef(void)
{
io_registry_entry_t registry_entry;
io_iterator_t tmp;
IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceNameMatching("IOPMrootDomain"), &tmp);
registry_entry = IOIteratorNext(tmp);
IOObjectRelease(tmp);
return registry_entry;
}
static int
ProcessHibernateSettings(CFDictionaryRef dict, io_registry_entry_t rootDomain)
{
IOReturn ret;
CFTypeRef obj;
CFURLRef url = NULL;
Boolean createFile = false;
Boolean haveFile = false;
struct stat statBuf;
char path[MAXPATHLEN];
int fd;
long long size;
size_t len;
fstore_t prealloc;
uint64_t filesize;
if ((obj = CFDictionaryGetValue(dict, CFSTR(kIOHibernateFileKey)))
&& isA_CFString(obj))
do
{
url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
obj, kCFURLPOSIXPathStyle, true);
if (!url || !CFURLGetFileSystemRepresentation(url, TRUE, path, MAXPATHLEN))
break;
len = sizeof(size);
if (sysctlbyname("hw.memsize", &size, &len, NULL, 0))
break;
filesize = size;
if (0 == stat(path, &statBuf))
{
if ((S_IFBLK == (S_IFMT & statBuf.st_mode))
|| (S_IFCHR == (S_IFMT & statBuf.st_mode)))
{
haveFile = true;
}
else if (S_IFREG == (S_IFMT & statBuf.st_mode))
{
if (statBuf.st_size >= 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;
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; 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 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 (0 != system(kGenSignatureCommand))
break;
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;
}
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 ((obj = CFDictionaryGetValue(dict, CFSTR(kIOHibernateModeKey)))
&& isA_CFNumber(obj))
{
ret = IORegistryEntrySetCFProperty(rootDomain, CFSTR(kIOHibernateModeKey), obj);
}
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;
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);
if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMWakeOnLANKey), providing_power))
{
type = kPMEthernetWakeOnLANSettings;
err = IOPMSetAggressiveness(PM_connection, type, p->fWakeOnLAN);
} else {
type = kPMEthernetWakeOnLANSettings;
err = IOPMSetAggressiveness(PM_connection, type, 0);
}
if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMDisplaySleepUsesDimKey), NULL))
{
type = kIODisplayDimAggressiveness;
err = IOPMSetAggressiveness(PM_connection, type, p->fDisplaySleepUsesDimming);
}
if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMWakeOnRingKey), NULL))
{
ret = IORegistryEntrySetCFProperty(PMRootDomain,
CFSTR(kIOPMSettingWakeOnRingKey),
(p->fWakeOnRing?number1:number0));
}
if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMRestartOnPowerLossKey), NULL))
{
ret = IORegistryEntrySetCFProperty(PMRootDomain,
CFSTR(kIOPMSettingRestartOnPowerLossKey),
(p->fAutomaticRestart?number1:number0));
}
if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMWakeOnACChangeKey), NULL))
{
ret = IORegistryEntrySetCFProperty(PMRootDomain,
CFSTR(kIOPMSettingWakeOnACChangeKey),
(p->fWakeOnACChange?number1:number0));
}
if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMSleepOnPowerButtonKey), NULL))
{
ret = IORegistryEntrySetCFProperty(PMRootDomain,
CFSTR(kIOPMSettingSleepOnPowerButtonKey),
(p->fSleepOnPowerButton?kCFBooleanFalse:kCFBooleanTrue));
}
if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMWakeOnClamshellKey), NULL))
{
ret = IORegistryEntrySetCFProperty(PMRootDomain,
CFSTR(kIOPMSettingWakeOnClamshellKey),
(p->fWakeOnClamshell?number1:number0));
}
if(true == IOPMFeatureIsAvailable(CFSTR(kIOPMMobileMotionModuleKey), NULL))
{
type = 7; IOPMSetAggressiveness(PM_connection, type, p->fMobileMotionModule);
}
CFDictionaryRef dict = NULL;
if((dict = CFDictionaryGetValue(System, prof)) )
{
ProcessHibernateSettings(dict, PMRootDomain);
}
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;
}
}
static int getAggressivenessFactorsFromProfile(
CFDictionaryRef System,
CFStringRef prof,
IOPMAggressivenessFactors *agg)
{
CFDictionaryRef p = NULL;
if( !(p = CFDictionaryGetValue(System, prof)) )
{
return -1;
}
if(!agg) return -1;
GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMDisplaySleepKey)),
kCFNumberSInt32Type, &agg->fMinutesToDim);
GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMDiskSleepKey)),
kCFNumberSInt32Type, &agg->fMinutesToSpin);
GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMSystemSleepKey)),
kCFNumberSInt32Type, &agg->fMinutesToSleep);
GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMWakeOnLANKey)),
kCFNumberSInt32Type, &agg->fWakeOnLAN);
GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMWakeOnRingKey)),
kCFNumberSInt32Type, &agg->fWakeOnRing);
GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMRestartOnPowerLossKey)),
kCFNumberSInt32Type, &agg->fAutomaticRestart);
GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMSleepOnPowerButtonKey)),
kCFNumberSInt32Type, &agg->fSleepOnPowerButton);
GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMWakeOnClamshellKey)),
kCFNumberSInt32Type, &agg->fWakeOnClamshell);
GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMWakeOnACChangeKey)),
kCFNumberSInt32Type, &agg->fWakeOnACChange);
GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMDisplaySleepUsesDimKey)),
kCFNumberSInt32Type, &agg->fDisplaySleepUsesDimming);
GetAggressivenessValue(CFDictionaryGetValue(p, CFSTR(kIOPMMobileMotionModuleKey)),
kCFNumberSInt32Type, &agg->fMobileMotionModule);
return 0;
}
bool IOPMFeatureIsAvailable(CFStringRef f, CFStringRef power_source)
{
CFDictionaryRef supportedFeatures = NULL;
CFArrayRef tmp_array;
io_registry_entry_t registry_entry = MACH_PORT_NULL;
bool ret = false;
registry_entry = IORegistryEntryFromPath(0,
kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
if(!registry_entry) goto IOPMFeatureIsAvailable_exitpoint;
supportedFeatures = IORegistryEntryCreateCFProperty(registry_entry, CFSTR("Supported Features"),
kCFAllocatorDefault, kNilOptions);
IOObjectRelease(registry_entry);
if(CFEqual(f, CFSTR(kIOPMDisplaySleepKey))
|| CFEqual(f, CFSTR(kIOPMSystemSleepKey))
|| CFEqual(f, CFSTR(kIOPMDiskSleepKey)))
{
ret = true;
goto IOPMFeatureIsAvailable_exitpoint;
}
if(CFEqual(f, CFSTR(kIOPMReduceBrightnessKey)))
{
CFTypeRef ps = IOPSCopyPowerSourcesInfo();
if( ps &&
( IOPSGetActiveBattery(ps) || IOPSGetActiveUPS(ps) ) &&
supportedFeatures &&
CFDictionaryGetValue(supportedFeatures, CFSTR("DisplayDims")) &&
(kCFCompareEqualTo !=
CFStringCompare(power_source, CFSTR(kIOPMACPowerKey), 0)) )
{
ret = true;
} else {
ret = false;
}
if(ps) CFRelease(ps);
goto IOPMFeatureIsAvailable_exitpoint;
}
if(CFEqual(f, CFSTR(kIOPMDisplaySleepUsesDimKey)))
{
if(supportedFeatures && CFDictionaryGetValue(supportedFeatures, CFSTR("DisplayDims")))
{
ret = true;
} else {
ret = false;
}
goto IOPMFeatureIsAvailable_exitpoint;
}
if(CFEqual(f, CFSTR(kIOPMReduceSpeedKey)))
{
if(!supportedFeatures) return false;
if(CFDictionaryGetValue(supportedFeatures, f))
ret = true;
else ret = false;
goto IOPMFeatureIsAvailable_exitpoint;
}
if(CFEqual(f, CFSTR(kIOPMDynamicPowerStepKey)))
{
if(!supportedFeatures) return false;
if(CFDictionaryGetValue(supportedFeatures, f))
ret = true;
else ret = false;
goto IOPMFeatureIsAvailable_exitpoint;
}
if(CFEqual(f, CFSTR(kIOPMWakeOnLANKey)))
{
if(supportedFeatures && CFDictionaryGetValue(supportedFeatures, CFSTR("WakeOnMagicPacket"))
&& (!power_source || !CFEqual(CFSTR(kIOPMBatteryPowerKey), power_source)))
{
ret = true;
} else {
ret = false;
}
goto IOPMFeatureIsAvailable_exitpoint;
}
if(CFEqual(f, CFSTR(kIOPMWakeOnRingKey)))
{
if(supportedFeatures && CFDictionaryGetValue(supportedFeatures, CFSTR("WakeOnRing")))
{
ret = true;
} else {
ret = false;
}
goto IOPMFeatureIsAvailable_exitpoint;
}
if(CFEqual(f, CFSTR(kIOPMRestartOnPowerLossKey)))
{
if(supportedFeatures && CFDictionaryGetValue(supportedFeatures, CFSTR("FileServer")))
{
ret = true;
} else {
ret = false;
}
goto IOPMFeatureIsAvailable_exitpoint;
}
if(CFEqual(f, CFSTR(kIOPMWakeOnACChangeKey)))
{
if(supportedFeatures && CFDictionaryGetValue(supportedFeatures, CFSTR("WakeOnACchange")))
{
ret = true;
} else {
ret = false;
}
goto IOPMFeatureIsAvailable_exitpoint;
}
if(CFEqual(f, CFSTR(kIOPMSleepOnPowerButtonKey)))
{
IOReturn r = IOPMCopyBatteryInfo(kIOMasterPortDefault, &tmp_array);
if((r == kIOReturnSuccess) && tmp_array)
{
CFRelease(tmp_array);
ret = false;
} else ret = true;
goto IOPMFeatureIsAvailable_exitpoint;
}
if(CFEqual(f, CFSTR(kIOPMWakeOnClamshellKey)))
{
if(!supportedFeatures) return false;
if(CFDictionaryGetValue(supportedFeatures, CFSTR("WakeOnLid")))
ret = true;
else ret = false;
goto IOPMFeatureIsAvailable_exitpoint;
}
if(CFEqual(f, CFSTR(kIOHibernateModeKey))
|| CFEqual(f, CFSTR(kIOHibernateFreeRatioKey))
|| CFEqual(f, CFSTR(kIOHibernateFreeTimeKey))
|| CFEqual(f, CFSTR(kIOHibernateFileKey)))
{
if(!supportedFeatures) return false;
if(CFDictionaryGetValue(supportedFeatures, CFSTR(kIOHibernateFeatureKey)))
ret = true;
else ret = false;
goto IOPMFeatureIsAvailable_exitpoint;
}
if(CFEqual(f, CFSTR(kIOPMMobileMotionModuleKey)))
{
if(!supportedFeatures) return false;
if(CFDictionaryGetValue(supportedFeatures, CFSTR("MobileMotionModule")))
ret = true;
else ret = false;
goto IOPMFeatureIsAvailable_exitpoint;
}
IOPMFeatureIsAvailable_exitpoint:
if(supportedFeatures) CFRelease(supportedFeatures);
return ret;
}
static void IOPMRemoveIrrelevantProperties(CFMutableDictionaryRef energyPrefs)
{
int profile_count = 0;
int dict_count = 0;
CFStringRef *profile_keys = NULL;
CFDictionaryRef *profile_vals = NULL;
CFStringRef *dict_keys = NULL;
CFDictionaryRef *dict_vals = NULL;
CFMutableDictionaryRef this_profile;
CFTypeRef ps_snapshot;
ps_snapshot = IOPSCopyPowerSourcesInfo();
profile_count = CFDictionaryGetCount(energyPrefs);
profile_keys = (CFStringRef *)malloc(sizeof(CFStringRef) * profile_count);
profile_vals = (CFDictionaryRef *)malloc(sizeof(CFDictionaryRef) * profile_count);
if(!profile_keys || !profile_vals) return;
CFDictionaryGetKeysAndValues(energyPrefs, (const void **)profile_keys, (const void **)profile_vals);
while(--profile_count >= 0)
{
if(kCFBooleanTrue != IOPSPowerSourceSupported(ps_snapshot, profile_keys[profile_count]))
{
CFDictionaryRemoveValue(energyPrefs, profile_keys[profile_count]);
} else {
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);
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);
while(--dict_count >= 0)
{
if( !IOPMFeatureIsAvailable((CFStringRef)dict_keys[dict_count],
(CFStringRef)profile_keys[profile_count]) )
{
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;
}
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; }
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;
}
tmp_dict = isA_CFDictionary(SCPreferencesGetValue(energyPrefs, CFSTR("Custom Profile")));
if(tmp_dict)
{
usingDefaults = false;
energyDict = CFDictionaryCreateMutableCopy(
kCFAllocatorDefault,
0,
tmp_dict);
if(!energyDict) goto failure_exit;
} else {
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);
}
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;
getCheetahPumaEnergySettings(energyDict);
getDefaultEnergySettings(energyDict);
IOPMRemoveIrrelevantProperties(energyDict);
if(usingDefaults) {
CFDictionarySetValue(energyDict, CFSTR(kIOPMDefaultPreferencesKey), kCFBooleanTrue);
}
if(energyPrefs) CFRelease(energyPrefs);
return energyDict;
failure_exit:
if(energyPrefs) CFRelease(energyPrefs);
if(energyDict) CFRelease(energyDict);
return 0;
}
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;
}
agg = (IOPMAggressivenessFactors *)malloc(sizeof(IOPMAggressivenessFactors));
getAggressivenessFactorsFromProfile(SystemProfiles, profile, agg);
sendEnergySettingsToKernel(SystemProfiles, profile, agg);
free(agg);
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( !activePMPrefs || (newPMPrefs && !CFEqual(activePMPrefs, newPMPrefs)) )
{
SCDynamicStoreSetValue(dynamic_store,
CFSTR(kIOPMDynamicStoreSettingsKey),
newPMPrefs);
}
if(activePMPrefs) CFRelease(activePMPrefs);
CFRelease(dynamic_store);
return kIOReturnSuccess;
}
IOReturn IOPMSetPMPreferences(CFDictionaryRef ESPrefs)
{
IOReturn ret = kIOReturnError;
SCPreferencesRef energyPrefs = NULL;
energyPrefs = SCPreferencesCreate( kCFAllocatorDefault, kIOPMAppName, kIOPMPrefsPath );
if(!energyPrefs) return kIOReturnError;
if(!SCPreferencesLock(energyPrefs, true))
{
if(kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged;
else ret = kIOReturnError;
goto exit;
}
if(!SCPreferencesSetValue(energyPrefs, CFSTR("Custom Profile"), ESPrefs))
{
ret = kIOReturnError;
goto exit;
}
SCPreferencesRemoveValue(energyPrefs, CFSTR(kIOPMACPowerKey));
SCPreferencesRemoveValue(energyPrefs, CFSTR(kIOPMBatteryPowerKey));
SCPreferencesRemoveValue(energyPrefs, CFSTR(kIOPMUPSPowerKey));
if(!SCPreferencesCommitChanges(energyPrefs))
{
if(kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged;
else ret = kIOReturnError;
goto exit;
}
if(!SCPreferencesApplyChanges(energyPrefs))
{
if(kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged;
else ret = kIOReturnError;
goto exit;
}
ret = kIOReturnSuccess;
exit:
if(energyPrefs) {
SCPreferencesUnlock(energyPrefs);
CFRelease(energyPrefs);
}
return ret;
}
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<count; i++)
{
CFDictionarySetValue(target, keys[i], objs[i]);
}
free((void *)keys);
free((void *)objs);
}
static CFArrayRef _copySystemProvidedProfiles()
{
io_registry_entry_t registry_entry = MACH_PORT_NULL;
CFTypeRef cftype_total_prof_override = NULL;
CFTypeRef cftype_overrides = NULL;
CFArrayRef retArray = NULL;
CFDictionaryRef overrides = NULL;
CFDictionaryRef ac_over = NULL;
CFDictionaryRef batt_over = NULL;
CFDictionaryRef ups_over = NULL;
CFArrayRef sysPowerProfiles = NULL;
CFMutableArrayRef mArrProfs = NULL;
int count = 0;
int i = 0;
registry_entry = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceNameMatching("IOPMrootDomain"));
if(MACH_PORT_NULL == registry_entry) return NULL;
cftype_overrides = IORegistryEntryCreateCFProperty(registry_entry,
CFSTR(kIOPMSystemDefaultOverrideKey),
kCFAllocatorDefault, 0);
if( !(overrides = isA_CFDictionary(cftype_overrides)) ) {
if(cftype_overrides) {
CFRelease(cftype_overrides); cftype_overrides = NULL;
}
goto TrySystemDefaultProfiles;
}
ac_over = CFDictionaryGetValue(overrides, CFSTR(kIOPMACPowerKey));
batt_over = CFDictionaryGetValue(overrides, CFSTR(kIOPMBatteryPowerKey));
ups_over = CFDictionaryGetValue(overrides, CFSTR(kIOPMUPSPowerKey));
if(ac_over && batt_over && ups_over)
{
} else if(!ac_over && !batt_over && !ups_over)
{
ac_over = batt_over = ups_over = overrides;
} else {
goto TrySystemDefaultProfiles;
}
sysPowerProfiles = _createDefaultSystemProfiles();
if(!sysPowerProfiles) goto exit;
count = CFArrayGetCount(sysPowerProfiles);
mArrProfs = CFArrayCreateMutable(0, count, &kCFTypeArrayCallBacks);
for(i=0; i<count; i++)
{
CFMutableDictionaryRef mSettingsAC;
CFMutableDictionaryRef mSettingsBatt;
CFMutableDictionaryRef mSettingsUPS;
CFMutableDictionaryRef mProfile;
CFDictionaryRef _profile;
CFDictionaryRef tmp;
_profile = (CFDictionaryRef)CFArrayGetValueAtIndex(sysPowerProfiles, i);
if(!_profile) continue;
mProfile = CFDictionaryCreateMutable(0,
CFDictionaryGetCount(_profile),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if(!mProfile) continue;
CFArraySetValueAtIndex(mArrProfs, i, mProfile);
CFRelease(mProfile);
tmp = (CFDictionaryRef)CFDictionaryGetValue(_profile,
CFSTR(kIOPMACPowerKey));
if(!tmp) continue;
mSettingsAC = CFDictionaryCreateMutableCopy(0,
CFDictionaryGetCount(tmp), tmp);
tmp = (CFDictionaryRef)CFDictionaryGetValue(_profile,
CFSTR(kIOPMBatteryPowerKey));
if(!tmp) continue;
mSettingsBatt = CFDictionaryCreateMutableCopy(0,
CFDictionaryGetCount(tmp), tmp);
tmp = (CFDictionaryRef)CFDictionaryGetValue(_profile,
CFSTR(kIOPMUPSPowerKey));
if(!tmp) continue;
mSettingsUPS = CFDictionaryCreateMutableCopy(0,
CFDictionaryGetCount(tmp), tmp);
if( !(mSettingsAC && mSettingsBatt && mSettingsUPS) ) {
if(sysPowerProfiles) {
CFRelease(sysPowerProfiles); sysPowerProfiles = NULL;
}
if(mSettingsAC) {
CFRelease(mSettingsAC); mSettingsAC = NULL;
}
if(mSettingsBatt) {
CFRelease(mSettingsBatt); mSettingsBatt = NULL;
}
if(mSettingsUPS) {
CFRelease(mSettingsUPS); mSettingsUPS = NULL;
}
if(mArrProfs) {
CFRelease(mArrProfs); mArrProfs = NULL;
}
goto TrySystemDefaultProfiles;
}
CFDictionarySetValue(mProfile,
CFSTR(kIOPMACPowerKey),
mSettingsAC);
CFDictionarySetValue(mProfile,
CFSTR(kIOPMBatteryPowerKey),
mSettingsBatt);
CFDictionarySetValue(mProfile,
CFSTR(kIOPMUPSPowerKey),
mSettingsUPS);
mergeDictIntoMutable(mSettingsAC, ac_over);
mergeDictIntoMutable(mSettingsBatt, batt_over);
mergeDictIntoMutable(mSettingsUPS, ups_over);
CFRelease(mSettingsAC); mSettingsAC = NULL;
CFRelease(mSettingsBatt); mSettingsBatt = NULL;
CFRelease(mSettingsUPS); mSettingsUPS = NULL;
}
retArray = (CFArrayRef)mArrProfs;
goto exit;
TrySystemDefaultProfiles:
cftype_total_prof_override = IORegistryEntryCreateCFProperty(registry_entry,
CFSTR(kIOPMSystemDefaultProfilesKey),
kCFAllocatorDefault, 0);
if( isA_CFArray(cftype_total_prof_override) ) {
retArray = (CFArrayRef)cftype_total_prof_override;
goto exit;
} else {
if(cftype_total_prof_override) {
CFRelease(cftype_total_prof_override);
cftype_total_prof_override = NULL;
}
}
exit:
if(sysPowerProfiles) {
CFRelease(sysPowerProfiles); sysPowerProfiles = NULL;
}
if(cftype_overrides) {
CFRelease(cftype_overrides); cftype_overrides = NULL;
}
IOObjectRelease(registry_entry);
return retArray;
}
static CFArrayRef _createDefaultSystemProfiles()
{
CFURLRef pm_bundle_url = 0;
CFBundleRef pm_bundle = 0;
CFURLRef profiles_url = 0;
CFStringRef profiles_path = 0;
CFArrayRef system_default_profiles = 0;
CFArrayRef return_array = 0;
SCPreferencesRef open_file = 0;
pm_bundle_url = CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,
CFSTR("/System/Library/SystemConfiguration/PowerManagement.bundle"),
kCFURLPOSIXPathStyle,
1);
if(!pm_bundle_url) {
goto exit;
}
pm_bundle = CFBundleCreate(
kCFAllocatorDefault,
pm_bundle_url);
if(!pm_bundle) {
goto exit;
}
profiles_url = CFBundleCopyResourceURL(
pm_bundle,
CFSTR("com.apple.SystemPowerProfileDefaults.plist"),
NULL,
NULL);
if(!profiles_url) {
goto exit;
}
profiles_path = CFURLCopyPath(profiles_url);
open_file = SCPreferencesCreate(
kCFAllocatorDefault,
CFSTR("PowerManagementPreferencse"),
profiles_path);
if(!open_file) {
goto exit;
}
system_default_profiles = SCPreferencesGetValue(
open_file,
CFSTR("SystemProfileDefaults"));
if(!isA_CFArray(system_default_profiles)) {
goto exit;
}
return_array = CFArrayCreateCopy(kCFAllocatorDefault, system_default_profiles);
exit:
if(pm_bundle_url) CFRelease(pm_bundle_url);
if(pm_bundle) CFRelease(pm_bundle);
if(profiles_url) CFRelease(profiles_url);
if(profiles_path) CFRelease(profiles_path);
if(open_file) CFRelease(open_file);
if(!return_array) {
syslog(LOG_INFO, "Power Management error: unable to load default System Power Profiles.\n");
}
return return_array;
}
static CFDictionaryRef _createDefaultProfileSelections(void)
{
CFURLRef pm_bundle_url = 0;
CFBundleRef pm_bundle = 0;
CFURLRef profiles_url = 0;
CFStringRef profiles_path = 0;
CFDictionaryRef default_profiles_selection = 0;
CFDictionaryRef return_dict = 0;
SCPreferencesRef open_file = 0;
pm_bundle_url = CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,
CFSTR("/System/Library/SystemConfiguration/PowerManagement.bundle"),
kCFURLPOSIXPathStyle,
1);
if(!pm_bundle_url) {
goto exit;
}
pm_bundle = CFBundleCreate(
kCFAllocatorDefault,
pm_bundle_url);
if(!pm_bundle) {
goto exit;
}
profiles_url = CFBundleCopyResourceURL(
pm_bundle,
CFSTR("com.apple.SystemPowerProfileDefaults.plist"),
NULL,
NULL);
if(!profiles_url) {
goto exit;
}
profiles_path = CFURLCopyPath(profiles_url);
open_file = SCPreferencesCreate(
kCFAllocatorDefault,
CFSTR("PowerManagementPreferences"),
profiles_path);
if(!open_file) {
goto exit;
}
default_profiles_selection = SCPreferencesGetValue(
open_file,
CFSTR("DefaultProfileChoices"));
if(!isA_CFDictionary(default_profiles_selection)) {
goto exit;
}
return_dict = CFDictionaryCreateCopy(kCFAllocatorDefault, default_profiles_selection);
exit:
if(pm_bundle_url) CFRelease(pm_bundle_url);
if(pm_bundle) CFRelease(pm_bundle);
if(profiles_url) CFRelease(profiles_url);
if(profiles_path) CFRelease(profiles_path);
if(open_file) CFRelease(open_file);
if(!return_dict) {
syslog(LOG_INFO, "Power Management error: unable to load default profiles selections.\n");
}
return return_dict;
}
static CFDictionaryRef _createAllCustomProfileSelections(void)
{
int j = -1;
CFNumberRef n;
CFMutableDictionaryRef custom_dict = NULL;
custom_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 3,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
n = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &j);
if(!custom_dict || !n) return NULL;
CFDictionarySetValue(custom_dict, CFSTR(kIOPMACPowerKey), n);
CFDictionarySetValue(custom_dict, CFSTR(kIOPMBatteryPowerKey), n);
CFDictionarySetValue(custom_dict, CFSTR(kIOPMUPSPowerKey), n);
CFRelease(n);
return custom_dict;
}
CFArrayRef IOPMCopyPowerProfiles(void)
{
CFArrayRef power_profiles = 0;
CFMutableArrayRef mutable_power_profiles = 0;
CFDictionaryRef tmp;
CFMutableDictionaryRef mutable_profile;
int i, p_count;
power_profiles = _copySystemProvidedProfiles();
if(!power_profiles) {
power_profiles = _createDefaultSystemProfiles();
}
if(!power_profiles) return NULL;
mutable_power_profiles = CFArrayCreateMutableCopy(0, 0, power_profiles);
if(!mutable_power_profiles) goto exit;
p_count = CFArrayGetCount(mutable_power_profiles);
for(i=0; i<p_count; i++)
{
tmp = CFArrayGetValueAtIndex(power_profiles, i);
if(!tmp) continue;
mutable_profile = CFDictionaryCreateMutableCopy(
kCFAllocatorDefault,
0,
tmp);
if(!mutable_profile) continue;
IOPMRemoveIrrelevantProperties(mutable_profile);
CFArraySetValueAtIndex(mutable_power_profiles, i, mutable_profile);
CFRelease(mutable_profile);
}
exit:
if(power_profiles) CFRelease(power_profiles);
return mutable_power_profiles;
}
static int _isActiveProfileDictValid(CFDictionaryRef p)
{
CFNumberRef val;
int j;
if(!p) return 0;
val = CFDictionaryGetValue(p, CFSTR(kIOPMACPowerKey));
if(!val) return 0;
CFNumberGetValue(val, kCFNumberIntType, &j);
if(j<-1 || j>= kIOPMNumPowerProfiles) return 0;
val = CFDictionaryGetValue(p, CFSTR(kIOPMBatteryPowerKey));
if(val) {
CFNumberGetValue(val, kCFNumberIntType, &j);
if(j<-1 || j>= kIOPMNumPowerProfiles) return 0;
}
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; i<count; i++)
{
if(kCFBooleanTrue != IOPSPowerSourceSupported(ps_snap, ps_names[i])) {
CFDictionaryRemoveValue(p, ps_names[i]);
}
}
exit:
if(ps_snap) CFRelease(ps_snap);
if(ps_names) free(ps_names);
}
CFDictionaryRef IOPMCopyActivePowerProfiles(void)
{
SCPreferencesRef energyPrefs = NULL;
CFDictionaryRef tmp = NULL;
CFDictionaryRef tmp_custom = NULL;
CFDictionaryRef defaultProfiles = NULL;
CFMutableDictionaryRef activeProfiles = NULL;
CFStringRef *profileKeys = NULL;
CFNumberRef *profileValues = NULL;
bool activeProfilesSpecified = false;
bool customSettingsSpecified = false;
int profileCount;
int i;
energyPrefs = SCPreferencesCreate( kCFAllocatorDefault, kIOPMAppName, kIOPMPrefsPath );
if(!energyPrefs) return NULL;
tmp = SCPreferencesGetValue(energyPrefs, CFSTR("ActivePowerProfiles"));
if(tmp && _isActiveProfileDictValid(tmp)) {
activeProfiles = CFDictionaryCreateMutableCopy(0, 0, tmp);
activeProfilesSpecified = true;
} else {
activeProfiles = CFDictionaryCreateMutable(0, 3,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
if(!activeProfiles) goto exit;
tmp_custom = IOPMCopyPMPreferences();
if(isA_CFDictionary(tmp_custom))
{
if(kCFBooleanTrue != CFDictionaryGetValue(tmp_custom, CFSTR("Defaults")))
{
customSettingsSpecified = true;
}
CFRelease(tmp_custom);
}
if(!activeProfilesSpecified && customSettingsSpecified)
{
defaultProfiles = _createAllCustomProfileSelections();
} else {
defaultProfiles = _createDefaultProfileSelections();
}
if(isA_CFDictionary(defaultProfiles))
{
profileCount = CFDictionaryGetCount(defaultProfiles);
profileKeys = malloc(sizeof(CFStringRef)*profileCount);
profileValues = malloc(sizeof(CFNumberRef)*profileCount);
if(!profileKeys || !profileValues) goto exit;
CFDictionaryGetKeysAndValues(defaultProfiles,
(const void **)profileKeys, (const void **)profileValues);
for(i=0; i<profileCount; i++)
{
if( isA_CFString(profileKeys[i]) &&
isA_CFNumber(profileValues[i]) )
{
CFDictionaryAddValue(activeProfiles, profileKeys[i], profileValues[i]);
}
}
free(profileKeys);
free(profileValues);
}
_purgeUnsupportedPowerSources(activeProfiles);
exit:
if(energyPrefs) CFRelease(energyPrefs);
if(defaultProfiles) CFRelease(defaultProfiles);
return activeProfiles;
}
IOReturn IOPMSetActivePowerProfiles(CFDictionaryRef which_profile)
{
CFDataRef profiles_data;
vm_address_t profiles_buffer;
IOByteCount buffer_len;
kern_return_t kern_result;
IOReturn return_val = kIOReturnError;
mach_port_t server_port = MACH_PORT_NULL;
if(!_isActiveProfileDictValid(which_profile)) {
return kIOReturnBadArgument;
}
kern_result = bootstrap_look_up(bootstrap_port,
kIOPMServerBootstrapName, &server_port);
if(KERN_SUCCESS != kern_result) {
return kIOReturnError;
}
profiles_data = IOCFSerialize(which_profile, 0);
profiles_buffer = (vm_address_t) CFDataGetBytePtr(profiles_data);
buffer_len = CFDataGetLength(profiles_data);
kern_result = io_pm_set_active_profile(server_port,
profiles_buffer, buffer_len,
&return_val);
mach_port_destroy(mach_task_self(), server_port);
CFRelease(profiles_data);
if(KERN_SUCCESS == kern_result) {
return return_val;
} else {
return kIOReturnInternalError;
}
}
typedef struct {
IOPMPrefsCallbackType callback;
void *context;
} user_callback_context;
static void ioCallout(SCDynamicStoreRef store, CFArrayRef keys, void *ctxt) {
user_callback_context *c;
IOPowerSourceCallbackType cb;
c = (user_callback_context *)CFDataGetBytePtr((CFDataRef)ctxt);
if(!c) return;
cb = c->callback;
if(!cb) return;
(*cb)(c->context);
}
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;
store = SCDynamicStoreCreate(kCFAllocatorDefault,
CFSTR("IOKit Preferences Copy"), ioCallout, (void *)&scContext);
if(!store) return NULL;
EnergyPrefsKey = SCDynamicStoreKeyCreatePreferences(
NULL,
kIOPMPrefsPath,
kSCPreferencesKeyApply);
if(EnergyPrefsKey) {
SCDynamicStoreAddWatchedKey(store, EnergyPrefsKey, FALSE);
CFRelease(EnergyPrefsKey);
}
SCDrls = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault, store, 0);
CFRelease(store);
return SCDrls;
}