1/*
2 * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <sys/cdefs.h>
25#include <TargetConditionals.h>
26
27#include "IOSystemConfiguration.h"
28#include <CoreFoundation/CoreFoundation.h>
29#include <IOKit/pwr_mgt/IOPM.h>
30#include <IOKit/pwr_mgt/IOPMPrivate.h>
31#include <IOKit/ps/IOPowerSources.h>
32#include <IOKit/ps/IOPowerSourcesPrivate.h>
33#include <IOKit/IOCFSerialize.h>
34#include <IOKit/IOHibernatePrivate.h>
35#include <servers/bootstrap.h>
36#include <bootstrap_priv.h>
37#include <sys/syslog.h>
38#include "IOPMLib.h"
39#include "IOPMLibPrivate.h"
40#include "powermanagement.h"
41
42#include <asl.h>
43#include <IOKit/IOKitLib.h>
44#include <IOKit/IOBSD.h>
45
46#include <mach/mach.h>
47#include <stdint.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <unistd.h>
51//#include <fcntl.h>
52//#include <pthread.h>
53//#include <sys/stat.h>
54//#include <sys/sysctl.h>
55//#include <sys/mount.h>
56
57#define kSecondsIn5Years            157680000
58
59typedef struct {
60    const char *keyName;
61    uint32_t    defaultValueAC;
62    uint32_t    defaultValueBattery;
63} PMSettingDescriptorStruct;
64#ifndef kIOPMAutoPowerOffEnabledKey
65#define kIOPMAutoPowerOffEnabledKey "poweroffenabled"
66#define kIOPMAutoPowerOffDelayKey "poweroffdelay"
67#endif
68PMSettingDescriptorStruct defaultSettings[] =
69{   /* Setting Name                             AC - Battery */
70    {kIOPMDisplaySleepKey,                              5,  5},
71    {kIOPMDiskSleepKey,                                 10, 5},
72    {kIOPMSystemSleepKey,                               10, 5},
73    {kIOPMWakeOnLANKey,                                 0,  0},
74    {kIOPMWakeOnRingKey,                                0,  0},
75    {kIOPMRestartOnPowerLossKey,                        0,  0},
76    {kIOPMWakeOnACChangeKey,                            0,  0},
77    {kIOPMSleepOnPowerButtonKey,                        1,  0},
78    {kIOPMWakeOnClamshellKey,                           1,  1},
79    {kIOPMReduceBrightnessKey,                          0,  1},
80    {kIOPMDisplaySleepUsesDimKey,                       1,  1},
81    {kIOPMMobileMotionModuleKey,                        1,  1},
82    {kIOPMTTYSPreventSleepKey,                          1,  1},
83    {kIOPMGPUSwitchKey,                                 0,  1},
84    {kIOPMPrioritizeNetworkReachabilityOverSleepKey,    0,  0},
85    {kIOPMDeepSleepEnabledKey,                          0,  0},
86    {kIOPMDeepSleepDelayKey,                            0,  0},
87    {kIOPMDarkWakeBackgroundTaskKey,                    1,  0},
88    {kIOPMAutoPowerOffEnabledKey,                       0,  0},
89    {kIOPMAutoPowerOffDelayKey,                         0,  0}
90};
91
92static const int kPMSettingsCount = sizeof(defaultSettings)/sizeof(PMSettingDescriptorStruct);
93
94/* com.apple.PowerManagement.plist general keys
95 */
96#define kIOPMPrefsPath                                  CFSTR("com.apple.PowerManagement.xml")
97#define kIOPMAppName                                    CFSTR("PowerManagement configd")
98
99#define kIOPMSystemPowerKey                             CFSTR("SystemPowerSettings")
100#define kIOPMCustomProfileKey                           CFSTR("Custom Profile")
101
102#define kIOHibernateDefaultFile                         "/var/vm/sleepimage"
103
104#define kIOPMPrefsPath                                  CFSTR("com.apple.PowerManagement.xml")
105#define kIOPMAppName                                    CFSTR("PowerManagement configd")
106
107/* IOPMRootDomain property keys for default settings
108 */
109#define kIOPMSystemDefaultProfilesKey                   "SystemPowerProfiles"
110#define kIOPMSystemDefaultOverrideKey                   "SystemPowerProfileOverrideDict"
111
112/* Keys for Cheetah Energy Settings shim
113 */
114#define kCheetahDimKey                                  CFSTR("MinutesUntilDisplaySleeps")
115#define kCheetahDiskKey                                 CFSTR("MinutesUntilHardDiskSleeps")
116#define kCheetahSleepKey                                CFSTR("MinutesUntilSystemSleeps")
117#define kCheetahRestartOnPowerLossKey                   CFSTR("RestartOnPowerLoss")
118#define kCheetahWakeForNetworkAccessKey                 CFSTR("WakeForNetworkAdministrativeAccess")
119#define kCheetahWakeOnRingKey                           CFSTR("WakeOnRing")
120
121// Supported Feature bitfields for IOPMrootDomain Supported Features
122enum {
123    kIOPMSupportedOnAC              = 1<<0,
124    kIOPMSupportedOnBatt            = 1<<1,
125    kIOPMSupportedOnUPS             = 1<<2
126};
127
128/* Power sources
129 *
130 */
131#define kPowerSourcesCount          3
132#define kPowerProfilesCount         5
133
134enum {
135    kIOPMKeepUnsupportedPreferences = false,
136    kIOPMRemoveUnsupportedPreferences = true
137};
138
139
140/* IOPMPrefsNotificationCreateRunLoopSource
141 * user_callback_context supports IOPMPrefsCallback
142 */
143typedef struct {
144    IOPMPrefsCallbackType       callback;
145    void                        *context;
146} user_callback_context;
147
148/******************************************************************************/
149/******************************************************************************/
150/******************************************************************************/
151// Forwards
152
153static CFStringRef getPowerSourceString(int i);
154
155static void mergeUserDefaultOverriddenSettings(
156               CFMutableDictionaryRef es);
157static int addDefaultEnergySettings(
158                CFMutableDictionaryRef sys );
159static void addSystemProfileEnergySettings(
160                CFDictionaryRef user_profile_selections,
161                CFMutableDictionaryRef passed_in);
162__private_extern__ io_registry_entry_t getPMRootDomainRef(void);
163static CFStringRef supportedNameForPMName( CFStringRef pm_name );
164static bool featureSupportsPowerSource(
165                CFTypeRef                       featureDetails,
166                CFStringRef                     power_source);
167static void IOPMRemoveIrrelevantProperties(
168                CFMutableDictionaryRef energyPrefs);
169static int getCheetahPumaEnergySettings(
170                CFMutableDictionaryRef energyPrefs);
171
172#define  kOverWriteDuplicates       true
173#define  kKeepOriginalValues        false
174static void mergeDictIntoMutable(
175                CFMutableDictionaryRef          target,
176                CFDictionaryRef                 overrides,
177                bool                            overwrite);
178static CFDictionaryRef  _copyActivePMPreferences(
179                bool    removeUnsupportedSettings);
180static CFArrayRef _copySystemProvidedProfiles(void);
181static CFArrayRef _createDefaultSystemProfiles(void);
182static CFDictionaryRef _createDefaultProfileSelections(void);
183static CFDictionaryRef _createAllCustomProfileSelections(void);
184static int _isActiveProfileDictValid( CFDictionaryRef p );
185static void _purgeUnsupportedPowerSources( CFMutableDictionaryRef p );
186static void ioCallout(
187                SCDynamicStoreRef store __unused,
188                CFArrayRef keys __unused,
189                void *ctxt);
190
191static IOReturn readAllPMPlistSettings(
192                bool    removeUnsupportedSettings,
193                CFMutableDictionaryRef *customSettings,
194                CFDictionaryRef *profileSelections,
195                bool    *defaultSettings);
196
197IOReturn _pm_connect(mach_port_t *newConnection);
198IOReturn _pm_disconnect(mach_port_t connection);
199/******************************************************************************/
200/******************************************************************************/
201/******************************************************************************/
202
203
204/**************************************************
205*
206* Energy Saver Preferences
207*
208**************************************************/
209
210CFDictionaryRef IOPMCopyCustomPMPreferences(void)
211{
212    CFMutableDictionaryRef      copiedPMPrefs = NULL;
213    CFDictionaryRef         immutableRetPrefs = NULL;
214
215    /* IOPMCopyCustomPMPreferences returns the same thing IOPMCopyPMPreferences
216     * does.  This is the recommended version to use; for clarity.
217     */
218
219    copiedPMPrefs = IOPMCopyPMPreferences();
220    if( copiedPMPrefs ) {
221        // Turn it from mutable to immutable
222        immutableRetPrefs = CFDictionaryCreateCopy(
223                        kCFAllocatorDefault, (CFDictionaryRef)copiedPMPrefs );
224        CFRelease(copiedPMPrefs);
225        return immutableRetPrefs;
226    } else {
227        return NULL;
228    }
229}
230
231/**************************************************/
232
233CFMutableDictionaryRef IOPMCopyPMPreferences(void)
234{
235    IOReturn                ret;
236    CFMutableDictionaryRef  settings = NULL;
237
238    ret = readAllPMPlistSettings(
239                        kIOPMRemoveUnsupportedPreferences,
240                        &settings,
241                        NULL, NULL );
242
243    if(kIOReturnSuccess == ret) {
244        return settings;
245    } else {
246        return NULL;
247    }
248}
249
250/**************************************************/
251#if !TARGET_OS_IPHONE
252
253IOReturn IOPMCopyPMSetting(
254    CFStringRef key,
255    CFStringRef power_source,
256    CFTypeRef *outValue)
257{
258    CFDictionaryRef ActiveSettings  = NULL;
259    CFDictionaryRef perPS           = NULL;
260    CFStringRef     usePowerSource  = power_source;
261    CFTypeRef       psblob          = NULL;
262    bool            supported       = false;
263
264    IOReturn        ret;
265
266    if (!key || !outValue) {
267        ret = kIOReturnBadArgument;
268        goto exit;
269    }
270
271    *outValue = 0;
272
273    if (!usePowerSource) {
274        IOPSPowerSourceIndex activeps;
275        IOPSGetSupportedPowerSources(&activeps, NULL, NULL);
276        if (kIOPSProvidedByExternalBattery == activeps) {
277            usePowerSource = CFSTR(kIOPMUPSPowerKey);
278        } else if (kIOPSProvidedByBattery == activeps) {
279            usePowerSource = CFSTR(kIOPMBatteryPowerKey);
280        } else {
281            usePowerSource = CFSTR(kIOPMACPowerKey);
282        }
283    }
284
285    supported = IOPMFeatureIsAvailable(key, usePowerSource);
286
287    if (!supported) {
288        ret = kIOReturnUnsupported;
289        goto exit;
290    }
291
292    ActiveSettings = _copyActivePMPreferences(true);
293    if (ActiveSettings) {
294        perPS = (CFDictionaryRef)CFDictionaryGetValue(
295                          ActiveSettings, usePowerSource);
296
297        if (perPS) {
298            *outValue = CFDictionaryGetValue(perPS, key);
299        }
300    }
301
302    if (*outValue) {
303        CFRetain(*outValue);
304        ret = kIOReturnSuccess;
305    } else {
306        ret = kIOReturnNotFound;
307    }
308
309    if (ActiveSettings) {
310        CFRelease(ActiveSettings);
311    }
312
313exit:
314    if (psblob) {
315        CFRelease(psblob);
316    }
317    return ret;
318}
319
320#endif
321/**************************************************/
322
323CFDictionaryRef IOPMCopyActivePMPreferences(void)
324{
325    return _copyActivePMPreferences(kIOPMRemoveUnsupportedPreferences);
326}
327
328CFDictionaryRef IOPMCopyUnabridgedActivePMPreferences(void)
329{
330    return _copyActivePMPreferences(kIOPMKeepUnsupportedPreferences);
331}
332
333static CFDictionaryRef  _copyActivePMPreferences(
334    bool                            removeUnsupportedSettings)
335{
336    CFDictionaryRef                 active_profiles = NULL;
337    CFArrayRef                      system_profiles = NULL;
338    CFMutableDictionaryRef          custom_settings = NULL;
339    CFMutableDictionaryRef          return_val = NULL;
340    CFStringRef                     *active_profile_dict_keys = NULL;
341    CFNumberRef                     *active_profile_dict_values = NULL;
342    IOReturn                        ret;
343    int                             ps_count;
344    int                             i;
345
346    system_profiles = IOPMCopyPowerProfiles();
347    if(!system_profiles) {
348        return NULL;
349    }
350
351    /* Depending on removeUnsupportedSettings argument,
352     * the returned custom_settings dictionary may have
353     * removed the settings lacking hardware support
354     * on this machine
355     */
356    ret = readAllPMPlistSettings( removeUnsupportedSettings,
357                                    &custom_settings,
358                                    &active_profiles, NULL );
359    if( kIOReturnSuccess != ret )
360    {
361        goto exit;
362    }
363
364    if(!active_profiles || !system_profiles || !custom_settings) goto exit;
365
366    return_val = CFDictionaryCreateMutable(0, 0,
367            &kCFTypeDictionaryKeyCallBacks,
368            &kCFTypeDictionaryValueCallBacks);
369
370    ps_count = CFDictionaryGetCount(active_profiles);
371    active_profile_dict_keys =
372                    (CFStringRef *)malloc(ps_count*sizeof(CFStringRef));
373    active_profile_dict_values =
374                    (CFNumberRef *)malloc(ps_count*sizeof(CFNumberRef));
375    if(!active_profile_dict_keys || !active_profile_dict_values) goto exit;
376
377    CFDictionaryGetKeysAndValues(
378        active_profiles,
379        (const void **)active_profile_dict_keys,
380        (const void **)active_profile_dict_values);
381
382    for(i=0; i<ps_count; i++)
383    {
384        int                         profile_index;
385        CFDictionaryRef             settings_per_power_source;
386        CFDictionaryRef             sys_profile;
387        CFDictionaryRef             tmp_settings;
388
389        if(!CFNumberGetValue(active_profile_dict_values[i],
390            kCFNumberIntType, &profile_index)) continue;
391        if(-1 == profile_index) {
392            // Custom profile for this power source
393            settings_per_power_source = CFDictionaryGetValue(
394                                custom_settings, active_profile_dict_keys[i]);
395        } else {
396            // user has selected a system defined profile for this source
397            if( (profile_index < 0) || (profile_index > 4) ) continue;
398            sys_profile = isA_CFDictionary(
399                CFArrayGetValueAtIndex(system_profiles, profile_index));
400            if(!sys_profile) continue;
401            settings_per_power_source = CFDictionaryGetValue(sys_profile,
402                                            active_profile_dict_keys[i]);
403        }
404        if(!settings_per_power_source) {
405            continue;
406        }
407        tmp_settings = CFDictionaryCreateCopy(kCFAllocatorDefault,
408                                                settings_per_power_source);
409        if(!tmp_settings) continue;
410        CFDictionarySetValue(return_val, active_profile_dict_keys[i],
411                                         tmp_settings);
412        CFRelease(tmp_settings);
413    }
414
415
416exit:
417    if(active_profile_dict_keys) free(active_profile_dict_keys);
418    if(active_profile_dict_values) free(active_profile_dict_values);
419    if(active_profiles) CFRelease(active_profiles);
420    if(system_profiles) CFRelease(system_profiles);
421    if(custom_settings) CFRelease(custom_settings);
422    return return_val;
423}
424
425/**************************************************/
426
427
428// A duplicate function for IOPMSetPMPreferences
429// Provided as "IOPMSetCustomPMPreferences" for clarity
430IOReturn IOPMSetCustomPMPreferences(CFDictionaryRef ESPrefs)
431{
432    return IOPMSetPMPreferences(ESPrefs);
433}
434/**************************************************/
435
436IOReturn IOPMRevertPMPreferences(CFArrayRef keys_arr)
437{
438    IOReturn                            ret = kIOReturnInternalError;
439    int                                 keys_i = 0;
440    int                                 keys_count = 0;
441    CFStringRef                         revert_this_setting = NULL;
442    bool                                these_are_defaults = false;
443    int                                 csi = 0;
444    CFMutableDictionaryRef              customSettings = NULL;
445    int                                 customSettingsCount = 0;
446    CFDictionaryRef                    *customSettingsDicts = NULL;
447    CFStringRef                        *customSettingsKeys = NULL;
448
449    readAllPMPlistSettings(kIOPMRemoveUnsupportedPreferences, &customSettings, NULL, &these_are_defaults);
450    if (these_are_defaults) {
451        /* If the system has default settings, then there's nothing
452         * for us to revert to default. Good bye.
453         */
454        ret = kIOReturnInvalid;
455        goto exit_and_free;
456    }
457
458    if (!keys_arr || (0 == (keys_count = CFArrayGetCount(keys_arr)))) {
459        /* Revert to OS Defaults
460         * PM tracks your current settings as indices into a now-defunct array of settings, called profiles.
461         * We "revert to defaults" by selecting profiles AC=2, Batt=1, UPS=1
462         * Note that "custom settings" are AC=-1, Batt=-1, UPS=-1
463         */
464
465        CFDictionaryRef twooneoneprofiles = NULL;
466
467        CFStringRef     tooKeys[kPowerSourcesCount] = { CFSTR(kIOPMACPowerKey), CFSTR(kIOPMBatteryPowerKey), CFSTR(kIOPMUPSPowerKey) };
468        CFNumberRef     tooVals[kPowerSourcesCount];
469        int             setVal = 0;
470
471        setVal = 2;
472        tooVals[0] = CFNumberCreate(0, kCFNumberIntType, &setVal);
473        setVal = 1;
474        tooVals[1] = CFNumberCreate(0, kCFNumberIntType, &setVal);
475        tooVals[2] = CFNumberCreate(0, kCFNumberIntType, &setVal);
476
477        twooneoneprofiles = CFDictionaryCreate(0, (const void **)tooKeys, (const void **)tooVals, kPowerSourcesCount,
478                                               &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
479
480        if (twooneoneprofiles) {
481            IOPMSetActivePowerProfiles(twooneoneprofiles);
482            CFRelease(twooneoneprofiles);
483        }
484
485        CFRelease(tooVals[0]);
486        CFRelease(tooVals[1]);
487        CFRelease(tooVals[2]);
488
489        ret = kIOReturnSuccess;
490        goto exit_and_free;
491    }
492
493    customSettingsCount = CFDictionaryGetCount(customSettings);
494    customSettingsKeys = (CFStringRef *)malloc(customSettingsCount * sizeof(CFStringRef));
495    customSettingsDicts = (CFDictionaryRef *)malloc(customSettingsCount * sizeof(CFDictionaryRef));
496    CFDictionaryGetKeysAndValues(customSettings, (const void **)customSettingsKeys, (const void **)customSettingsDicts);
497
498    for (csi=0; csi<customSettingsCount; csi++) {
499        CFMutableDictionaryRef      mutablePerPowerSourceCopy = NULL;
500        mutablePerPowerSourceCopy = CFDictionaryCreateMutableCopy(0, 0, customSettingsDicts[csi]);
501        if (!mutablePerPowerSourceCopy) {
502            continue;
503        }
504
505        // Remove each key in the caller's array from the PM Prefs dictionary
506        for (keys_i = 0; keys_i < keys_count; keys_i++) {
507            revert_this_setting = CFArrayGetValueAtIndex(keys_arr, keys_i);
508            if (isA_CFString(revert_this_setting)) {
509                CFDictionaryRemoveValue(mutablePerPowerSourceCopy, revert_this_setting);
510            }
511        }
512
513        CFDictionarySetValue(customSettings, customSettingsKeys[csi], mutablePerPowerSourceCopy);
514        CFRelease(mutablePerPowerSourceCopy);
515    }
516
517    ret = IOPMSetPMPreferences(customSettings);
518
519exit_and_free:
520    if (customSettings) {
521        CFRelease(customSettings);
522    }
523    if (customSettingsKeys) {
524        free(customSettingsKeys);
525    }
526    if (customSettingsDicts) {
527        free(customSettingsDicts);
528    }
529    return ret;
530}
531
532/**************************************************/
533
534static IOReturn _doTouchEnergyPrefs(SCDynamicStoreRef ds)
535{
536    CFStringRef                 energyPrefsKey = NULL;
537    IOReturn                    ret;
538
539    energyPrefsKey = SCDynamicStoreKeyCreatePreferences(NULL, kIOPMPrefsPath, kSCPreferencesKeyCommit);
540
541    if (!energyPrefsKey) {
542        return kIOReturnInternalError;
543    }
544
545    // Trigger a notification that the prefs have changed
546
547    if (!SCDynamicStoreNotifyValue(ds, energyPrefsKey))
548    {
549        if(kSCStatusAccessError == SCError()) {
550            ret = kIOReturnNotPrivileged;
551        } else {
552            ret = kIOReturnError;
553        }
554    } else {
555        ret = kIOReturnSuccess;
556    }
557
558    if (energyPrefsKey) {
559        CFRelease(energyPrefsKey);
560    }
561
562    return ret;
563}
564
565// Sets (and activates) Custom power profile
566IOReturn IOPMSetPMPreferences(CFDictionaryRef ESPrefs)
567{
568    IOReturn                    ret = kIOReturnError;
569    SCPreferencesRef            energyPrefs = NULL;
570
571    if(NULL == ESPrefs)
572    {
573        SCDynamicStoreRef ds = NULL;
574        ds = SCDynamicStoreCreate(0, CFSTR("IOKit User Library - Touch"), NULL, NULL);
575        if(!ds) {
576            ret = kIOReturnInternalError;
577        } else {
578            ret = _doTouchEnergyPrefs(ds);
579            CFRelease(ds);
580        }
581        return ret;
582    }
583
584    energyPrefs = SCPreferencesCreate(0, kIOPMAppName, kIOPMPrefsPath);
585    if(!energyPrefs) {
586        return kIOReturnError;
587    }
588
589    if(!SCPreferencesLock(energyPrefs, true))
590    {
591        // handle error
592        if(kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged;
593        else ret = kIOReturnError;
594        goto exit;
595    }
596
597    if(!SCPreferencesSetValue(energyPrefs, CFSTR("Custom Profile"), ESPrefs))
598    {
599        ret = kIOReturnError;
600        goto exit;
601    }
602
603    // If older profiles exist, remove them in favor of the new format
604    SCPreferencesRemoveValue(energyPrefs, CFSTR(kIOPMACPowerKey));
605    SCPreferencesRemoveValue(energyPrefs, CFSTR(kIOPMBatteryPowerKey));
606    SCPreferencesRemoveValue(energyPrefs, CFSTR(kIOPMUPSPowerKey));
607
608    if(!SCPreferencesCommitChanges(energyPrefs))
609    {
610        // handle error
611        if(kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged;
612        else ret = kIOReturnError;
613        goto exit;
614    }
615
616    ret = kIOReturnSuccess;
617exit:
618    if(energyPrefs) {
619        SCPreferencesUnlock(energyPrefs);
620        CFRelease(energyPrefs);
621    }
622    return ret;
623}
624
625/**************************************************/
626
627/*
628 * IOPMFeatureIsAvailable
629 (
630 * @param PMFeature - Name of a PM feature (like "WakeOnRing" or "Reduce Processor Speed")
631 * @param power_source - The current power source (like "AC Power" or "Battery Power")
632 * @result true if the given PM feature is supported on the given power source,
633 *      false if the feature is unsupported.
634 */
635bool IOPMFeatureIsAvailable(CFStringRef PMFeature, CFStringRef power_source)
636{
637    CFDictionaryRef             supportedFeatures = NULL;
638    io_registry_entry_t         registry_entry = MACH_PORT_NULL;
639    int                         return_this_value = 0;
640
641    if(!(registry_entry = getPMRootDomainRef()))
642        return false;
643
644    supportedFeatures = IORegistryEntryCreateCFProperty(registry_entry, CFSTR("Supported Features"),
645                                                        kCFAllocatorDefault, kNilOptions);
646
647    if (!supportedFeatures)
648        return false;
649
650    if( CFEqual(PMFeature, CFSTR(kIOPMDarkWakeBackgroundTaskKey)) )
651    {
652
653#if TARGET_OS_IPHONE
654        goto exit;
655#else
656        return_this_value = 0;
657
658        if (!power_source)
659            power_source = CFSTR(kIOPMACPowerKey);
660
661        // On new machines (late 2012 and beyond), IOPPF publishes PowerNap
662        // support using the kIOPMPowerNapSupportedKey
663        CFTypeRef pnDetails = CFDictionaryGetValue( supportedFeatures,
664                                CFSTR(kIOPMPowerNapSupportedKey));
665        if(featureSupportsPowerSource(pnDetails, power_source))
666        {
667            return_this_value = 1;
668            goto exit;
669        }
670
671
672        CFTypeRef btdetails = CFDictionaryGetValue( supportedFeatures,
673                                CFSTR(kIOPMDarkWakeBackgroundTaskKey));
674        CFTypeRef ssdetails = CFDictionaryGetValue( supportedFeatures,
675                                CFSTR(kIOPMSleepServicesKey));
676        if(featureSupportsPowerSource(btdetails, power_source) ||
677           featureSupportsPowerSource(ssdetails, power_source))
678        {
679            return_this_value = 1;
680        }
681#endif
682    }
683    else
684    {
685       return_this_value = IOPMFeatureIsAvailableWithSupportedTable(
686                               PMFeature,
687                               power_source,
688                               supportedFeatures);
689    }
690
691exit:
692    CFRelease(supportedFeatures);
693
694    return (return_this_value ? true:false);
695}
696
697
698bool IOPMFeatureIsAvailableWithSupportedTable(
699     CFStringRef                PMFeature,
700     CFStringRef                power_source,
701     CFDictionaryRef            supportedFeatures)
702{
703    CFStringRef                 supportedString = NULL;
704    CFTypeRef                   featureDetails = NULL;
705    bool                        ret = false;
706
707    if (!power_source)
708        power_source = CFSTR(kIOPMACPowerKey);
709
710    if (!supportedFeatures)
711        return false;
712
713    /* Basic sleep timer settings are always available *
714     * TTY connection ability to prevent sleep is always available */
715    if (CFEqual(PMFeature, CFSTR(kIOPMDisplaySleepKey))
716        || CFEqual(PMFeature, CFSTR(kIOPMSystemSleepKey))
717        || CFEqual(PMFeature, CFSTR(kIOPMDiskSleepKey))
718        || CFEqual(PMFeature, CFSTR(kIOPMTTYSPreventSleepKey)))
719    {
720        ret = true;
721        goto exit;
722    }
723
724    /* deprecated - kIOPMRestartOnKernelPanicKey
725     * 11195840 Remove "restart automatically if computer freezes" check-box
726     */
727    if (CFEqual(PMFeature, CFSTR(kIOPMRestartOnKernelPanicKey))) {
728        ret = false;
729        goto exit;
730    }
731
732    // *********************************
733    // Special case for PowerButtonSleep
734
735    if(CFEqual(PMFeature, CFSTR(kIOPMSleepOnPowerButtonKey)))
736    {
737#if TARGET_OS_IPHONE
738        ret = false;
739#else
740        CFArrayRef  tmp_array = NULL;
741        // Pressing the power button only causes sleep on desktop PowerMacs,
742        // cubes, and iMacs.
743        // Therefore this feature is not supported on portables.
744        // We'll use the presence of a battery (or the capability for a battery)
745        // as evidence whether this is a portable or not.
746        IOReturn r = IOPMCopyBatteryInfo(kIOMasterPortDefault, &tmp_array);
747        if((r == kIOReturnSuccess) && tmp_array)
748        {
749            CFRelease(tmp_array);
750            ret = false;
751        } else ret = true;
752#endif
753        goto exit;
754    }
755
756    // *********************************
757    // Special case for ReduceBrightness
758
759    if ( CFEqual(PMFeature, CFSTR(kIOPMReduceBrightnessKey)) )
760    {
761        // ReduceBrightness feature is only supported on laptops
762        // and on desktops with UPS with brightness-adjustable LCD displays.
763        // These machines report a "DisplayDims" property in the
764        // supportedFeatures dictionary.
765        // ReduceBrightness is never supported on AC Power.
766        bool hasBatt = false;
767        bool hasUPS = false;
768        IOPSGetSupportedPowerSources(NULL, &hasBatt, &hasUPS);
769
770        if (( hasBatt || hasUPS )
771            && supportedFeatures
772            && CFDictionaryGetValue(supportedFeatures, CFSTR("DisplayDims"))
773            && !CFEqual(power_source, CFSTR(kIOPMACPowerKey)) )
774        {
775            ret = true;
776        } else {
777            ret = false;
778        }
779
780        goto exit;
781    }
782
783    // ***********************************
784    // Generic code for all other settings
785
786    supportedString = supportedNameForPMName( PMFeature );
787    if(!supportedString) {
788        ret = false;
789        goto exit;
790    }
791
792    featureDetails = CFDictionaryGetValue(supportedFeatures, supportedString);
793    if(!featureDetails) {
794        ret = false;
795        goto exit;
796    }
797
798    if(featureSupportsPowerSource(featureDetails, power_source))
799    {
800        ret = true;
801    }
802
803
804exit:
805    return ret;
806}
807
808/**************************************************/
809
810// How we determine what ActivePowerProfiles to return:
811// (1) If the user has specified any profiles in the
812//     PM prefs file, we'll return those.
813// (2) If the user hasn't explicitly specified any
814//     profiles, we'll look to their Custom settings:
815// (3) If, in the past, a user has specified any PM settings at
816//     all (say from before an upgrade install), we'll return
817//     (-1, -1, -1) and respect those settings as custom settings.
818// (4) If there are no specified profiles and no previous specified
819//     custom settings, then we'll return (2, 1, 1) as specified
820//     in PowerManagement.bundle's com.apple.SystemPowerProfileDefaults.plist
821//
822// Also, note that in the case of (1), we'll re-populate any settings not
823// specified for a particular power source (UPS's are easy to plug/unplug)
824// with the defaults obtained as in (4).
825//
826// For all steps above, we'll strip any irrelevant settings before
827// returning the dictionary (i.e. battery or UPS settings will not be
828// returned where unsupported)
829
830CFDictionaryRef     IOPMCopyActivePowerProfiles(void)
831{
832    IOReturn                ret;
833    CFDictionaryRef         activeProfiles;
834
835    ret = readAllPMPlistSettings(
836                        kIOPMRemoveUnsupportedPreferences,
837                        NULL,
838                        &activeProfiles, NULL);
839
840    if(kIOReturnSuccess == ret) {
841        return activeProfiles;
842    } else {
843        return NULL;
844    }
845}
846
847/**************************************************/
848
849IOReturn IOPMSetActivePowerProfiles(CFDictionaryRef which_profile)
850{
851    CFDataRef           profiles_data;
852    vm_address_t        profiles_buffer;
853    IOByteCount         buffer_len;
854    kern_return_t       kern_result;
855    IOReturn            return_val = kIOReturnError;
856    mach_port_t         server_port = MACH_PORT_NULL;
857
858    if(!_isActiveProfileDictValid(which_profile)) {
859        return kIOReturnBadArgument;
860    }
861
862    // open reference to PM configd
863    kern_result = bootstrap_look_up2(bootstrap_port,
864                                     kIOPMServerBootstrapName,
865                                     &server_port,
866                                     0,
867                                     BOOTSTRAP_PRIVILEGED_SERVER);
868    if(KERN_SUCCESS != kern_result) {
869        return kIOReturnError;
870    }
871
872    profiles_data = IOCFSerialize(which_profile, 0);
873    profiles_buffer = (vm_address_t) CFDataGetBytePtr(profiles_data);
874    buffer_len = CFDataGetLength(profiles_data);
875
876    // toss dictionary over the wall to conigd via mig-generated interface
877    // configd will perform a permissions check. If the caller is root,
878    // admin, or console, configd will write the prefs file from its
879    // root context.
880    kern_result = io_pm_set_active_profile(server_port,
881                            profiles_buffer, buffer_len,
882                            &return_val);
883
884    mach_port_deallocate(mach_task_self(), server_port);
885    CFRelease(profiles_data);
886
887    if(KERN_SUCCESS == kern_result) {
888        return return_val;
889    } else {
890        return kIOReturnInternalError;
891    }
892}
893
894/**************************************************/
895
896/***
897 Returns a CFRunLoopSourceRef that notifies the caller when power source
898 information changes.
899 Arguments:
900    IOPowerSourceCallbackType callback - A function to be called whenever
901        ES prefs file on disk changes
902    void *context - Any user-defined pointer, passed to the callback.
903 Returns NULL if there were any problems.
904 Caller must CFRelease() the returned value.
905***/
906CFRunLoopSourceRef IOPMPrefsNotificationCreateRunLoopSource(
907    IOPMPrefsCallbackType callback,
908    void *context)
909{
910    SCDynamicStoreRef           store = NULL;
911    CFStringRef                 EnergyPrefsKey = NULL;
912    CFRunLoopSourceRef          SCDrls = NULL;
913    user_callback_context       *ioContext = NULL;
914    SCDynamicStoreContext       scContext = {0, NULL, CFRetain, CFRelease, NULL};
915
916    if(!callback) return NULL;
917
918    scContext.info = CFDataCreateMutable(NULL, sizeof(user_callback_context));
919    CFDataSetLength(scContext.info, sizeof(user_callback_context));
920    ioContext = (user_callback_context *)CFDataGetBytePtr(scContext.info);
921    ioContext->context = context;
922    ioContext->callback = callback;
923
924    // Open connection to SCDynamicStore. User's callback as context.
925    store = SCDynamicStoreCreate(kCFAllocatorDefault,
926                CFSTR("IOKit Preferences Copy"), ioCallout, (void *)&scContext);
927    if(!store) return NULL;
928
929    // Setup notification for changes in Energy Saver prefences
930    EnergyPrefsKey = SCDynamicStoreKeyCreatePreferences(
931                    NULL,
932                    kIOPMPrefsPath,
933                    kSCPreferencesKeyApply);
934    if(EnergyPrefsKey) {
935        SCDynamicStoreAddWatchedKey(store, EnergyPrefsKey, FALSE);
936        CFRelease(EnergyPrefsKey);
937    }
938
939    // Obtain the CFRunLoopSourceRef from this SCDynamicStoreRef session
940    SCDrls = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault, store, 0);
941    CFRelease(store);
942
943    return SCDrls;
944}
945
946/******************************************************************************/
947/******************************************************************************/
948/******************************************************************************/
949// Internals
950
951static void mergeUserDefaultOverriddenSettings(CFMutableDictionaryRef es)
952{
953    CFMutableDictionaryRef  batt        = NULL;
954    CFMutableDictionaryRef  ac          = NULL;
955    CFMutableDictionaryRef  ups         = NULL;
956    CFDictionaryRef         acOver      = NULL;
957    CFDictionaryRef         battOver    = NULL;
958    CFDictionaryRef         upsOver     = NULL;
959    SCDynamicStoreRef       dynamic_store = NULL;
960    CFDictionaryRef         userOverrides = NULL;
961
962    /*
963     * There might be a CFDictionary in the SCDynamicStore at
964     *     "State:/IOKit/PowerManagement/UserOverrides"
965     *      == kIOPMDynamicStoreUserOverridesKey
966     * If there is, then we will prefer to use its settings
967     * as default settings, rather than our hard-coded defaults,
968     * for unspecified setting values.
969     */
970    dynamic_store = SCDynamicStoreCreate(0, CFSTR("IOKit User Library - PM defaults"), NULL, NULL);
971
972    if (dynamic_store)
973    {
974        userOverrides = SCDynamicStoreCopyValue(dynamic_store, CFSTR(kIOPMDynamicStoreUserOverridesKey));
975        CFRelease(dynamic_store);
976    }
977
978    if (NULL == userOverrides)
979        return;
980
981    if (!isA_CFDictionary(userOverrides)) {
982        CFRelease(userOverrides);
983        return;
984    }
985
986    acOver     = CFDictionaryGetValue(userOverrides, CFSTR(kIOPMACPowerKey));
987    battOver   = CFDictionaryGetValue(userOverrides, CFSTR(kIOPMBatteryPowerKey));
988    upsOver    = CFDictionaryGetValue(userOverrides, CFSTR(kIOPMUPSPowerKey));
989
990    // Overrides either contains 3 dictionaries of PM Settings keyed as
991    // AC, Battery, and UPS Power, or it is itself a dictionary of PM Settings.
992    if(acOver && battOver && upsOver)
993    {
994        // Good. All 3 power source settings types are represented.
995        // Do nothing here.
996    } else if(!acOver && !battOver && !upsOver)
997    {
998        // The dictionary didn't specify any per-power source overrides, which
999        // means that it's a flat dictionary strictly of PM settings.
1000        // We duplicate it 3 ways, as each overridden setting in this dictionary
1001        // will be applied to each power source's settings.
1002        acOver = battOver = upsOver = userOverrides;
1003    } else {
1004        return;
1005    }
1006
1007    ac      = (CFMutableDictionaryRef)CFDictionaryGetValue(es, CFSTR(kIOPMACPowerKey));
1008    batt    = (CFMutableDictionaryRef)CFDictionaryGetValue(es, CFSTR(kIOPMBatteryPowerKey));
1009    ups     = (CFMutableDictionaryRef)CFDictionaryGetValue(es, CFSTR(kIOPMUPSPowerKey));
1010
1011    if (ac) {
1012        mergeDictIntoMutable(ac,    acOver,     kKeepOriginalValues);
1013    }
1014
1015    if (batt) {
1016        mergeDictIntoMutable(batt,  battOver,   kKeepOriginalValues);
1017    }
1018
1019    if (ups) {
1020        mergeDictIntoMutable(ups,   upsOver,    kKeepOriginalValues);
1021    }
1022
1023    CFRelease (userOverrides);
1024
1025    return;
1026}
1027
1028static int addDefaultEnergySettings(CFMutableDictionaryRef sys)
1029{
1030    CFMutableDictionaryRef  batt = NULL;
1031    CFMutableDictionaryRef  ac = NULL;
1032    CFMutableDictionaryRef  ups = NULL;
1033    int             i;
1034    CFNumberRef     val;
1035    CFStringRef     key;
1036
1037
1038    batt    = (CFMutableDictionaryRef)CFDictionaryGetValue(sys, CFSTR(kIOPMBatteryPowerKey));
1039    ac      = (CFMutableDictionaryRef)CFDictionaryGetValue(sys, CFSTR(kIOPMACPowerKey));
1040    ups     = (CFMutableDictionaryRef)CFDictionaryGetValue(sys, CFSTR(kIOPMUPSPowerKey));
1041
1042    /*
1043     * Note that in the following "poplulation" loops, we're using
1044     * CFDictionaryAddValue rather than CFDictionarySetValue. If a value is
1045     * already present AddValue will not replace it.
1046     */
1047
1048    /*
1049     * Populate default battery dictionary
1050     */
1051
1052    if (batt) {
1053        for (i=0; i<kPMSettingsCount; i++)
1054        {
1055            key = CFStringCreateWithCString(0, defaultSettings[i].keyName, kCFStringEncodingMacRoman);
1056            val = CFNumberCreate(0, kCFNumberSInt32Type, &defaultSettings[i].defaultValueBattery);
1057
1058            CFDictionaryAddValue(batt, key, val);
1059
1060            CFRelease(key);
1061            CFRelease(val);
1062        }
1063        CFDictionaryAddValue(batt, CFSTR(kIOHibernateFileKey), CFSTR(kIOHibernateDefaultFile));
1064    }
1065
1066    /*
1067     * Populate default AC dictionary
1068     */
1069    if (ac)
1070    {
1071        for (i=0; i<kPMSettingsCount; i++)
1072        {
1073            key = CFStringCreateWithCString(0, defaultSettings[i].keyName, kCFStringEncodingMacRoman);
1074            val = CFNumberCreate(0, kCFNumberSInt32Type, &defaultSettings[i].defaultValueAC);
1075
1076            CFDictionaryAddValue(ac, key, val);
1077
1078            CFRelease(key);
1079            CFRelease(val);
1080        }
1081
1082        CFDictionaryAddValue(ac, CFSTR(kIOHibernateFileKey), CFSTR(kIOHibernateDefaultFile));
1083    }
1084
1085    /*
1086     * Populate default UPS dictionary
1087     */
1088    if (ups) {
1089        for (i=0; i<kPMSettingsCount; i++)
1090        {
1091            key = CFStringCreateWithCString(0, defaultSettings[i].keyName, kCFStringEncodingMacRoman);
1092            val = CFNumberCreate(0, kCFNumberSInt32Type, &defaultSettings[i].defaultValueAC);
1093
1094            CFDictionaryAddValue(ups, key, val);
1095
1096            CFRelease(key);
1097            CFRelease(val);
1098        }
1099
1100        CFDictionaryAddValue(ups, CFSTR(kIOHibernateFileKey), CFSTR(kIOHibernateDefaultFile));
1101    }
1102
1103    return 0;
1104}
1105
1106static void addSystemProfileEnergySettings(
1107    CFDictionaryRef user_profile_selections,
1108    CFMutableDictionaryRef passed_in)
1109{
1110    CFArrayRef                  system_profiles = NULL;
1111    CFDictionaryRef             profile_at_idx = NULL;
1112    CFDictionaryRef             finally_actual_settings = NULL;
1113
1114    CFNumberRef                 this_profile_choice = NULL;
1115    CFNumberRef                 default_profile_choice = NULL;
1116    CFDictionaryRef             default_profile_selections = NULL;
1117    int                         int_profile_choice = 0;
1118
1119    CFMutableDictionaryRef      ps_passed_in = NULL;
1120    CFStringRef                 this_power_source = NULL;
1121    int                         i;
1122
1123    // Does the user currently have any profiles selected?
1124    // If not, IOPMCopyActivePowerProfiles returns a (2,1,1) default
1125    if(!user_profile_selections) return;
1126
1127    default_profile_selections = _createDefaultProfileSelections();
1128    if(!isA_CFDictionary(default_profile_selections))
1129        return;
1130
1131    // Copy the full CFArray of system profiles
1132    system_profiles = IOPMCopyPowerProfiles();
1133    if(!system_profiles) goto exit_cleanup;
1134
1135    // For each power source,
1136    for(i = 0; i<kPowerSourcesCount; i++)
1137    {
1138        this_power_source = getPowerSourceString(i);
1139        if(!this_power_source) continue;
1140
1141        // Grab the profile number from user_profile_selections
1142        this_profile_choice = isA_CFNumber( CFDictionaryGetValue(
1143                                user_profile_selections, this_power_source));
1144        if(this_profile_choice) {
1145            CFNumberGetValue( this_profile_choice,
1146                                kCFNumberIntType, &int_profile_choice);
1147        }
1148
1149        /* -1 == Custom settings in use?
1150           Then we need to merge in the default settings [from profiles 2,1,1]
1151           for this power source.
1152         */
1153        if( -1 == int_profile_choice ) {
1154            default_profile_choice = isA_CFNumber( CFDictionaryGetValue(
1155                                default_profile_selections, this_power_source));
1156            if(default_profile_choice) {
1157                CFNumberGetValue( default_profile_choice,
1158                                    kCFNumberIntType, &int_profile_choice);
1159            }
1160        }
1161
1162        // And if the integer profile index is outside the acceptable range,
1163        // we give it a sane value
1164        if ( (int_profile_choice < 0)
1165            || (int_profile_choice > kPowerProfilesCount) )
1166        {
1167            int_profile_choice = 2;
1168        }
1169
1170        // Index into systemProfiles at profileNumber
1171        profile_at_idx = CFArrayGetValueAtIndex( system_profiles,
1172                                                 int_profile_choice);
1173        if(!profile_at_idx) continue;
1174
1175        // From the profile's CFDictionary, extract the final actual
1176        // settings CFDictionary for "this profile number" and for
1177        // "this power source"
1178        finally_actual_settings = CFDictionaryGetValue(
1179                                    profile_at_idx, this_power_source);
1180
1181        // Gently merge this settings CFDictionary into the passed-in
1182        // settings dictionary's appropiate power-source specific dictionary
1183
1184        ps_passed_in = (CFMutableDictionaryRef)
1185                            CFDictionaryGetValue(passed_in, this_power_source);
1186
1187        if(!finally_actual_settings || !ps_passed_in) continue;
1188
1189        mergeDictIntoMutable( ps_passed_in,
1190                              finally_actual_settings,
1191                              kKeepOriginalValues);
1192    }
1193
1194exit_cleanup:
1195//    if(user_profile_selections) CFRelease(user_profile_selections);
1196    if(default_profile_selections) CFRelease(default_profile_selections);
1197    if(system_profiles) CFRelease(system_profiles);
1198
1199    return;
1200}
1201
1202
1203/* getPMRootDomainRef
1204 *
1205 * Caller should not release the returned io_registry_entry_t
1206 */
1207__private_extern__ io_registry_entry_t  getPMRootDomainRef(void)
1208{
1209    static io_registry_entry_t cached_root_domain = MACH_PORT_NULL;
1210
1211    if( MACH_PORT_NULL == cached_root_domain ) {
1212        cached_root_domain = IORegistryEntryFromPath( kIOMasterPortDefault,
1213                        kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
1214
1215    }
1216    return cached_root_domain;
1217}
1218
1219
1220/* Maps a PowerManagement string constant
1221 *   -> to its corresponding Supported Feature in IOPMrootDomain
1222 */
1223static CFStringRef
1224supportedNameForPMName( CFStringRef pm_name )
1225{
1226#if TARGET_OS_IPHONE
1227    if( CFEqual(pm_name, CFSTR(kIOPMReduceBrightnessKey))
1228        || CFEqual(pm_name, CFSTR(kIOPMDisplaySleepUsesDimKey)) )
1229#else
1230    if(CFEqual(pm_name, CFSTR(kIOPMDisplaySleepUsesDimKey)))
1231#endif /* TARGET_OS_IPHONE */
1232    {
1233        return CFSTR("DisplayDims");
1234    }
1235
1236    if(CFEqual(pm_name, CFSTR(kIOPMWakeOnLANKey))
1237       || CFEqual(pm_name, CFSTR(kIOPMPrioritizeNetworkReachabilityOverSleepKey)))
1238    {
1239        return CFSTR("WakeOnMagicPacket");
1240    }
1241
1242    if(CFEqual(pm_name, CFSTR(kIOPMMobileMotionModuleKey)))
1243    {
1244        return CFSTR("MobileMotionModule");
1245    }
1246
1247    if( CFEqual(pm_name, CFSTR(kIOHibernateModeKey))
1248        || CFEqual(pm_name, CFSTR(kIOHibernateFreeRatioKey))
1249        || CFEqual(pm_name, CFSTR(kIOHibernateFreeTimeKey))
1250        || CFEqual(pm_name, CFSTR(kIOHibernateFileKey))
1251        || CFEqual(pm_name, CFSTR(kIOHibernateFeatureKey)))
1252    {
1253        return CFSTR(kIOHibernateFeatureKey);
1254    }
1255
1256    if (CFEqual(pm_name, CFSTR(kIOPMDeepSleepEnabledKey))
1257        || CFEqual(pm_name, CFSTR(kIOPMDeepSleepDelayKey)))
1258    {
1259        return CFSTR("DeepSleep");
1260    }
1261
1262    if (CFEqual(pm_name, CFSTR(kIOPMAutoPowerOffEnabledKey))
1263        || CFEqual(pm_name, CFSTR(kIOPMAutoPowerOffDelayKey)))
1264    {
1265        return CFSTR("AutoPowerOff");
1266    }
1267
1268    return pm_name;
1269}
1270
1271// Helper for IOPMFeatureIsAvailable
1272static bool
1273featureSupportsPowerSource(CFTypeRef featureDetails, CFStringRef power_source)
1274{
1275    CFNumberRef         featureNum   = NULL;
1276    CFNumberRef         tempNum      = NULL;
1277    CFArrayRef          featureArr   = NULL;
1278    uint32_t            ps_support   = 0;
1279    uint32_t            tmp;
1280    unsigned int        i;
1281
1282    if( (featureNum = isA_CFNumber(featureDetails)) )
1283    {
1284        CFNumberGetValue(featureNum, kCFNumberSInt32Type, &ps_support);
1285    } else if( (featureArr = isA_CFArray(featureDetails)) )
1286    {
1287        // If several entitites are asserting a given feature, we OR
1288        // together their supported power sources.
1289
1290        unsigned int arrayCount = CFArrayGetCount(featureArr);
1291        for(i = 0; i<arrayCount; i++)
1292        {
1293            tempNum = isA_CFNumber(CFArrayGetValueAtIndex(featureArr, i));
1294            if(tempNum) {
1295                CFNumberGetValue(tempNum, kCFNumberSInt32Type, &tmp);
1296                ps_support |= tmp;
1297            }
1298        }
1299    }
1300
1301    if(!power_source) {
1302
1303        // Lack of a defined power source just gets a "true" return
1304        // if the setting is supported on ANY power source.
1305
1306        return (ps_support ? true : false);
1307    }
1308
1309    if(CFEqual(CFSTR(kIOPMACPowerKey), power_source) )
1310    {
1311        return (ps_support & kIOPMSupportedOnAC) ? true : false;
1312    } else if(CFEqual(CFSTR(kIOPMBatteryPowerKey), power_source) )
1313    {
1314        return (ps_support & kIOPMSupportedOnBatt) ? true : false;
1315    } else if(CFEqual(CFSTR(kIOPMUPSPowerKey), power_source) )
1316    {
1317        return (ps_support & kIOPMSupportedOnUPS) ? true : false;
1318    } else {
1319        // unexpected power source argument
1320        return false;
1321    }
1322
1323}
1324
1325static bool checkPowerSourceSupported(CFStringRef str)
1326{
1327    bool hasBatt;
1328    bool hasUPS;
1329
1330    IOPSGetSupportedPowerSources(NULL, &hasBatt, &hasUPS);
1331
1332    if (CFEqual(str, CFSTR(kIOPMACPowerKey))) {
1333        return true;
1334    }
1335
1336    if (CFEqual(str, CFSTR(kIOPMBatteryPowerKey))) {
1337        return hasBatt;
1338    }
1339
1340    if (CFEqual(str, CFSTR(kIOPMUPSPowerKey))) {
1341        return hasUPS;
1342    }
1343    return false;
1344}
1345
1346/***
1347 * removeIrrelevantPMProperties
1348 *
1349 * Prunes unsupported properties from the energy dictionary.
1350 * e.g. If your machine doesn't have a modem, this removes the Wake On Ring property.
1351 ***/
1352static void IOPMRemoveIrrelevantProperties(CFMutableDictionaryRef energyPrefs)
1353{
1354    int                         profile_count = 0;
1355    int                         dict_count    = 0;
1356    CFStringRef                 *profile_keys = NULL;
1357    CFDictionaryRef             *profile_vals = NULL;
1358    CFStringRef                 *dict_keys    = NULL;
1359    CFDictionaryRef             *dict_vals    = NULL;
1360    CFMutableDictionaryRef      this_profile  = NULL;
1361    CFDictionaryRef                _supportedCached = NULL;
1362    io_registry_entry_t         _rootDomain   = IO_OBJECT_NULL;
1363
1364
1365    // Grab a copy of RootDomain's supported energy saver settings
1366    _rootDomain = getPMRootDomainRef();
1367    if (IO_OBJECT_NULL != _rootDomain)
1368    {
1369        _supportedCached = IORegistryEntryCreateCFProperty(_rootDomain,
1370                                                           CFSTR("Supported Features"),
1371                                                           kCFAllocatorDefault, kNilOptions);
1372    }
1373
1374    /*
1375     * Remove features when not supported -
1376     *      Wake On Administrative Access, Dynamic Speed Step, etc.
1377     */
1378    profile_count = CFDictionaryGetCount(energyPrefs);
1379    profile_keys = (CFStringRef *)malloc(sizeof(CFStringRef) * profile_count);
1380    profile_vals = (CFDictionaryRef *)malloc(sizeof(CFDictionaryRef) * profile_count);
1381    if (!profile_keys || !profile_vals)
1382        goto exit;
1383
1384    CFDictionaryGetKeysAndValues(energyPrefs, (const void **)profile_keys,
1385                                 (const void **)profile_vals);
1386    // For each CFDictionary at the top level (battery, AC)
1387    while(--profile_count >= 0)
1388    {
1389        if(!checkPowerSourceSupported(profile_keys[profile_count]))
1390        {
1391            // Remove dictionary if the whole power source isn't supported on this machine.
1392            CFDictionaryRemoveValue(energyPrefs, profile_keys[profile_count]);
1393        } else {
1394
1395            // Make a mutable copy of the prefs dictionary
1396
1397            this_profile = (CFMutableDictionaryRef)isA_CFDictionary(
1398                                                                    CFDictionaryGetValue(energyPrefs, profile_keys[profile_count]));
1399            if(!this_profile)
1400                continue;
1401
1402            this_profile = CFDictionaryCreateMutableCopy(NULL, 0, this_profile);
1403            if(!this_profile)
1404                continue;
1405
1406            CFDictionarySetValue(energyPrefs, profile_keys[profile_count], this_profile);
1407            CFRelease(this_profile);
1408
1409            // And prune unneeded settings from our new mutable property
1410
1411            dict_count = CFDictionaryGetCount(this_profile);
1412            dict_keys = (CFStringRef *)malloc(sizeof(CFStringRef) * dict_count);
1413            dict_vals = (CFDictionaryRef *)malloc(sizeof(CFDictionaryRef) * dict_count);
1414            if (!dict_keys || !dict_vals)
1415                continue;
1416            CFDictionaryGetKeysAndValues(this_profile,
1417                                         (const void **)dict_keys, (const void **)dict_vals);
1418            // For each specific property within each dictionary
1419            while(--dict_count >= 0)
1420            {
1421                if( CFEqual((CFStringRef)dict_keys[dict_count], CFSTR(kIOPMDarkWakeBackgroundTaskKey)) )
1422                {
1423#if !TARGET_OS_IPHONE
1424                    // We conditionalize PowerNap support on kIOPMPowerNapSupportedKey for all
1425                    // machines late 2012 and beyond. The presence of this key is a sufficient
1426                    // condition to support PowerNap
1427                    bool supportsNewPNKey = false;
1428                    if(IOPMFeatureIsAvailableWithSupportedTable( CFSTR(kIOPMPowerNapSupportedKey),
1429                           (CFStringRef)profile_keys[profile_count], _supportedCached)) {
1430                            supportsNewPNKey = true;
1431                    }
1432
1433                    // For legacy machines, we look for either the kIOPMDarkWakeBackgroundTaskKey or the
1434                    // kIOPMSleepServicesKey
1435                    if ( ((!IOPMFeatureIsAvailableWithSupportedTable( CFSTR(kIOPMDarkWakeBackgroundTaskKey),
1436                            (CFStringRef)profile_keys[profile_count], _supportedCached)  &&
1437                        !IOPMFeatureIsAvailableWithSupportedTable( CFSTR(kIOPMSleepServicesKey),
1438                            (CFStringRef)profile_keys[profile_count], _supportedCached))
1439                         && !supportsNewPNKey
1440                      )
1441                   {
1442                       CFDictionaryRemoveValue(this_profile, (CFStringRef)dict_keys[dict_count]);
1443                   }
1444#endif /* !TARGET_OS_IPHONE */
1445                }
1446                else if( !IOPMFeatureIsAvailableWithSupportedTable((CFStringRef)dict_keys[dict_count],
1447                                    (CFStringRef)profile_keys[profile_count], _supportedCached) )
1448                {
1449                    // If the property isn't supported, remove it
1450                    CFDictionaryRemoveValue(this_profile,
1451                                            (CFStringRef)dict_keys[dict_count]);
1452                }
1453            }
1454            free(dict_keys);
1455            free(dict_vals);
1456        }
1457    }
1458
1459exit:
1460    if (profile_keys)
1461        free(profile_keys);
1462    if (profile_vals)
1463        free(profile_vals);
1464    if (_supportedCached)
1465        CFRelease(_supportedCached);
1466    return;
1467}
1468
1469/***
1470 * getCheetahPumaEnergySettings
1471 *
1472 * Reads the old Energy Saver preferences file from /Library/Preferences/com.apple.PowerManagement.xml
1473 *
1474 ***/
1475static int getCheetahPumaEnergySettings(CFMutableDictionaryRef energyPrefs)
1476{
1477   SCPreferencesRef             CheetahPrefs = NULL;
1478   CFMutableDictionaryRef       s = NULL;
1479   CFNumberRef                  n;
1480   CFBooleanRef                 b;
1481
1482   if(!energyPrefs) return 0;
1483   CheetahPrefs = SCPreferencesCreate (kCFAllocatorDefault,
1484                CFSTR("I/O Kit PM Library"),
1485                CFSTR("/Library/Preferences/com.apple.PowerManagement.plist"));
1486
1487    if(!CheetahPrefs) return 0;
1488
1489    s = (CFMutableDictionaryRef)CFDictionaryGetValue( energyPrefs,
1490                                            CFSTR(kIOPMBatteryPowerKey));
1491    if(!s)
1492    {
1493        CFRelease(CheetahPrefs);
1494        return 0;
1495    }
1496    n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahDimKey);
1497    if(n) CFDictionaryAddValue(s, CFSTR(kIOPMDisplaySleepKey), n);
1498    n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahDiskKey);
1499    if(n) CFDictionaryAddValue(s, CFSTR(kIOPMDiskSleepKey), n);
1500    n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahSleepKey);
1501    if(n) CFDictionaryAddValue(s, CFSTR(kIOPMSystemSleepKey), n);
1502    b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahRestartOnPowerLossKey);
1503    if(b) CFDictionaryAddValue(s, CFSTR(kIOPMRestartOnPowerLossKey), b);
1504    b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahWakeForNetworkAccessKey);
1505    if(b) CFDictionaryAddValue(s, CFSTR(kIOPMWakeOnLANKey), b);
1506    b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahWakeOnRingKey);
1507    if(b) CFDictionaryAddValue(s, CFSTR(kIOPMWakeOnRingKey), b);
1508
1509
1510    s = (CFMutableDictionaryRef)CFDictionaryGetValue(energyPrefs, CFSTR(kIOPMACPowerKey));
1511    if(!s)
1512    {
1513        CFRelease(CheetahPrefs);
1514        return 0;
1515    }
1516    n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahDimKey);
1517    if(n) CFDictionaryAddValue(s, CFSTR(kIOPMDisplaySleepKey), n);
1518    n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahDiskKey);
1519    if(n) CFDictionaryAddValue(s, CFSTR(kIOPMDiskSleepKey), n);
1520    n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahSleepKey);
1521    if(n) CFDictionaryAddValue(s, CFSTR(kIOPMSystemSleepKey), n);
1522    b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahRestartOnPowerLossKey);
1523    if(b) CFDictionaryAddValue(s, CFSTR(kIOPMRestartOnPowerLossKey), b);
1524    b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahWakeForNetworkAccessKey);
1525    if(b) CFDictionaryAddValue(s, CFSTR(kIOPMWakeOnLANKey), b);
1526    b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahWakeOnRingKey);
1527    if(b) CFDictionaryAddValue(s, CFSTR(kIOPMWakeOnRingKey), b);
1528
1529
1530    CFRelease(CheetahPrefs);
1531
1532     return 1; // success
1533}
1534
1535
1536/**************************************************
1537*
1538* System Power Settings
1539*
1540**************************************************/
1541
1542IOReturn IOPMActivateSystemPowerSettings( void )
1543{
1544    io_registry_entry_t         rootdomain = MACH_PORT_NULL;
1545    CFDictionaryRef             settings = NULL;
1546    IOReturn                    ret = kIOReturnSuccess;
1547    bool                        disable_sleep = false;
1548
1549    settings = IOPMCopySystemPowerSettings();
1550    if(!settings) {
1551        goto exit;
1552    }
1553
1554    // Disable Sleep?
1555    disable_sleep = (kCFBooleanTrue ==
1556                        CFDictionaryGetValue( settings, kIOPMSleepDisabledKey ));
1557
1558    rootdomain = getPMRootDomainRef();
1559    ret = IORegistryEntrySetCFProperty( rootdomain, kIOPMSleepDisabledKey,
1560                        (disable_sleep ? kCFBooleanTrue : kCFBooleanFalse));
1561
1562#if !TARGET_OS_IPHONE
1563    bool    avoid_keyStore = false;
1564    // Disable FDE Key Store on SMC
1565    avoid_keyStore = (kCFBooleanTrue ==
1566                        CFDictionaryGetValue( settings, CFSTR(kIOPMDestroyFVKeyOnStandbyKey) ));
1567    ret = IORegistryEntrySetCFProperty( rootdomain, CFSTR(kIOPMDestroyFVKeyOnStandbyKey),
1568                        (avoid_keyStore ? kCFBooleanTrue : kCFBooleanFalse));
1569
1570#endif
1571
1572exit:
1573    if(settings) CFRelease( settings );
1574    return ret;
1575}
1576
1577CFDictionaryRef IOPMCopySystemPowerSettings(void)
1578{
1579    CFDictionaryRef                         systemPowerDictionary = NULL;
1580    CFDictionaryRef                         tmp_dict = NULL;
1581    SCPreferencesRef                        energyPrefs = NULL;
1582
1583    energyPrefs = SCPreferencesCreate( kCFAllocatorDefault,
1584                                        kIOPMAppName, kIOPMPrefsPath );
1585    if(!energyPrefs) {
1586        return NULL;
1587    }
1588
1589    tmp_dict = isA_CFDictionary(SCPreferencesGetValue( energyPrefs,
1590                                                CFSTR("SystemPowerSettings")));
1591
1592    if(!tmp_dict) {
1593        goto exit;
1594    }
1595
1596    systemPowerDictionary = CFDictionaryCreateCopy(0, tmp_dict);
1597
1598exit:
1599    if(energyPrefs) CFRelease(energyPrefs);
1600    return systemPowerDictionary;
1601}
1602
1603IOReturn IOPMSetSystemPowerSetting( CFStringRef key, CFTypeRef value)
1604{
1605    IOReturn                    ret = kIOReturnError;
1606    SCPreferencesRef            energyPrefs = NULL;
1607
1608    CFMutableDictionaryRef      systemPowerDictionary = NULL;
1609    CFDictionaryRef             tmp_dict = NULL;
1610
1611    energyPrefs = SCPreferencesCreate( 0, kIOPMAppName, kIOPMPrefsPath );
1612    if(!energyPrefs)
1613    {
1614        if(kSCStatusAccessError == SCError())
1615           return kIOReturnNotPrivileged;
1616        else
1617           return kIOReturnError;
1618    }
1619
1620    /* We lock energyPrefs here to prevent multiple simultaneous writes
1621     * modifying the same data. Must lock energyPrefs before reading
1622     * systemPowerSettings in IOPMCopySystemPowerSettings.
1623     */
1624    if(!SCPreferencesLock(energyPrefs, true))
1625    {
1626        if(kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged;
1627        else ret = kIOReturnError;
1628        goto exit;
1629    }
1630
1631    tmp_dict = IOPMCopySystemPowerSettings();
1632    if(tmp_dict) {
1633        systemPowerDictionary = CFDictionaryCreateMutableCopy(0, 0, tmp_dict);
1634        CFRelease(tmp_dict);
1635        tmp_dict = NULL;
1636    } else {
1637        systemPowerDictionary = CFDictionaryCreateMutable(0, 0,
1638                                        &kCFTypeDictionaryKeyCallBacks,
1639                                        &kCFTypeDictionaryValueCallBacks);
1640    }
1641
1642    if(!systemPowerDictionary) {
1643        goto exit;
1644    }
1645
1646    CFDictionarySetValue( systemPowerDictionary, key, value);
1647
1648    ret = kIOReturnSuccess;
1649
1650    if(!SCPreferencesSetValue( energyPrefs,
1651                                CFSTR("SystemPowerSettings"),
1652                                systemPowerDictionary))
1653    {
1654        ret = kIOReturnError;
1655        goto exit;
1656    }
1657
1658    if(!SCPreferencesCommitChanges(energyPrefs))
1659    {
1660        // handle error
1661        if(kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged;
1662        else ret = kIOReturnError;
1663        goto exit;
1664    }
1665
1666    ret = kIOReturnSuccess;
1667exit:
1668    if(energyPrefs) {
1669        SCPreferencesUnlock(energyPrefs);
1670        CFRelease(energyPrefs);
1671    }
1672    return ret;
1673
1674}
1675
1676
1677void IOPMOverrideDefaultPMPreferences(CFDictionaryRef overrideSettings)
1678{
1679    SCDynamicStoreRef               dynamic_store = NULL;
1680
1681    if(0 == isA_CFDictionary(overrideSettings)) {
1682        return;
1683    }
1684
1685    dynamic_store = SCDynamicStoreCreate(kCFAllocatorDefault,
1686                                         CFSTR("IOKit User Library - Override"),
1687                                         NULL, NULL);
1688    if(dynamic_store == NULL)
1689        return;
1690
1691    // This is the simplest possible implementation of IOPMOverrideDefaultPMPreferences.
1692    // This assumes only one caller. If called multiple times, the last caller will
1693    // overwrite all previous callers values.
1694    SCDynamicStoreSetValue(dynamic_store, CFSTR(kIOPMDynamicStoreUserOverridesKey), overrideSettings);
1695
1696    // And send a notification to anyone watching the preferences file.
1697    _doTouchEnergyPrefs(dynamic_store);
1698
1699    CFRelease(dynamic_store);
1700    return;
1701}
1702
1703
1704
1705
1706/**************************************************
1707*
1708* Power Profiles
1709*
1710*
1711**************************************************/
1712
1713static void mergeDictIntoMutable(
1714    CFMutableDictionaryRef  target,
1715    CFDictionaryRef         overrides,
1716    bool                    overwrite)
1717{
1718    const CFStringRef         *keys;
1719    const CFTypeRef           *objs;
1720    int                 count;
1721    int                 i;
1722
1723    count = CFDictionaryGetCount(overrides);
1724    if(0 == count) return;
1725
1726    keys = (CFStringRef *)malloc(sizeof(CFStringRef) * count);
1727    objs = (CFTypeRef *)malloc(sizeof(CFTypeRef) * count);
1728    if(!keys || !objs) return;
1729
1730    CFDictionaryGetKeysAndValues(overrides,
1731                    (const void **)keys, (const void **)objs);
1732    for(i=0; i<count; i++)
1733    {
1734        if(overwrite) {
1735            CFDictionarySetValue(target, keys[i], objs[i]);
1736        } else {
1737            // no value added if key already present
1738            CFDictionaryAddValue(target, keys[i], objs[i]);
1739        }
1740    }
1741    free((void *)keys);
1742    free((void *)objs);
1743}
1744
1745/* _copySystemProvidedProfiles()
1746 *
1747 * The PlatformExpert kext on the system may conditionally override the Energy
1748 * Saver's profiles. Only the PlatformExpert should be setting these properties.
1749 *
1750 * We use two supported properties - kIOPMSystemDefaultOverrideKey &
1751 * kIOPMSystemDefaultProfilesKey. We check first for
1752 * kIOPMSystemDefaultOverrideKey (a partial settings defaults substitution),
1753 * and if it's not present we'll use kIOPMSystemDefaultProfilesKey
1754 * (a complete settings defaults substitution).
1755 *
1756 * Overrides are a single dictionary of PM settings merged into the
1757 * default PM profiles found on the root volume, under the PM bundle, as
1758 * com.apple.SystemPowerProfileDefaults.plist
1759 *
1760 * Alternatively, Overrides are a 3 dictionary set, each dictionary
1761 * being a proper PM settings dictionary. The 3 keys must be
1762 * "AC Power", "Battery Power" and "UPS Power" respectively. Each
1763 * dictionary under those keys should contain only PM settings.
1764 *
1765 * DefaultProfiles is a CFArray of size 5, containing CFDictionaries
1766 * which each contain 3 dictionaries in turn
1767 */
1768static CFArrayRef      _copySystemProvidedProfiles()
1769{
1770    io_registry_entry_t         registry_entry = MACH_PORT_NULL;
1771    CFTypeRef                   cftype_total_prof_override = NULL;
1772    CFTypeRef                   cftype_overrides = NULL;
1773    CFArrayRef                  retArray = NULL;
1774    CFDictionaryRef             overrides = NULL;
1775    CFDictionaryRef             ac_over = NULL;
1776    CFDictionaryRef             batt_over = NULL;
1777    CFDictionaryRef             ups_over = NULL;
1778
1779    CFArrayRef                  sysPowerProfiles = NULL;
1780    CFMutableArrayRef           mArrProfs = NULL;
1781    int                         count = 0;
1782    int                         i = 0;
1783
1784    registry_entry = getPMRootDomainRef();
1785    if(MACH_PORT_NULL == registry_entry) return NULL;
1786
1787    /* O v e r r i d e */
1788
1789    cftype_overrides = IORegistryEntryCreateCFProperty(registry_entry,
1790                        CFSTR(kIOPMSystemDefaultOverrideKey),
1791                        kCFAllocatorDefault, 0);
1792    if( !(overrides = isA_CFDictionary(cftype_overrides)) ) {
1793        // Expect overrides to be a CFDictionary. If not, skip.
1794        if(cftype_overrides) {
1795            CFRelease(cftype_overrides); cftype_overrides = NULL;
1796        }
1797        goto TrySystemDefaultProfiles;
1798    }
1799
1800    ac_over = CFDictionaryGetValue(overrides, CFSTR(kIOPMACPowerKey));
1801    batt_over = CFDictionaryGetValue(overrides, CFSTR(kIOPMBatteryPowerKey));
1802    ups_over = CFDictionaryGetValue(overrides, CFSTR(kIOPMUPSPowerKey));
1803
1804    // Overrides either contains 3 dictionaries of PM Settings keyed as
1805    // AC, Battery, and UPS Power, or it is itself a dictionary of PM Settings.
1806    if(ac_over && batt_over && ups_over)
1807    {
1808        // Good. All 3 power source settings types are represented.
1809        // Do nothing here.
1810    } else if(!ac_over && !batt_over && !ups_over)
1811    {
1812        // The dictionary didn't specify any per-power source overrides, which
1813        // means that it's a flat dictionary strictly of PM settings.
1814        // We duplicate it 3 ways, as each overridden setting in this dictionary
1815        // will be applied to each power source's settings.
1816        ac_over = batt_over = ups_over = overrides;
1817    } else {
1818        // Bad form for overrides dictionary.
1819        goto TrySystemDefaultProfiles;
1820    }
1821
1822    // ac_over, batt_over, ups_over now contain the PM settings to be merged
1823    // into the system's default profiles. The settings defined in ac_over,
1824    // batt_over, and ups_over, will override the system's defaults from file:
1825    //
1826    // com.apple.SystemPowerProfileDefaults.plist in PowerManagement.bundle
1827
1828
1829    sysPowerProfiles = _createDefaultSystemProfiles();
1830    if(!sysPowerProfiles) goto exit;
1831    count = CFArrayGetCount(sysPowerProfiles);
1832
1833    mArrProfs = CFArrayCreateMutable(0, count, &kCFTypeArrayCallBacks);
1834    for(i=0; i<count; i++)
1835    {
1836        CFMutableDictionaryRef      mSettingsAC;
1837        CFMutableDictionaryRef      mSettingsBatt;
1838        CFMutableDictionaryRef      mSettingsUPS;
1839        CFMutableDictionaryRef      mProfile;
1840        CFDictionaryRef             _profile;
1841        CFDictionaryRef             tmp;
1842
1843        _profile = (CFDictionaryRef)CFArrayGetValueAtIndex(sysPowerProfiles, i);
1844        if(!_profile) continue;
1845
1846        // Create a new mutable profile to modify & override selected settings
1847        mProfile = CFDictionaryCreateMutable(0,
1848                        CFDictionaryGetCount(_profile),
1849                        &kCFTypeDictionaryKeyCallBacks,
1850                        &kCFTypeDictionaryValueCallBacks);
1851
1852        if(!mProfile) continue;
1853        // Add new mutable profile to new mutable array of profiles
1854        CFArraySetValueAtIndex(mArrProfs, i, mProfile);
1855        CFRelease(mProfile);
1856
1857        tmp = (CFDictionaryRef)CFDictionaryGetValue(_profile,
1858                        CFSTR(kIOPMACPowerKey));
1859        if(!tmp) continue;
1860        mSettingsAC = CFDictionaryCreateMutableCopy(0,
1861                        CFDictionaryGetCount(tmp), tmp);
1862
1863
1864        tmp = (CFDictionaryRef)CFDictionaryGetValue(_profile,
1865                        CFSTR(kIOPMBatteryPowerKey));
1866        if(!tmp) continue;
1867        mSettingsBatt = CFDictionaryCreateMutableCopy(0,
1868                        CFDictionaryGetCount(tmp), tmp);
1869
1870        tmp = (CFDictionaryRef)CFDictionaryGetValue(_profile,
1871                        CFSTR(kIOPMUPSPowerKey));
1872        if(!tmp) continue;
1873        mSettingsUPS = CFDictionaryCreateMutableCopy(0,
1874                        CFDictionaryGetCount(tmp), tmp);
1875
1876        if( !(mSettingsAC && mSettingsBatt && mSettingsUPS) ) {
1877            if(sysPowerProfiles) {
1878                CFRelease(sysPowerProfiles); sysPowerProfiles = NULL;
1879            }
1880            if(mSettingsAC) {
1881                CFRelease(mSettingsAC); mSettingsAC = NULL;
1882            }
1883            if(mSettingsBatt) {
1884                CFRelease(mSettingsBatt); mSettingsBatt = NULL;
1885            }
1886            if(mSettingsUPS) {
1887                CFRelease(mSettingsUPS); mSettingsUPS = NULL;
1888            }
1889            if(mArrProfs) {
1890                CFRelease(mArrProfs); mArrProfs = NULL;
1891            }
1892            goto TrySystemDefaultProfiles;
1893        }
1894
1895        // Add these new mutable dictionaries to our new mutable profile
1896
1897        CFDictionarySetValue(mProfile,
1898                            CFSTR(kIOPMACPowerKey),
1899                            mSettingsAC);
1900
1901        CFDictionarySetValue(mProfile,
1902                            CFSTR(kIOPMBatteryPowerKey),
1903                            mSettingsBatt);
1904
1905        CFDictionarySetValue(mProfile,
1906                            CFSTR(kIOPMUPSPowerKey),
1907                            mSettingsUPS);
1908
1909        // And now... what we've all been waiting for... merge in the system
1910        // platform expert's provided default profiles.
1911        // true == overwrite existing settings
1912        mergeDictIntoMutable(mSettingsAC, ac_over, kOverWriteDuplicates);
1913        mergeDictIntoMutable(mSettingsBatt, batt_over, kOverWriteDuplicates);
1914        mergeDictIntoMutable(mSettingsUPS, ups_over, kOverWriteDuplicates);
1915
1916        // And release...
1917
1918        CFRelease(mSettingsAC); mSettingsAC = NULL;
1919        CFRelease(mSettingsBatt); mSettingsBatt = NULL;
1920        CFRelease(mSettingsUPS); mSettingsUPS = NULL;
1921    }
1922
1923    // Currently holding one retain on mArrProfs
1924    retArray = (CFArrayRef)mArrProfs;
1925
1926    goto exit;
1927
1928TrySystemDefaultProfiles:
1929
1930    /* D e f a u l t   P r o f i l e s */
1931
1932    // If there were no override PM settings, we check for a complete
1933    // power profiles definition instead. If so, return the CFArray
1934    // it contains wholesale.
1935
1936    cftype_total_prof_override = IORegistryEntryCreateCFProperty(registry_entry,
1937                        CFSTR(kIOPMSystemDefaultProfilesKey),
1938                        kCFAllocatorDefault, 0);
1939    if( isA_CFArray(cftype_total_prof_override) ) {
1940        retArray = (CFArrayRef)cftype_total_prof_override;
1941        goto exit;
1942    } else {
1943        if(cftype_total_prof_override) {
1944            CFRelease(cftype_total_prof_override);
1945            cftype_total_prof_override = NULL;
1946        }
1947    }
1948
1949exit:
1950    if(sysPowerProfiles) {
1951        CFRelease(sysPowerProfiles); sysPowerProfiles = NULL;
1952    }
1953    if(cftype_overrides) {
1954        CFRelease(cftype_overrides); cftype_overrides = NULL;
1955    }
1956    return retArray;
1957}
1958
1959static CFArrayRef       _createDefaultSystemProfiles()
1960{
1961    CFURLRef                pm_bundle_url = 0;
1962    CFBundleRef             pm_bundle = 0;
1963    CFURLRef                profiles_url = 0;
1964    CFStringRef             profiles_path = 0;
1965    CFArrayRef              system_default_profiles = 0;
1966    CFArrayRef              return_array = 0;
1967    SCPreferencesRef        open_file = 0;
1968
1969    pm_bundle_url = CFURLCreateWithFileSystemPath(0, CFSTR(kIOPMBundlePath), kCFURLPOSIXPathStyle, true);
1970    if(!pm_bundle_url) {
1971        goto exit;
1972    }
1973
1974    pm_bundle = CFBundleCreate(kCFAllocatorDefault, pm_bundle_url);
1975    if(!pm_bundle) {
1976        goto exit;
1977    }
1978
1979    profiles_url = CFBundleCopyResourceURL(pm_bundle,
1980        CFSTR("com.apple.SystemPowerProfileDefaults.plist"), NULL, NULL);
1981    if(!profiles_url) {
1982        goto exit;
1983    }
1984    profiles_path = CFURLCopyPath(profiles_url);
1985
1986    open_file = SCPreferencesCreate(0, CFSTR("PowerManagementPreferences"), profiles_path);
1987    if(!open_file) {
1988        goto exit;
1989    }
1990
1991    system_default_profiles = SCPreferencesGetValue(open_file, CFSTR("SystemProfileDefaults"));
1992    if(!isA_CFArray(system_default_profiles)) {
1993        goto exit;
1994    }
1995
1996    return_array = CFArrayCreateCopy(0, system_default_profiles);
1997
1998exit:
1999    if(pm_bundle_url)       CFRelease(pm_bundle_url);
2000    if(pm_bundle)           CFRelease(pm_bundle);
2001    if(profiles_url)        CFRelease(profiles_url);
2002    if(profiles_path)       CFRelease(profiles_path);
2003    if(open_file)           CFRelease(open_file);
2004
2005    return return_array;
2006}
2007
2008static CFDictionaryRef      _createDefaultProfileSelections(void)
2009{
2010    CFURLRef                pm_bundle_url = 0;
2011    CFBundleRef             pm_bundle = 0;
2012    CFURLRef                profiles_url = 0;
2013    CFStringRef             profiles_path = 0;
2014    CFDictionaryRef         default_profiles_selection = 0;
2015    CFDictionaryRef         return_dict = 0;
2016    SCPreferencesRef        open_file = 0;
2017
2018    pm_bundle_url = CFURLCreateWithFileSystemPath(0, CFSTR(kIOPMBundlePath), kCFURLPOSIXPathStyle, true);
2019    if(!pm_bundle_url) {
2020        goto exit;
2021    }
2022
2023    pm_bundle = CFBundleCreate(
2024        kCFAllocatorDefault,
2025        pm_bundle_url);
2026    if(!pm_bundle) {
2027        goto exit;
2028    }
2029
2030    profiles_url = CFBundleCopyResourceURL(
2031        pm_bundle,
2032        CFSTR("com.apple.SystemPowerProfileDefaults.plist"),
2033        NULL,
2034        NULL);
2035    if(!profiles_url) {
2036        //syslog(LOG_INFO, "Can't find path to profiles\n");
2037        goto exit;
2038    }
2039    profiles_path = CFURLCopyPath(profiles_url);
2040
2041    open_file = SCPreferencesCreate(
2042        kCFAllocatorDefault,
2043        CFSTR("PowerManagementPreferences"),
2044        profiles_path);
2045    if(!open_file) {
2046        //syslog(LOG_INFO, "PM could not open System Profile defaults\n");
2047        goto exit;
2048    }
2049
2050    default_profiles_selection = SCPreferencesGetValue(
2051        open_file,
2052        CFSTR("DefaultProfileChoices"));
2053    if(!isA_CFDictionary(default_profiles_selection)) {
2054        goto exit;
2055    }
2056
2057    return_dict = CFDictionaryCreateCopy(kCFAllocatorDefault, default_profiles_selection);
2058
2059exit:
2060    if(pm_bundle_url)       CFRelease(pm_bundle_url);
2061    if(pm_bundle)           CFRelease(pm_bundle);
2062    if(profiles_url)        CFRelease(profiles_url);
2063    if(profiles_path)       CFRelease(profiles_path);
2064    if(open_file)           CFRelease(open_file);
2065
2066    return return_dict;
2067}
2068
2069static CFDictionaryRef _createAllCustomProfileSelections(void)
2070{
2071    int                         j = -1;
2072    CFNumberRef                 n;
2073    CFMutableDictionaryRef      custom_dict = NULL;
2074
2075    custom_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 3,
2076        &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2077    n = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &j);
2078    if(!custom_dict || !n) return NULL;
2079
2080    CFDictionarySetValue(custom_dict, CFSTR(kIOPMACPowerKey), n);
2081    CFDictionarySetValue(custom_dict, CFSTR(kIOPMBatteryPowerKey), n);
2082    CFDictionarySetValue(custom_dict, CFSTR(kIOPMUPSPowerKey), n);
2083
2084    CFRelease(n);
2085    return custom_dict;
2086}
2087
2088
2089CFArrayRef          IOPMCopyPowerProfiles(void)
2090{
2091    CFArrayRef                      power_profiles = 0;
2092    CFMutableArrayRef               mutable_power_profiles = 0;
2093    CFDictionaryRef                 tmp;
2094    CFMutableDictionaryRef          mutable_profile;
2095    int                             i, p_count;
2096
2097    // Provide the platform expert driver a chance to define better default
2098    // power settings for the machine this code is running on.
2099    power_profiles = _copySystemProvidedProfiles();
2100    if(!power_profiles) {
2101        power_profiles = _createDefaultSystemProfiles();
2102    }
2103    if(!power_profiles) return NULL;
2104
2105    mutable_power_profiles = CFArrayCreateMutableCopy(0, 0, power_profiles);
2106    if(!mutable_power_profiles) goto exit;
2107
2108    // Prune unsupported power supplies and unsupported
2109    // settings
2110    p_count = CFArrayGetCount(mutable_power_profiles);
2111    for(i=0; i<p_count; i++)
2112    {
2113        tmp = CFArrayGetValueAtIndex(power_profiles, i);
2114        if(!tmp)
2115            continue;
2116
2117        mutable_profile = CFDictionaryCreateMutableCopy(0, 0, tmp);
2118        if(!mutable_profile)
2119            continue;
2120
2121        mergeUserDefaultOverriddenSettings(mutable_profile);
2122
2123        addDefaultEnergySettings(mutable_profile);
2124
2125        IOPMRemoveIrrelevantProperties(mutable_profile);
2126
2127        CFArraySetValueAtIndex(mutable_power_profiles, i, mutable_profile);
2128        CFRelease(mutable_profile);
2129    }
2130exit:
2131    if(power_profiles) CFRelease(power_profiles);
2132    return mutable_power_profiles;
2133}
2134
2135static int _isActiveProfileDictValid(CFDictionaryRef p)
2136{
2137    CFNumberRef     val;
2138    int             j;
2139
2140    if(!p) return 0;
2141
2142    // AC value required
2143    val = CFDictionaryGetValue(p, CFSTR(kIOPMACPowerKey));
2144    if(!val) return 0;
2145    CFNumberGetValue(val, kCFNumberIntType, &j);
2146    if(j<-1 || j>= kIOPMNumPowerProfiles) return 0;
2147
2148    // Battery value optional
2149    val = CFDictionaryGetValue(p, CFSTR(kIOPMBatteryPowerKey));
2150    if(val) {
2151        CFNumberGetValue(val, kCFNumberIntType, &j);
2152        if(j<-1 || j>= kIOPMNumPowerProfiles) return 0;
2153    }
2154
2155    // UPS value optional
2156    val = CFDictionaryGetValue(p, CFSTR(kIOPMUPSPowerKey));
2157    if(val) {
2158        CFNumberGetValue(val, kCFNumberIntType, &j);
2159        if(j<-1 || j>= kIOPMNumPowerProfiles) return 0;
2160    }
2161
2162    return 1;
2163}
2164
2165static void _purgeUnsupportedPowerSources(CFMutableDictionaryRef p)
2166{
2167    CFStringRef                     *ps_names = NULL;
2168    int                             count;
2169    int                             i;
2170
2171    count = CFDictionaryGetCount(p);
2172    ps_names = (CFStringRef *)malloc(count*sizeof(CFStringRef));
2173    if(!ps_names) goto exit;
2174    CFDictionaryGetKeysAndValues(p, (CFTypeRef *)ps_names, NULL);
2175    for(i=0; i<count; i++)
2176    {
2177        if(!checkPowerSourceSupported(ps_names[i]))
2178        {
2179            CFDictionaryRemoveValue(p, ps_names[i]);
2180        }
2181    }
2182exit:
2183    if(ps_names) free(ps_names);
2184}
2185
2186static CFStringRef getPowerSourceString(int i)
2187{
2188    if(i == 1) return CFSTR(kIOPMBatteryPowerKey);
2189    if(i == 2) return CFSTR(kIOPMUPSPowerKey);
2190
2191    return CFSTR(kIOPMACPowerKey);
2192}
2193
2194/**************************************************
2195*
2196* Support for IOPMPrefsNotificationCreateRunLoopSource
2197*
2198**************************************************/
2199
2200/* SCDynamicStoreCallback */
2201static void ioCallout(
2202    SCDynamicStoreRef store __unused,
2203    CFArrayRef keys __unused,
2204    void *ctxt)
2205{
2206    user_callback_context   *c;
2207    IOPowerSourceCallbackType cb;
2208
2209    c = (user_callback_context *)CFDataGetBytePtr((CFDataRef)ctxt);
2210    if(!c) return;
2211    cb = c->callback;
2212    if(!cb) return;
2213
2214    // Execute callback
2215    (*cb)(c->context);
2216}
2217
2218
2219/*******************************************************************************
2220****
2221**** readAllPMPlistSettings
2222****
2223*******************************************************************************/
2224
2225IOReturn readAllPMPlistSettings(
2226    bool                        removeUnsupportedSettings,
2227    CFMutableDictionaryRef      *customSettings,
2228    CFDictionaryRef             *profileSelections,
2229    bool                        *returnDefaultSettings)
2230{
2231    /*
2232     * Read Custom Settings
2233     */
2234    CFMutableDictionaryRef                  energyDict = NULL;
2235    CFDictionaryRef                         tmp_dict = NULL;
2236    SCPreferencesRef                        energyPrefs = NULL;
2237    CFMutableDictionaryRef                  batterySettings = NULL;
2238    CFMutableDictionaryRef                  ACSettings = NULL;
2239    CFMutableDictionaryRef                  UPSSettings = NULL;
2240    bool                                    usingDefaults = true;
2241    bool                                    prefsSuccess = false;
2242
2243    /*
2244     * Read profiles
2245     */
2246    CFDictionaryRef                         tmp = NULL;
2247    CFDictionaryRef                         defaultProfiles = NULL;
2248    CFStringRef                             *profileKeys = NULL;
2249    CFNumberRef                             *profileValues = NULL;
2250    bool                                    activeProfilesSpecified = false;
2251    int                                     profileCount;
2252    int                                     i;
2253    bool                                    profilesSuccess = false;
2254    CFMutableDictionaryRef                  acquiredProfiles = NULL;
2255
2256
2257    energyPrefs = SCPreferencesCreate( 0, kIOPMAppName, kIOPMPrefsPath );
2258
2259    if(!energyPrefs) {
2260        // Utter failure!!!
2261        if(customSettings) *customSettings = NULL;
2262        if(profileSelections) *profileSelections = NULL;
2263        return kIOReturnNotOpen;
2264    }
2265
2266/*******************************************************************************
2267**** Read raw profiles com.apple.PowerManagement.plist
2268*******************************************************************************/
2269
2270    tmp = SCPreferencesGetValue(energyPrefs, CFSTR("ActivePowerProfiles"));
2271    if(tmp && _isActiveProfileDictValid(tmp)) {
2272        acquiredProfiles = CFDictionaryCreateMutableCopy(0, 0, tmp);
2273        activeProfilesSpecified = true;
2274    } else {
2275        acquiredProfiles = NULL;
2276    }
2277
2278/*******************************************************************************
2279**** Read custom settings dictionary from com.apple.PowerManagement.plist
2280*******************************************************************************/
2281
2282    // Attempt to read battery & AC settings
2283    tmp_dict = isA_CFDictionary(SCPreferencesGetValue(energyPrefs,
2284                                        CFSTR("Custom Profile")));
2285
2286    // If com.apple.PowerManagement.xml opened correctly, read data from it
2287    if(tmp_dict)
2288    {
2289        usingDefaults = false;
2290
2291        // Tiger preferences file format
2292        energyDict = CFDictionaryCreateMutableCopy(
2293            kCFAllocatorDefault,
2294            0,
2295            tmp_dict);
2296        if(!energyDict) goto prefsExit;
2297    } else {
2298        // Try Panther/Jaguar  prefs formats
2299
2300        batterySettings = (CFMutableDictionaryRef)isA_CFDictionary(
2301            SCPreferencesGetValue(energyPrefs, CFSTR(kIOPMBatteryPowerKey)));
2302        ACSettings = (CFMutableDictionaryRef)isA_CFDictionary(
2303            SCPreferencesGetValue(energyPrefs, CFSTR(kIOPMACPowerKey)));
2304        UPSSettings = (CFMutableDictionaryRef)isA_CFDictionary(
2305            SCPreferencesGetValue(energyPrefs, CFSTR(kIOPMUPSPowerKey)));
2306
2307        if ( batterySettings || ACSettings || UPSSettings )
2308            usingDefaults = false;
2309
2310        energyDict = CFDictionaryCreateMutable(
2311            kCFAllocatorDefault,
2312            0,
2313            &kCFTypeDictionaryKeyCallBacks,
2314            &kCFTypeDictionaryValueCallBacks);
2315        if(!energyDict) goto prefsExit;
2316
2317        if(batterySettings) {
2318            CFDictionaryAddValue(energyDict, CFSTR(kIOPMBatteryPowerKey),
2319                                                batterySettings);
2320        }
2321        if(ACSettings) {
2322            CFDictionaryAddValue(energyDict, CFSTR(kIOPMACPowerKey),
2323                                                ACSettings);
2324        }
2325        if(UPSSettings) {
2326            CFDictionaryAddValue(energyDict, CFSTR(kIOPMUPSPowerKey),
2327                                                UPSSettings);
2328        }
2329    }
2330
2331    // Make sure that the enclosed dictionaries are all mutable
2332    tmp = isA_CFDictionary(CFDictionaryGetValue(
2333                                energyDict, CFSTR(kIOPMBatteryPowerKey)));
2334    if(tmp) {
2335        batterySettings = CFDictionaryCreateMutableCopy(0, 0, tmp);
2336    } else {
2337        batterySettings = CFDictionaryCreateMutable(0, 0,
2338                                    &kCFTypeDictionaryKeyCallBacks,
2339                                    &kCFTypeDictionaryValueCallBacks);
2340    }
2341    if(batterySettings)
2342    {
2343        CFDictionarySetValue(energyDict, CFSTR(kIOPMBatteryPowerKey),
2344                                         batterySettings);
2345        CFRelease(batterySettings);
2346    } else goto prefsExit;
2347
2348    tmp = isA_CFDictionary(CFDictionaryGetValue(
2349                                energyDict, CFSTR(kIOPMACPowerKey)));
2350    if(tmp) {
2351        ACSettings = CFDictionaryCreateMutableCopy(0, 0, tmp);
2352    } else {
2353        ACSettings = CFDictionaryCreateMutable(0, 0,
2354                                    &kCFTypeDictionaryKeyCallBacks,
2355                                    &kCFTypeDictionaryValueCallBacks);
2356    }
2357    if(ACSettings) {
2358        CFDictionarySetValue(energyDict, CFSTR(kIOPMACPowerKey), ACSettings);
2359        CFRelease(ACSettings);
2360    } else goto prefsExit;
2361
2362    tmp = isA_CFDictionary(CFDictionaryGetValue(
2363                                energyDict, CFSTR(kIOPMUPSPowerKey)));
2364    if(tmp) {
2365        UPSSettings = CFDictionaryCreateMutableCopy(0, 0, tmp);
2366    } else {
2367        UPSSettings = CFDictionaryCreateMutable(0, 0,
2368                                    &kCFTypeDictionaryKeyCallBacks,
2369                                    &kCFTypeDictionaryValueCallBacks);
2370    }
2371    if(UPSSettings) {
2372        CFDictionarySetValue(energyDict, CFSTR(kIOPMUPSPowerKey), UPSSettings);
2373        CFRelease(UPSSettings);
2374    } else goto prefsExit;
2375
2376    // INVARIANT: At this point we want a mutable dictionary energyDict
2377    // containing 3 mutable preferences dictionaries that are either
2378    // empty or contain some settings.
2379
2380    // Check for existence of Puma/Cheetah prefs format
2381    // And add settings defined there if present
2382    getCheetahPumaEnergySettings(energyDict);
2383
2384    // Fill in any undefined settings from the system's provided defaults
2385    // IOPlatformExpert may specify different profile defaults, so we must
2386    // respect those when present.
2387    addSystemProfileEnergySettings(acquiredProfiles, energyDict);
2388
2389    // Fill in any settings overriden by a user process.
2390    mergeUserDefaultOverriddenSettings(energyDict);
2391
2392    // Fill in any undefined settings with our defaults
2393    // If no current or legacy prefs files exist, addDefaultEnergySettings()
2394    // completely populates the default EnergySaver preferences.
2395    addDefaultEnergySettings(energyDict);
2396
2397    if (removeUnsupportedSettings)
2398    {
2399        // Remove any unsupported key/value pairs (including some of
2400        // those we just added in getDefaultEnergySettings)
2401        IOPMRemoveIrrelevantProperties(energyDict);
2402    }
2403
2404    if(usingDefaults) {
2405        // If we couldn't find any user-specified settings on disk,
2406        // tag this dictionary as "Defaults" so that BatteryMonitor and
2407        // EnergySaver can tell whether these are user-selected
2408        // values or just the system defaults.
2409        CFDictionarySetValue(energyDict, CFSTR(kIOPMDefaultPreferencesKey),
2410                                         kCFBooleanTrue);
2411    }
2412
2413    prefsSuccess = true;
2414    if( customSettings ) {
2415        *customSettings = energyDict;
2416    }
2417
2418prefsExit:
2419
2420    if ( !prefsSuccess && customSettings) {
2421        *customSettings = NULL;
2422    }
2423
2424/*******************************************************************************
2425 **** Read custom profiles dictionary from com.apple.PowerManagement.plist
2426 ******************************************************************************/
2427
2428    if( !profileSelections ) {
2429        profilesSuccess = true;
2430    } else {
2431        // acquiredProfiles already contains the pre-read profiles data
2432        if(!acquiredProfiles) {
2433            acquiredProfiles = CFDictionaryCreateMutable(0, 3,
2434                        &kCFTypeDictionaryKeyCallBacks,
2435                        &kCFTypeDictionaryValueCallBacks);
2436        }
2437
2438
2439        if(!activeProfilesSpecified && !usingDefaults)
2440        {
2441            defaultProfiles = _createAllCustomProfileSelections();
2442        } else {
2443            defaultProfiles = _createDefaultProfileSelections();
2444        }
2445
2446        // Merge default profiles into active profiles
2447        // If the user has any specified Profiles, we'll merge in the defaults
2448        // for any power sources that aren't specified. If there weren't any
2449        // profile choices, we'll just merge in (-1, -1, -1) for all custom or
2450        // (2, 1, 1) to the empty dictionary, as described in comments above.
2451
2452        if(isA_CFDictionary(defaultProfiles))
2453        {
2454            profileCount = CFDictionaryGetCount(defaultProfiles);
2455            profileKeys = malloc(sizeof(CFStringRef)*profileCount);
2456            profileValues = malloc(sizeof(CFNumberRef)*profileCount);
2457            if ( !profileKeys || !profileValues ) goto profilesExit;
2458            CFDictionaryGetKeysAndValues(defaultProfiles,
2459                    (const void **)profileKeys, (const void **)profileValues);
2460
2461            for(i=0; i<profileCount; i++)
2462            {
2463                if( isA_CFString(profileKeys[i]) &&
2464                    isA_CFNumber(profileValues[i]) )
2465                {
2466                    // use the softer AddValue that won't replace any existing
2467                    // settings in the existing chosen profiles dictionary.
2468                    CFDictionaryAddValue(acquiredProfiles, profileKeys[i],
2469                                                         profileValues[i]);
2470                }
2471            }
2472            free(profileKeys);
2473            free(profileValues);
2474        }
2475
2476        /* Note: removeUnsupportedSettings argument does not affect the pruning
2477         * of unsupported power sources; we prune these regardless.
2478         * And remove all the unsupported profiles that we just added.
2479         */
2480        _purgeUnsupportedPowerSources(acquiredProfiles);
2481
2482        *profileSelections = acquiredProfiles;
2483        profilesSuccess = true;
2484
2485profilesExit:
2486        if(defaultProfiles) CFRelease(defaultProfiles);
2487        if(!profilesSuccess) *profileSelections = NULL;
2488    }
2489
2490// common exit
2491
2492    if( energyPrefs ) CFRelease(energyPrefs);
2493
2494    if( !customSettings && energyDict )
2495    {
2496        // If the caller did not request a copy of the PM settings, we
2497        // release them here. Otherwise it's the caller's responsibility
2498        // to CFRelease(*customSettings);
2499
2500        CFRelease(energyDict);
2501    }
2502
2503    if( !profileSelections && acquiredProfiles )
2504    {
2505        // If the caller did not request a copy of the profiles, we
2506        // release them here. Otherwise it's the caller's responsibility
2507        // to CFRelease(*profileSelections);
2508
2509        CFRelease(acquiredProfiles);
2510    }
2511
2512    if (returnDefaultSettings) {
2513        *returnDefaultSettings = usingDefaults;
2514    }
2515
2516    if( prefsSuccess && profilesSuccess) {
2517        return kIOReturnSuccess;
2518    } else {
2519        return kIOReturnError;
2520    }
2521}
2522
2523
2524
2525