1/*
2 * Copyright (c) 2004, 2012 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 <CoreFoundation/CoreFoundation.h>
25#include <CoreFoundation/CFXPCBridge.h>
26#include <TargetConditionals.h>
27#include <IOKit/IOKitLib.h>
28#include <IOKit/pwr_mgt/IOPMPrivate.h>
29#include <IOKit/pwr_mgt/IOPMLib.h>
30#include <mach/mach_init.h>
31#include <mach/mach_port.h>
32#include <mach/vm_map.h>
33#include <servers/bootstrap.h>
34#include <bootstrap_priv.h>
35#include <sys/types.h>
36#include <sys/sysctl.h>
37#include <notify.h>
38#include "IOSystemConfiguration.h"
39#include "IOPMLibPrivate.h"
40#include "powermanagement.h"
41#include <asl.h>
42#include <xpc/xpc.h>
43
44#include <unistd.h>
45#include <stdlib.h>
46#include <dirent.h>
47#include <pthread.h>
48
49
50#define pwrLogDirName "/System/Library/PowerEvents"
51
52static const int kMaxNameLength = 128;
53static mach_port_t powerd_connection = MACH_PORT_NULL;
54static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
55
56static void _reset_connection( )
57{
58  pthread_mutexattr_t attr;
59
60  powerd_connection = MACH_PORT_NULL;
61  pthread_mutexattr_init(&attr);
62  pthread_mutex_init(&lock, &attr);
63}
64
65IOReturn _pm_connect(mach_port_t *newConnection)
66{
67    kern_return_t       kern_result = KERN_SUCCESS;
68    IOReturn            ret = kIOReturnSuccess;
69
70    if(!newConnection) return kIOReturnBadArgument;
71    if (powerd_connection != MACH_PORT_NULL) {
72        *newConnection = powerd_connection;
73
74        return kIOReturnSuccess;
75    }
76
77    pthread_mutex_lock(&lock);
78
79    // Check again and see if the port is created by another thread
80    if (powerd_connection != MACH_PORT_NULL) {
81        *newConnection = powerd_connection;
82        goto exit;
83    }
84    // open reference to powerd
85    kern_result = bootstrap_look_up2(bootstrap_port,
86                                     kIOPMServerBootstrapName,
87                                     &powerd_connection,
88                                     0,
89                                     BOOTSTRAP_PRIVILEGED_SERVER);
90    if(KERN_SUCCESS != kern_result) {
91        *newConnection = powerd_connection =  MACH_PORT_NULL;
92        asl_log(NULL, NULL, ASL_LEVEL_ERR,
93                "bootstrap_look_up2 failed with 0x%x\n", kern_result);
94        ret = kIOReturnError;
95        goto exit;
96    }
97    *newConnection = powerd_connection;
98    if (pthread_atfork(NULL, NULL, _reset_connection) != 0)
99       powerd_connection = MACH_PORT_NULL;
100
101exit:
102    pthread_mutex_unlock(&lock);
103
104    return ret;
105}
106
107IOReturn _pm_disconnect(mach_port_t connection __unused)
108{
109    // Do nothing. We re-use the mach port
110    return kIOReturnSuccess;
111}
112
113
114bool IOPMUserIsActive(void)
115{
116    io_service_t                service = IO_OBJECT_NULL;
117    CFBooleanRef                userIsActiveBool = NULL;
118    bool                        ret_val = false;
119
120    service = IORegistryEntryFromPath(kIOMasterPortDefault,
121            kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
122
123    if (IO_OBJECT_NULL != service) {
124        userIsActiveBool = IORegistryEntryCreateCFProperty(
125                       service,
126                       CFSTR(kIOPMUserIsActiveKey),
127                       kCFAllocatorDefault, 0);
128        IOObjectRelease(service);
129    }
130
131    ret_val = (kCFBooleanTrue == userIsActiveBool);
132
133    if (userIsActiveBool) {
134        CFRelease(userIsActiveBool);
135    }
136    return ret_val;
137}
138
139typedef struct {
140// UserActive
141    void (^callblock_bool)(bool);
142    IONotificationPortRef           notify;
143    io_object_t                     letItGo;
144// UserActivityLevel
145    void (^callblock_activity)(uint64_t, uint64_t);
146    int                             dtoken;
147} _UserActiveNotification;
148
149void IOPMUserDidChangeCallback(
150    void *refcon __unused,
151    io_service_t service __unused,
152    uint32_t messageType,
153    void *messageArgument __unused)
154{
155    _UserActiveNotification *_useractive = (_UserActiveNotification *)refcon;
156
157    if (_useractive && (messageType == kIOPMMessageUserIsActiveChanged))
158    {
159        _useractive->callblock_bool( IOPMUserIsActive() );
160    }
161}
162
163
164IOPMNotificationHandle IOPMScheduleUserActiveChangedNotification(dispatch_queue_t queue, void (^block)(bool))
165{
166    _UserActiveNotification *_useractive = NULL;
167    io_registry_entry_t     service = IO_OBJECT_NULL;
168    kern_return_t           kr = KERN_INVALID_VALUE;
169
170    _useractive = calloc(1, sizeof(_UserActiveNotification));
171
172    if (_useractive)
173    {
174        _useractive->callblock_bool = Block_copy(block);
175
176        _useractive->notify = IONotificationPortCreate(MACH_PORT_NULL);
177        if (_useractive->notify) {
178            IONotificationPortSetDispatchQueue(_useractive->notify, queue);
179        }
180
181        service = IORegistryEntryFromPath(kIOMasterPortDefault,
182                kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
183
184        kr = IOServiceAddInterestNotification(
185                _useractive->notify, service, kIOGeneralInterest,
186                IOPMUserDidChangeCallback, (void *)_useractive, &_useractive->letItGo);
187
188        IOObjectRelease(service);
189    }
190
191    if (kIOReturnSuccess != kr) {
192        IOPMUnregisterNotification((IOPMNotificationHandle)_useractive);
193        _useractive = NULL;
194    }
195
196    return _useractive;
197}
198
199void IOPMUnregisterNotification(IOPMNotificationHandle handle)
200{
201    _UserActiveNotification *_useractive = (_UserActiveNotification *)handle;
202
203    if (_useractive)
204    {
205        if (_useractive->callblock_bool) {
206            Block_release(_useractive->callblock_bool);
207        }
208        if (_useractive->notify) {
209            IONotificationPortDestroy(_useractive->notify);
210        }
211        if (IO_OBJECT_NULL != _useractive->letItGo) {
212            IOObjectRelease(_useractive->letItGo);
213        }
214        if (_useractive->dtoken) {
215            notify_cancel(_useractive->dtoken);
216        }
217        bzero(_useractive, sizeof(_useractive));
218        free(_useractive);
219    }
220}
221
222
223static void decodeUserActivityLevel64(uint64_t in,
224                                      uint64_t *outActive,
225                                      uint64_t *outMSA)
226{
227    if (outActive) {
228        *outActive = in;
229    }
230    if (outMSA) {
231        *outMSA = in ? (in & (1 << (ffsl(in)-1))) : 0;
232    }
233}
234
235
236IOReturn IOPMGetUserActivityLevel(uint64_t *outUserActive,
237                                  uint64_t *mostSignificantActivity)
238{
239    int         token = 0;
240    uint64_t    payload = 0;
241    uint32_t    r = 0;
242
243    r = notify_register_check("com.apple.system.powermanagement.useractivity2",
244                              &token);
245
246    if (NOTIFY_STATUS_OK == r)
247    {
248        notify_get_state(token, &payload);
249        notify_cancel(token);
250    }
251
252    decodeUserActivityLevel64(payload,
253                              outUserActive,
254                              mostSignificantActivity);
255
256
257    return kIOReturnSuccess;
258}
259
260IOPMNotificationHandle IOPMScheduleUserActivityLevelNotification(dispatch_queue_t queue,
261                                                                 void (^inblock)(uint64_t, uint64_t))
262{
263    _UserActiveNotification *_useractive = NULL;
264    uint32_t                r = 0;
265
266    _useractive = calloc(1, sizeof(_UserActiveNotification));
267
268    if (_useractive)
269    {
270        notify_handler_t calloutBlock = ^(int token)
271        {
272            uint64_t data = 0;
273            uint64_t active = 0;
274            uint64_t most = 0;
275            uint32_t r2;
276
277            r2 = notify_get_state(token, &data);
278            if (NOTIFY_STATUS_OK == r2)
279            {
280                decodeUserActivityLevel64(data, &active, &most);
281
282                if (_useractive)
283                    inblock(active, most);
284            }
285        };
286
287        r = notify_register_dispatch("com.apple.system.powermanagement.useractivity2",
288                                     &_useractive->dtoken,
289                                     queue,
290                                     calloutBlock);
291        if (NOTIFY_STATUS_OK != r) {
292            free(_useractive);
293            _useractive = NULL;
294        }
295    }
296
297    return _useractive;
298}
299
300
301CFStringRef IOPMCopyUserActivityLevelDescription(uint64_t userActive)
302{
303    int                prev = 0;
304    CFMutableStringRef  result = CFStringCreateMutable(0, 0);
305
306    if (0==userActive) {
307        CFStringAppend(result, CFSTR("Inactive"));
308        goto exit;
309    }
310
311    if (kIOPMUserPresentActive & userActive) {
312        if (prev++) CFStringAppend(result,CFSTR(" "));
313        CFStringAppend(result, CFSTR("PresentActive"));
314    }
315    if (kIOPMUserPresentPassive & userActive) {
316        if (prev++) CFStringAppend(result,CFSTR(" "));
317        CFStringAppend(result, CFSTR("PresentPassive"));
318    }
319    if (kIOPMUserRemoteClientActive & userActive) {
320        if (prev++) CFStringAppend(result,CFSTR(" "));
321        CFStringAppend(result, CFSTR("RemoteActive"));
322    }
323    if (kIOPMUserNotificationActive  & userActive) {
324        if (prev++) CFStringAppend(result,CFSTR(" "));
325        CFStringAppend(result, CFSTR("NotificationActive"));
326    }
327exit:
328    return result;
329}
330
331
332
333/*****************************************************************************/
334/*****************************************************************************/
335
336/******************************************************************************
337 * IOPMCopyHIDPostEventHistory
338 *
339 ******************************************************************************/
340
341IOReturn IOPMCopyHIDPostEventHistory(CFArrayRef *outArray)
342{
343    CFDataRef               serializedData = NULL;
344    vm_address_t            outBuffer = 0;
345    vm_size_t               outSize = 0;
346    mach_port_t             pmserverport = MACH_PORT_NULL;
347    IOReturn                ret = kIOReturnError;
348    int                     history_return = 0;
349
350    if (kIOReturnSuccess != _pm_connect(&pmserverport))
351        goto exit;
352
353    if (KERN_SUCCESS != io_pm_hid_event_copy_history(pmserverport,
354                                &outBuffer, (mach_msg_type_number_t *) &outSize, &history_return))
355    {
356        goto exit;
357    }
358
359    serializedData = CFDataCreate(0, (const UInt8 *)outBuffer, outSize);
360    if (serializedData) {
361        *outArray = (CFArrayRef)CFPropertyListCreateWithData(0, serializedData, 0, NULL, NULL);
362        CFRelease(serializedData);
363    }
364
365    if (*outArray)
366        ret = kIOReturnSuccess;
367
368    vm_deallocate(mach_task_self(), outBuffer, outSize);
369    _pm_disconnect(pmserverport);
370exit:
371    return ret;
372}
373
374/******************************************************************************
375 * IOPMGetLastWakeTime
376 *
377 ******************************************************************************/
378
379IOReturn IOPMGetLastWakeTime(
380    CFAbsoluteTime      *lastWakeTimeOut,
381    CFTimeInterval      *adjustedForPhysicalWakeOut)
382{
383    IOReturn            ret;
384    CFTimeInterval      lastSMCS3S0WakeInterval = 0.0;
385    CFAbsoluteTime      lastWakeTime;
386    struct timeval      rawLastWakeTime;
387    size_t              rawLastWakeTimeSize = sizeof(rawLastWakeTime);
388
389    if (!lastWakeTimeOut || !adjustedForPhysicalWakeOut) {
390        return kIOReturnBadArgument;
391    }
392
393    *lastWakeTimeOut = 0.0;
394    *adjustedForPhysicalWakeOut = 0.0;
395
396    ret = sysctlbyname("kern.waketime", &rawLastWakeTime, &rawLastWakeTimeSize, NULL, 0);
397    if (ret || !rawLastWakeTime.tv_sec) {
398        return kIOReturnNotReady;
399    }
400
401    // Convert the timeval, which is in UNIX time, to a CFAbsoluteTime
402    lastWakeTime = rawLastWakeTime.tv_sec + (rawLastWakeTime.tv_usec / 1000000.0);
403    lastWakeTime -= kCFAbsoluteTimeIntervalSince1970;
404
405
406    *lastWakeTimeOut = lastWakeTime;
407    *adjustedForPhysicalWakeOut = lastSMCS3S0WakeInterval;
408
409    return kIOReturnSuccess;
410}
411
412
413#pragma mark -
414#pragma mark API
415
416/******************************************************************************
417 * IOPMCopyPowerHistory
418 *
419 ******************************************************************************/
420IOReturn IOPMCopyPowerHistory(CFArrayRef *outArray)
421{
422  DIR *dp;
423  struct dirent *ep;
424
425  CFMutableArrayRef logs = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
426
427  dp = opendir(pwrLogDirName);
428  if(dp == NULL)
429    return kIOReturnError;
430
431  CFMutableDictionaryRef uuid_details;
432  CFStringRef uuid;
433  CFStringRef timestamp;
434
435  char *tok;
436  char *d_name;
437  int fileCount = 0;
438
439  while ((ep = readdir(dp))) {
440    if(!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
441      continue;
442    else
443     fileCount++;
444
445    uuid_details = CFDictionaryCreateMutable(kCFAllocatorDefault,
446                                             0,
447                                             &kCFTypeDictionaryKeyCallBacks,
448                                             &kCFTypeDictionaryValueCallBacks);
449    d_name = strdup(ep->d_name);
450
451    // Parse filename for metadata
452    int part = 1;
453    while((tok = strsep(&d_name, "_")) != NULL) {
454
455      if(part == 1) {
456        timestamp = CFStringCreateWithCString(kCFAllocatorDefault,
457                                              tok,
458                                              kCFStringEncodingUTF8);
459        CFDictionarySetValue(uuid_details,
460                             CFSTR(kIOPMPowerHistoryTimestampKey),
461                             timestamp);
462        CFRelease(timestamp);
463      }
464      else if(part == 2) {
465        uuid = CFStringCreateWithCString(kCFAllocatorDefault,
466                                         tok,
467                                         kCFStringEncodingUTF8);
468        CFDictionarySetValue(uuid_details,
469                             CFSTR(kIOPMPowerHistoryUUIDKey),
470                             uuid);
471        CFRelease(uuid);
472      }
473      else if(part == 3) {
474        // We don't want the extension .plog to be part of the
475        // timestamp
476        tok = strsep(&tok, ".");
477        timestamp = CFStringCreateWithCString(kCFAllocatorDefault,
478                                              tok,
479                                              kCFStringEncodingUTF8);
480        CFDictionarySetValue(uuid_details,
481                             CFSTR(kIOPMPowerHistoryTimestampCompletedKey),
482                             timestamp);
483        CFRelease(timestamp);
484      }
485
486      part++;
487    }
488
489    CFArrayAppendValue(logs, uuid_details);
490    CFRelease(uuid_details);
491    free(d_name);
492  }
493
494  closedir(dp);
495
496  if(fileCount == 0) {
497    *outArray = NULL;
498    return kIOReturnNotFound;
499  }
500  else
501    *outArray = logs;
502
503  return kIOReturnSuccess;
504}
505
506
507/******************************************************************************
508 * IOPMCopyPowerHistoryDetailed
509 *
510 ******************************************************************************/
511IOReturn IOPMCopyPowerHistoryDetailed(CFStringRef UUID, CFDictionaryRef *details)//CFArrayRef *outArray)
512{
513    IOReturn                return_code = kIOReturnBadArgument;
514    CFDataRef               serializedData = NULL;
515    char                    uuid_cstr[kMaxNameLength];
516
517    CFURLRef                fileURL = NULL;
518    CFMutableStringRef      fileName = CFStringCreateMutable(
519                                                    kCFAllocatorDefault,
520                                                    255);
521
522    CFStringAppend(fileName, CFSTR(pwrLogDirName));
523    CFStringAppend(fileName, CFSTR("/"));
524
525    if (NULL == details || NULL == UUID) {
526        goto exit;
527    }
528
529    *details = NULL;
530
531    if (!CFStringGetCString(UUID, uuid_cstr, sizeof(uuid_cstr), kCFStringEncodingMacRoman)) {
532        goto exit;
533    }
534
535    DIR *dp;
536    struct dirent *ep;
537
538    dp = opendir(pwrLogDirName);
539
540    if(dp == NULL) {
541      return_code = kIOReturnError;
542      goto exit;
543    }
544
545    while ((ep = readdir(dp))) {
546      if(strstr(ep->d_name, uuid_cstr)) {
547        CFStringRef uuid_file = CFStringCreateWithCString(
548                                                    kCFAllocatorDefault,
549                                                    ep->d_name,
550                                                    kCFStringEncodingUTF8);
551        CFStringAppend(fileName, uuid_file);
552        fileURL = CFURLCreateWithFileSystemPath(
553                                               kCFAllocatorDefault,
554                                               fileName,
555                                               kCFURLPOSIXPathStyle,
556                                               false);
557
558        CFRelease(uuid_file);
559      }
560    }
561
562    closedir(dp);
563
564    if(!fileURL) {
565      return_code = kIOReturnError;
566      goto exit;
567    }
568    SInt32 errorCode;
569    Boolean status = CFURLCreateDataAndPropertiesFromResource(
570                                                kCFAllocatorDefault,
571                                                fileURL,
572                                                &serializedData,
573                                                NULL,
574                                                NULL,
575                                                &errorCode);
576
577    if (serializedData && status) {
578        *details = (CFDictionaryRef)CFPropertyListCreateWithData(0, serializedData, 0, NULL, NULL);
579        CFRelease(serializedData);
580    }
581
582    if (NULL == details) {
583        return_code = kIOReturnError;
584    } else {
585        return_code = kIOReturnSuccess;
586    }
587
588    CFRelease(fileURL);
589    CFRelease(fileName);
590
591exit:
592    return return_code;
593}
594
595/******************************************************************************
596 * IOPMSetSleepServiceCapTimeout
597 *
598 ******************************************************************************/
599IOReturn IOPMSetSleepServicesWakeTimeCap(CFTimeInterval cap)
600{
601   mach_port_t             pm_server       = MACH_PORT_NULL;
602   kern_return_t           return_code     = KERN_SUCCESS;
603   int                     pm_mig_return = -1;
604
605   return_code = _pm_connect(&pm_server);
606
607   if(kIOReturnSuccess != return_code) {
608      return return_code;
609   }
610
611   return_code = io_pm_set_sleepservice_wake_time_cap(pm_server, (int)cap, &pm_mig_return);
612
613   _pm_disconnect(pm_server);
614   if (pm_mig_return == kIOReturnSuccess)
615      return return_code;
616   else
617      return pm_mig_return;
618}
619
620/******************************************************************************
621 * IOPMSleepWakeSetUUID
622 *
623 ******************************************************************************/
624IOReturn IOPMSleepWakeSetUUID(CFStringRef newUUID)
625{
626    IOReturn        ret = kIOReturnSuccess;
627    io_service_t    service = IO_OBJECT_NULL;
628    CFTypeRef       setObject = NULL;
629
630    if (!newUUID) {
631        // Clear active UUID
632        setObject = kCFBooleanFalse;
633    } else {
634        // cache the upcoming UUID
635        setObject = newUUID;
636    }
637
638    service = IORegistryEntryFromPath(kIOMasterPortDefault,
639            kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
640
641    if (IO_OBJECT_NULL != service) {
642        ret = IORegistryEntrySetCFProperty(
643                    service, CFSTR(kIOPMSleepWakeUUIDKey),
644                    setObject);
645        IOObjectRelease(service);
646    }
647    return ret;
648}
649
650/******************************************************************************
651 * IOPMSleepWakeCopyUUID
652 *
653 ******************************************************************************/
654CFStringRef IOPMSleepWakeCopyUUID(void)
655{
656    CFStringRef     uuidString = NULL;
657    io_service_t    service = IO_OBJECT_NULL;
658
659    service = IORegistryEntryFromPath(kIOMasterPortDefault,
660            kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
661
662    if (IO_OBJECT_NULL != service) {
663        uuidString = IORegistryEntryCreateCFProperty(
664                       service,
665                       CFSTR(kIOPMSleepWakeUUIDKey),
666                       kCFAllocatorDefault, 0);
667        IOObjectRelease(service);
668    }
669
670    // Caller must release uuidString, if non-NULL
671    return uuidString;
672}
673
674
675bool IOPMGetUUID(int whichUUID, char *putTheUUIDHere, int sizeOfBuffer)
676{
677    bool return_bool_value = false;
678
679    if (kIOPMSleepWakeUUID == whichUUID)
680    {
681        CFStringRef bs = IOPMSleepWakeCopyUUID();
682        if (bs) {
683            Boolean bool_result;
684            bool_result = CFStringGetCString(bs, putTheUUIDHere, sizeOfBuffer, kCFStringEncodingUTF8);
685            CFRelease(bs);
686            return bool_result;
687        }
688        return false;
689    }
690    else if (kIOPMSleepServicesUUID == whichUUID)
691    {
692        mach_port_t             pm_server       = MACH_PORT_NULL;
693        kern_return_t           return_code     = KERN_SUCCESS;
694        char                    strPtr[kPMMIGStringLength];
695        int                     pm_mig_return = -1;
696
697        return_code = _pm_connect(&pm_server);
698
699        if(kIOReturnSuccess != return_code) {
700            return false;
701        }
702
703        bzero(strPtr, sizeof(strPtr));
704        return_code = io_pm_get_uuid(pm_server, kIOPMSleepServicesUUID, strPtr, &pm_mig_return);
705
706        if ((KERN_SUCCESS == return_code) && (KERN_SUCCESS == pm_mig_return))
707        {
708            bzero(putTheUUIDHere, sizeOfBuffer);
709
710            strncpy(putTheUUIDHere, strPtr, sizeOfBuffer-1);
711
712            return_bool_value = true;
713        }
714
715        _pm_disconnect(pm_server);
716    }
717
718    return return_bool_value;
719}
720
721/******************************************************************************
722 * IOPMDebugTracePoint
723 *
724 ******************************************************************************/
725IOReturn IOPMDebugTracePoint(CFStringRef facility, uint8_t *data, int dataCount)
726{
727    io_registry_entry_t gRoot = IO_OBJECT_NULL;
728    CFNumberRef         setNum = NULL;
729    IOReturn            ret = kIOReturnError;
730    if (data == NULL || facility == NULL || 1 != dataCount)
731        return kIOReturnBadArgument;
732
733    gRoot = IORegistryEntryFromPath( kIOMasterPortDefault,
734        kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
735
736    if (IO_OBJECT_NULL == gRoot)
737        return kIOReturnError;
738
739    // We allow CF to treat this number as a signed integer. We're using it as a bitfield;
740    // we shouldn't have to worry about sign extension when it gets unpacked.
741    setNum = CFNumberCreate(0, kCFNumberSInt8Type, data);
742    if (!setNum)
743        goto exit;
744
745    ret = IORegistryEntrySetCFProperty( gRoot,
746                        CFSTR(kIOPMLoginWindowSecurityDebugKey),
747                        setNum);
748exit:
749    if (setNum)
750        CFRelease(setNum);
751    if (gRoot)
752        IOObjectRelease(gRoot);
753    return ret;
754}
755
756/******************************************************************************
757 * IOPMCopySleepWakeFailure
758 *
759 ******************************************************************************/
760CFDictionaryRef IOPMCopySleepWakeFailure(void)
761{
762    CFStringRef         scFailureKey = NULL;
763    CFDictionaryRef     scFailureDictionary = NULL;
764    SCDynamicStoreRef   scDynStore = NULL;
765
766    scDynStore = SCDynamicStoreCreate(0, CFSTR("IOPMSleepFailure"), NULL, NULL);
767    if (!scDynStore)
768        goto exit;
769
770    scFailureKey = SCDynamicStoreKeyCreate(
771                            kCFAllocatorDefault,
772                            CFSTR("%@%@/%@"),
773                            kSCDynamicStoreDomainState,
774                            CFSTR("PowerManagement"),
775                            CFSTR(kIOPMDynamicStoreSleepFailureKey));
776    if (!scFailureKey)
777        goto exit;
778
779    scFailureDictionary = isA_CFDictionary(SCDynamicStoreCopyValue(scDynStore, scFailureKey));
780
781exit:
782    if (scDynStore)
783        CFRelease(scDynStore);
784    if (scFailureKey)
785        CFRelease(scFailureKey);
786    return scFailureDictionary;
787}
788
789
790#define POWERD_XPC_ID   "com.apple.iokit.powerdxpc"
791
792void IOPMClaimSystemWakeEvent(
793    CFStringRef         identity,
794    CFStringRef         reason,
795    CFDictionaryRef     description)
796{
797    xpc_connection_t        connection = NULL;
798    xpc_object_t            sendClaim = NULL;
799    xpc_object_t            msg = NULL;
800    xpc_object_t            desc = NULL;
801    char                    str[255];
802
803    connection = xpc_connection_create_mach_service(POWERD_XPC_ID,
804                            dispatch_get_global_queue(DISPATCH_QUEUE_CONCURRENT, 0), 0);
805
806    if (!connection) {
807        goto exit;
808    }
809
810    xpc_connection_set_target_queue(connection,
811                            dispatch_get_global_queue(DISPATCH_QUEUE_CONCURRENT, 0));
812
813    xpc_connection_set_event_handler(connection,
814                                     ^(xpc_object_t e __unused) { });
815
816    sendClaim = xpc_dictionary_create(NULL, NULL, 0);
817    if (sendClaim) {
818        if (identity) {
819            CFStringGetCString(identity, str, sizeof(str), kCFStringEncodingUTF8);
820            xpc_dictionary_set_string(sendClaim, "identity", str);
821        }
822        if (reason) {
823            CFStringGetCString(reason, str, sizeof(str), kCFStringEncodingUTF8);
824            xpc_dictionary_set_string(sendClaim, "reason", str);
825        }
826
827        if (description) {
828            desc = _CFXPCCreateXPCObjectFromCFObject(description);
829            if (desc) {
830                xpc_dictionary_set_value(sendClaim, "description", desc);
831                xpc_release(desc);
832            }
833        }
834    }
835
836    msg = xpc_dictionary_create(NULL, NULL, 0);
837    if (msg) {
838        xpc_dictionary_set_value(msg, "claimSystemWakeEvent", sendClaim);
839        xpc_connection_resume(connection);
840        xpc_connection_send_message(connection, msg);
841        xpc_release(msg);
842    }
843exit:
844    if (connection) {
845        xpc_release(connection);
846    }
847}
848
849/*****************************************************************************/
850/*****************************************************************************/
851/*****************************************************************************/
852/*****************************************************************************/
853
854/* __IOPMConnection is the IOKit-tracking struct to keep track of
855 * open connections.
856 */
857typedef struct {
858    uint32_t                id;
859    int                     pid;
860    CFStringRef             connectionName;
861
862    /* for dispatch-style notifications */
863    mach_port_t             mach_port;
864    dispatch_source_t       dispatchDelivery;
865
866    /* for CFRunLoop-style notifications */
867    CFMachPortRef           localCFMachPort;
868    CFRunLoopSourceRef      localCFMachPortRLS;
869
870    IOPMEventHandlerType    userCallout;
871    void                    *userParam;
872    int                     runLoopCount;
873} __IOPMConnection;
874
875
876/*****************************************************************************/
877/*****************************************************************************/
878
879/* iopm_mach_port_callback
880 * The caller installed this callback on a runloop of their choice.
881 * Note that this code is running in the caller's runloop context; we don't have
882 * it serialized.
883 */
884#define kMsgPayloadCount    2
885
886typedef struct {
887    mach_msg_header_t   header;
888    mach_msg_body_t     body;
889    uint32_t            payload[kMsgPayloadCount];
890} IOPMMessageStructure;
891
892static void iopm_mach_port_callback(
893    CFMachPortRef port __unused,
894    void *msg,
895    CFIndex size __unused,
896    void *info)
897{
898    IOPMMessageStructure *m  = (IOPMMessageStructure *)msg;
899
900    __IOPMConnection        *connection = (__IOPMConnection *)info;
901
902    if (!connection || !connection->userCallout) {
903        return;
904    }
905
906    (*(connection->userCallout))(
907                    connection->userParam,
908                    (IOPMConnection)connection,
909                    m->payload[1],      // messageToken argument
910                    m->payload[0]);     // event DATA
911
912    return;
913}
914
915/*****************************************************************************/
916/*****************************************************************************/
917
918static kern_return_t _conveyMachPortToPowerd(
919                                             __IOPMConnection *connection,
920                                             mach_port_t the_port,
921                                             bool enable)
922{
923    mach_port_t             pm_server       = MACH_PORT_NULL;
924    kern_return_t           return_code     = KERN_SUCCESS;
925
926    return_code = _pm_connect(&pm_server);
927
928    if(kIOReturnSuccess != return_code) {
929        goto exit;
930    }
931
932    return_code = io_pm_connection_schedule_notification(pm_server, connection->id, the_port, enable ? 0:1, &return_code);
933
934    _pm_disconnect(pm_server);
935
936exit:
937    return return_code;
938}
939
940
941/*****************************************************************************/
942/*****************************************************************************/
943#pragma mark -
944#pragma mark IOPMConnection
945
946IOReturn IOPMConnectionSetNotification(
947    IOPMConnection myConnection,
948    void *param,
949    IOPMEventHandlerType handler)
950{
951    __IOPMConnection *connection = (__IOPMConnection *)myConnection;
952
953    if (!connection || !handler)
954        return kIOReturnBadArgument;
955
956    connection->userParam = param;
957    connection->userCallout = handler;
958
959    return kIOReturnSuccess;
960}
961
962/*****************************************************************************/
963/*****************************************************************************/
964
965IOReturn IOPMConnectionScheduleWithRunLoop(
966    IOPMConnection myConnection,
967    CFRunLoopRef theRunLoop,
968    CFStringRef runLoopMode)
969{
970    __IOPMConnection *connection = (__IOPMConnection *)myConnection;
971
972    IOReturn                return_code = kIOReturnError;
973    CFMachPortContext       mpContext = { 1, (void *)connection, NULL, NULL, NULL };
974
975    if (!connection || !theRunLoop || !runLoopMode)
976        return kIOReturnBadArgument;
977
978    if (NULL == connection->localCFMachPort)
979    {
980        // Create the mach port on which we'll receive mach messages
981        // from PM configd.
982        connection->localCFMachPort = CFMachPortCreate(
983                                            kCFAllocatorDefault,
984                                            iopm_mach_port_callback,
985                                            &mpContext, NULL);
986
987        if (connection->localCFMachPort) {
988            connection->localCFMachPortRLS = CFMachPortCreateRunLoopSource(
989                                            kCFAllocatorDefault,
990                                            connection->localCFMachPort,
991                                            0);
992        }
993    }
994
995    if (!connection->localCFMachPortRLS)
996        return kIOReturnInternalError;
997
998    // Record our new run loop.
999    connection->runLoopCount++;
1000
1001    CFRunLoopAddSource(theRunLoop, connection->localCFMachPortRLS, runLoopMode);
1002
1003    // We have a mapping of one mach_port connected to PM configd to as many
1004    // CFRunLoopSources that the caller originates.
1005    if (1 == connection->runLoopCount)
1006    {
1007        mach_port_t notify_mach_port = MACH_PORT_NULL;
1008
1009        if (connection->localCFMachPort) {
1010            notify_mach_port = CFMachPortGetPort(connection->localCFMachPort);
1011        }
1012
1013        return_code =_conveyMachPortToPowerd(connection, notify_mach_port, true);
1014    }
1015
1016    return return_code;
1017}
1018
1019/*****************************************************************************/
1020/*****************************************************************************/
1021
1022IOReturn IOPMConnectionUnscheduleFromRunLoop(
1023                                             IOPMConnection myConnection,
1024                                             CFRunLoopRef theRunLoop,
1025                                             CFStringRef runLoopMode)
1026{
1027    __IOPMConnection    *connection = (__IOPMConnection *)myConnection;
1028    IOReturn            return_code = kIOReturnSuccess;
1029
1030    if (!connection || !theRunLoop || !runLoopMode)
1031        return kIOReturnBadArgument;
1032
1033    if (connection->localCFMachPort) {
1034        CFRunLoopRemoveSource(theRunLoop, connection->localCFMachPortRLS, runLoopMode);
1035    }
1036
1037    connection->runLoopCount--;
1038
1039    if (0 == connection->runLoopCount)
1040    {
1041        mach_port_t notify_mach_port = MACH_PORT_NULL;
1042
1043        if (connection->localCFMachPort) {
1044            notify_mach_port = CFMachPortGetPort(connection->localCFMachPort);
1045        }
1046
1047        return_code = _conveyMachPortToPowerd(connection, notify_mach_port, false);
1048    }
1049
1050    return return_code;
1051}
1052
1053/*****************************************************************************/
1054/*****************************************************************************/
1055
1056void IOPMConnectionSetDispatchQueue(
1057    IOPMConnection myConnection,
1058    dispatch_queue_t myQueue)
1059{
1060    __IOPMConnection *connection = (__IOPMConnection *)myConnection;
1061
1062    if (!connection)
1063        return;
1064
1065    if (!myQueue) {
1066        /* Clean up a previously scheduled dispatch. */
1067        if (connection->dispatchDelivery)
1068        {
1069            dispatch_source_cancel(connection->dispatchDelivery);
1070        }
1071        return;
1072    }
1073
1074    if (KERN_SUCCESS != mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &connection->mach_port))
1075    {
1076        // Error allocating mach port
1077        return;
1078    }
1079
1080    mach_port_insert_right(mach_task_self(), connection->mach_port, connection->mach_port,
1081                           MACH_MSG_TYPE_MAKE_SEND);
1082
1083    if (!(connection->dispatchDelivery
1084          = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, connection->mach_port, 0, myQueue)))
1085    {
1086        // Error creating dispatch_source
1087        mach_port_deallocate(mach_task_self(), connection->mach_port);
1088        mach_port_mod_refs(mach_task_self(), connection->mach_port, MACH_PORT_RIGHT_RECEIVE, -1);
1089        return;
1090    }
1091
1092    dispatch_source_set_cancel_handler(connection->dispatchDelivery,
1093                                       ^{
1094                                           _conveyMachPortToPowerd(connection, connection->mach_port, false);
1095
1096                                           dispatch_release(connection->dispatchDelivery);
1097                                           connection->dispatchDelivery = 0;
1098
1099                                           mach_port_mod_refs(mach_task_self(), connection->mach_port, MACH_PORT_RIGHT_RECEIVE, -1);
1100                                           mach_port_deallocate(mach_task_self(), connection->mach_port);
1101                                           connection->mach_port = MACH_PORT_NULL;
1102                                       });
1103
1104    dispatch_source_set_event_handler(connection->dispatchDelivery,
1105                                      ^{
1106                                        struct {
1107                                            IOPMMessageStructure    m;
1108                                            mach_msg_trailer_t      trailer;
1109                                        } msg;
1110
1111                                        bzero(&msg, sizeof(msg));
1112                                        kern_return_t status = mach_msg( ( void * )&msg,
1113                                                         MACH_RCV_MSG | MACH_RCV_TIMEOUT,
1114                                                         0,
1115                                                         sizeof( msg ),
1116                                                         connection->mach_port,
1117                                                         0,
1118                                                         MACH_PORT_NULL );
1119
1120                                        if (!connection || !connection->userCallout
1121                                            || (KERN_SUCCESS != status))
1122                                        {
1123                                            return;
1124                                        }
1125
1126                                        (*(connection->userCallout))(connection->userParam,
1127                                                                 (IOPMConnection)connection,
1128                                                                 msg.m.payload[1], msg.m.payload[0]);
1129                                    });
1130
1131    dispatch_resume(connection->dispatchDelivery);
1132
1133    _conveyMachPortToPowerd(connection, connection->mach_port, true);
1134
1135    return;
1136}
1137
1138/*****************************************************************************/
1139/*****************************************************************************/
1140
1141IOReturn IOPMConnectionCreate(
1142    CFStringRef myName,
1143    IOPMCapabilityBits interests,
1144    IOPMConnection *newConnection)
1145{
1146    __IOPMConnection        *connection = NULL;
1147
1148    mach_port_t             pm_server = MACH_PORT_NULL;
1149    int                     return_code = kIOReturnError;
1150    IOReturn                err = kIOReturnError;
1151    kern_return_t           kern_result = KERN_SUCCESS;
1152
1153    char                    arg_name_str[kMaxNameLength];
1154    uint32_t                new_connection_id = 0;
1155
1156    // * vet argument newConnection
1157    // * and create new connection
1158    if (!newConnection)
1159        return kIOReturnBadArgument;
1160
1161    *newConnection = NULL;
1162
1163    err = _pm_connect(&pm_server);
1164    if(kIOReturnSuccess != err) {
1165        return_code = kIOReturnInternalError;
1166        goto exit;
1167    }
1168
1169    // * vet argument 'interests'
1170    // A caller specifying 0 interests would get no notifications
1171    if (0 == interests) {
1172        return_code = kIOReturnBadArgument;
1173        goto exit;
1174    }
1175
1176    // * vet argument 'myName'
1177    if (!myName || (kMaxNameLength < CFStringGetLength(myName))) {
1178        return_code = kIOReturnBadArgument;
1179        goto exit;
1180    }
1181    CFStringGetCString( myName, arg_name_str,
1182                        sizeof(arg_name_str), kCFStringEncodingMacRoman);
1183
1184
1185    connection = calloc(1, sizeof(__IOPMConnection));
1186    if (!connection) {
1187        return_code = kIOReturnInternalError;
1188        goto exit;
1189    }
1190
1191    kern_result = io_pm_connection_create(
1192                                    pm_server,
1193                                    mach_task_self(),
1194                                    arg_name_str,
1195                                    interests,
1196                                    &new_connection_id,
1197                                    &return_code);
1198
1199    if (KERN_SUCCESS != kern_result) {
1200        return_code = kern_result;
1201        goto exit;
1202    }
1203
1204    connection->id = (int)new_connection_id;
1205    *newConnection = (void *)connection;
1206
1207    return_code = kIOReturnSuccess;
1208
1209exit:
1210    if (MACH_PORT_NULL != pm_server) {
1211        _pm_disconnect(pm_server);
1212    }
1213
1214    return return_code;
1215
1216}
1217
1218/*****************************************************************************/
1219/*****************************************************************************/
1220
1221IOReturn IOPMConnectionRelease(IOPMConnection connection)
1222{
1223    __IOPMConnection    *connection_private = (__IOPMConnection *)connection;
1224    IOReturn            return_code = kIOReturnError;
1225    mach_port_t         pm_server = MACH_PORT_NULL;
1226    kern_return_t       kern_result;
1227    IOReturn            err;
1228
1229    err = _pm_connect(&pm_server);
1230    if(kIOReturnSuccess != err) {
1231        return_code = kIOReturnInternalError;
1232        goto exit;
1233    }
1234
1235#if !TARGET_OS_IPHONE
1236    if (connection_private->dispatchDelivery) {
1237        IOPMConnectionSetDispatchQueue(connection, NULL);
1238    }
1239#endif
1240
1241    kern_result = io_pm_connection_release(pm_server,
1242                                            connection_private->id,
1243                                            &return_code);
1244    if (kern_result != KERN_SUCCESS) {
1245        return_code = kern_result;
1246    }
1247exit:
1248    if (MACH_PORT_NULL != pm_server) {
1249        _pm_disconnect(pm_server);
1250    }
1251
1252    return return_code;
1253}
1254
1255/*****************************************************************************/
1256/*****************************************************************************/
1257
1258IOReturn IOPMConnectionAcknowledgeEvent(
1259    IOPMConnection connect,
1260    IOPMConnectionMessageToken token)
1261{
1262#if TARGET_OS_IPHONE
1263    (void)connect;
1264    (void)token;
1265
1266    return kIOReturnUnsupported;
1267#else
1268    return IOPMConnectionAcknowledgeEventWithOptions(
1269                           connect, token, NULL);
1270#endif /* TARGET_OS_IPHONE */
1271}
1272
1273
1274/*****************************************************************************/
1275/*****************************************************************************/
1276
1277IOReturn IOPMConnectionAcknowledgeEventWithOptions(
1278    IOPMConnection myConnection,
1279    IOPMConnectionMessageToken token,
1280    CFDictionaryRef options)
1281{
1282#if TARGET_OS_IPHONE
1283    (void)myConnection;
1284    (void)token;
1285    (void)options;
1286
1287    return kIOReturnUnsupported;
1288#else
1289    __IOPMConnection    *connection = (__IOPMConnection *)myConnection;
1290
1291    IOReturn            return_code = kIOReturnError;
1292    mach_port_t         pm_server = MACH_PORT_NULL;
1293    kern_return_t       kern_result;
1294    IOReturn            err;
1295
1296    CFDataRef           serializedData = NULL;
1297    vm_offset_t         buffer_ptr = 0;
1298    size_t              buffer_size = 0;
1299
1300    // No response is expected when token is 0
1301    if (token == 0)
1302        return kIOReturnSuccess;
1303
1304    err = _pm_connect(&pm_server);
1305    if(kIOReturnSuccess != err) {
1306        return_code = kIOReturnInternalError;
1307        goto exit;
1308    }
1309
1310    if (options)
1311    {
1312        serializedData = CFPropertyListCreateData(
1313                                    kCFAllocatorDefault,
1314                                    (CFPropertyListRef)options,
1315                                    kCFPropertyListBinaryFormat_v1_0, 0, NULL);
1316
1317        if (serializedData)
1318        {
1319            buffer_ptr = (vm_offset_t)CFDataGetBytePtr(serializedData);
1320            buffer_size = (size_t)CFDataGetLength(serializedData);
1321
1322        }
1323    }
1324
1325    kern_result = io_pm_connection_acknowledge_event(pm_server,
1326                                    (uint32_t)connection->id,
1327                                    (uint32_t)token,
1328                                    buffer_ptr,
1329                                    buffer_size,
1330                                    &return_code);
1331
1332    if (kern_result != KERN_SUCCESS) {
1333        return_code = kern_result;
1334    }
1335exit:
1336    if (MACH_PORT_NULL != pm_server) {
1337        _pm_disconnect(pm_server);
1338    }
1339
1340    if (serializedData) CFRelease(serializedData);
1341
1342    return return_code;
1343#endif /* TARGET_OS_IPHONE */
1344}
1345
1346/*****************************************************************************/
1347/*****************************************************************************/
1348
1349IOReturn IOPMCopyConnectionStatus(int statusSelector, CFTypeRef *output)
1350{
1351    int                 return_code = kIOReturnError;
1352    mach_port_t         pm_server = MACH_PORT_NULL;
1353    kern_return_t       kern_result;
1354    IOReturn            err;
1355
1356    vm_offset_t         buffer_ptr = 0;
1357    mach_msg_type_number_t    buffer_size = 0;
1358
1359    CFDictionaryRef     *dictionaryOutput = (CFDictionaryRef *)output;
1360
1361    err = _pm_connect(&pm_server);
1362    if(kIOReturnSuccess != err) {
1363        return_code = kIOReturnInternalError;
1364        goto exit;
1365    }
1366
1367    // TODO: serialize passed-in options into buffer_ptr & buffer_size
1368    *dictionaryOutput = NULL;
1369
1370
1371    kern_result = io_pm_connection_copy_status(pm_server,
1372                                            (uint32_t)statusSelector,
1373                                            &buffer_ptr,
1374                                            &buffer_size,
1375                                            &return_code);
1376
1377    if (kern_result != KERN_SUCCESS) {
1378        return_code = kern_result;
1379    }
1380exit:
1381    if (MACH_PORT_NULL != pm_server) {
1382        _pm_disconnect(pm_server);
1383    }
1384
1385    return return_code;
1386}
1387
1388/*****************************************************************************/
1389/*****************************************************************************/
1390
1391#define SYSTEM_ON_CAPABILITIES (kIOPMCapabilityCPU | kIOPMCapabilityVideo | kIOPMCapabilityAudio \
1392                                | kIOPMCapabilityNetwork | kIOPMCapabilityDisk)
1393
1394IOPMCapabilityBits IOPMConnectionGetSystemCapabilities(void)
1395{
1396
1397    mach_port_t             pm_server = MACH_PORT_NULL;
1398    kern_return_t           kern_result;
1399    IOPMCapabilityBits      ret_cap = SYSTEM_ON_CAPABILITIES;
1400    IOReturn                return_code = kIOReturnError;
1401
1402    return_code = _pm_connect(&pm_server);
1403
1404    if(pm_server == MACH_PORT_NULL)
1405      return ret_cap;
1406
1407    kern_result = io_pm_get_capability_bits(pm_server, &ret_cap, &return_code);
1408
1409    _pm_disconnect(pm_server);
1410
1411    return ret_cap;
1412
1413
1414}
1415
1416
1417bool IOPMIsADarkWake(IOPMCapabilityBits c)
1418{
1419    return ((c & kIOPMCapabilityCPU) && !(c & kIOPMCapabilityVideo));
1420}
1421
1422bool IOPMAllowsBackgroundTask(IOPMCapabilityBits c)
1423{
1424    return (0 != (c & kIOPMCapabilityBackgroundTask));
1425}
1426
1427bool IOPMAllowsPushServiceTask(IOPMCapabilityBits c)
1428{
1429    return (0 != (c & kIOPMCapabilityPushServiceTask));
1430}
1431
1432bool IOPMIsASilentWake(IOPMCapabilityBits c)
1433{
1434    return (0 != (c & kIOPMCapabilitySilentRunning));
1435}
1436
1437bool IOPMIsAUserWake(IOPMCapabilityBits c)
1438{
1439    return (0 != (c & kIOPMCapabilityVideo));
1440}
1441
1442bool IOPMIsASleep(IOPMCapabilityBits c)
1443{
1444    return (0 == (c & kIOPMCapabilityCPU));
1445}
1446
1447bool IOPMGetCapabilitiesDescription(char *buf, int buf_size, IOPMCapabilityBits in_caps)
1448{
1449    uint64_t caps = (uint64_t)in_caps;
1450    int printed_total = 0;
1451    char *on_sleep_dark = "";
1452
1453    if (IOPMIsASleep(caps))
1454    {
1455        on_sleep_dark = "Sleep";
1456    } else if (IOPMIsADarkWake(caps))
1457    {
1458        on_sleep_dark = "DarkWake";
1459    } else if (IOPMIsAUserWake(caps))
1460    {
1461        on_sleep_dark = "FullWake";
1462    } else
1463    {
1464        on_sleep_dark = "Unknown";
1465    }
1466
1467    printed_total = snprintf(buf, buf_size, "%s:%s%s%s%s%s%s%s",
1468                             on_sleep_dark,
1469                             (caps & kIOPMCapabilityCPU) ? "cpu ":"<off> ",
1470                             (caps & kIOPMCapabilityDisk) ? "disk ":"",
1471                             (caps & kIOPMCapabilityNetwork) ? "net ":"",
1472                             (caps & kIOPMCapabilityAudio) ? "aud ":"",
1473                             (caps & kIOPMCapabilityVideo) ? "vid ":"",
1474                             (caps & kIOPMCapabilityPushServiceTask) ? "push ":"",
1475                             (caps & kIOPMCapabilityBackgroundTask) ? "bg ":"");
1476
1477    return (printed_total <= buf_size);
1478}
1479
1480
1481/*****************************************************************************/
1482/*****************************************************************************/
1483#pragma mark -
1484#pragma mark Talking about DarkWake
1485
1486bool IOPMGetSleepServicesActive(void)
1487{
1488    int         token = 0;
1489    uint64_t    payload = 0;
1490
1491    if (NOTIFY_STATUS_OK == notify_register_check(kIOPMSleepServiceActiveNotifyName, &token))
1492    {
1493        notify_get_state(token, &payload);
1494        notify_cancel(token);
1495    }
1496
1497    return ((payload &  kIOPMSleepServiceActiveNotifyBit) ? true : false);
1498}
1499
1500
1501int IOPMGetDarkWakeThermalEmergencyCount(void)
1502{
1503    return IOPMGetValueInt(kIOPMDarkWakeThermalEventCount);
1504}
1505
1506/*****************************************************************************/
1507/*****************************************************************************/
1508#pragma mark -
1509#pragma mark Power Internals
1510
1511/*!
1512 * @function        IOPMGetValueInt
1513 * @abstract        For IOKit use only.
1514 */
1515int IOPMGetValueInt(int selector) {
1516    mach_port_t             pm_server = MACH_PORT_NULL;
1517    int                     valint = 0;
1518    kern_return_t           kern_result;
1519
1520    if (kIOReturnSuccess == _pm_connect(&pm_server))
1521    {
1522        kern_result = io_pm_get_value_int(
1523                                          pm_server,
1524                                          selector,
1525                                          &valint);
1526        if (KERN_SUCCESS != kern_result) {
1527            valint = 0;
1528        }
1529        _pm_disconnect(pm_server);
1530    }
1531    return valint;
1532}
1533
1534/*!
1535 * @function        IOPMSetValueInt
1536 * @abstract        For IOKit use only.
1537 */
1538void IOPMSetValueInt(int selector, int value) {
1539    mach_port_t             pm_server = MACH_PORT_NULL;
1540    int                     rc = kIOReturnSuccess;
1541
1542    if (kIOReturnSuccess == _pm_connect(&pm_server))
1543    {
1544        io_pm_set_value_int(
1545                            pm_server,
1546                            selector,
1547                            value, &rc);
1548        _pm_disconnect(pm_server);
1549    }
1550    return;
1551}
1552
1553
1554IOReturn IOPMSetDebugFlags(uint32_t newFlags, uint32_t *oldFlags)
1555{
1556
1557    mach_port_t             pm_server = MACH_PORT_NULL;
1558    kern_return_t           kern_result;
1559    uint32_t                flags;
1560    IOReturn                return_code = kIOReturnError;
1561
1562    return_code = _pm_connect(&pm_server);
1563
1564    if(pm_server == MACH_PORT_NULL)
1565      return kIOReturnNotReady;
1566
1567    kern_result = io_pm_set_debug_flags(pm_server, newFlags, kIOPMDebugFlagsSetValue, &flags, &return_code);
1568
1569    _pm_disconnect(pm_server);
1570
1571    if ( kern_result == KERN_SUCCESS && return_code == kIOReturnSuccess) {
1572        if (oldFlags)
1573            *oldFlags = flags;
1574        return kIOReturnSuccess;
1575    }
1576    else
1577        return return_code;
1578}
1579
1580#if TARGET_OS_IPHONE
1581IOReturn IOPMSetBTWakeInterval(uint32_t newInterval __unused,
1582      uint32_t *oldInterval __unused)
1583{
1584#else
1585IOReturn IOPMSetBTWakeInterval(uint32_t newInterval, uint32_t *oldInterval)
1586{
1587
1588    mach_port_t             pm_server = MACH_PORT_NULL;
1589    kern_return_t           kern_result;
1590    uint32_t                interval = 0;
1591    IOReturn                return_code = kIOReturnError;
1592
1593    return_code = _pm_connect(&pm_server);
1594
1595    if(pm_server == MACH_PORT_NULL)
1596      return kIOReturnNotReady;
1597
1598    kern_result = io_pm_set_bt_wake_interval(pm_server, newInterval, &interval, &return_code);
1599
1600    _pm_disconnect(pm_server);
1601
1602    if ( kern_result == KERN_SUCCESS && return_code == kIOReturnSuccess) {
1603        if (oldInterval)
1604            *oldInterval = interval;
1605        return kIOReturnSuccess;
1606    }
1607    else
1608        return return_code;
1609
1610#endif
1611    return kIOReturnSuccess;
1612
1613}
1614
1615#if TARGET_OS_IPHONE
1616IOReturn IOPMSetDWLingerInterval(uint32_t newInterval __unused,
1617      uint32_t *oldInterval __unused)
1618{
1619#else
1620IOReturn IOPMSetDWLingerInterval(uint32_t newInterval, uint32_t *oldInterval)
1621{
1622
1623    mach_port_t             pm_server = MACH_PORT_NULL;
1624    kern_return_t           kern_result;
1625    uint32_t                interval = 0;
1626    IOReturn                return_code = kIOReturnError;
1627
1628    return_code = _pm_connect(&pm_server);
1629
1630    if(pm_server == MACH_PORT_NULL)
1631      return kIOReturnNotReady;
1632
1633    kern_result = io_pm_set_dw_linger_interval(pm_server, newInterval, &interval, &return_code);
1634
1635    _pm_disconnect(pm_server);
1636
1637    if ( kern_result == KERN_SUCCESS && return_code == kIOReturnSuccess) {
1638        if (oldInterval)
1639            *oldInterval = interval;
1640        return kIOReturnSuccess;
1641    }
1642    else
1643        return return_code;
1644
1645#endif
1646    return kIOReturnSuccess;
1647
1648}
1649
1650IOReturn IOPMChangeSystemActivityAssertionBehavior(uint32_t newFlags, uint32_t *oldFlags)
1651{
1652    mach_port_t             pm_server = MACH_PORT_NULL;
1653    kern_return_t           kern_result;
1654    uint32_t                flags = 0;
1655    IOReturn                return_code = kIOReturnError;
1656
1657    return_code = _pm_connect(&pm_server);
1658
1659    if(pm_server == MACH_PORT_NULL)
1660      return kIOReturnNotReady;
1661
1662    kern_result = io_pm_change_sa_assertion_behavior(pm_server, newFlags, &flags, &return_code);
1663
1664    _pm_disconnect(pm_server);
1665
1666    if ( kern_result == KERN_SUCCESS && return_code == kIOReturnSuccess)
1667    {
1668        if(flags)
1669            *oldFlags = flags;
1670        return kIOReturnSuccess;
1671    }
1672    else
1673        return return_code;
1674}
1675
1676/*****************************************************************************/
1677/*****************************************************************************/
1678IOReturn IOPMCtlAssertionType(char *type, int op)
1679{
1680    mach_port_t             pm_server = MACH_PORT_NULL;
1681    kern_return_t           kern_result;
1682    IOReturn                return_code = kIOReturnError;
1683
1684    return_code = _pm_connect(&pm_server);
1685
1686    if(pm_server == MACH_PORT_NULL)
1687      return kIOReturnNotReady;
1688
1689    kern_result = io_pm_ctl_assertion_type(pm_server, type,
1690            op, &return_code);
1691
1692    _pm_disconnect(pm_server);
1693
1694    if ( kern_result == KERN_SUCCESS && return_code == kIOReturnSuccess) {
1695        return kIOReturnSuccess;
1696    }
1697    else
1698        return return_code;
1699}
1700
1701/*****************************************************************************/
1702/*****************************************************************************/
1703#define kPMReportPowerOn       0x01
1704#define kPMReportDeviceUsable  0x02
1705#define kPMReportLowPower      0x04
1706CFDictionaryRef  IOPMCopyPowerStateInfo(uint64_t state_id)
1707{
1708    CFMutableDictionaryRef dict = NULL;
1709    CFTypeRef objRef = NULL;
1710    uint32_t val = 0;
1711
1712    dict  = CFDictionaryCreateMutable(kCFAllocatorDefault,
1713                                 0,
1714                                 &kCFTypeDictionaryKeyCallBacks,
1715                                 &kCFTypeDictionaryValueCallBacks);
1716
1717    if (!dict)
1718        return kIOReturnNoMemory;
1719
1720    val = state_id & 0xf;
1721    objRef = CFNumberCreate(0, kCFNumberIntType, &val);
1722    if (objRef) {
1723        CFDictionarySetValue(dict, kIOPMNodeCurrentState, objRef);
1724        CFRelease(objRef);
1725    }
1726
1727    val = ((state_id >> 4) & 0xf);
1728    objRef = CFNumberCreate(0, kCFNumberIntType, &val);
1729    if (objRef) {
1730        CFDictionarySetValue(dict, kIOPMNodeMaxState, objRef);
1731        CFRelease(objRef); objRef = NULL;
1732    }
1733
1734    if ( (state_id >> 8) & kPMReportPowerOn)
1735        CFDictionarySetValue(dict, kIOPMNodeIsPowerOn, kCFBooleanTrue);
1736    else
1737        CFDictionarySetValue(dict, kIOPMNodeIsPowerOn, kCFBooleanFalse);
1738
1739    if ( (state_id >> 8) & kPMReportDeviceUsable)
1740        CFDictionarySetValue(dict, kIOPMNodeIsDeviceUsable, kCFBooleanTrue);
1741    else
1742        CFDictionarySetValue(dict, kIOPMNodeIsDeviceUsable, kCFBooleanFalse);
1743
1744
1745    if ( (state_id >> 8) & kPMReportLowPower)
1746        CFDictionarySetValue(dict, kIOPMNodeIsLowPower, kCFBooleanTrue);
1747    else
1748        CFDictionarySetValue(dict, kIOPMNodeIsLowPower, kCFBooleanFalse);
1749
1750    return dict;
1751}
1752/*****************************************************************************/
1753/*****************************************************************************/
1754
1755IOReturn IOPMAssertionNotify(char *name, int req_type)
1756{
1757    mach_port_t             pm_server = MACH_PORT_NULL;
1758    kern_return_t           kern_result;
1759    IOReturn                return_code = kIOReturnError;
1760
1761    return_code = _pm_connect(&pm_server);
1762
1763    if(pm_server == MACH_PORT_NULL)
1764      return kIOReturnNotReady;
1765
1766    kern_result = io_pm_assertion_notify(pm_server, name,
1767            req_type, &return_code);
1768
1769    _pm_disconnect(pm_server);
1770
1771    if ( kern_result == KERN_SUCCESS && return_code == kIOReturnSuccess) {
1772        return kIOReturnSuccess;
1773    }
1774    else
1775        return return_code;
1776}
1777
1778/*****************************************************************************/
1779
1780#if 0
1781bool IOPMSystemPowerStateSupportsAcknowledgementOption(
1782    IOPMCapabilityBits stateDescriptor,
1783    CFStringRef acknowledgementOption)
1784{
1785    if (!acknowledgementOption)
1786        return false;
1787
1788    if ( 0 != (stateDescriptor & kIOPMSytemPowerStateCapabilitiesMask) )
1789    {
1790        // The flags date & requiredcapabilities are only valid on going to sleep transitions
1791        return false;
1792    }
1793
1794    if (CFEqual(acknowledgementOption, kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
1795        || CFEqual(acknowledgementOption, kIOPMAcknowledgmentOptionWakeDate))
1796    {
1797        return true;
1798    }
1799
1800    return false;
1801}
1802#endif
1803