/* * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include "IOSystemConfiguration.h" #include "IOPowerSources.h" #include "IOPowerSourcesPrivate.h" #include "IOPSKeys.h" #include "powermanagement.h" #include #include #include #include /* IOPSCopyInternalBatteriesArray * * Argument: * CFTypeRef power_sources: The return value from IOPSCoyPowerSourcesInfo() * Return value: * CFArrayRef: all the batteries we found * NULL if none are found */ 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 AC Power return CFSTR(kIOPMACPowerKey); } else { // optimization opportunity: needless loops inside IOPSGetActiveUPS 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))) { // no batteries, yes UPS, UPS is running off of AC power -> AC Power return CFSTR(kIOPMACPowerKey); } else if(ps_state && CFEqual(ps_state, CFSTR(kIOPSBatteryPowerValue))) { // no batteries, yes UPS, UPS is running off of Battery power -> UPS Power return CFSTR(kIOPMUPSPowerKey); } } // Error in the data we were passed return CFSTR(kIOPMACPowerKey); } else { // Optimization opportunity: needless loops inside IOPSGetActiveBattery 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))) { // Yes batteries, yes running on battery power -> Battery power return CFSTR(kIOPMBatteryPowerKey); } else { // batteries are on AC power. let's check UPS. // optimize. if(kCFBooleanFalse == IOPSPowerSourceSupported(ps_blob, CFSTR(kIOPMUPSPowerKey))) { // yes batteries on AC power, no UPS -> AC Power 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))) { // yes batteries on AC power, UPS is on battery power -> UPS Power return CFSTR(kIOPMUPSPowerKey); } else if(ps_state && CFEqual(ps_state, CFSTR(kIOPSACPowerValue))) { // yes batteries on AC Power, UPS is on AC Power -> AC Power return CFSTR(kIOPMACPowerKey); } } } // Error in the data we were passed. // syslog(LOG_INFO, "PowerManagement: unexpected point 3 reached in _getProvidingPowerSourceType\n"); } // Should not reach this point. Return something safe. return CFSTR(kIOPMACPowerKey); } /*** * int powerSourceSupported(CFStringRef) * takes: CFSTR of kIOPMACPowerKey, kIOPMBatteryPowerKey, kIOPMUPSPowerKey * returns true if this machine supports (has) that power type. */ 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; } /****************************************************************************** IOPSPowerSourceID - publishing a power source from user space ******************************************************************************/ static IOReturn _pm_connect(mach_port_t *newConnection) { kern_return_t kern_result = KERN_SUCCESS; if(!newConnection) return kIOReturnBadArgument; // open reference to PM configd 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; } /* OpaqueIOPSPowerSourceID * As typecast in the header: * typedef struct OpaqueIOPSPowerSourceID *IOPSPowerSourceID; */ 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 - This tracking structure must be freed by IOPSReleasePowerSource() newPS = calloc(1, sizeof(struct OpaqueIOPSPowerSourceID)); if (!newPS) return kIOReturnVMError; // We allocate a port in our namespace, and pass it to configd. // If this process dies, configd will cleanup our unattached power sources. 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, // in: mach port psType, // in: type name scdsKey, // out: SCDS key &return_code); // out: Return code if(KERN_SUCCESS != kr) { ret = kIOReturnNotResponding; goto fail; } _pm_disconnect(pm_server); newPS->scdsKey = CFStringCreateWithCString(0, scdsKey, kCFStringEncodingUTF8); // success: *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; // TODO: avoid creating a store for every single transaction 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) { // mach_port_destroy(mach_task_self(), // CFMachPortGetPort(whichPS->configdConnection)); CFRelease(whichPS->configdConnection); } if (whichPS->scdsKey) CFRelease(whichPS->scdsKey); free(whichPS); return kIOReturnSuccess; }