#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFUnserialize.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <mach/mach_init.h>
#include <mach/mach_port.h>
#include <mach/vm_map.h>
#include <servers/bootstrap.h>
#include <SystemConfiguration/SCValidation.h>
#include "IOPMLibPrivate.h"
#include "powermanagement.h"
#define kAssertionsArraySize 5
static IOReturn _pm_connect(mach_port_t *newConnection)
{
kern_return_t kern_result = KERN_SUCCESS;
if(!newConnection) return kIOReturnBadArgument;
kern_result = bootstrap_look_up(bootstrap_port,
kIOPMServerBootstrapName, newConnection);
if(KERN_SUCCESS != kern_result) {
return kIOReturnError;
}
return kIOReturnSuccess;
}
static IOReturn _pm_disconnect(mach_port_t connection)
{
if(!connection) return kIOReturnBadArgument;
mach_port_destroy(mach_task_self(), connection);
return kIOReturnSuccess;
}
IOReturn IOPMAssertionCreate(CFStringRef assertion, int level, IOPMAssertionID *assertion_id)
{
IOReturn return_code = kIOReturnError;
kern_return_t kern_result = KERN_SUCCESS;
char profile_str[50];
int profile_len = 50;
mach_port_t pm_server = MACH_PORT_NULL;
mach_port_t task_self = mach_task_self();
IOReturn err;
*assertion_id = -1;
if(kCFCompareEqualTo !=
CFStringCompare(assertion, kIOPMCPUBoundAssertion, 0))
{
return kIOReturnUnsupported;
}
err = _pm_connect(&pm_server);
if(kIOReturnSuccess != err) {
return_code = kIOReturnInternalError;
goto exit;
}
CFStringGetCString(assertion, profile_str, profile_len, kCFStringEncodingMacRoman);
profile_len = strlen(profile_str)+1;
kern_result = io_pm_assertion_create(
pm_server,
task_self,
profile_str,
profile_len,
level,
assertion_id,
&return_code);
if(KERN_SUCCESS != kern_result) {
return_code = kIOReturnInternalError;
}
_pm_disconnect(pm_server);
exit:
return return_code;
}
IOReturn IOPMAssertionRelease(IOPMAssertionID assertion_id)
{
IOReturn return_code = kIOReturnError;
kern_return_t kern_result = KERN_SUCCESS;
mach_port_t pm_server = MACH_PORT_NULL;
mach_port_t task_self = mach_task_self();
IOReturn err;
if((assertion_id < 0) || (assertion_id >= kAssertionsArraySize)) {
return_code = kIOReturnBadArgument;
goto exit;
}
err = _pm_connect(&pm_server);
if(kIOReturnSuccess != err) {
return_code = kIOReturnInternalError;
goto exit;
}
kern_result = io_pm_assertion_release(
pm_server,
task_self,
assertion_id,
&return_code);
if(KERN_SUCCESS != kern_result) {
return_code = kIOReturnInternalError;
}
_pm_disconnect(pm_server);
exit:
return return_code;
}
IOReturn IOPMCopyAssertionsByProcess(CFDictionaryRef *assertions_by_pid)
{
IOReturn return_code = kIOReturnError;
kern_return_t kern_result = KERN_SUCCESS;
CFDictionaryRef activeProfiles = NULL;
mach_port_t pm_server = MACH_PORT_NULL;
void *out_buf;
int buf_size;
IOReturn err;
*assertions_by_pid = NULL;
err = _pm_connect(&pm_server);
if(kIOReturnSuccess != err) {
return_code = kIOReturnInternalError;
goto exit;
}
kern_result = io_pm_copy_active_assertions(
pm_server,
&out_buf,
&buf_size);
if(KERN_SUCCESS != kern_result) {
return_code = kIOReturnInternalError;
goto exit;
}
activeProfiles = (CFDictionaryRef)IOCFUnserialize(out_buf, 0, 0, 0);
if(isA_CFDictionary(activeProfiles))
{
CFMutableDictionaryRef ret_dict;
CFStringRef *pid_keys;
char *endptr;
CFArrayRef *arr_vals;
CFNumberRef tmp_pid;
char pid_str[10];
int the_pid;
int dict_count;
int i;
ret_dict = CFDictionaryCreateMutable(0, 0,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
dict_count = CFDictionaryGetCount(activeProfiles);
pid_keys = (CFStringRef *)malloc(dict_count * sizeof(CFStringRef));
arr_vals = (CFArrayRef *)malloc(dict_count * sizeof(CFArrayRef));
if(!pid_keys || !arr_vals) goto exit;
CFDictionaryGetKeysAndValues(
activeProfiles,
(const void **)pid_keys,
(const void **)arr_vals);
for(i=0; i<dict_count; i++)
{
if(!pid_keys[i]) continue;
CFStringGetCString(pid_keys[i], pid_str, 10, kCFStringEncodingMacRoman);
the_pid = strtol(pid_str, &endptr, 10);
if(0 != *endptr) continue;
tmp_pid = CFNumberCreate(0, kCFNumberIntType, &the_pid);
CFDictionarySetValue(ret_dict, tmp_pid, arr_vals[i]);
CFRelease(tmp_pid);
}
free(pid_keys);
free(arr_vals);
CFRelease(activeProfiles);
*assertions_by_pid = ret_dict;
return_code = kIOReturnSuccess;
} else {
if(activeProfiles) CFRelease(activeProfiles);
}
vm_deallocate(mach_task_self(), (vm_address_t)out_buf, buf_size);
_pm_disconnect(pm_server);
return_code = kIOReturnSuccess;
exit:
return return_code;
}
IOReturn IOPMCopyAssertionsStatus(CFDictionaryRef *assertions_status)
{
IOReturn return_code = kIOReturnError;
kern_return_t kern_result = KERN_SUCCESS;
CFDictionaryRef supported_assertions = NULL;
mach_port_t pm_server = MACH_PORT_NULL;
void *out_buf = NULL;
int buf_size = NULL;
IOReturn err;
*assertions_status = NULL;
err = _pm_connect(&pm_server);
if(kIOReturnSuccess != err) {
return_code = kIOReturnInternalError;
goto exit;
}
kern_result = io_pm_copy_assertions_status(
pm_server,
&out_buf,
&buf_size);
if(KERN_SUCCESS != kern_result) {
return_code = kIOReturnInternalError;
goto exit;
}
supported_assertions = (CFDictionaryRef)IOCFUnserialize(out_buf, 0, 0, 0);
if(isA_CFDictionary(supported_assertions)) {
*assertions_status = supported_assertions;
return_code = kIOReturnSuccess;
} else
{
if(supported_assertions) CFRelease(supported_assertions);
return_code = kIOReturnInternalError;
}
vm_deallocate(mach_task_self(), (vm_address_t)out_buf, buf_size);
_pm_disconnect(pm_server);
exit:
return return_code;
}