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