1/* 2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 30 * 31 */ 32 33#include <IOKit/assert.h> 34#include <IOKit/IOLib.h> 35#include <IOKit/IOKitKeys.h> 36#include <IOKit/IOBufferMemoryDescriptor.h> 37#include "RootDomainUserClient.h" 38#include <IOKit/pwr_mgt/IOPMLibDefs.h> 39#include <IOKit/pwr_mgt/IOPMPrivate.h> 40 41#define super IOUserClient 42 43/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 44 45OSDefineMetaClassAndStructors(RootDomainUserClient, IOUserClient) 46 47/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 48 49bool RootDomainUserClient::initWithTask(task_t owningTask, void *security_id, 50 UInt32 type, OSDictionary * properties) 51{ 52 if (properties) 53 properties->setObject(kIOUserClientCrossEndianCompatibleKey, kOSBooleanTrue); 54 55 if (!super::initWithTask(owningTask, security_id, type, properties)) 56 return false; 57 58 fOwningTask = owningTask; 59 task_reference (fOwningTask); 60 return true; 61} 62 63 64bool RootDomainUserClient::start( IOService * provider ) 65{ 66 assert(OSDynamicCast(IOPMrootDomain, provider)); 67 if(!super::start(provider)) 68 return false; 69 fOwner = (IOPMrootDomain *)provider; 70 71 72 return true; 73} 74 75IOReturn RootDomainUserClient::secureSleepSystem( uint32_t *return_code ) 76{ 77 return secureSleepSystemOptions(NULL, 0, return_code); 78} 79 80IOReturn RootDomainUserClient::secureSleepSystemOptions( 81 const void *inOptions, 82 IOByteCount inOptionsSize __unused, 83 uint32_t *returnCode) 84{ 85 86 int local_priv = 0; 87 int admin_priv = 0; 88 IOReturn ret = kIOReturnNotPrivileged; 89 OSDictionary *unserializedOptions = NULL; 90 OSString *unserializeErrorString = NULL; 91 92 ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeLocalUser); 93 local_priv = (kIOReturnSuccess == ret); 94 95 ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator); 96 admin_priv = (kIOReturnSuccess == ret); 97 98 99 if (inOptions) 100 { 101 unserializedOptions = OSDynamicCast( OSDictionary, 102 OSUnserializeXML((const char *)inOptions, &unserializeErrorString)); 103 104 if (!unserializedOptions) { 105 IOLog("IOPMRootDomain SleepSystem unserialization failure: %s\n", 106 unserializeErrorString ? unserializeErrorString->getCStringNoCopy() : "Unknown"); 107 } 108 } 109 110 if ( (local_priv || admin_priv) 111 && fOwner ) 112 { 113 if (unserializedOptions) 114 { 115 // Publish Sleep Options in registry under root_domain 116 fOwner->setProperty( kRootDomainSleepOptionsKey, unserializedOptions); 117 118 *returnCode = fOwner->sleepSystemOptions( unserializedOptions ); 119 120 unserializedOptions->release(); 121 } else { 122 // No options 123 // Clear any pre-existing options 124 fOwner->removeProperty( kRootDomainSleepOptionsKey ); 125 126 *returnCode = fOwner->sleepSystemOptions( NULL ); 127 } 128 129 } else { 130 *returnCode = kIOReturnNotPrivileged; 131 } 132 133 return kIOReturnSuccess; 134} 135 136IOReturn RootDomainUserClient::secureSetAggressiveness( 137 unsigned long type, 138 unsigned long newLevel, 139 int *return_code ) 140{ 141 int local_priv = 0; 142 int admin_priv = 0; 143 IOReturn ret = kIOReturnNotPrivileged; 144 145 ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeLocalUser); 146 local_priv = (kIOReturnSuccess == ret); 147 148 ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator); 149 admin_priv = (kIOReturnSuccess == ret); 150 151 if((local_priv || admin_priv) && fOwner) { 152 *return_code = fOwner->setAggressiveness(type, newLevel); 153 } else { 154 *return_code = kIOReturnNotPrivileged; 155 } 156 return kIOReturnSuccess; 157} 158 159IOReturn RootDomainUserClient::secureSetMaintenanceWakeCalendar( 160 IOPMCalendarStruct *inCalendar, 161 uint32_t *returnCode) 162{ 163 int admin_priv = 0; 164 IOReturn ret = kIOReturnNotPrivileged; 165 166 ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator); 167 admin_priv = (kIOReturnSuccess == ret); 168 169 if (admin_priv && fOwner) { 170 *returnCode = fOwner->setMaintenanceWakeCalendar(inCalendar); 171 } else { 172 *returnCode = kIOReturnNotPrivileged; 173 } 174 return kIOReturnSuccess; 175} 176 177IOReturn RootDomainUserClient::secureSetUserAssertionLevels( 178 uint32_t assertionBitfield) 179{ 180 int admin_priv = 0; 181 IOReturn ret = kIOReturnNotPrivileged; 182 183 ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator); 184 admin_priv = (kIOReturnSuccess == ret); 185 186 if (admin_priv && fOwner) { 187 ret = fOwner->setPMAssertionUserLevels(assertionBitfield); 188 } else { 189 ret = kIOReturnNotPrivileged; 190 } 191 return kIOReturnSuccess; 192} 193 194IOReturn RootDomainUserClient::secureGetSystemSleepType( 195 uint32_t *outSleepType) 196{ 197 int admin_priv = 0; 198 IOReturn ret; 199 200 ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator); 201 admin_priv = (kIOReturnSuccess == ret); 202 203 if (admin_priv && fOwner) { 204 ret = fOwner->getSystemSleepType(outSleepType); 205 } else { 206 ret = kIOReturnNotPrivileged; 207 } 208 return ret; 209} 210 211IOReturn RootDomainUserClient::clientClose( void ) 212{ 213 detach(fOwner); 214 215 if(fOwningTask) { 216 task_deallocate(fOwningTask); 217 fOwningTask = 0; 218 } 219 220 return kIOReturnSuccess; 221} 222 223IOReturn RootDomainUserClient::clientMemoryForType( 224 UInt32 type, 225 IOOptionBits *options, 226 IOMemoryDescriptor ** memory) 227{ 228 if (!fOwner) 229 return kIOReturnNotReady; 230 231 if (kPMRootDomainMapTraceBuffer == type) 232 { 233 *memory = fOwner->getPMTraceMemoryDescriptor(); 234 if (*memory) { 235 (*memory)->retain(); 236 *options = 0; 237 return kIOReturnSuccess; 238 } else { 239 return kIOReturnNotFound; 240 } 241 242 } 243 return kIOReturnUnsupported; 244} 245 246IOReturn RootDomainUserClient::externalMethod( 247 uint32_t selector, 248 IOExternalMethodArguments * arguments, 249 IOExternalMethodDispatch * dispatch __unused, 250 OSObject * target __unused, 251 void * reference __unused ) 252{ 253 IOReturn ret = kIOReturnBadArgument; 254 255 switch (selector) 256 { 257 case kPMSetAggressiveness: 258 if ((2 == arguments->scalarInputCount) 259 && (1 == arguments->scalarOutputCount)) 260 { 261 ret = this->secureSetAggressiveness( 262 (unsigned long)arguments->scalarInput[0], 263 (unsigned long)arguments->scalarInput[1], 264 (int *)&arguments->scalarOutput[0]); 265 } 266 break; 267 268 case kPMGetAggressiveness: 269 if ((1 == arguments->scalarInputCount) 270 && (1 == arguments->scalarOutputCount)) 271 { 272 ret = fOwner->getAggressiveness( 273 (unsigned long)arguments->scalarInput[0], 274 (unsigned long *)&arguments->scalarOutput[0]); 275 } 276 break; 277 278 case kPMSleepSystem: 279 if (1 == arguments->scalarOutputCount) 280 { 281 ret = this->secureSleepSystem( 282 (uint32_t *)&arguments->scalarOutput[0]); 283 } 284 break; 285 286 case kPMAllowPowerChange: 287 if (1 == arguments->scalarInputCount) 288 { 289 ret = fOwner->allowPowerChange( 290 arguments->scalarInput[0]); 291 } 292 break; 293 294 case kPMCancelPowerChange: 295 if (1 == arguments->scalarInputCount) 296 { 297 ret = fOwner->cancelPowerChange( 298 arguments->scalarInput[0]); 299 } 300 break; 301 302 case kPMShutdownSystem: 303 // deperecated interface 304 ret = kIOReturnUnsupported; 305 break; 306 307 case kPMRestartSystem: 308 // deperecated interface 309 ret = kIOReturnUnsupported; 310 break; 311 312 case kPMSleepSystemOptions: 313 ret = this->secureSleepSystemOptions( 314 arguments->structureInput, 315 arguments->structureInputSize, 316 (uint32_t *)&arguments->scalarOutput[0]); 317 break; 318 case kPMSetMaintenanceWakeCalendar: 319 ret = this->secureSetMaintenanceWakeCalendar( 320 (IOPMCalendarStruct *)arguments->structureInput, 321 (uint32_t *)&arguments->structureOutput); 322 arguments->structureOutputSize = sizeof(uint32_t); 323 break; 324 325 case kPMSetUserAssertionLevels: 326 ret = this->secureSetUserAssertionLevels( 327 (uint32_t)arguments->scalarInput[0]); 328 break; 329 330 case kPMActivityTickle: 331 if ( fOwner->checkSystemCanSustainFullWake() ) 332 { 333 fOwner->reportUserInput( ); 334 fOwner->setProperty(kIOPMRootDomainWakeTypeKey, "UserActivity Assertion"); 335 } 336 ret = kIOReturnSuccess; 337 break; 338 339 case kPMSetClamshellSleepState: 340 fOwner->setDisableClamShellSleep(arguments->scalarInput[0] ? true : false); 341 ret = kIOReturnSuccess; 342 break; 343 344 case kPMGetSystemSleepType: 345 if (1 == arguments->scalarOutputCount) 346 { 347 ret = this->secureGetSystemSleepType( 348 (uint32_t *) &arguments->scalarOutput[0]); 349 } 350 break; 351/* 352 case kPMMethodCopySystemTimeline: 353 // intentional fallthrough 354 case kPMMethodCopyDetailedTimeline: 355 356 if (!arguments->structureOutputDescriptor) 357 { 358 // TODO: Force IOKit.framework to always send this data out 359 // of line; so I don't have to create a MemoryDescriptor here. 360 mem_size = arguments->structureOutputSize; 361 mem = IOMemoryDescriptor::withAddressRange( 362 (mach_vm_address_t)arguments->structureOutput, 363 (mach_vm_size_t)mem_size, 364 kIODirectionIn, current_task()); 365 } else { 366 mem_size = arguments->structureOutputDescriptorSize; 367 if (( mem = arguments->structureOutputDescriptor )) 368 mem->retain(); 369 } 370 371 if (mem) 372 { 373 mem->prepare(kIODirectionNone); 374 375 if (kPMMethodCopySystemTimeline == selector) { 376 arguments->scalarOutput[0] = fOwner->copySystemTimeline( 377 mem, &mem_size); 378 } 379 else 380 if (kPMMethodCopyDetailedTimeline == selector) { 381 arguments->scalarOutput[0] = fOwner->copyDetailedTimeline( 382 mem, &mem_size); 383 } 384 385 if (arguments->structureOutputDescriptor) { 386 arguments->structureOutputDescriptorSize = mem_size; 387 } else { 388 arguments->structureOutputSize = mem_size; 389 } 390 391 mem->release(); 392 393 ret = kIOReturnSuccess; 394 } else { 395 ret = kIOReturnCannotWire; 396 } 397 398 break; 399*/ 400 default: 401 // bad selector 402 return kIOReturnBadArgument; 403 } 404 405 return ret; 406} 407 408/* getTargetAndMethodForIndex 409 * Not used. We prefer to use externalMethod() for user client invocations. 410 * We maintain getTargetAndExternalMethod since it's an exported symbol, 411 * and only for that reason. 412 */ 413IOExternalMethod * RootDomainUserClient::getTargetAndMethodForIndex( 414 IOService ** targetP, UInt32 index ) 415{ 416 // DO NOT EDIT 417 return super::getTargetAndMethodForIndex(targetP, index); 418} 419 420/* setPreventative 421 * Does nothing. Exists only for exported symbol compatibility. 422 */ 423void 424RootDomainUserClient::setPreventative(UInt32 on_off, UInt32 types_of_sleep) 425{ return; } // DO NOT EDIT 426