IOPowerSourcesPrivate.c [plain text]
#include <CoreFoundation/CoreFoundation.h>
#include "IOSystemConfiguration.h"
#include "IOPowerSources.h"
#include "IOPowerSourcesPrivate.h"
#include "IOPSKeys.h"
#include "powermanagement.h"
#include <IOKit/pwr_mgt/IOPMLibPrivate.h>
#include <mach/mach_port.h>
#include <mach/vm_map.h>
#include <servers/bootstrap.h>
CFArrayRef
IOPSCopyInternalBatteriesArray(CFTypeRef power_sources)
{
CFArrayRef array = isA_CFArray(IOPSCopyPowerSourcesList(power_sources));
CFMutableArrayRef ret_arr;
CFTypeRef name = NULL;
CFDictionaryRef ps;
CFStringRef transport_type;
int i, count;
if(!array) return NULL;
count = CFArrayGetCount(array);
name = NULL;
ret_arr = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if(!ret_arr) goto exit;
for(i=0; i<count; i++) {
name = CFArrayGetValueAtIndex(array, i);
ps = isA_CFDictionary(IOPSGetPowerSourceDescription(power_sources, name));
if(ps) {
transport_type = isA_CFString(CFDictionaryGetValue(ps, CFSTR(kIOPSTransportTypeKey)));
if(transport_type && CFEqual(transport_type, CFSTR(kIOPSInternalType)))
{
CFArrayAppendValue(ret_arr, name);
}
}
}
if(0 == CFArrayGetCount(ret_arr)) {
CFRelease(ret_arr);
ret_arr = NULL;
}
exit:
CFRelease(array);
return ret_arr;
}
CFArrayRef
IOPSCopyUPSArray(CFTypeRef power_sources)
{
CFArrayRef array = isA_CFArray(IOPSCopyPowerSourcesList(power_sources));
CFMutableArrayRef ret_arr;
CFTypeRef name = NULL;
CFDictionaryRef ps;
CFStringRef transport_type;
int i, count;
if(!array) return NULL;
count = CFArrayGetCount(array);
name = NULL;
ret_arr = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if(!ret_arr) goto exit;
for(i=0; i<count; i++) {
name = CFArrayGetValueAtIndex(array, i);
ps = isA_CFDictionary(IOPSGetPowerSourceDescription(power_sources, name));
if(ps) {
transport_type = isA_CFString(CFDictionaryGetValue(ps, CFSTR(kIOPSTransportTypeKey)));
if(transport_type && ( CFEqual(transport_type, CFSTR(kIOPSSerialTransportType)) ||
CFEqual(transport_type, CFSTR(kIOPSUSBTransportType)) ||
CFEqual(transport_type, CFSTR(kIOPSNetworkTransportType)) ) )
{
CFArrayAppendValue(ret_arr, name);
}
}
}
if(0 == CFArrayGetCount(ret_arr)) {
CFRelease(ret_arr);
ret_arr = NULL;
}
exit:
CFRelease(array);
return ret_arr;
}
CFTypeRef
IOPSGetActiveUPS(CFTypeRef ps_blob)
{
CFTypeRef ret_ups;
CFArrayRef ups_arr;
ups_arr = IOPSCopyUPSArray(ps_blob);
if(!ups_arr)
{
return NULL;
}
ret_ups = CFArrayGetValueAtIndex(ups_arr, 0);
CFRelease(ups_arr);
return ret_ups;
}
CFTypeRef
IOPSGetActiveBattery(CFTypeRef ps_blob)
{
CFTypeRef ret_ups;
CFArrayRef ups_arr;
ups_arr = IOPSCopyInternalBatteriesArray(ps_blob);
if(!ups_arr)
{
return NULL;
}
ret_ups = CFArrayGetValueAtIndex(ups_arr, 0);
CFRelease(ups_arr);
return ret_ups;
}
static CFStringRef getPowerSourceState(CFTypeRef blob, CFTypeRef id)
{
CFDictionaryRef the_dict = IOPSGetPowerSourceDescription(blob, id);
return CFDictionaryGetValue(the_dict, CFSTR(kIOPSPowerSourceStateKey));
}
CFStringRef IOPSGetProvidingPowerSourceType(CFTypeRef ps_blob)
{
CFTypeRef the_ups = NULL;
CFTypeRef the_batt = NULL;
CFStringRef ps_state = NULL;
if(kCFBooleanFalse == IOPSPowerSourceSupported(ps_blob, CFSTR(kIOPMBatteryPowerKey)))
{
if(kCFBooleanFalse == IOPSPowerSourceSupported(ps_blob, CFSTR(kIOPMUPSPowerKey))) {
return CFSTR(kIOPMACPowerKey);
} else {
the_ups = IOPSGetActiveUPS(ps_blob);
if(!the_ups) return CFSTR(kIOPMACPowerKey);
ps_state = getPowerSourceState(ps_blob, the_ups);
if(ps_state && CFEqual(ps_state, CFSTR(kIOPSACPowerValue)))
{
return CFSTR(kIOPMACPowerKey);
} else if(ps_state && CFEqual(ps_state, CFSTR(kIOPSBatteryPowerValue)))
{
return CFSTR(kIOPMUPSPowerKey);
}
}
return CFSTR(kIOPMACPowerKey);
} else {
the_batt = IOPSGetActiveBattery(ps_blob);
if(!the_batt) return CFSTR(kIOPMACPowerKey);
ps_state = getPowerSourceState(ps_blob, the_batt);
if(ps_state && CFEqual(ps_state, CFSTR(kIOPSBatteryPowerValue)))
{
return CFSTR(kIOPMBatteryPowerKey);
} else {
if(kCFBooleanFalse == IOPSPowerSourceSupported(ps_blob, CFSTR(kIOPMUPSPowerKey)))
{
return CFSTR(kIOPMACPowerKey);
} else {
the_ups = IOPSGetActiveUPS(ps_blob);
if(!the_ups) return CFSTR(kIOPMACPowerKey);
ps_state = getPowerSourceState(ps_blob, the_ups);
if(ps_state && CFEqual(ps_state, CFSTR(kIOPSBatteryPowerValue)))
{
return CFSTR(kIOPMUPSPowerKey);
} else if(ps_state && CFEqual(ps_state, CFSTR(kIOPSACPowerValue)))
{
return CFSTR(kIOPMACPowerKey);
}
}
}
}
return CFSTR(kIOPMACPowerKey);
}
CFBooleanRef IOPSPowerSourceSupported(CFTypeRef ps_blob, CFStringRef ps_type)
{
if(!isA_CFString(ps_type))
{
return kCFBooleanFalse;
}
if(CFEqual(ps_type, CFSTR(kIOPMACPowerKey)))
{
return kCFBooleanTrue;
}
#if defined (__i386__) || defined (__x86_64__)
if (CFEqual(ps_type, CFSTR(kIOPMBatteryPowerKey)))
{
CFBooleanRef ret = kCFBooleanFalse;
io_registry_entry_t platform = IO_OBJECT_NULL;
CFDataRef systemTypeData = NULL;
int *systemType = 0;
platform = IORegistryEntryFromPath(kIOMasterPortDefault,
kIODeviceTreePlane ":/");
if (IO_OBJECT_NULL == platform) {
return kCFBooleanFalse;
}
systemTypeData = (CFDataRef)IORegistryEntryCreateCFProperty(
platform, CFSTR("system-type"),
kCFAllocatorDefault, kNilOptions);
if (systemTypeData
&& (CFDataGetLength(systemTypeData) > 0)
&& (systemType = (int *)CFDataGetBytePtr(systemTypeData))
&& (2 == *systemType))
{
ret = kCFBooleanTrue;
} else {
ret = kCFBooleanFalse;
}
if (systemTypeData)
CFRelease(systemTypeData);
IOObjectRelease(platform);
return ret;
}
#else
if (ps_blob
&& CFEqual(ps_type, CFSTR(kIOPMBatteryPowerKey))
&& IOPSGetActiveBattery(ps_blob))
{
return kCFBooleanTrue;
}
#endif
if (ps_blob
&& CFEqual(ps_type, CFSTR(kIOPMUPSPowerKey))
&& IOPSGetActiveUPS(ps_blob))
{
return kCFBooleanTrue;
}
return kCFBooleanFalse;
}
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;
}
struct OpaqueIOPSPowerSourceID {
CFMachPortRef configdConnection;
CFStringRef scdsKey;
};
#define kMaxPSTypeLength 25
#define kMaxSCDSKeyLength 1024
IOReturn IOPSCreatePowerSource(
IOPSPowerSourceID *outPS,
CFStringRef powerSourceType)
{
IOPSPowerSourceID newPS = NULL;
mach_port_t pm_server = MACH_PORT_NULL;
char psType[kMaxPSTypeLength];
char scdsKey[kMaxSCDSKeyLength];
mach_port_t local_port = MACH_PORT_NULL;
int return_code = kIOReturnSuccess;
kern_return_t kr = KERN_SUCCESS;
IOReturn ret = kIOReturnError;
if (!powerSourceType || !outPS)
return kIOReturnBadArgument;
newPS = calloc(1, sizeof(struct OpaqueIOPSPowerSourceID));
if (!newPS)
return kIOReturnVMError;
newPS->configdConnection = CFMachPortCreate(kCFAllocatorDefault, NULL, NULL, NULL);
if (newPS->configdConnection)
local_port = CFMachPortGetPort(newPS->configdConnection);
if (MACH_PORT_NULL == local_port) {
ret = kIOReturnInternalError;
goto fail;
}
if (!CFStringGetCString(powerSourceType, psType, sizeof(psType), kCFStringEncodingMacRoman)) {
ret = kIOReturnBadMedia;
goto fail;
}
ret = _pm_connect(&pm_server);
if(kIOReturnSuccess != ret) {
ret = kIOReturnNotOpen;
goto fail;
}
kr = io_pm_new_pspowersource(
pm_server,
local_port, psType, scdsKey, &return_code);
if(KERN_SUCCESS != kr) {
ret = kIOReturnNotResponding;
goto fail;
}
_pm_disconnect(pm_server);
newPS->scdsKey = CFStringCreateWithCString(0, scdsKey, kCFStringEncodingUTF8);
*outPS = newPS;
return (IOReturn)return_code;
fail:
if (newPS)
free(newPS);
if (IO_OBJECT_NULL != pm_server)
_pm_disconnect(pm_server);
*outPS = NULL;
return ret;
}
IOReturn IOPSSetPowerSourceDetails(
IOPSPowerSourceID whichPS,
CFDictionaryRef details)
{
IOReturn ret = kIOReturnSuccess;
SCDynamicStoreRef temp_store = NULL;
if (!whichPS || !isA_CFString(whichPS->scdsKey) || !isA_CFDictionary(details))
return kIOReturnBadArgument;
temp_store = SCDynamicStoreCreate(0, CFSTR("IOKit PM - IOPSSetPowerSourceDetails"), NULL, NULL);
if (!temp_store)
return kIOReturnNotResponding;
if (!SCDynamicStoreSetValue(temp_store, whichPS->scdsKey, details))
{
if(kSCStatusAccessError == SCError())
ret = kIOReturnNotPrivileged;
else
ret = kIOReturnError;
}
CFRelease(temp_store);
return ret;
}
IOReturn IOPSReleasePowerSource(
IOPSPowerSourceID whichPS)
{
if (!whichPS)
return kIOReturnBadArgument;
if (whichPS->configdConnection)
{
CFRelease(whichPS->configdConnection);
}
if (whichPS->scdsKey)
CFRelease(whichPS->scdsKey);
free(whichPS);
return kIOReturnSuccess;
}