#include <CoreFoundation/CoreFoundation.h>
#include <mach/mach.h>
#include <mach/mach_init.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFSerialize.h>
#include <IOKit/pwr_mgt/IOPM.h>
#include "IOPMLib.h"
#define arrayCnt(var) (sizeof(var) / sizeof(var[0]))
io_connect_t IOPMFindPowerManagement( mach_port_t master_device_port )
{
io_connect_t fb;
kern_return_t kr;
io_service_t obj = MACH_PORT_NULL;
obj = IORegistryEntryFromPath( master_device_port,
kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
if( obj ) {
kr = IOServiceOpen( obj,mach_task_self(), 0, &fb);
if ( kr == kIOReturnSuccess ) {
IOObjectRelease(obj);
return fb;
}
IOObjectRelease(obj);
}
return 0;
}
IOReturn IOPMGetAggressiveness (
io_connect_t fb,
unsigned long type,
unsigned long * lAggressiveness )
{
uint64_t inData = type;
uint64_t aggressiveness = 0;
uint32_t len = 1;
kern_return_t err = IOConnectCallScalarMethod(fb, kPMGetAggressiveness,
&inData, 1, &aggressiveness, &len);
*lAggressiveness = aggressiveness;
if (err)
return kIOReturnError;
else
return err;
}
IOReturn IOPMSetAggressiveness (
io_connect_t fb,
unsigned long type,
unsigned long aggressiveness )
{
uint64_t inData[] = { type, aggressiveness };
uint64_t rtn = 0;
uint32_t len = 1;
kern_return_t err = IOConnectCallScalarMethod(fb, kPMSetAggressiveness,
inData, arrayCnt(inData), &rtn, &len);
if (err)
return kIOReturnError;
else
return (IOReturn) rtn;
}
IOReturn IOPMSleepSystem ( io_connect_t fb )
{
uint64_t rtn = 0;
uint32_t len = 1;
kern_return_t err = IOConnectCallScalarMethod(fb, kPMSleepSystem,
NULL, 0, &rtn, &len);
if (err)
return kIOReturnError;
else
return (IOReturn) rtn;
}
IOReturn IOPMSleepSystemWithOptions ( io_connect_t fb, CFDictionaryRef options )
{
uint64_t rtn = 0;
uint32_t len = sizeof(uint32_t);
kern_return_t err;
CFDataRef serializedOptions = NULL;
if( !options ) {
return IOPMSleepSystem( fb );
}
serializedOptions = IOCFSerialize( options, 0 );
if (!serializedOptions)
{
return kIOReturnInternalError;
}
err = IOConnectCallStructMethod(
fb,
kPMSleepSystemOptions,
CFDataGetBytePtr(serializedOptions),
CFDataGetLength(serializedOptions),
&rtn,
&len);
if (kIOReturnSuccess != err)
return err;
else
return (IOReturn) rtn;
}
IOReturn IOPMCopyBatteryInfo( mach_port_t masterPort, CFArrayRef * oInfo )
{
io_registry_entry_t root_domain;
IOReturn kr = kIOReturnUnsupported;
*oInfo = NULL;
root_domain = IORegistryEntryFromPath( masterPort,
kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
if(!root_domain) return kIOReturnUnsupported;
*oInfo = IORegistryEntryCreateCFProperty(
root_domain, CFSTR(kIOBatteryInfoKey),
kCFAllocatorDefault, kNilOptions);
IOObjectRelease(root_domain);
if(*oInfo) {
return kIOReturnSuccess;
}
int batt_count = 0;
io_registry_entry_t battery;
io_iterator_t ioreg_batteries;
CFMutableArrayRef legacyArray = CFArrayCreateMutable(
kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
if(!legacyArray) return kIOReturnNoMemory;
kr = IOServiceGetMatchingServices(
MACH_PORT_NULL,
IOServiceMatching("IOPMPowerSource"),
&ioreg_batteries);
if(KERN_SUCCESS != kr) {
CFRelease(legacyArray);
return kIOReturnError;
}
while( (battery = (io_registry_entry_t)IOIteratorNext(ioreg_batteries)) )
{
CFDictionaryRef legacyDict;
legacyDict = IORegistryEntryCreateCFProperty( battery,
CFSTR(kIOPMPSLegacyBatteryInfoKey),
kCFAllocatorDefault,
0);
if(!legacyDict) continue;
batt_count++;
CFArrayAppendValue(legacyArray, legacyDict);
CFRelease(legacyDict);
IOObjectRelease(battery);
}
IOObjectRelease(ioreg_batteries);
if(batt_count > 0) {
*oInfo = legacyArray;
} else {
CFRelease(legacyArray);
return kIOReturnUnsupported;
}
return kIOReturnSuccess;
}
io_connect_t IORegisterApp(
void * refcon,
io_service_t theDriver,
IONotificationPortRef * thePortRef,
IOServiceInterestCallback callback,
io_object_t * notifier )
{
io_connect_t fb = MACH_PORT_NULL;
kern_return_t kr;
*notifier = MACH_PORT_NULL;
if ( theDriver == MACH_PORT_NULL ) goto failure_exit;
kr = IOServiceOpen(theDriver, mach_task_self(), 0, &fb);
if ( (kr != kIOReturnSuccess) || (fb == MACH_PORT_NULL) ) {
goto failure_exit;
}
kr = IOServiceAddInterestNotification(
*thePortRef, theDriver, kIOAppPowerStateInterest,
callback, refcon, notifier);
if ( kr == KERN_SUCCESS ) {
return fb;
}
failure_exit:
if ( fb != MACH_PORT_NULL ) {
IOServiceClose(fb);
}
if ( *notifier != MACH_PORT_NULL ) {
IOObjectRelease(*notifier);
}
return MACH_PORT_NULL;
}
io_connect_t IORegisterForSystemPower ( void * refcon,
IONotificationPortRef * thePortRef,
IOServiceInterestCallback callback,
io_object_t * root_notifier )
{
io_connect_t fb = MACH_PORT_NULL;
IONotificationPortRef notify = NULL;
kern_return_t kr;
io_service_t obj = MACH_PORT_NULL;
*root_notifier = MACH_PORT_NULL;
notify = IONotificationPortCreate(MACH_PORT_NULL);
obj = IORegistryEntryFromPath( MACH_PORT_NULL,
kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
if( obj == MACH_PORT_NULL ) goto failure_exit;
kr = IOServiceOpen( obj,mach_task_self(), 0, &fb);
if ( (kr != kIOReturnSuccess) || (fb == MACH_PORT_NULL) ) {
goto failure_exit;
}
kr = IOServiceAddInterestNotification(
notify,obj,kIOAppPowerStateInterest,
callback,refcon,root_notifier);
IOObjectRelease(obj);
if ( kr == KERN_SUCCESS ) {
*thePortRef = notify;
return fb;
}
failure_exit:
if ( obj != MACH_PORT_NULL ) {
IOObjectRelease(obj);
}
if ( notify != MACH_PORT_NULL ) {
IONotificationPortDestroy(notify);
}
if ( fb != MACH_PORT_NULL ) {
IOServiceClose(fb);
}
if ( *root_notifier != MACH_PORT_NULL ) {
IOObjectRelease(*root_notifier);
}
return MACH_PORT_NULL;
}
IOReturn IODeregisterApp ( io_object_t * notifier )
{
if ( *notifier ) {
IOObjectRelease(*notifier);
*notifier = MACH_PORT_NULL;
}
return kIOReturnSuccess;
}
IOReturn IODeregisterForSystemPower ( io_object_t * root_notifier )
{
if ( *root_notifier ) {
IOObjectRelease(*root_notifier);
*root_notifier = MACH_PORT_NULL;
}
return kIOReturnSuccess;
}
IOReturn IOAllowPowerChange(io_connect_t kernelPort, long notificationID)
{
uint64_t inData = notificationID;
kern_return_t err = IOConnectCallScalarMethod(
kernelPort, kPMAllowPowerChange,
&inData, 1, NULL, NULL);
if (err) {
return kIOReturnError;
} else {
return err;
}
}
IOReturn IOCancelPowerChange ( io_connect_t kernelPort, long notificationID )
{
uint64_t inData = notificationID;
kern_return_t err = IOConnectCallScalarMethod(
kernelPort, kPMCancelPowerChange,
&inData, 1, NULL, NULL);
if (err) {
return kIOReturnError;
} else {
return err;
}
}
boolean_t IOPMSleepEnabled ( void )
{
io_registry_entry_t root;
boolean_t flag = false;
CFTypeRef data = NULL;
root = IORegistryEntryFromPath(MACH_PORT_NULL,
kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
if ( !root ) return false;
data = IORegistryEntryCreateCFProperty(
root, CFSTR("IOSleepSupported"),
kCFAllocatorDefault, kNilOptions);
if ( data ) {
flag = true;
CFRelease(data);
}
IOObjectRelease(root);
return flag;
}