1/* 2 * Copyright (c) 2006 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#include <CoreFoundation/CoreFoundation.h> 24 25#include <mach/mach.h> 26#include <mach/mach_init.h> 27#include <notify.h> 28 29#include <IOKit/IOKitLib.h> 30#include <IOKit/IOCFSerialize.h> 31#include <IOKit/pwr_mgt/IOPM.h> 32#include "IOSystemConfiguration.h" 33#include "IOPMLib.h" 34 35#define arrayCnt(var) (sizeof(var) / sizeof(var[0])) 36 37io_connect_t IOPMFindPowerManagement( mach_port_t master_device_port ) 38{ 39 io_connect_t fb; 40 kern_return_t kr; 41 io_service_t obj = MACH_PORT_NULL; 42 43 obj = IORegistryEntryFromPath( master_device_port, 44 kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain"); 45 if( obj ) { 46 kr = IOServiceOpen( obj,mach_task_self(), 0, &fb); 47 if ( kr == kIOReturnSuccess ) { 48 IOObjectRelease(obj); 49 return fb; 50 } 51 IOObjectRelease(obj); 52 } 53 return 0; 54} 55 56 57IOReturn IOPMGetAggressiveness ( 58 io_connect_t fb, 59 unsigned long type, 60 unsigned long * lAggressiveness ) 61{ 62 63 uint64_t inData = type; 64 uint64_t aggressiveness = 0; 65 uint32_t len = 1; 66 kern_return_t err = IOConnectCallScalarMethod(fb, kPMGetAggressiveness, 67 &inData, 1, &aggressiveness, &len); 68 *lAggressiveness = aggressiveness; 69 70 if (err) 71 return kIOReturnError; 72 else 73 return err; 74} 75 76 77IOReturn IOPMSetAggressiveness ( 78 io_connect_t fb, 79 unsigned long type, 80 unsigned long aggressiveness ) 81{ 82 uint64_t inData[] = { type, aggressiveness }; 83 uint64_t rtn = 0; 84 uint32_t len = 1; 85 kern_return_t err = IOConnectCallScalarMethod(fb, kPMSetAggressiveness, 86 inData, arrayCnt(inData), &rtn, &len); 87 88 if (err) 89 return kIOReturnError; 90 else 91 return (IOReturn) rtn; 92} 93 94 95IOReturn IOPMSleepSystem ( io_connect_t fb ) 96{ 97 uint64_t rtn = 0; 98 uint32_t len = 1; 99 kern_return_t err = IOConnectCallScalarMethod(fb, kPMSleepSystem, 100 NULL, 0, &rtn, &len); 101 102 if (err) 103 return kIOReturnError; 104 else 105 return (IOReturn) rtn; 106} 107 108/* Private call for Apple Internal use only */ 109IOReturn IOPMSleepSystemWithOptions ( io_connect_t fb, CFDictionaryRef options ) 110{ 111 uint64_t rtn = 0; 112 size_t len = sizeof(uint32_t); 113 kern_return_t err; 114 CFDataRef serializedOptions = NULL; 115 116 if( !options ) { 117 return IOPMSleepSystem( fb ); 118 } 119 120 serializedOptions = IOCFSerialize( options, 0 ); 121 122 if (!serializedOptions) 123 { 124 return kIOReturnInternalError; 125 } 126 127 /* kPMSleepSystemOptions 128 * in: serialized CFDictionary of options 129 * out: IOReturn code returned from sleepSystem 130 */ 131 err = IOConnectCallStructMethod( 132 fb, 133 kPMSleepSystemOptions, 134 CFDataGetBytePtr(serializedOptions), /* inputStruct */ 135 CFDataGetLength(serializedOptions), /* inputStructCnt */ 136 &rtn, /* outputStruct */ 137 &len); /* outputStructCnt */ 138 139 CFRelease(serializedOptions); 140 141 if (kIOReturnSuccess != err) 142 return err; 143 else 144 return (IOReturn) rtn; 145} 146 147 148IOReturn IOPMCopyBatteryInfo( mach_port_t masterPort, CFArrayRef * oInfo ) 149{ 150 io_registry_entry_t root_domain; 151 IOReturn kr = kIOReturnUnsupported; 152 153 *oInfo = NULL; 154 155 // ******************************************************************** 156 // For PPC machines (with PMU), battery location is published under 157 // IOPMrootDomain 158 root_domain = IORegistryEntryFromPath( masterPort, 159 kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain"); 160 if(!root_domain) return kIOReturnUnsupported; 161 *oInfo = IORegistryEntryCreateCFProperty( 162 root_domain, CFSTR(kIOBatteryInfoKey), 163 kCFAllocatorDefault, kNilOptions); 164 IOObjectRelease(root_domain); 165 166 if(*oInfo) { 167 // Successfully read battery info from IOPMrootDomain 168 return kIOReturnSuccess; 169 } 170 171 172 // ******************************************************************** 173 // For non-PMU based batteries with IOPMPowerSource conforming classes 174 // Scan IORegistry for IOPMPowerSource nodes with IOLegacyBatteryInfo 175 // - Toss all IOLegacyBatteryInfo dictionaries into an OSArray 176 int batt_count = 0; 177 io_registry_entry_t battery; 178 io_iterator_t ioreg_batteries; 179 CFMutableArrayRef legacyArray = CFArrayCreateMutable( 180 kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks); 181 182 if(!legacyArray) return kIOReturnNoMemory; 183 184 kr = IOServiceGetMatchingServices( 185 MACH_PORT_NULL, 186 IOServiceMatching("IOPMPowerSource"), 187 &ioreg_batteries); 188 if(KERN_SUCCESS != kr) { 189 CFRelease(legacyArray); 190 return kIOReturnError; 191 } 192 193 while( (battery = (io_registry_entry_t)IOIteratorNext(ioreg_batteries)) ) 194 { 195 CFDictionaryRef legacyDict; 196 197 legacyDict = IORegistryEntryCreateCFProperty( battery, 198 CFSTR(kIOPMPSLegacyBatteryInfoKey), 199 kCFAllocatorDefault, 200 0); 201 202 if(!legacyDict) continue; 203 204 batt_count++; 205 CFArrayAppendValue(legacyArray, legacyDict); 206 CFRelease(legacyDict); 207 IOObjectRelease(battery); 208 } 209 IOObjectRelease(ioreg_batteries); 210 211 if(batt_count > 0) { 212 *oInfo = legacyArray; 213 } else { 214 CFRelease(legacyArray); 215 216 // Returns kIOReturnUnsupported if no batteries found 217 return kIOReturnUnsupported; 218 } 219 220 return kIOReturnSuccess; 221} 222 223 224io_connect_t IORegisterApp( 225 void * refcon, 226 io_service_t theDriver, 227 IONotificationPortRef * thePortRef, 228 IOServiceInterestCallback callback, 229 io_object_t * notifier ) 230{ 231 io_connect_t fb = MACH_PORT_NULL; 232 kern_return_t kr; 233 234 *notifier = MACH_PORT_NULL; 235 236 if ( theDriver == MACH_PORT_NULL ) goto failure_exit; 237 238 kr = IOServiceOpen(theDriver, mach_task_self(), 0, &fb); 239 240 if ( (kr != kIOReturnSuccess) || (fb == MACH_PORT_NULL) ) { 241 goto failure_exit; 242 } 243 244 kr = IOServiceAddInterestNotification( 245 *thePortRef, theDriver, kIOAppPowerStateInterest, 246 callback, refcon, notifier); 247 248 if ( kr == KERN_SUCCESS ) { 249 // Successful exit case 250 return fb; 251 } 252 253failure_exit: 254 if ( fb != MACH_PORT_NULL ) { 255 IOServiceClose(fb); 256 } 257 if ( *notifier != MACH_PORT_NULL ) { 258 IOObjectRelease(*notifier); 259 } 260 return MACH_PORT_NULL; 261} 262 263 264io_connect_t IORegisterForSystemPower ( void * refcon, 265 IONotificationPortRef * thePortRef, 266 IOServiceInterestCallback callback, 267 io_object_t * root_notifier ) 268{ 269 io_connect_t fb = MACH_PORT_NULL; 270 IONotificationPortRef notify = NULL; 271 kern_return_t kr; 272 io_service_t obj = MACH_PORT_NULL; 273 274 *root_notifier = MACH_PORT_NULL; 275 276 notify = IONotificationPortCreate(MACH_PORT_NULL); 277 278 obj = IORegistryEntryFromPath( MACH_PORT_NULL, 279 kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain"); 280 281 if( obj == MACH_PORT_NULL ) goto failure_exit; 282 283 kr = IOServiceOpen( obj,mach_task_self(), 0, &fb); 284 285 if ( (kr != kIOReturnSuccess) || (fb == MACH_PORT_NULL) ) { 286 goto failure_exit; 287 } 288 289 kr = IOServiceAddInterestNotification( 290 notify,obj,kIOAppPowerStateInterest, 291 callback,refcon,root_notifier); 292 293 IOObjectRelease(obj); 294 if ( kr == KERN_SUCCESS ) { 295 // Successful exit case 296 *thePortRef = notify; 297 return fb; 298 } 299 300failure_exit: 301 if ( obj != MACH_PORT_NULL ) { 302 IOObjectRelease(obj); 303 } 304 if ( notify != MACH_PORT_NULL ) { 305 IONotificationPortDestroy(notify); 306 } 307 if ( fb != MACH_PORT_NULL ) { 308 IOServiceClose(fb); 309 } 310 if ( *root_notifier != MACH_PORT_NULL ) { 311 IOObjectRelease(*root_notifier); 312 } 313 314 return MACH_PORT_NULL; 315} 316 317 318IOReturn IODeregisterApp ( io_object_t * notifier ) 319{ 320 if ( *notifier ) { 321 IOObjectRelease(*notifier); 322 *notifier = MACH_PORT_NULL; 323 } 324 return kIOReturnSuccess; 325} 326 327 328IOReturn IODeregisterForSystemPower ( io_object_t * root_notifier ) 329{ 330 if ( *root_notifier ) { 331 IOObjectRelease(*root_notifier); 332 *root_notifier = MACH_PORT_NULL; 333 } 334 return kIOReturnSuccess; 335} 336 337 338IOReturn IOAllowPowerChange(io_connect_t kernelPort, long notificationID) 339{ 340 uint64_t inData = notificationID; 341 kern_return_t err = IOConnectCallScalarMethod( 342 kernelPort, kPMAllowPowerChange, 343 &inData, 1, NULL, NULL); 344 345 if (err) { 346 return kIOReturnError; 347 } else { 348 return err; 349 } 350} 351 352 353IOReturn IOCancelPowerChange ( io_connect_t kernelPort, long notificationID ) 354{ 355 uint64_t inData = notificationID; 356 kern_return_t err = IOConnectCallScalarMethod( 357 kernelPort, kPMCancelPowerChange, 358 &inData, 1, NULL, NULL); 359 360 if (err) { 361 return kIOReturnError; 362 } else { 363 return err; 364 } 365} 366 367 368boolean_t IOPMSleepEnabled ( void ) 369{ 370 io_registry_entry_t root; 371 boolean_t flag = false; 372 CFTypeRef data = NULL; 373 374 root = IORegistryEntryFromPath(MACH_PORT_NULL, 375 kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain"); 376 if ( !root ) return false; 377 378 data = IORegistryEntryCreateCFProperty( 379 root, CFSTR("IOSleepSupported"), 380 kCFAllocatorDefault, kNilOptions); 381 if ( data ) { 382 flag = true; 383 CFRelease(data); 384 } 385 386 IOObjectRelease(root); 387 return flag; 388} 389 390/************************************************** 391* 392* System Load Advisory 393* 394* Reads system load state out of SCDynamicStore. 395* PM configd plugin maintains state. 396* 397**************************************************/ 398 399#define kSLALevelPath CFSTR("/IOKit/PowerManagement/SystemLoad") 400#define kSLADetailedPath CFSTR("/IOKit/PowerManagement/SystemLoad/Detailed") 401 402/* IOGetSystemLoadAdvisory 403 * In case of error, or inability to find system load advisory level, 404 * returns kIOSystemLoadAdvisoryLevelOK. 405 */ 406IOSystemLoadAdvisoryLevel IOGetSystemLoadAdvisory( void ) 407{ 408 IOSystemLoadAdvisoryLevel _gt = kIOSystemLoadAdvisoryLevelOK; 409 int notifyToken = 0; 410 int status; 411 uint64_t newval; 412 413 status = notify_register_check(kIOSystemLoadAdvisoryNotifyName, ¬ifyToken); 414 if (NOTIFY_STATUS_OK == status) 415 { 416 notify_get_state(notifyToken, &newval); 417 notify_cancel(notifyToken); 418 _gt = (IOSystemLoadAdvisoryLevel)newval; 419 } 420 421 return _gt; 422} 423 424/* IOCopyLoadAdvisoryLevelDetailed 425 * In case of error, or inability to find system load advisory level, 426 * returns NULL. 427 */ 428CFDictionaryRef IOCopySystemLoadAdvisoryDetailed(void) 429{ 430 CFDictionaryRef gtDetailed = NULL; 431 SCDynamicStoreRef storage = NULL; 432 CFStringRef gtDetailedKey = SCDynamicStoreKeyCreate( 433 kCFAllocatorDefault, 434 CFSTR("%@%@"), 435 _io_kSCDynamicStoreDomainState, 436 kSLADetailedPath); 437 438 storage = SCDynamicStoreCreate( 439 kCFAllocatorDefault, 440 CFSTR("IOKit IOGetSystemLoadAdvisoryDetailed"), 441 NULL, 442 NULL); 443 444 if (!storage || !gtDetailedKey) { 445 goto exit; 446 } 447 gtDetailed = isA_CFDictionary(SCDynamicStoreCopyValue(storage, gtDetailedKey)); 448exit: 449 if (gtDetailedKey) CFRelease(gtDetailedKey); 450 if (storage) CFRelease(storage); 451 return gtDetailed; 452} 453 454