2 * Copyright (c) 1998-2014 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <IOKit/system.h>
31 #include <IOKit/IOService.h>
32 #include <libkern/OSDebug.h>
33 #include <libkern/c++/OSContainers.h>
34 #include <libkern/c++/OSKext.h>
35 #include <libkern/c++/OSUnserialize.h>
36 #include <IOKit/IOCatalogue.h>
37 #include <IOKit/IOCommand.h>
38 #include <IOKit/IODeviceTreeSupport.h>
39 #include <IOKit/IODeviceMemory.h>
40 #include <IOKit/IOInterrupts.h>
41 #include <IOKit/IOInterruptController.h>
42 #include <IOKit/IOPlatformExpert.h>
43 #include <IOKit/IOMessage.h>
44 #include <IOKit/IOLib.h>
45 #include <IOKit/IOKitKeysPrivate.h>
46 #include <IOKit/IOBSD.h>
47 #include <IOKit/IOUserClient.h>
48 #include <IOKit/IOWorkLoop.h>
49 #include <IOKit/IOTimeStamp.h>
50 #include <IOKit/IOHibernatePrivate.h>
51 #include <IOKit/IOInterruptAccountingPrivate.h>
52 #include <IOKit/IOKernelReporters.h>
53 #include <IOKit/AppleKeyStoreInterface.h>
54 #include <IOKit/IOCPU.h>
55 #include <mach/sync_policy.h>
56 #include <IOKit/assert.h>
57 #include <sys/errno.h>
58 #include <sys/kdebug.h>
61 #include <machine/pal_routines.h>
66 #define OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x)))
68 #include "IOServicePrivate.h"
69 #include "IOKitKernelInternal.h"
71 // take lockForArbitration before LOCKNOTIFY
73 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
75 #define super IORegistryEntry
77 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
79 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
81 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
83 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
85 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
87 OSDefineMetaClassAndStructors(IOResources
, IOService
)
89 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
91 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
93 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
95 static IOPlatformExpert
* gIOPlatform
;
96 static class IOPMrootDomain
* gIOPMRootDomain
;
97 const IORegistryPlane
* gIOServicePlane
;
98 const IORegistryPlane
* gIOPowerPlane
;
99 const OSSymbol
* gIODeviceMemoryKey
;
100 const OSSymbol
* gIOInterruptControllersKey
;
101 const OSSymbol
* gIOInterruptSpecifiersKey
;
103 const OSSymbol
* gIOResourcesKey
;
104 const OSSymbol
* gIOResourceMatchKey
;
105 const OSSymbol
* gIOProviderClassKey
;
106 const OSSymbol
* gIONameMatchKey
;
107 const OSSymbol
* gIONameMatchedKey
;
108 const OSSymbol
* gIOPropertyMatchKey
;
109 const OSSymbol
* gIOLocationMatchKey
;
110 const OSSymbol
* gIOParentMatchKey
;
111 const OSSymbol
* gIOPathMatchKey
;
112 const OSSymbol
* gIOMatchCategoryKey
;
113 const OSSymbol
* gIODefaultMatchCategoryKey
;
114 const OSSymbol
* gIOMatchedServiceCountKey
;
116 const OSSymbol
* gIOMapperIDKey
;
117 const OSSymbol
* gIOUserClientClassKey
;
118 const OSSymbol
* gIOKitDebugKey
;
120 const OSSymbol
* gIOCommandPoolSizeKey
;
122 const OSSymbol
* gIOConsoleLockedKey
;
123 const OSSymbol
* gIOConsoleUsersKey
;
124 const OSSymbol
* gIOConsoleSessionUIDKey
;
125 const OSSymbol
* gIOConsoleSessionAuditIDKey
;
126 const OSSymbol
* gIOConsoleUsersSeedKey
;
127 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
128 const OSSymbol
* gIOConsoleSessionLoginDoneKey
;
129 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
130 const OSSymbol
* gIOConsoleSessionScreenLockedTimeKey
;
132 clock_sec_t gIOConsoleLockTime
;
133 static bool gIOConsoleLoggedIn
;
135 static uint32_t gIOScreenLockState
;
137 static IORegistryEntry
* gIOChosenEntry
;
139 static int gIOResourceGenerationCount
;
141 const OSSymbol
* gIOServiceKey
;
142 const OSSymbol
* gIOPublishNotification
;
143 const OSSymbol
* gIOFirstPublishNotification
;
144 const OSSymbol
* gIOMatchedNotification
;
145 const OSSymbol
* gIOFirstMatchNotification
;
146 const OSSymbol
* gIOTerminatedNotification
;
148 const OSSymbol
* gIOGeneralInterest
;
149 const OSSymbol
* gIOBusyInterest
;
150 const OSSymbol
* gIOAppPowerStateInterest
;
151 const OSSymbol
* gIOPriorityPowerStateInterest
;
152 const OSSymbol
* gIOConsoleSecurityInterest
;
154 const OSSymbol
* gAKSGetKey
;
155 #if defined(__i386__) || defined(__x86_64__)
156 const OSSymbol
* gIOCreateEFIDevicePathSymbol
;
159 static OSDictionary
* gNotifications
;
160 static IORecursiveLock
* gNotificationLock
;
162 static IOService
* gIOResources
;
163 static IOService
* gIOServiceRoot
;
165 static OSOrderedSet
* gJobs
;
166 static semaphore_port_t gJobsSemaphore
;
167 static IOLock
* gJobsLock
;
168 static int gOutstandingJobs
;
169 static int gNumConfigThreads
;
170 static int gNumWaitingThreads
;
171 static IOLock
* gIOServiceBusyLock
;
172 static bool gCPUsRunning
;
174 static thread_t gIOTerminateThread
;
175 static UInt32 gIOTerminateWork
;
176 static OSArray
* gIOTerminatePhase2List
;
177 static OSArray
* gIOStopList
;
178 static OSArray
* gIOStopProviderList
;
179 static OSArray
* gIOFinalizeList
;
181 static SInt32 gIOConsoleUsersSeed
;
182 static OSData
* gIOConsoleUsersSeedValue
;
184 extern const OSSymbol
* gIODTPHandleKey
;
186 const OSSymbol
* gIOPlatformFunctionHandlerSet
;
188 static IOLock
* gIOConsoleUsersLock
;
189 static thread_call_t gIOConsoleLockCallout
;
191 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
193 #define LOCKREADNOTIFY() \
194 IORecursiveLockLock( gNotificationLock )
195 #define LOCKWRITENOTIFY() \
196 IORecursiveLockLock( gNotificationLock )
197 #define LOCKWRITE2READNOTIFY()
198 #define UNLOCKNOTIFY() \
199 IORecursiveLockUnlock( gNotificationLock )
200 #define SLEEPNOTIFY(event) \
201 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
202 #define SLEEPNOTIFYTO(event, deadline) \
203 IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT )
204 #define WAKEUPNOTIFY(event) \
205 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
207 #define randomDelay() \
208 int del = read_processor_clock(); \
209 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
212 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
214 #define queue_element(entry, element, type, field) do { \
215 vm_address_t __ele = (vm_address_t) (entry); \
216 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
217 (element) = (type) __ele; \
220 #define iterqueue(que, elt) \
221 for (queue_entry_t elt = queue_first(que); \
222 !queue_end(que, elt); \
223 elt = queue_next(elt))
225 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
227 struct IOInterruptAccountingReporter
{
228 IOSimpleReporter
* reporter
; /* Reporter responsible for communicating the statistics */
229 IOInterruptAccountingData
* statistics
; /* The live statistics values, if any */
232 struct ArbitrationLockQueueElement
{
241 static queue_head_t gArbitrationLockQueueActive
;
242 static queue_head_t gArbitrationLockQueueWaiting
;
243 static queue_head_t gArbitrationLockQueueFree
;
244 static IOLock
* gArbitrationLockQueueLock
;
246 bool IOService::isInactive( void ) const
247 { return( 0 != (kIOServiceInactiveState
& getState())); }
249 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
251 #if defined(__i386__) || defined(__x86_64__)
253 // Only used by the intel implementation of
254 // IOService::requireMaxBusStall(UInt32 ns)
255 // IOService::requireMaxInterruptDelay(uint32_t ns)
258 IOService
* fService
;
264 kCpuDelayBusStall
, kCpuDelayInterrupt
,
268 static OSData
*sCpuDelayData
= OSData::withCapacity(8 * sizeof(CpuDelayEntry
));
269 static IORecursiveLock
*sCpuDelayLock
= IORecursiveLockAlloc();
270 static OSArray
*sCpuLatencyHandlers
[kCpuNumDelayTypes
];
271 const OSSymbol
*sCPULatencyFunctionName
[kCpuNumDelayTypes
];
272 static OSNumber
* sCPULatencyHolder
[kCpuNumDelayTypes
];
273 static char sCPULatencyHolderName
[kCpuNumDelayTypes
][128];
274 static OSNumber
* sCPULatencySet
[kCpuNumDelayTypes
];
277 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
);
279 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
);
281 #endif /* defined(__i386__) || defined(__x86_64__) */
283 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
285 void IOService::initialize( void )
289 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
290 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
292 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
293 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
294 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
295 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
296 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
297 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
298 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
300 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
301 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
302 kIODefaultMatchCategoryKey
);
303 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
304 kIOMatchedServiceCountKey
);
306 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
308 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
309 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
311 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
312 gIOInterruptControllersKey
313 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
314 gIOInterruptSpecifiersKey
315 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
317 gIOMapperIDKey
= OSSymbol::withCStringNoCopy(kIOMapperIDKey
);
319 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
321 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
323 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
324 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
325 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
326 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
327 gIOConsoleSecurityInterest
= OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest
);
329 gNotifications
= OSDictionary::withCapacity( 1 );
330 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
331 kIOPublishNotification
);
332 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
333 kIOFirstPublishNotification
);
334 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
335 kIOMatchedNotification
);
336 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
337 kIOFirstMatchNotification
);
338 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
339 kIOTerminatedNotification
);
340 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
342 gIOConsoleLockedKey
= OSSymbol::withCStringNoCopy( kIOConsoleLockedKey
);
343 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
344 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
345 gIOConsoleSessionAuditIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey
);
347 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey
);
348 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey
);
349 gIOConsoleSessionLoginDoneKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey
);
350 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey
);
351 gIOConsoleSessionScreenLockedTimeKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey
);
353 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
355 gIOPlatformFunctionHandlerSet
= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet
);
356 #if defined(__i386__) || defined(__x86_64__)
357 sCPULatencyFunctionName
[kCpuDelayBusStall
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay
);
358 sCPULatencyFunctionName
[kCpuDelayInterrupt
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay
);
360 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++)
362 sCPULatencySet
[idx
] = OSNumber::withNumber(-1U, 32);
363 sCPULatencyHolder
[idx
] = OSNumber::withNumber(0ULL, 64);
364 assert(sCPULatencySet
[idx
] && sCPULatencyHolder
[idx
]);
366 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
368 gNotificationLock
= IORecursiveLockAlloc();
370 gAKSGetKey
= OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY
);
372 assert( gIOServicePlane
&& gIODeviceMemoryKey
373 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
374 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
375 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
376 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
377 && gIOPublishNotification
&& gIOMatchedNotification
378 && gIOTerminatedNotification
&& gIOServiceKey
379 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
380 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
381 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
383 gJobsLock
= IOLockAlloc();
384 gJobs
= OSOrderedSet::withCapacity( 10 );
386 gIOServiceBusyLock
= IOLockAlloc();
388 gIOConsoleUsersLock
= IOLockAlloc();
390 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
392 gIOConsoleLockCallout
= thread_call_allocate(&IOService::consoleLockTimer
, NULL
);
394 IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey
, kOSBooleanTrue
);
396 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& gIOConsoleUsersLock
397 && gIOConsoleLockCallout
&& (err
== KERN_SUCCESS
) );
399 gIOResources
= IOResources::resources();
400 assert( gIOResources
);
402 gArbitrationLockQueueLock
= IOLockAlloc();
403 queue_init(&gArbitrationLockQueueActive
);
404 queue_init(&gArbitrationLockQueueWaiting
);
405 queue_init(&gArbitrationLockQueueFree
);
407 assert( gArbitrationLockQueueLock
);
409 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
410 gIOStopList
= OSArray::withCapacity( 16 );
411 gIOStopProviderList
= OSArray::withCapacity( 16 );
412 gIOFinalizeList
= OSArray::withCapacity( 16 );
413 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
417 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
419 #if defined(__i386__) || defined(__x86_64__)
422 const char *getCpuDelayBusStallHolderName(void) {
423 return sCPULatencyHolderName
[kCpuDelayBusStall
];
430 static UInt64
getDebugFlags( OSDictionary
* props
)
432 OSNumber
* debugProp
;
435 debugProp
= OSDynamicCast( OSNumber
,
436 props
->getObject( gIOKitDebugKey
));
438 debugFlags
= debugProp
->unsigned64BitValue();
440 debugFlags
= gIOKitDebug
;
442 return( debugFlags
);
446 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
448 // Probe a matched service and return an instance to be started.
449 // The default score is from the property table, & may be altered
450 // during probe to change the start order.
452 IOService
* IOService::probe( IOService
* provider
,
458 bool IOService::start( IOService
* provider
)
463 void IOService::stop( IOService
* provider
)
467 bool IOService::init( OSDictionary
* dictionary
)
471 ret
= super::init(dictionary
);
472 if (!ret
) return (false);
473 if (reserved
) return (true);
475 reserved
= IONew(ExpansionData
, 1);
476 if (!reserved
) return (false);
477 bzero(reserved
, sizeof(*reserved
));
480 * TODO: Improve on this. Previous efforts to more lazily allocate this
481 * lock based on the presence of specifiers ran into issues as some
482 * platforms set up the specifiers after IOService initialization.
484 * We may be able to get away with a global lock, as this should only be
485 * contended by IOReporting clients and driver start/stop (unless a
486 * driver wants to remove/add handlers in the course of normal operation,
487 * which should be unlikely).
489 reserved
->interruptStatisticsLock
= IOLockAlloc();
490 if (!reserved
->interruptStatisticsLock
) return (false);
495 bool IOService::init( IORegistryEntry
* from
,
496 const IORegistryPlane
* inPlane
)
500 ret
= super::init(from
, inPlane
);
501 if (!ret
) return (false);
502 if (reserved
) return (true);
504 reserved
= IONew(ExpansionData
, 1);
505 if (!reserved
) return (false);
506 bzero(reserved
, sizeof(*reserved
));
509 * TODO: Improve on this. Previous efforts to more lazily allocate this
510 * lock based on the presence of specifiers ran into issues as some
511 * platforms set up the specifiers after IOService initialization.
513 * We may be able to get away with a global lock, as this should only be
514 * contended by IOReporting clients and driver start/stop (unless a
515 * driver wants to remove/add handlers in the course of normal operation,
516 * which should be unlikely).
518 reserved
->interruptStatisticsLock
= IOLockAlloc();
519 if (!reserved
->interruptStatisticsLock
) return (false);
524 void IOService::free( void )
527 requireMaxBusStall(0);
528 requireMaxInterruptDelay(0);
529 if( getPropertyTable())
530 unregisterAllInterest();
534 if (reserved
->interruptStatisticsArray
) {
535 for (i
= 0; i
< reserved
->interruptStatisticsArrayCount
; i
++) {
536 if (reserved
->interruptStatisticsArray
[i
].reporter
)
537 reserved
->interruptStatisticsArray
[i
].reporter
->release();
540 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
543 if (reserved
->interruptStatisticsLock
)
544 IOLockFree(reserved
->interruptStatisticsLock
);
545 IODelete(reserved
, ExpansionData
, 1);
548 if (_numInterruptSources
&& _interruptSources
)
550 IOFree(_interruptSources
, _numInterruptSources
* sizeof(IOInterruptSource
));
551 _interruptSources
= 0;
558 * Attach in service plane
560 bool IOService::attach( IOService
* provider
)
566 if( gIOKitDebug
& kIOLogAttach
)
567 LOG( "%s::attach(%s)\n", getName(),
568 provider
->getName());
570 provider
->lockForArbitration();
571 if( provider
->__state
[0] & kIOServiceInactiveState
)
574 ok
= attachToParent( provider
, gIOServicePlane
);
575 provider
->unlockForArbitration();
578 gIOServiceRoot
= this;
579 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
582 if (ok
&& !__provider
) (void) getProvider();
587 IOService
* IOService::getServiceRoot( void )
589 return( gIOServiceRoot
);
592 void IOService::detach( IOService
* provider
)
594 IOService
* newProvider
= 0;
598 if( gIOKitDebug
& kIOLogAttach
)
599 LOG("%s::detach(%s)\n", getName(), provider
->getName());
601 lockForArbitration();
603 uint64_t regID1
= provider
->getRegistryEntryID();
604 uint64_t regID2
= getRegistryEntryID();
608 (uintptr_t) (regID1
>> 32),
610 (uintptr_t) (regID2
>> 32));
612 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
613 && (provider
== getProvider()));
615 detachFromParent( provider
, gIOServicePlane
);
618 newProvider
= getProvider();
619 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
620 _adjustBusy( -busy
);
623 if (kIOServiceInactiveState
& __state
[0]) {
624 getMetaClass()->removeInstance(this);
625 IORemoveServicePlatformActions(this);
628 unlockForArbitration();
631 newProvider
->lockForArbitration();
632 newProvider
->_adjustBusy(1);
633 newProvider
->unlockForArbitration();
636 // check for last client detach from a terminated service
637 if( provider
->lockForArbitration( true ))
639 if (kIOServiceStartState
& __state
[1])
641 provider
->scheduleTerminatePhase2();
643 if( adjParent
) provider
->_adjustBusy( -1 );
644 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
645 && (0 == provider
->getClient())) {
646 provider
->scheduleFinalize(false);
648 provider
->unlockForArbitration();
653 * Register instance - publish it for matching
656 void IOService::registerService( IOOptionBits options
)
662 enum { kMaxPathLen
= 256 };
663 enum { kMaxChars
= 63 };
665 IORegistryEntry
* parent
= this;
666 IORegistryEntry
* root
= getRegistryRoot();
667 while( parent
&& (parent
!= root
))
668 parent
= parent
->getParentEntry( gIOServicePlane
);
670 if( parent
!= root
) {
671 IOLog("%s: not registry member at registerService()\n", getName());
675 // Allow the Platform Expert to adjust this node.
676 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
679 IOInstallServicePlatformActions(this);
681 if( (this != gIOResources
)
682 && (kIOLogRegister
& gIOKitDebug
)) {
684 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
686 IOLog( "Registering: " );
689 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
692 if( len
> kMaxChars
) {
696 if( (skip
= strchr( path
, '/')))
702 IOLog( "%s\n", path
);
705 IOFree( pathBuf
, kMaxPathLen
);
708 startMatching( options
);
711 void IOService::startMatching( IOOptionBits options
)
713 IOService
* provider
;
716 bool needWake
= false;
721 lockForArbitration();
723 sync
= (options
& kIOServiceSynchronous
)
724 || ((provider
= getProvider())
725 && (provider
->__state
[1] & kIOServiceSynchronousState
));
727 if ( options
& kIOServiceAsynchronous
)
730 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
731 && (0 == (__state
[0] & kIOServiceInactiveState
));
733 __state
[1] |= kIOServiceNeedConfigState
;
735 // __state[0] &= ~kIOServiceInactiveState;
737 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
738 // OSKernelStackRemaining(), getName());
741 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
745 __state
[1] |= kIOServiceSynchronousState
;
747 __state
[1] &= ~kIOServiceSynchronousState
;
749 if( needConfig
) prevBusy
= _adjustBusy( 1 );
751 unlockForArbitration();
756 IOLockLock( gIOServiceBusyLock
);
757 thread_wakeup( (event_t
) this/*&__state[1]*/ );
758 IOLockUnlock( gIOServiceBusyLock
);
760 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
762 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
766 if( (__state
[1] & kIOServiceNeedConfigState
))
767 doServiceMatch( options
);
769 lockForArbitration();
770 IOLockLock( gIOServiceBusyLock
);
772 waitAgain
= ((prevBusy
< (__state
[1] & kIOServiceBusyStateMask
))
773 && (0 == (__state
[0] & kIOServiceInactiveState
)));
776 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
778 __state
[1] &= ~kIOServiceSyncPubState
;
780 unlockForArbitration();
783 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
785 IOLockUnlock( gIOServiceBusyLock
);
787 thread_block(THREAD_CONTINUE_NULL
);
789 } while( waitAgain
);
793 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
795 OSDictionary
* table
;
805 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
808 set
= (OSSet
*) copyExistingServices( table
,
809 kIOServiceRegisteredState
,
810 kIOServiceExistingSet
);
815 count
+= set
->getCount();
818 allSet
->merge((const OSSet
*) set
);
826 if( getDebugFlags( table
) & kIOLogMatch
)
827 LOG("Matching service count = %ld\n", (long)count
);
829 newTables
->removeObject(table
);
833 while( (service
= (IOService
*) allSet
->getAnyObject())) {
834 service
->startMatching(kIOServiceAsynchronous
);
835 allSet
->removeObject(service
);
840 newTables
->release();
842 return( kIOReturnSuccess
);
845 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
846 IOOptionBits options
)
850 job
= new _IOServiceJob
;
851 if( job
&& !job
->init()) {
859 job
->options
= options
;
860 nub
->retain(); // thread will release()
868 * Called on a registered service to see if it matches
872 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
874 return( matchPropertyTable(table
) );
877 bool IOService::matchPropertyTable( OSDictionary
* table
)
883 * Called on a matched service to allocate resources
884 * before first driver is attached.
887 IOReturn
IOService::getResources( void )
889 return( kIOReturnSuccess
);
893 * Client/provider accessors
896 IOService
* IOService::getProvider( void ) const
898 IOService
* self
= (IOService
*) this;
902 generation
= getGenerationCount();
903 if( __providerGeneration
== generation
)
904 return( __provider
);
906 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
907 if( parent
== IORegistryEntry::getRegistryRoot())
908 /* root is not an IOService */
911 self
->__provider
= parent
;
913 // save the count from before call to getParentEntry()
914 self
->__providerGeneration
= generation
;
919 IOWorkLoop
* IOService::getWorkLoop() const
921 IOService
*provider
= getProvider();
924 return provider
->getWorkLoop();
929 OSIterator
* IOService::getProviderIterator( void ) const
931 return( getParentIterator( gIOServicePlane
));
934 IOService
* IOService::getClient( void ) const
936 return( (IOService
*) getChildEntry( gIOServicePlane
));
939 OSIterator
* IOService::getClientIterator( void ) const
941 return( getChildIterator( gIOServicePlane
));
944 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
945 const IOService
* client
,
946 const IOService
* provider
)
948 _IOOpenServiceIterator
* inst
;
953 inst
= new _IOOpenServiceIterator
;
955 if( inst
&& !inst
->init()) {
961 inst
->client
= client
;
962 inst
->provider
= provider
;
968 void _IOOpenServiceIterator::free()
972 last
->unlockForArbitration();
976 OSObject
* _IOOpenServiceIterator::getNextObject()
981 last
->unlockForArbitration();
983 while( (next
= (IOService
*) iter
->getNextObject())) {
985 next
->lockForArbitration();
986 if( (client
&& (next
->isOpen( client
)))
987 || (provider
&& (provider
->isOpen( next
))) )
989 next
->unlockForArbitration();
997 bool _IOOpenServiceIterator::isValid()
999 return( iter
->isValid() );
1002 void _IOOpenServiceIterator::reset()
1005 last
->unlockForArbitration();
1011 OSIterator
* IOService::getOpenProviderIterator( void ) const
1013 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
1016 OSIterator
* IOService::getOpenClientIterator( void ) const
1018 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
1022 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
1023 bool waitForFunction
,
1024 void *param1
, void *param2
,
1025 void *param3
, void *param4
)
1027 IOReturn result
= kIOReturnUnsupported
;
1028 IOService
*provider
;
1030 if (gIOPlatformFunctionHandlerSet
== functionName
)
1032 #if defined(__i386__) || defined(__x86_64__)
1033 const OSSymbol
* functionHandlerName
= (const OSSymbol
*) param1
;
1034 IOService
* target
= (IOService
*) param2
;
1035 bool enable
= (param3
!= 0);
1037 if (sCPULatencyFunctionName
[kCpuDelayBusStall
] == functionHandlerName
)
1038 result
= setLatencyHandler(kCpuDelayBusStall
, target
, enable
);
1039 else if (sCPULatencyFunctionName
[kCpuDelayInterrupt
] == param1
)
1040 result
= setLatencyHandler(kCpuDelayInterrupt
, target
, enable
);
1041 #endif /* defined(__i386__) || defined(__x86_64__) */
1044 if ((kIOReturnUnsupported
== result
) && (provider
= getProvider())) {
1045 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
1046 param1
, param2
, param3
, param4
);
1052 IOReturn
IOService::callPlatformFunction( const char * functionName
,
1053 bool waitForFunction
,
1054 void *param1
, void *param2
,
1055 void *param3
, void *param4
)
1057 IOReturn result
= kIOReturnNoMemory
;
1058 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
1060 if (functionSymbol
!= 0) {
1061 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
1062 param1
, param2
, param3
, param4
);
1063 functionSymbol
->release();
1071 * Accessors for global services
1074 IOPlatformExpert
* IOService::getPlatform( void )
1076 return( gIOPlatform
);
1079 class IOPMrootDomain
* IOService::getPMRootDomain( void )
1081 return( gIOPMRootDomain
);
1084 IOService
* IOService::getResourceService( void )
1086 return( gIOResources
);
1089 void IOService::setPlatform( IOPlatformExpert
* platform
)
1091 gIOPlatform
= platform
;
1092 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
1094 #if defined(__i386__) || defined(__x86_64__)
1096 static const char * keys
[kCpuNumDelayTypes
] = {
1097 kIOPlatformMaxBusDelay
, kIOPlatformMaxInterruptDelay
};
1098 const OSObject
* objs
[2];
1102 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++)
1104 objs
[0] = sCPULatencySet
[idx
];
1105 objs
[1] = sCPULatencyHolder
[idx
];
1106 array
= OSArray::withObjects(objs
, 2);
1108 platform
->setProperty(keys
[idx
], array
);
1111 #endif /* defined(__i386__) || defined(__x86_64__) */
1114 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
1116 gIOPMRootDomain
= rootDomain
;
1117 publishResource("IOKit");
1124 bool IOService::lockForArbitration( bool isSuccessRequired
)
1128 ArbitrationLockQueueElement
* element
;
1129 ArbitrationLockQueueElement
* active
;
1130 ArbitrationLockQueueElement
* waiting
;
1132 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
1134 // lock global access
1135 IOTakeLock( gArbitrationLockQueueLock
);
1137 // obtain an unused queue element
1138 if( !queue_empty( &gArbitrationLockQueueFree
)) {
1139 queue_remove_first( &gArbitrationLockQueueFree
,
1141 ArbitrationLockQueueElement
*,
1144 element
= IONew( ArbitrationLockQueueElement
, 1 );
1148 // prepare the queue element
1149 element
->thread
= IOThreadSelf();
1150 element
->service
= this;
1152 element
->required
= isSuccessRequired
;
1153 element
->aborted
= false;
1155 // determine whether this object is already locked (ie. on active queue)
1157 queue_iterate( &gArbitrationLockQueueActive
,
1159 ArbitrationLockQueueElement
*,
1162 if( active
->service
== element
->service
) {
1168 if( found
) { // this object is already locked
1170 // determine whether it is the same or a different thread trying to lock
1171 if( active
->thread
!= element
->thread
) { // it is a different thread
1173 ArbitrationLockQueueElement
* victim
= 0;
1175 // before placing this new thread on the waiting queue, we look for
1176 // a deadlock cycle...
1179 // determine whether the active thread holding the object we
1180 // want is waiting for another object to be unlocked
1182 queue_iterate( &gArbitrationLockQueueWaiting
,
1184 ArbitrationLockQueueElement
*,
1187 if( waiting
->thread
== active
->thread
) {
1188 assert( false == waiting
->aborted
);
1194 if( found
) { // yes, active thread waiting for another object
1196 // this may be a candidate for rejection if the required
1197 // flag is not set, should we detect a deadlock later on
1198 if( false == waiting
->required
)
1201 // find the thread that is holding this other object, that
1202 // is blocking the active thread from proceeding (fun :-)
1204 queue_iterate( &gArbitrationLockQueueActive
,
1205 active
, // (reuse active queue element)
1206 ArbitrationLockQueueElement
*,
1209 if( active
->service
== waiting
->service
) {
1215 // someone must be holding it or it wouldn't be waiting
1218 if( active
->thread
== element
->thread
) {
1220 // doh, it's waiting for the thread that originated
1221 // this whole lock (ie. current thread) -> deadlock
1222 if( false == element
->required
) { // willing to fail?
1224 // the originating thread doesn't have the required
1225 // flag, so it can fail
1226 success
= false; // (fail originating lock request)
1227 break; // (out of while)
1229 } else { // originating thread is not willing to fail
1231 // see if we came across a waiting thread that did
1232 // not have the 'required' flag set: we'll fail it
1235 // we do have a willing victim, fail it's lock
1236 victim
->aborted
= true;
1238 // take the victim off the waiting queue
1239 queue_remove( &gArbitrationLockQueueWaiting
,
1241 ArbitrationLockQueueElement
*,
1245 IOLockWakeup( gArbitrationLockQueueLock
,
1247 /* one thread */ true );
1249 // allow this thread to proceed (ie. wait)
1250 success
= true; // (put request on wait queue)
1251 break; // (out of while)
1254 // all the waiting threads we came across in
1255 // finding this loop had the 'required' flag
1256 // set, so we've got a deadlock we can't avoid
1257 panic("I/O Kit: Unrecoverable deadlock.");
1261 // repeat while loop, redefining active thread to be the
1262 // thread holding "this other object" (see above), and
1263 // looking for threads waiting on it; note the active
1264 // variable points to "this other object" already... so
1265 // there nothing to do in this else clause.
1267 } else { // no, active thread is not waiting for another object
1269 success
= true; // (put request on wait queue)
1270 break; // (out of while)
1274 if( success
) { // put the request on the waiting queue?
1275 kern_return_t wait_result
;
1277 // place this thread on the waiting queue and put it to sleep;
1278 // we place it at the tail of the queue...
1279 queue_enter( &gArbitrationLockQueueWaiting
,
1281 ArbitrationLockQueueElement
*,
1284 // declare that this thread will wait for a given event
1285 restart_sleep
: wait_result
= assert_wait( element
,
1286 element
->required
? THREAD_UNINT
1287 : THREAD_INTERRUPTIBLE
);
1289 // unlock global access
1290 IOUnlock( gArbitrationLockQueueLock
);
1292 // put thread to sleep, waiting for our event to fire...
1293 if (wait_result
== THREAD_WAITING
)
1294 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1297 // ...and we've been woken up; we might be in one of two states:
1298 // (a) we've been aborted and our queue element is not on
1299 // any of the three queues, but is floating around
1300 // (b) we're allowed to proceed with the lock and we have
1301 // already been moved from the waiting queue to the
1303 // ...plus a 3rd state, should the thread have been interrupted:
1304 // (c) we're still on the waiting queue
1306 // determine whether we were interrupted out of our sleep
1307 if( THREAD_INTERRUPTED
== wait_result
) {
1309 // re-lock global access
1310 IOTakeLock( gArbitrationLockQueueLock
);
1312 // determine whether we're still on the waiting queue
1314 queue_iterate( &gArbitrationLockQueueWaiting
,
1315 waiting
, // (reuse waiting queue element)
1316 ArbitrationLockQueueElement
*,
1319 if( waiting
== element
) {
1325 if( found
) { // yes, we're still on the waiting queue
1327 // determine whether we're willing to fail
1328 if( false == element
->required
) {
1330 // mark us as aborted
1331 element
->aborted
= true;
1333 // take us off the waiting queue
1334 queue_remove( &gArbitrationLockQueueWaiting
,
1336 ArbitrationLockQueueElement
*,
1338 } else { // we are not willing to fail
1340 // ignore interruption, go back to sleep
1345 // unlock global access
1346 IOUnlock( gArbitrationLockQueueLock
);
1348 // proceed as though this were a normal wake up
1349 wait_result
= THREAD_AWAKENED
;
1352 assert( THREAD_AWAKENED
== wait_result
);
1354 // determine whether we've been aborted while we were asleep
1355 if( element
->aborted
) {
1356 assert( false == element
->required
);
1358 // re-lock global access
1359 IOTakeLock( gArbitrationLockQueueLock
);
1361 action
= kPutOnFreeQueue
;
1363 } else { // we weren't aborted, so we must be ready to go :-)
1365 // we've already been moved from waiting to active queue
1369 } else { // the lock request is to be failed
1371 // return unused queue element to queue
1372 action
= kPutOnFreeQueue
;
1374 } else { // it is the same thread, recursive access is allowed
1376 // add one level of recursion
1379 // return unused queue element to queue
1380 action
= kPutOnFreeQueue
;
1383 } else { // this object is not already locked, so let this thread through
1384 action
= kPutOnActiveQueue
;
1388 // put the new element on a queue
1389 if( kPutOnActiveQueue
== action
) {
1390 queue_enter( &gArbitrationLockQueueActive
,
1392 ArbitrationLockQueueElement
*,
1394 } else if( kPutOnFreeQueue
== action
) {
1395 queue_enter( &gArbitrationLockQueueFree
,
1397 ArbitrationLockQueueElement
*,
1400 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1403 // unlock global access
1404 IOUnlock( gArbitrationLockQueueLock
);
1409 void IOService::unlockForArbitration( void )
1412 ArbitrationLockQueueElement
* element
;
1414 // lock global access
1415 IOTakeLock( gArbitrationLockQueueLock
);
1417 // find the lock element for this object (ie. on active queue)
1419 queue_iterate( &gArbitrationLockQueueActive
,
1421 ArbitrationLockQueueElement
*,
1424 if( element
->service
== this ) {
1432 // determine whether the lock has been taken recursively
1433 if( element
->count
> 1 ) {
1434 // undo one level of recursion
1439 // remove it from the active queue
1440 queue_remove( &gArbitrationLockQueueActive
,
1442 ArbitrationLockQueueElement
*,
1445 // put it on the free queue
1446 queue_enter( &gArbitrationLockQueueFree
,
1448 ArbitrationLockQueueElement
*,
1451 // determine whether a thread is waiting for object (head to tail scan)
1453 queue_iterate( &gArbitrationLockQueueWaiting
,
1455 ArbitrationLockQueueElement
*,
1458 if( element
->service
== this ) {
1464 if ( found
) { // we found an interested thread on waiting queue
1466 // remove it from the waiting queue
1467 queue_remove( &gArbitrationLockQueueWaiting
,
1469 ArbitrationLockQueueElement
*,
1472 // put it on the active queue
1473 queue_enter( &gArbitrationLockQueueActive
,
1475 ArbitrationLockQueueElement
*,
1478 // wake the waiting thread
1479 IOLockWakeup( gArbitrationLockQueueLock
,
1481 /* one thread */ true );
1485 // unlock global access
1486 IOUnlock( gArbitrationLockQueueLock
);
1489 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1492 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1493 context
, gIOServicePlane
);
1496 void IOService::applyToClients( IOServiceApplierFunction applier
,
1499 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1500 context
, gIOServicePlane
);
1509 // send a message to a client or interested party of this service
1510 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1511 void * argument
, vm_size_t argSize
)
1514 IOService
* service
;
1515 _IOServiceInterestNotifier
* notify
;
1517 if( (service
= OSDynamicCast( IOService
, client
)))
1518 ret
= service
->message( type
, this, argument
);
1520 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1522 _IOServiceNotifierInvocation invocation
;
1525 invocation
.thread
= current_thread();
1528 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1531 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1532 _IOServiceNotifierInvocation
*, link
);
1538 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1539 type
, this, argument
, argSize
);
1542 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1543 _IOServiceNotifierInvocation
*, link
);
1544 if( kIOServiceNotifyWaiter
& notify
->state
) {
1545 notify
->state
&= ~kIOServiceNotifyWaiter
;
1546 WAKEUPNOTIFY( notify
);
1551 ret
= kIOReturnSuccess
;
1554 ret
= kIOReturnBadArgument
;
1560 applyToInterestNotifiers(const IORegistryEntry
*target
,
1561 const OSSymbol
* typeOfInterest
,
1562 OSObjectApplierFunction applier
,
1565 OSArray
* copyArray
= 0;
1569 IOCommand
*notifyList
=
1570 OSDynamicCast( IOCommand
, target
->getProperty( typeOfInterest
));
1573 copyArray
= OSArray::withCapacity(1);
1575 // iterate over queue, entry is set to each element in the list
1576 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1577 _IOServiceInterestNotifier
* notify
;
1579 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1580 copyArray
->setObject(notify
);
1589 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1590 (*applier
)(next
, context
);
1591 copyArray
->release();
1595 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1596 OSObjectApplierFunction applier
,
1599 if (gIOGeneralInterest
== typeOfInterest
)
1600 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1601 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1604 struct MessageClientsContext
{
1605 IOService
* service
;
1612 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1615 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1617 ret
= context
->service
->messageClient( context
->type
,
1618 object
, context
->argument
, context
->argSize
);
1619 if( kIOReturnSuccess
!= ret
)
1623 // send a message to all clients
1624 IOReturn
IOService::messageClients( UInt32 type
,
1625 void * argument
, vm_size_t argSize
)
1627 MessageClientsContext context
;
1629 context
.service
= this;
1630 context
.type
= type
;
1631 context
.argument
= argument
;
1632 context
.argSize
= argSize
;
1633 context
.ret
= kIOReturnSuccess
;
1635 applyToInterested( gIOGeneralInterest
,
1636 &messageClientsApplier
, &context
);
1638 return( context
.ret
);
1641 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1642 IOOptionBits response
)
1644 return( kIOReturnUnsupported
);
1647 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1648 IOServiceInterestHandler handler
, void * target
, void * ref
)
1650 _IOServiceInterestNotifier
* notify
= 0;
1651 IOReturn rc
= kIOReturnError
;
1653 notify
= new _IOServiceInterestNotifier
;
1654 if (!notify
) return NULL
;
1656 if(notify
->init()) {
1657 rc
= registerInterestForNotifer(notify
, typeOfInterest
,
1658 handler
, target
, ref
);
1661 if (rc
!= kIOReturnSuccess
) {
1669 IOReturn
IOService::registerInterestForNotifer( IONotifier
*svcNotify
, const OSSymbol
* typeOfInterest
,
1670 IOServiceInterestHandler handler
, void * target
, void * ref
)
1672 IOReturn rc
= kIOReturnSuccess
;
1673 _IOServiceInterestNotifier
*notify
= 0;
1675 if( (typeOfInterest
!= gIOGeneralInterest
)
1676 && (typeOfInterest
!= gIOBusyInterest
)
1677 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1678 && (typeOfInterest
!= gIOConsoleSecurityInterest
)
1679 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1680 return( kIOReturnBadArgument
);
1682 if (!svcNotify
|| !(notify
= OSDynamicCast(_IOServiceInterestNotifier
, svcNotify
)))
1683 return( kIOReturnBadArgument
);
1685 lockForArbitration();
1686 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1688 notify
->handler
= handler
;
1689 notify
->target
= target
;
1691 notify
->state
= kIOServiceNotifyEnable
;
1697 // Get the head of the notifier linked list
1698 IOCommand
* notifyList
;
1699 OSObject
* obj
= copyProperty( typeOfInterest
);
1700 if (!(notifyList
= OSDynamicCast(IOCommand
, obj
))) {
1701 notifyList
= OSTypeAlloc(IOCommand
);
1704 bool ok
= setProperty( typeOfInterest
, notifyList
);
1705 notifyList
->release();
1706 if (!ok
) notifyList
= 0;
1709 if (obj
) obj
->release();
1712 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1713 notify
->retain(); // ref'ed while in list
1719 rc
= kIOReturnNotReady
;
1721 unlockForArbitration();
1726 static void cleanInterestList( OSObject
* head
)
1728 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1733 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1734 queue_next(entry
) = queue_prev(entry
) = 0;
1736 _IOServiceInterestNotifier
* notify
;
1738 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1744 void IOService::unregisterAllInterest( void )
1746 cleanInterestList( getProperty( gIOGeneralInterest
));
1747 cleanInterestList( getProperty( gIOBusyInterest
));
1748 cleanInterestList( getProperty( gIOAppPowerStateInterest
));
1749 cleanInterestList( getProperty( gIOPriorityPowerStateInterest
));
1750 cleanInterestList( getProperty( gIOConsoleSecurityInterest
));
1754 * _IOServiceInterestNotifier
1757 // wait for all threads, other than the current one,
1758 // to exit the handler
1760 void _IOServiceInterestNotifier::wait()
1762 _IOServiceNotifierInvocation
* next
;
1767 queue_iterate( &handlerInvocations
, next
,
1768 _IOServiceNotifierInvocation
*, link
) {
1769 if( next
->thread
!= current_thread() ) {
1775 state
|= kIOServiceNotifyWaiter
;
1782 void _IOServiceInterestNotifier::free()
1784 assert( queue_empty( &handlerInvocations
));
1788 void _IOServiceInterestNotifier::remove()
1792 if( queue_next( &chain
)) {
1794 queue_next( &chain
) = queue_prev( &chain
) = 0;
1798 state
&= ~kIOServiceNotifyEnable
;
1807 bool _IOServiceInterestNotifier::disable()
1813 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1814 state
&= ~kIOServiceNotifyEnable
;
1823 void _IOServiceInterestNotifier::enable( bool was
)
1827 state
|= kIOServiceNotifyEnable
;
1829 state
&= ~kIOServiceNotifyEnable
;
1833 bool _IOServiceInterestNotifier::init()
1835 queue_init( &handlerInvocations
);
1836 return (OSObject::init());
1838 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1844 #define tailQ(o) setObject(o)
1845 #define headQ(o) setObject(0, o)
1846 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
1848 static void _workLoopAction( IOWorkLoop::Action action
,
1849 IOService
* service
,
1850 void * p0
= 0, void * p1
= 0,
1851 void * p2
= 0, void * p3
= 0 )
1855 if( (wl
= service
->getWorkLoop())) {
1857 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1860 (*action
)( service
, p0
, p1
, p2
, p3
);
1863 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1867 // if its our only provider
1868 ok
= isParent( provider
, gIOServicePlane
, true);
1872 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1873 ok
= (0 != (kIOServiceInactiveState
& __state
[0]));
1880 bool IOService::terminatePhase1( IOOptionBits options
)
1885 OSArray
* makeInactive
;
1886 OSArray
* waitingInactive
;
1887 int waitResult
= THREAD_AWAKENED
;
1891 bool startPhase2
= false;
1893 TLOG("%s[0x%qx]::terminatePhase1(%08llx)\n", getName(), getRegistryEntryID(), (long long)options
);
1895 uint64_t regID
= getRegistryEntryID();
1897 IOSERVICE_TERMINATE_PHASE1
,
1899 (uintptr_t) (regID
>> 32),
1901 (uintptr_t) options
);
1904 if( options
& kIOServiceRecursing
) {
1905 lockForArbitration();
1906 if (0 == (kIOServiceInactiveState
& __state
[0]))
1908 __state
[0] |= kIOServiceInactiveState
;
1909 __state
[1] |= kIOServiceRecursing
| kIOServiceTermPhase1State
;
1911 unlockForArbitration();
1917 makeInactive
= OSArray::withCapacity( 16 );
1918 waitingInactive
= OSArray::withCapacity( 16 );
1919 if(!makeInactive
|| !waitingInactive
) return( false );
1926 didInactive
= victim
->lockForArbitration( true );
1929 uint64_t regID1
= victim
->getRegistryEntryID();
1930 IOServiceTrace(IOSERVICE_TERM_SET_INACTIVE
,
1932 (uintptr_t) (regID1
>> 32),
1933 (uintptr_t) victim
->__state
[1],
1936 enum { kRP1
= kIOServiceRecursing
| kIOServiceTermPhase1State
};
1937 didInactive
= (kRP1
== (victim
->__state
[1] & kRP1
))
1938 || (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1942 // a multiply attached IOService can be visited twice
1943 if (-1U == waitingInactive
->getNextIndexOfObject(victim
, 0)) do
1945 IOLockLock(gIOServiceBusyLock
);
1946 wait
= (victim
->__state
[1] & kIOServiceTermPhase1State
);
1948 TLOG("%s[0x%qx]::waitPhase1(%s[0x%qx])\n",
1949 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
1950 victim
->__state
[1] |= kIOServiceTerm1WaiterState
;
1951 victim
->unlockForArbitration();
1952 assert_wait((event_t
)&victim
->__state
[1], THREAD_UNINT
);
1954 IOLockUnlock(gIOServiceBusyLock
);
1956 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
1957 TLOG("%s[0x%qx]::did waitPhase1(%s[0x%qx])\n",
1958 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
1959 victim
->lockForArbitration();
1962 while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
1966 victim
->__state
[0] |= kIOServiceInactiveState
;
1967 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1968 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1969 victim
->__state
[1] &= ~kIOServiceRecursing
;
1970 victim
->__state
[1] |= kIOServiceTermPhase1State
;
1971 waitingInactive
->headQ(victim
);
1974 if (kIOServiceTerminateNeedWillTerminate
& options
)
1976 victim
->__state
[1] |= kIOServiceNeedWillTerminate
;
1979 victim
->_adjustBusy( 1 );
1981 victim
->unlockForArbitration();
1983 if( victim
== this) startPhase2
= didInactive
;
1986 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1987 IOUserClient::destroyUserReferences( victim
);
1989 iter
= victim
->getClientIterator();
1991 while( (client
= (IOService
*) iter
->getNextObject())) {
1992 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], %08llx)\n",
1993 client
->getName(), client
->getRegistryEntryID(),
1994 victim
->getName(), victim
->getRegistryEntryID(), (long long)options
);
1995 ok
= client
->requestTerminate( victim
, options
);
1996 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], ok = %d)\n",
1997 client
->getName(), client
->getRegistryEntryID(),
1998 victim
->getName(), victim
->getRegistryEntryID(), ok
);
2000 uint64_t regID1
= client
->getRegistryEntryID();
2001 uint64_t regID2
= victim
->getRegistryEntryID();
2003 (ok
? IOSERVICE_TERMINATE_REQUEST_OK
2004 : IOSERVICE_TERMINATE_REQUEST_FAIL
),
2006 (uintptr_t) (regID1
>> 32),
2008 (uintptr_t) (regID2
>> 32));
2011 makeInactive
->setObject( client
);
2017 victim
= (IOService
*) makeInactive
->getObject(0);
2020 makeInactive
->removeObject(0);
2023 makeInactive
->release();
2025 while ((victim
= (IOService
*) waitingInactive
->getObject(0)))
2028 waitingInactive
->removeObject(0);
2030 victim
->lockForArbitration();
2031 victim
->__state
[1] &= ~kIOServiceTermPhase1State
;
2032 if (kIOServiceTerm1WaiterState
& victim
->__state
[1])
2034 victim
->__state
[1] &= ~kIOServiceTerm1WaiterState
;
2035 TLOG("%s[0x%qx]::wakePhase1\n", victim
->getName(), victim
->getRegistryEntryID());
2036 IOLockLock( gIOServiceBusyLock
);
2037 thread_wakeup( (event_t
) &victim
->__state
[1]);
2038 IOLockUnlock( gIOServiceBusyLock
);
2040 victim
->unlockForArbitration();
2043 waitingInactive
->release();
2048 lockForArbitration();
2049 scheduleTerminatePhase2(options
);
2050 unlockForArbitration();
2057 void IOService::setTerminateDefer(IOService
* provider
, bool defer
)
2059 lockForArbitration();
2060 if (defer
) __state
[1] |= kIOServiceStartState
;
2061 else __state
[1] &= ~kIOServiceStartState
;
2062 unlockForArbitration();
2064 if (provider
&& !defer
)
2066 provider
->lockForArbitration();
2067 provider
->scheduleTerminatePhase2();
2068 provider
->unlockForArbitration();
2072 // call with lockForArbitration
2073 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
2075 AbsoluteTime deadline
;
2077 int waitResult
= THREAD_AWAKENED
;
2078 bool wait
, haveDeadline
= false;
2080 if (!(__state
[0] & kIOServiceInactiveState
)) return;
2082 regID1
= getRegistryEntryID();
2084 IOSERVICE_TERM_SCHED_PHASE2
,
2086 (uintptr_t) (regID1
>> 32),
2087 (uintptr_t) __state
[1],
2088 (uintptr_t) options
);
2090 if (__state
[1] & kIOServiceTermPhase1State
) return;
2093 unlockForArbitration();
2094 options
|= kIOServiceRequired
;
2095 IOLockLock( gJobsLock
);
2097 if( (options
& kIOServiceSynchronous
)
2098 && (current_thread() != gIOTerminateThread
)) {
2101 wait
= (gIOTerminateThread
!= 0);
2103 // wait to become the terminate thread
2104 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
2108 gIOTerminateThread
= current_thread();
2109 gIOTerminatePhase2List
->setObject( this );
2113 while( gIOTerminateWork
)
2114 terminateWorker( options
);
2115 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
2117 // wait for the victim to go non-busy
2118 if( !haveDeadline
) {
2119 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
2120 haveDeadline
= true;
2122 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
2123 deadline
, THREAD_UNINT
);
2124 if( waitResult
== THREAD_TIMED_OUT
) {
2125 IOLog("%s[0x%qx]::terminate(kIOServiceSynchronous) timeout\n", getName(), getRegistryEntryID());
2128 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
2130 gIOTerminateThread
= 0;
2131 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2134 // ! kIOServiceSynchronous
2136 gIOTerminatePhase2List
->setObject( this );
2137 if( 0 == gIOTerminateWork
++) {
2138 if( !gIOTerminateThread
)
2139 kernel_thread_start(&terminateThread
, (void *)(uintptr_t) options
, &gIOTerminateThread
);
2141 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
2145 IOLockUnlock( gJobsLock
);
2146 lockForArbitration();
2150 void IOService::terminateThread( void * arg
, wait_result_t waitResult
)
2152 IOLockLock( gJobsLock
);
2154 while (gIOTerminateWork
)
2155 terminateWorker( (uintptr_t) arg
);
2157 thread_deallocate(gIOTerminateThread
);
2158 gIOTerminateThread
= 0;
2159 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2161 IOLockUnlock( gJobsLock
);
2164 void IOService::scheduleStop( IOService
* provider
)
2166 uint64_t regID1
= getRegistryEntryID();
2167 uint64_t regID2
= provider
->getRegistryEntryID();
2169 TLOG("%s[0x%qx]::scheduleStop(%s[0x%qx])\n", getName(), regID1
, provider
->getName(), regID2
);
2171 IOSERVICE_TERMINATE_SCHEDULE_STOP
,
2173 (uintptr_t) (regID1
>> 32),
2175 (uintptr_t) (regID2
>> 32));
2177 IOLockLock( gJobsLock
);
2178 gIOStopList
->tailQ( this );
2179 gIOStopProviderList
->tailQ( provider
);
2181 if( 0 == gIOTerminateWork
++) {
2182 if( !gIOTerminateThread
)
2183 kernel_thread_start(&terminateThread
, (void *) 0, &gIOTerminateThread
);
2185 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
2188 IOLockUnlock( gJobsLock
);
2191 void IOService::scheduleFinalize(bool now
)
2193 uint64_t regID1
= getRegistryEntryID();
2195 TLOG("%s[0x%qx]::scheduleFinalize\n", getName(), regID1
);
2197 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE
,
2199 (uintptr_t) (regID1
>> 32),
2202 if (now
|| IOUserClient::finalizeUserReferences(this))
2204 IOLockLock( gJobsLock
);
2205 gIOFinalizeList
->tailQ(this);
2206 if( 0 == gIOTerminateWork
++)
2208 if( !gIOTerminateThread
)
2209 kernel_thread_start(&terminateThread
, (void *) 0, &gIOTerminateThread
);
2211 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
2213 IOLockUnlock( gJobsLock
);
2217 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
2222 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
2224 if( false == *defer
) {
2226 if( lockForArbitration( true )) {
2227 if( false == provider
->handleIsOpen( this ))
2228 scheduleStop( provider
);
2231 message( kIOMessageServiceIsRequestingClose
, provider
, (void *)(uintptr_t) options
);
2232 if( false == provider
->handleIsOpen( this ))
2233 scheduleStop( provider
);
2236 unlockForArbitration();
2243 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
2244 OSArray
* doPhase2List
,
2245 void *unused2 __unused
,
2246 void *unused3 __unused
)
2251 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2253 iter
= victim
->getClientIterator();
2255 while( (client
= (IOService
*) iter
->getNextObject())) {
2257 regID1
= client
->getRegistryEntryID();
2258 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2259 client
->getName(), regID1
,
2260 victim
->getName(), regID2
, (long long)options
);
2262 IOSERVICE_TERMINATE_WILL
,
2264 (uintptr_t) (regID1
>> 32),
2266 (uintptr_t) (regID2
>> 32));
2268 ok
= client
->willTerminate( victim
, options
);
2269 doPhase2List
->tailQ( client
);
2275 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
,
2276 void *unused1 __unused
, void *unused2 __unused
,
2277 void *unused3 __unused
)
2282 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2284 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *)(uintptr_t) options
);
2286 iter
= victim
->getClientIterator();
2288 while( (client
= (IOService
*) iter
->getNextObject())) {
2290 regID1
= client
->getRegistryEntryID();
2291 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2292 client
->getName(), regID1
,
2293 victim
->getName(), regID2
, (long long)options
);
2295 client
->didTerminate( victim
, options
, &defer
);
2298 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2299 : IOSERVICE_TERMINATE_DID
),
2301 (uintptr_t) (regID1
>> 32),
2303 (uintptr_t) (regID2
>> 32));
2305 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2306 client
->getName(), regID1
,
2307 victim
->getName(), regID2
, defer
);
2314 void IOService::actionWillStop( IOService
* victim
, IOOptionBits options
,
2315 void *unused1 __unused
, void *unused2 __unused
,
2316 void *unused3 __unused
)
2319 IOService
* provider
;
2321 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2323 iter
= victim
->getProviderIterator();
2325 while( (provider
= (IOService
*) iter
->getNextObject())) {
2327 regID1
= provider
->getRegistryEntryID();
2328 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2329 victim
->getName(), regID2
,
2330 provider
->getName(), regID1
, (long long)options
);
2332 IOSERVICE_TERMINATE_WILL
,
2334 (uintptr_t) (regID2
>> 32),
2336 (uintptr_t) (regID1
>> 32));
2338 ok
= victim
->willTerminate( provider
, options
);
2344 void IOService::actionDidStop( IOService
* victim
, IOOptionBits options
,
2345 void *unused1 __unused
, void *unused2 __unused
,
2346 void *unused3 __unused
)
2349 IOService
* provider
;
2351 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2353 iter
= victim
->getProviderIterator();
2355 while( (provider
= (IOService
*) iter
->getNextObject())) {
2357 regID1
= provider
->getRegistryEntryID();
2358 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2359 victim
->getName(), regID2
,
2360 provider
->getName(), regID1
, (long long)options
);
2361 victim
->didTerminate( provider
, options
, &defer
);
2364 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2365 : IOSERVICE_TERMINATE_DID
),
2367 (uintptr_t) (regID2
>> 32),
2369 (uintptr_t) (regID1
>> 32));
2371 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2372 victim
->getName(), regID2
,
2373 provider
->getName(), regID1
, defer
);
2380 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
,
2381 void *unused1 __unused
, void *unused2 __unused
,
2382 void *unused3 __unused
)
2384 uint64_t regID1
= victim
->getRegistryEntryID();
2385 TLOG("%s[0x%qx]::finalize(%08llx)\n", victim
->getName(), regID1
, (long long)options
);
2387 IOSERVICE_TERMINATE_FINALIZE
,
2389 (uintptr_t) (regID1
>> 32),
2392 victim
->finalize( options
);
2395 void IOService::actionStop( IOService
* provider
, IOService
* client
,
2396 void *unused1 __unused
, void *unused2 __unused
,
2397 void *unused3 __unused
)
2399 uint64_t regID1
= provider
->getRegistryEntryID();
2400 uint64_t regID2
= client
->getRegistryEntryID();
2402 TLOG("%s[0x%qx]::stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2404 IOSERVICE_TERMINATE_STOP
,
2406 (uintptr_t) (regID1
>> 32),
2408 (uintptr_t) (regID2
>> 32));
2410 client
->stop( provider
);
2411 if( provider
->isOpen( client
))
2412 provider
->close( client
);
2414 TLOG("%s[0x%qx]::detach(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2415 client
->detach( provider
);
2418 void IOService::terminateWorker( IOOptionBits options
)
2420 OSArray
* doPhase2List
;
2421 OSArray
* didPhase2List
;
2427 IOService
* provider
;
2433 options
|= kIOServiceRequired
;
2435 doPhase2List
= OSArray::withCapacity( 16 );
2436 didPhase2List
= OSArray::withCapacity( 16 );
2437 freeList
= OSSet::withCapacity( 16 );
2438 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
2442 workDone
= gIOTerminateWork
;
2444 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
2447 gIOTerminatePhase2List
->removeObject(0);
2448 IOLockUnlock( gJobsLock
);
2450 uint64_t regID1
= victim
->getRegistryEntryID();
2452 IOSERVICE_TERM_START_PHASE2
,
2454 (uintptr_t) (regID1
>> 32),
2460 doPhase2
= victim
->lockForArbitration( true );
2462 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
2465 uint64_t regID1
= victim
->getRegistryEntryID();
2467 IOSERVICE_TERM_TRY_PHASE2
,
2469 (uintptr_t) (regID1
>> 32),
2470 (uintptr_t) victim
->__state
[1],
2473 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
2474 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
2476 if (doPhase2
&& (iter
= victim
->getClientIterator())) {
2477 while (doPhase2
&& (client
= (IOService
*) iter
->getNextObject())) {
2478 doPhase2
= (0 == (client
->__state
[1] & kIOServiceStartState
));
2481 uint64_t regID1
= client
->getRegistryEntryID();
2483 IOSERVICE_TERM_UC_DEFER
,
2485 (uintptr_t) (regID1
>> 32),
2486 (uintptr_t) client
->__state
[1],
2488 TLOG("%s[0x%qx]::defer phase2(%s[0x%qx])\n",
2489 victim
->getName(), victim
->getRegistryEntryID(),
2490 client
->getName(), client
->getRegistryEntryID());
2496 victim
->__state
[1] |= kIOServiceTermPhase2State
;
2498 victim
->unlockForArbitration();
2502 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
2503 _workLoopAction( (IOWorkLoop::Action
) &actionWillStop
,
2504 victim
, (void *)(uintptr_t) options
, NULL
);
2507 if( 0 == victim
->getClient()) {
2509 // no clients - will go to finalize
2510 victim
->scheduleFinalize(false);
2513 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
2514 victim
, (void *)(uintptr_t) options
, (void *)(uintptr_t) doPhase2List
);
2516 didPhase2List
->headQ( victim
);
2519 victim
= (IOService
*) doPhase2List
->getObject(0);
2522 doPhase2List
->removeObject(0);
2526 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
2528 if( victim
->lockForArbitration( true )) {
2529 victim
->__state
[1] |= kIOServiceTermPhase3State
;
2530 victim
->unlockForArbitration();
2532 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
2533 victim
, (void *)(uintptr_t) options
);
2534 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
2535 _workLoopAction( (IOWorkLoop::Action
) &actionDidStop
,
2536 victim
, (void *)(uintptr_t) options
, NULL
);
2538 didPhase2List
->removeObject(0);
2540 IOLockLock( gJobsLock
);
2547 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
2549 IOLockUnlock( gJobsLock
);
2550 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
2551 victim
, (void *)(uintptr_t) options
);
2552 IOLockLock( gJobsLock
);
2554 freeList
->setObject( victim
);
2555 // safe if finalize list is append only
2556 gIOFinalizeList
->removeObject(0);
2560 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
2562 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
2565 uint64_t regID1
= provider
->getRegistryEntryID();
2566 uint64_t regID2
= client
->getRegistryEntryID();
2568 if( !provider
->isChild( client
, gIOServicePlane
)) {
2569 // may be multiply queued - nop it
2570 TLOG("%s[0x%qx]::nop stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2572 IOSERVICE_TERMINATE_STOP_NOP
,
2574 (uintptr_t) (regID1
>> 32),
2576 (uintptr_t) (regID2
>> 32));
2579 // a terminated client is not ready for stop if it has clients, skip it
2580 if( (kIOServiceInactiveState
& client
->__state
[0]) && client
->getClient()) {
2581 TLOG("%s[0x%qx]::defer stop(%s[0x%qx])\n",
2582 client
->getName(), regID2
,
2583 client
->getClient()->getName(), client
->getClient()->getRegistryEntryID());
2585 IOSERVICE_TERMINATE_STOP_DEFER
,
2587 (uintptr_t) (regID1
>> 32),
2589 (uintptr_t) (regID2
>> 32));
2595 IOLockUnlock( gJobsLock
);
2596 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
2597 provider
, (void *) client
);
2598 IOLockLock( gJobsLock
);
2599 // check the finalize list now
2603 freeList
->setObject( client
);
2604 freeList
->setObject( provider
);
2606 // safe if stop list is append only
2607 gIOStopList
->removeObject( idx
);
2608 gIOStopProviderList
->removeObject( idx
);
2612 } while( doPhase3
);
2614 gIOTerminateWork
-= workDone
;
2615 moreToDo
= (gIOTerminateWork
!= 0);
2618 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
2620 IOSERVICE_TERMINATE_DONE
,
2621 (uintptr_t) gIOStopList
->getCount(), 0, 0, 0);
2624 } while( moreToDo
);
2626 IOLockUnlock( gJobsLock
);
2628 freeList
->release();
2629 doPhase2List
->release();
2630 didPhase2List
->release();
2632 IOLockLock( gJobsLock
);
2635 bool IOService::finalize( IOOptionBits options
)
2638 IOService
* provider
;
2639 uint64_t regID1
, regID2
= getRegistryEntryID();
2641 iter
= getProviderIterator();
2645 while( (provider
= (IOService
*) iter
->getNextObject())) {
2648 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
2649 /* we come down here on programmatic terminate */
2651 regID1
= provider
->getRegistryEntryID();
2652 TLOG("%s[0x%qx]::stop1(%s[0x%qx])\n", getName(), regID2
, provider
->getName(), regID1
);
2654 IOSERVICE_TERMINATE_STOP
,
2656 (uintptr_t) (regID1
>> 32),
2658 (uintptr_t) (regID2
>> 32));
2661 if( provider
->isOpen( this ))
2662 provider
->close( this );
2666 if( provider
->lockForArbitration( true )) {
2667 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2668 scheduleStop( provider
);
2669 provider
->unlockForArbitration();
2686 void IOService::doServiceTerminate( IOOptionBits options
)
2690 // a method in case someone needs to override it
2691 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2695 if( client
->isParent( this, gIOServicePlane
, true))
2696 // we are the clients only provider
2697 ok
= client
->terminate( options
);
2704 bool IOService::terminate( IOOptionBits options
)
2706 options
|= kIOServiceTerminate
;
2708 return( terminatePhase1( options
));
2711 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2717 struct ServiceOpenMessageContext
2719 IOService
* service
;
2721 IOService
* excludeClient
;
2722 IOOptionBits options
;
2725 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2727 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2729 if( object
!= context
->excludeClient
)
2730 context
->service
->messageClient( context
->type
, object
, (void *)(uintptr_t) context
->options
);
2733 bool IOService::open( IOService
* forClient
,
2734 IOOptionBits options
,
2738 ServiceOpenMessageContext context
;
2740 context
.service
= this;
2741 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2742 context
.excludeClient
= forClient
;
2743 context
.options
= options
;
2745 applyToInterested( gIOGeneralInterest
,
2746 &serviceOpenMessageApplier
, &context
);
2748 if( false == lockForArbitration(false) )
2751 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2753 ok
= handleOpen( forClient
, options
, arg
);
2755 unlockForArbitration();
2760 void IOService::close( IOService
* forClient
,
2761 IOOptionBits options
)
2766 lockForArbitration();
2768 wasClosed
= handleIsOpen( forClient
);
2770 handleClose( forClient
, options
);
2771 last
= (__state
[1] & kIOServiceTermPhase3State
);
2774 unlockForArbitration();
2777 forClient
->scheduleStop( this );
2779 else if( wasClosed
) {
2781 ServiceOpenMessageContext context
;
2783 context
.service
= this;
2784 context
.type
= kIOMessageServiceWasClosed
;
2785 context
.excludeClient
= forClient
;
2786 context
.options
= options
;
2788 applyToInterested( gIOGeneralInterest
,
2789 &serviceOpenMessageApplier
, &context
);
2793 bool IOService::isOpen( const IOService
* forClient
) const
2795 IOService
* self
= (IOService
*) this;
2798 self
->lockForArbitration();
2800 ok
= handleIsOpen( forClient
);
2802 self
->unlockForArbitration();
2807 bool IOService::handleOpen( IOService
* forClient
,
2808 IOOptionBits options
,
2813 ok
= (0 == __owner
);
2815 __owner
= forClient
;
2817 else if( options
& kIOServiceSeize
) {
2818 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2819 __owner
, (void *)(uintptr_t) options
));
2820 if( ok
&& (0 == __owner
))
2821 __owner
= forClient
;
2828 void IOService::handleClose( IOService
* forClient
,
2829 IOOptionBits options
)
2831 if( __owner
== forClient
)
2835 bool IOService::handleIsOpen( const IOService
* forClient
) const
2838 return( __owner
== forClient
);
2840 return( __owner
!= forClient
);
2844 * Probing & starting
2846 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2848 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2849 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2857 val1
= obj1
->priority
;
2860 val2
= obj2
->priority
;
2862 return ( val1
- val2
);
2865 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2867 OSDictionary
* dict
;
2868 IOService
* service
;
2869 _IOServiceNotifier
* notify
;
2870 OSSymbol
* key
= (OSSymbol
*) ref
;
2873 if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2874 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2875 else if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2876 return( notify
->priority
);
2878 else if( (service
= OSDynamicCast( IOService
, entry
)))
2879 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2886 return( (SInt32
) offset
->unsigned32BitValue());
2888 return( kIODefaultProbeScore
);
2891 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2893 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2894 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2902 val1
= IOServiceObjectOrder( obj1
, ref
);
2905 val2
= IOServiceObjectOrder( obj2
, ref
);
2907 return ( val1
- val2
);
2910 IOService
* IOService::copyClientWithCategory( const OSSymbol
* category
)
2912 IOService
* service
= 0;
2914 const OSSymbol
* nextCat
;
2916 iter
= getClientIterator();
2918 while( (service
= (IOService
*) iter
->getNextObject())) {
2919 if( kIOServiceInactiveState
& service
->__state
[0])
2921 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2922 service
->getProperty( gIOMatchCategoryKey
));
2923 if( category
== nextCat
)
2934 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2937 service
= copyClientWithCategory(category
);
2943 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2945 _IOServiceNotifierInvocation invocation
;
2949 invocation
.thread
= current_thread();
2952 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2955 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2956 _IOServiceNotifierInvocation
*, link
);
2962 ret
= (*notify
->handler
)(notify
->target
, notify
->ref
, this, notify
);
2965 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2966 _IOServiceNotifierInvocation
*, link
);
2967 if( kIOServiceNotifyWaiter
& notify
->state
) {
2968 notify
->state
&= ~kIOServiceNotifyWaiter
;
2969 WAKEUPNOTIFY( notify
);
2978 * Alloc and probe matching classes,
2979 * called on the provider instance
2982 void IOService::probeCandidates( OSOrderedSet
* matches
)
2984 OSDictionary
* match
= 0;
2987 IOService
* newInst
;
2988 OSDictionary
* props
;
2991 OSOrderedSet
* familyMatches
= 0;
2992 OSOrderedSet
* startList
;
2993 OSDictionary
* startDict
= 0;
2994 const OSSymbol
* category
;
2996 _IOServiceNotifier
* notify
;
2997 OSObject
* nextMatch
= 0;
2999 bool needReloc
= false;
3003 IOService
* client
= NULL
;
3007 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
3009 nextMatch
->retain();
3010 matches
->removeObject(nextMatch
);
3012 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
3014 lockForArbitration();
3015 if( 0 == (__state
[0] & kIOServiceInactiveState
))
3016 invokeNotifer( notify
);
3017 unlockForArbitration();
3018 nextMatch
->release();
3022 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
3023 nextMatch
->release();
3030 debugFlags
= getDebugFlags( match
);
3034 category
= OSDynamicCast( OSSymbol
,
3035 match
->getObject( gIOMatchCategoryKey
));
3037 category
= gIODefaultMatchCategoryKey
;
3039 if( (client
= copyClientWithCategory(category
)) ) {
3041 if( (debugFlags
& kIOLogMatch
) && (this != gIOResources
))
3042 LOG("%s: match category %s exists\n", getName(),
3043 category
->getCStringNoCopy());
3045 nextMatch
->release();
3054 // create a copy now in case its modified during matching
3055 props
= OSDictionary::withDictionary( match
, match
->getCount());
3058 props
->setCapacityIncrement(1);
3060 // check the nub matches
3061 if( false == matchPassive(props
, kIOServiceChangesOK
| kIOServiceClassDone
))
3064 // Check to see if driver reloc has been loaded.
3065 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
3068 if( debugFlags
& kIOLogCatalogue
)
3069 LOG("%s: stalling for module\n", getName());
3071 // If reloc hasn't been loaded, exit;
3072 // reprobing will occur after reloc has been loaded.
3076 // reorder on family matchPropertyTable score.
3077 if( 0 == familyMatches
)
3078 familyMatches
= OSOrderedSet::withCapacity( 1,
3079 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3081 familyMatches
->setObject( props
);
3086 nextMatch
->release();
3095 if( familyMatches
) {
3098 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
3101 familyMatches
->removeObject( props
);
3106 debugFlags
= getDebugFlags( props
);
3109 symbol
= OSDynamicCast( OSSymbol
,
3110 props
->getObject( gIOClassKey
));
3114 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), OBFUSCATE(symbol), OBFUSCATE(props));
3116 // alloc the driver instance
3117 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
3120 IOLog("Couldn't alloc class \"%s\"\n",
3121 symbol
->getCStringNoCopy());
3125 // init driver instance
3126 if( !(inst
->init( props
))) {
3128 if( debugFlags
& kIOLogStart
)
3129 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
3133 if( __state
[1] & kIOServiceSynchronousState
)
3134 inst
->__state
[1] |= kIOServiceSynchronousState
;
3136 // give the driver the default match category if not specified
3137 category
= OSDynamicCast( OSSymbol
,
3138 props
->getObject( gIOMatchCategoryKey
));
3140 category
= gIODefaultMatchCategoryKey
;
3141 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
3142 // attach driver instance
3143 if( !(inst
->attach( this )))
3146 // pass in score from property table
3147 score
= familyMatches
->orderObject( props
);
3149 // & probe the new driver instance
3151 if( debugFlags
& kIOLogProbe
)
3152 LOG("%s::probe(%s)\n",
3153 inst
->getMetaClass()->getClassName(), getName());
3156 newInst
= inst
->probe( this, &score
);
3157 inst
->detach( this );
3160 if( debugFlags
& kIOLogProbe
)
3161 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
3167 newPri
= OSNumber::withNumber( score
, 32 );
3169 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
3173 // add to start list for the match category
3175 startDict
= OSDictionary::withCapacity( 1 );
3176 assert( startDict
);
3177 startList
= (OSOrderedSet
*)
3178 startDict
->getObject( category
);
3179 if( 0 == startList
) {
3180 startList
= OSOrderedSet::withCapacity( 1,
3181 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3182 if( startDict
&& startList
) {
3183 startDict
->setObject( category
, startList
);
3184 startList
->release();
3187 assert( startList
);
3189 startList
->setObject( newInst
);
3197 familyMatches
->release();
3201 // start the best (until success) of each category
3203 iter
= OSCollectionIterator::withCollection( startDict
);
3205 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
3207 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
3208 assert( startList
);
3213 while( true // (!started)
3214 && (inst
= (IOService
*)startList
->getFirstObject())) {
3217 startList
->removeObject(inst
);
3220 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
3222 if( debugFlags
& kIOLogStart
) {
3224 LOG( "match category exists, skipping " );
3225 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
3226 getName(), inst
->getRetainCount());
3229 if( false == started
)
3230 started
= startCandidate( inst
);
3232 if( (debugFlags
& kIOLogStart
) && (false == started
))
3233 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
3234 inst
->getRetainCount());
3243 // adjust the busy count by +1 if matching is stalled for a module,
3244 // or -1 if a previously stalled matching is complete.
3245 lockForArbitration();
3247 uint64_t regID
= getRegistryEntryID();
3250 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
3254 IOSERVICE_MODULESTALL
,
3256 (uintptr_t) (regID
>> 32),
3260 __state
[1] |= kIOServiceModuleStallState
;
3263 } else if( __state
[1] & kIOServiceModuleStallState
) {
3266 IOSERVICE_MODULEUNSTALL
,
3268 (uintptr_t) (regID
>> 32),
3272 __state
[1] &= ~kIOServiceModuleStallState
;
3276 _adjustBusy( adjBusy
);
3277 unlockForArbitration();
3280 startDict
->release();
3284 * Start a previously attached & probed instance,
3285 * called on exporting object instance
3288 bool IOService::startCandidate( IOService
* service
)
3292 ok
= service
->attach( this );
3296 if (this != gIOResources
)
3298 // stall for any nub resources
3300 // stall for any driver resources
3301 service
->checkResources();
3304 AbsoluteTime startTime
;
3305 AbsoluteTime endTime
;
3308 if (kIOLogStart
& gIOKitDebug
)
3309 clock_get_uptime(&startTime
);
3311 ok
= service
->start(this);
3313 if (kIOLogStart
& gIOKitDebug
)
3315 clock_get_uptime(&endTime
);
3317 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
3319 SUB_ABSOLUTETIME(&endTime
, &startTime
);
3320 absolutetime_to_nanoseconds(endTime
, &nano
);
3321 if (nano
> 500000000ULL)
3322 IOLog("%s::start took %ld ms\n", service
->getName(), (long)(UInt32
)(nano
/ 1000000ULL));
3326 service
->detach( this );
3331 void IOService::publishResource( const char * key
, OSObject
* value
)
3333 const OSSymbol
* sym
;
3335 if( (sym
= OSSymbol::withCString( key
))) {
3336 publishResource( sym
, value
);
3341 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
3344 value
= (OSObject
*) gIOServiceKey
;
3346 gIOResources
->setProperty( key
, value
);
3348 if( IORecursiveLockHaveLock( gNotificationLock
))
3351 gIOResourceGenerationCount
++;
3352 gIOResources
->registerService();
3355 bool IOService::addNeededResource( const char * key
)
3357 OSObject
* resourcesProp
;
3362 resourcesProp
= getProperty( gIOResourceMatchKey
);
3364 newKey
= OSString::withCString( key
);
3365 if( (0 == resourcesProp
) || (0 == newKey
))
3368 set
= OSDynamicCast( OSSet
, resourcesProp
);
3370 set
= OSSet::withCapacity( 1 );
3372 set
->setObject( resourcesProp
);
3377 set
->setObject( newKey
);
3379 ret
= setProperty( gIOResourceMatchKey
, set
);
3385 bool IOService::checkResource( OSObject
* matching
)
3388 OSDictionary
* table
;
3390 if( (str
= OSDynamicCast( OSString
, matching
))) {
3391 if( gIOResources
->getProperty( str
))
3396 table
= resourceMatching( str
);
3397 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
3400 IOLog("%s: Can't match using: %s\n", getName(),
3401 matching
->getMetaClass()->getClassName());
3402 /* false would stall forever */
3406 if( gIOKitDebug
& kIOLogConfig
)
3407 LOG("config(%p): stalling %s\n", OBFUSCATE(IOThreadSelf()), getName());
3409 waitForService( table
);
3411 if( gIOKitDebug
& kIOLogConfig
)
3412 LOG("config(%p): waking\n", OBFUSCATE(IOThreadSelf()) );
3417 bool IOService::checkResources( void )
3419 OSObject
* resourcesProp
;
3424 resourcesProp
= getProperty( gIOResourceMatchKey
);
3425 if( 0 == resourcesProp
)
3428 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
3430 iter
= OSCollectionIterator::withCollection( set
);
3432 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
3433 ok
= checkResource( resourcesProp
);
3438 ok
= checkResource( resourcesProp
);
3444 void _IOConfigThread::configThread( void )
3446 _IOConfigThread
* inst
;
3449 if( !(inst
= new _IOConfigThread
))
3454 if (KERN_SUCCESS
!= kernel_thread_start(&_IOConfigThread::main
, inst
, &unused
))
3467 void _IOConfigThread::free( void )
3469 thread_deallocate(current_thread());
3473 void IOService::doServiceMatch( IOOptionBits options
)
3475 _IOServiceNotifier
* notify
;
3477 OSOrderedSet
* matches
;
3478 SInt32 catalogGeneration
;
3479 bool keepGuessing
= true;
3480 bool reRegistered
= true;
3483 // job->nub->deliverNotification( gIOPublishNotification,
3484 // kIOServiceRegisteredState, 0xffffffff );
3486 while( keepGuessing
) {
3488 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
3489 // the matches list should always be created by findDrivers()
3492 lockForArbitration();
3493 if( 0 == (__state
[0] & kIOServiceFirstPublishState
)) {
3494 getMetaClass()->addInstance(this);
3495 deliverNotification( gIOFirstPublishNotification
,
3496 kIOServiceFirstPublishState
, 0xffffffff );
3499 __state
[1] &= ~kIOServiceNeedConfigState
;
3500 __state
[1] |= kIOServiceConfigState
;
3501 didRegister
= (0 == (kIOServiceRegisteredState
& __state
[0]));
3502 __state
[0] |= kIOServiceRegisteredState
;
3504 keepGuessing
&= (0 == (__state
[0] & kIOServiceInactiveState
));
3505 if (reRegistered
&& keepGuessing
) {
3506 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3507 gNotifications
->getObject( gIOPublishNotification
) );
3509 while((notify
= (_IOServiceNotifier
*)
3510 iter
->getNextObject())) {
3512 if( matchPassive(notify
->matching
, 0)
3513 && (kIOServiceNotifyEnable
& notify
->state
))
3514 matches
->setObject( notify
);
3521 unlockForArbitration();
3523 if (keepGuessing
&& matches
->getCount() && (kIOReturnSuccess
== getResources()))
3524 probeCandidates( matches
);
3529 lockForArbitration();
3530 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
3532 (reRegistered
|| (catalogGeneration
!=
3533 gIOCatalogue
->getGenerationCount()))
3534 && (0 == (__state
[0] & kIOServiceInactiveState
));
3537 unlockForArbitration();
3540 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3541 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
3542 deliverNotification( gIOMatchedNotification
,
3543 kIOServiceMatchedState
, 0xffffffff );
3544 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
3545 deliverNotification( gIOFirstMatchNotification
,
3546 kIOServiceFirstMatchState
, 0xffffffff );
3549 __state
[1] &= ~kIOServiceConfigState
;
3550 scheduleTerminatePhase2();
3553 unlockForArbitration();
3556 UInt32
IOService::_adjustBusy( SInt32 delta
)
3561 bool wasQuiet
, nowQuiet
, needWake
;
3564 result
= __state
[1] & kIOServiceBusyStateMask
;
3568 next
->lockForArbitration();
3569 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
3570 wasQuiet
= (0 == count
);
3571 if (((delta
< 0) && wasQuiet
) || ((delta
> 0) && (kIOServiceBusyMax
== count
)))
3572 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next
->getName(), count
, delta
);
3575 next
->__state
[1] = (next
->__state
[1] & ~kIOServiceBusyStateMask
) | count
;
3576 nowQuiet
= (0 == count
);
3577 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
3580 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
3581 IOLockLock( gIOServiceBusyLock
);
3582 thread_wakeup( (event_t
) next
);
3583 IOLockUnlock( gIOServiceBusyLock
);
3586 next
->unlockForArbitration();
3588 if( (wasQuiet
|| nowQuiet
) ) {
3590 uint64_t regID
= next
->getRegistryEntryID();
3592 ((wasQuiet
/*nowBusy*/) ? IOSERVICE_BUSY
: IOSERVICE_NONBUSY
),
3594 (uintptr_t) (regID
>> 32),
3600 next
->__timeBusy
= mach_absolute_time();
3604 next
->__accumBusy
+= mach_absolute_time() - next
->__timeBusy
;
3605 next
->__timeBusy
= 0;
3608 MessageClientsContext context
;
3610 context
.service
= next
;
3611 context
.type
= kIOMessageServiceBusyStateChange
;
3612 context
.argument
= (void *) wasQuiet
; /*nowBusy*/
3613 context
.argSize
= 0;
3615 applyToInterestNotifiers( next
, gIOBusyInterest
,
3616 &messageClientsApplier
, &context
);
3619 if( nowQuiet
&& (next
== gIOServiceRoot
)) {
3620 OSKext::considerUnloads();
3621 IOServiceTrace(IOSERVICE_REGISTRY_QUIET
, 0, 0, 0, 0);
3626 delta
= nowQuiet
? -1 : +1;
3628 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
3633 void IOService::adjustBusy( SInt32 delta
)
3635 lockForArbitration();
3636 _adjustBusy( delta
);
3637 unlockForArbitration();
3640 uint64_t IOService::getAccumulatedBusyTime( void )
3642 uint64_t accumBusy
= __accumBusy
;
3643 uint64_t timeBusy
= __timeBusy
;
3648 accumBusy
= __accumBusy
;
3649 timeBusy
= __timeBusy
;
3651 accumBusy
+= mach_absolute_time() - timeBusy
;
3653 while (timeBusy
!= __timeBusy
);
3655 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&accumBusy
, &nano
);
3660 UInt32
IOService::getBusyState( void )
3662 return( __state
[1] & kIOServiceBusyStateMask
);
3665 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3666 mach_timespec_t
* timeout
)
3668 panic("waitForState");
3669 return (kIOReturnUnsupported
);
3672 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3676 int waitResult
= THREAD_AWAKENED
;
3677 bool computeDeadline
= true;
3678 AbsoluteTime abstime
;
3681 lockForArbitration();
3682 IOLockLock( gIOServiceBusyLock
);
3683 wait
= (value
!= (__state
[1] & mask
));
3685 __state
[1] |= kIOServiceBusyWaiterState
;
3686 unlockForArbitration();
3687 if( timeout
!= UINT64_MAX
) {
3688 if( computeDeadline
) {
3689 AbsoluteTime nsinterval
;
3690 nanoseconds_to_absolutetime(timeout
, &nsinterval
);
3691 clock_absolutetime_interval_to_deadline(nsinterval
, &abstime
);
3692 computeDeadline
= false;
3694 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
3697 assert_wait((event_t
)this, THREAD_UNINT
);
3699 unlockForArbitration();
3700 IOLockUnlock( gIOServiceBusyLock
);
3702 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
3704 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3706 if( waitResult
== THREAD_TIMED_OUT
)
3707 return( kIOReturnTimeout
);
3709 return( kIOReturnSuccess
);
3712 IOReturn
IOService::waitQuiet( uint64_t timeout
)
3715 ret
= waitForState( kIOServiceBusyStateMask
, 0, timeout
);
3716 if ((kIOReturnTimeout
== ret
) && (timeout
>= 41000000000) && (kIOWaitQuietPanics
& gIOKitDebug
))
3718 IORegistryIterator
* iter
;
3720 OSOrderedSet
* leaves
;
3722 IOService
* nextParent
;
3728 string
= IONew(char, len
);
3730 iter
= IORegistryIterator::iterateOver(this, gIOServicePlane
, kIORegistryIterateRecursively
);
3731 leaves
= OSOrderedSet::withCapacity(4);
3732 if (iter
) set
= iter
->iterateAll();
3733 if (string
&& leaves
&& set
)
3735 while ((next
= (IOService
*) set
->getLastObject()))
3737 if (next
->getBusyState())
3739 leaves
->setObject(next
);
3741 while ((nextParent
= nextParent
->getProvider()))
3743 set
->removeObject(nextParent
);
3744 leaves
->removeObject(nextParent
);
3747 set
->removeObject(next
);
3750 while ((next
= (IOService
*) leaves
->getLastObject()))
3752 l
= snprintf(s
, len
, "%s'%s'", ((s
== string
) ? "" : ", "), next
->getName());
3753 if (l
>= len
) break;
3756 leaves
->removeObject(next
);
3759 panic("busy timeout(%llds): %s", timeout
/ 1000000000ULL, string
? string
: "");
3764 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
3770 timeoutNS
= timeout
->tv_sec
;
3771 timeoutNS
*= kSecondScale
;
3772 timeoutNS
+= timeout
->tv_nsec
;
3775 timeoutNS
= UINT64_MAX
;
3777 return (waitQuiet(timeoutNS
));
3780 bool IOService::serializeProperties( OSSerialize
* s
) const
3783 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
3784 sizeof( __state
), "__state");
3786 return( super::serializeProperties(s
) );
3790 void _IOConfigThread::main(void * arg
, wait_result_t result
)
3792 _IOConfigThread
* self
= (_IOConfigThread
*) arg
;
3793 _IOServiceJob
* job
;
3797 thread_precedence_policy_data_t precedence
= { -1 };
3799 kr
= thread_policy_set(current_thread(),
3800 THREAD_PRECEDENCE_POLICY
,
3801 (thread_policy_t
) &precedence
,
3802 THREAD_PRECEDENCE_POLICY_COUNT
);
3803 if (KERN_SUCCESS
!= kr
)
3804 IOLog("thread_policy_set(%d)\n", kr
);
3810 semaphore_wait( gJobsSemaphore
);
3812 IOTakeLock( gJobsLock
);
3813 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
3815 gJobs
->removeObject(job
);
3818 // gNumConfigThreads--; // we're out of service
3819 gNumWaitingThreads
--; // we're out of service
3821 IOUnlock( gJobsLock
);
3827 if( gIOKitDebug
& kIOLogConfig
)
3828 LOG("config(%p): starting on %s, %d\n",
3829 OBFUSCATE(IOThreadSelf()), job
->nub
->getName(), job
->type
);
3831 switch( job
->type
) {
3834 nub
->doServiceMatch( job
->options
);
3838 LOG("config(%p): strange type (%d)\n",
3839 OBFUSCATE(IOThreadSelf()), job
->type
);
3846 IOTakeLock( gJobsLock
);
3847 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
3849 gNumWaitingThreads
++; // back in service
3850 // gNumConfigThreads++;
3852 if( 0 == --gNumConfigThreads
) {
3853 // IOLog("MATCH IDLE\n");
3854 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3857 IOUnlock( gJobsLock
);
3862 if( gIOKitDebug
& kIOLogConfig
)
3863 LOG("config(%p): terminating\n", OBFUSCATE(IOThreadSelf()) );
3868 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3871 int waitResult
= THREAD_AWAKENED
;
3872 bool computeDeadline
= true;
3873 AbsoluteTime deadline
;
3875 IOLockLock( gJobsLock
);
3877 wait
= (0 != gNumConfigThreads
);
3880 if( computeDeadline
) {
3881 clock_interval_to_deadline(
3882 msToWait
, kMillisecondScale
, &deadline
);
3883 computeDeadline
= false;
3885 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
3886 deadline
, THREAD_UNINT
);
3888 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3892 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3893 IOLockUnlock( gJobsLock
);
3895 if( waitResult
== THREAD_TIMED_OUT
)
3896 return( kIOReturnTimeout
);
3898 return( kIOReturnSuccess
);
3901 void IOService::cpusRunning(void)
3903 gCPUsRunning
= true;
3906 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3913 IOTakeLock( gJobsLock
);
3916 gJobs
->setLastObject( job
);
3918 count
= gNumWaitingThreads
;
3919 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3921 create
= ( (gOutstandingJobs
> count
)
3922 && ((gNumConfigThreads
< kMaxConfigThreads
)
3923 || (job
->nub
== gIOResources
)
3926 gNumConfigThreads
++;
3927 gNumWaitingThreads
++;
3930 IOUnlock( gJobsLock
);
3935 if( gIOKitDebug
& kIOLogConfig
)
3936 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3937 _IOConfigThread::configThread();
3940 semaphore_signal( gJobsSemaphore
);
3943 struct IOServiceMatchContext
3945 OSDictionary
* table
;
3953 bool IOService::instanceMatch(const OSObject
* entry
, void * context
)
3955 IOServiceMatchContext
* ctx
= (typeof(ctx
)) context
;
3956 IOService
* service
= (typeof(service
)) entry
;
3957 OSDictionary
* table
= ctx
->table
;
3958 uint32_t options
= ctx
->options
;
3959 uint32_t state
= ctx
->state
;
3966 match
= ((state
== (state
& service
->__state
[0]))
3967 && (0 == (service
->__state
[0] & kIOServiceInactiveState
)));
3969 ctx
->count
+= table
->getCount();
3970 match
= service
->matchInternal(table
, options
, &done
);
3977 if ((kIONotifyOnce
& options
) && (ctx
->done
== ctx
->count
))
3980 ctx
->result
= service
;
3983 else if (!ctx
->result
)
3985 ctx
->result
= OSSet::withObjects((const OSObject
**) &service
, 1, 1);
3989 ((OSSet
*)ctx
->result
)->setObject(service
);
3994 // internal - call with gNotificationLock
3995 OSObject
* IOService::copyExistingServices( OSDictionary
* matching
,
3996 IOOptionBits inState
, IOOptionBits options
)
3998 OSObject
* current
= 0;
4000 IOService
* service
;
4008 OSSerialize
* s
= OSSerialize::withCapacity(128);
4009 matching
->serialize(s
);
4012 if((obj
= matching
->getObject(gIOProviderClassKey
))
4014 && gIOResourcesKey
->isEqualTo(obj
)
4015 && (service
= gIOResources
))
4017 if( (inState
== (service
->__state
[0] & inState
))
4018 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
4019 && service
->matchPassive(matching
, options
))
4021 if( options
& kIONotifyOnce
)
4027 current
= OSSet::withObjects((const OSObject
**) &service
, 1, 1 );
4032 IOServiceMatchContext ctx
;
4033 ctx
.table
= matching
;
4034 ctx
.state
= inState
;
4037 ctx
.options
= options
;
4040 if ((str
= OSDynamicCast(OSString
, obj
)))
4042 const OSSymbol
* sym
= OSSymbol::withString(str
);
4043 OSMetaClass::applyToInstancesOfClassName(sym
, instanceMatch
, &ctx
);
4048 IOService::gMetaClass
.applyToInstances(instanceMatch
, &ctx
);
4052 current
= ctx
.result
;
4054 options
|= kIOServiceInternalDone
| kIOServiceClassDone
;
4055 if (current
&& (ctx
.done
!= ctx
.count
))
4058 source
= OSDynamicCast(OSSet
, current
);
4060 while ((service
= (IOService
*) source
->getAnyObject()))
4062 if (service
->matchPassive(matching
, options
))
4064 if( options
& kIONotifyOnce
)
4072 ((OSSet
*)current
)->setObject( service
);
4076 current
= OSSet::withObjects(
4077 (const OSObject
**) &service
, 1, 1 );
4080 source
->removeObject(service
);
4088 OSObject
* _current
= 0;
4090 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
4091 kIORegistryIterateRecursively
);
4095 while( (service
= (IOService
*) iter
->getNextObject())) {
4096 if( (inState
== (service
->__state
[0] & inState
))
4097 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
4098 && service
->matchPassive(matching
, 0)) {
4100 if( options
& kIONotifyOnce
) {
4106 ((OSSet
*)_current
)->setObject( service
);
4108 _current
= OSSet::withObjects(
4109 (const OSObject
**) &service
, 1, 1 );
4112 } while( !service
&& !iter
->isValid());
4117 if ( ((current
!= 0) != (_current
!= 0))
4118 || (current
&& _current
&& !current
->isEqualTo(_current
)))
4120 OSSerialize
* s1
= OSSerialize::withCapacity(128);
4121 OSSerialize
* s2
= OSSerialize::withCapacity(128);
4122 current
->serialize(s1
);
4123 _current
->serialize(s2
);
4124 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", OBFUSCATE(current
),
4125 OBFUSCATE(_current
), s
->text(), s1
->text(), s2
->text());
4130 if (_current
) _current
->release();
4136 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
4137 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
4146 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
4150 // is a lock even needed?
4153 iter
= (OSIterator
*) copyExistingServices( matching
,
4154 kIOServiceMatchedState
);
4161 IOService
* IOService::copyMatchingService( OSDictionary
* matching
)
4163 IOService
* service
;
4165 // is a lock even needed?
4168 service
= (IOService
*) copyExistingServices( matching
,
4169 kIOServiceMatchedState
, kIONotifyOnce
);
4176 struct _IOServiceMatchingNotificationHandlerRef
4178 IOServiceNotificationHandler handler
;
4182 static bool _IOServiceMatchingNotificationHandler( void * target
, void * refCon
,
4183 IOService
* newService
,
4184 IONotifier
* notifier
)
4186 return ((*((_IOServiceNotifier
*) notifier
)->compatHandler
)(target
, refCon
, newService
));
4189 // internal - call with gNotificationLock
4190 IONotifier
* IOService::setNotification(
4191 const OSSymbol
* type
, OSDictionary
* matching
,
4192 IOServiceMatchingNotificationHandler handler
, void * target
, void * ref
,
4195 _IOServiceNotifier
* notify
= 0;
4201 notify
= new _IOServiceNotifier
;
4202 if( notify
&& !notify
->init()) {
4208 notify
->handler
= handler
;
4209 notify
->target
= target
;
4210 notify
->matching
= matching
;
4212 if (handler
== &_IOServiceMatchingNotificationHandler
)
4214 notify
->compatHandler
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->handler
;
4215 notify
->ref
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->ref
;
4219 notify
->priority
= priority
;
4220 notify
->state
= kIOServiceNotifyEnable
;
4221 queue_init( ¬ify
->handlerInvocations
);
4225 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
4226 set
= OSOrderedSet::withCapacity( 1,
4227 IONotifyOrdering
, 0 );
4229 gNotifications
->setObject( type
, set
);
4233 notify
->whence
= set
;
4235 set
->setObject( notify
);
4241 // internal - call with gNotificationLock
4242 IONotifier
* IOService::doInstallNotification(
4243 const OSSymbol
* type
, OSDictionary
* matching
,
4244 IOServiceMatchingNotificationHandler handler
,
4245 void * target
, void * ref
,
4246 SInt32 priority
, OSIterator
** existing
)
4249 IONotifier
* notify
;
4250 IOOptionBits inState
;
4255 if( type
== gIOPublishNotification
)
4256 inState
= kIOServiceRegisteredState
;
4258 else if( type
== gIOFirstPublishNotification
)
4259 inState
= kIOServiceFirstPublishState
;
4261 else if( (type
== gIOMatchedNotification
)
4262 || (type
== gIOFirstMatchNotification
))
4263 inState
= kIOServiceMatchedState
;
4264 else if( type
== gIOTerminatedNotification
)
4269 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
4272 // get the current set
4273 exist
= (OSIterator
*) copyExistingServices( matching
, inState
);
4282 #if !defined(__LP64__)
4283 IONotifier
* IOService::installNotification(const OSSymbol
* type
, OSDictionary
* matching
,
4284 IOServiceNotificationHandler handler
,
4285 void * target
, void * refCon
,
4286 SInt32 priority
, OSIterator
** existing
)
4288 IONotifier
* result
;
4289 _IOServiceMatchingNotificationHandlerRef ref
;
4290 ref
.handler
= handler
;
4293 result
= (_IOServiceNotifier
*) installNotification( type
, matching
,
4294 &_IOServiceMatchingNotificationHandler
,
4295 target
, &ref
, priority
, existing
);
4297 matching
->release();
4301 #endif /* !defined(__LP64__) */
4304 IONotifier
* IOService::installNotification(
4305 const OSSymbol
* type
, OSDictionary
* matching
,
4306 IOServiceMatchingNotificationHandler handler
,
4307 void * target
, void * ref
,
4308 SInt32 priority
, OSIterator
** existing
)
4310 IONotifier
* notify
;
4314 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
4315 priority
, existing
);
4322 IONotifier
* IOService::addNotification(
4323 const OSSymbol
* type
, OSDictionary
* matching
,
4324 IOServiceNotificationHandler handler
,
4325 void * target
, void * refCon
,
4328 IONotifier
* result
;
4329 _IOServiceMatchingNotificationHandlerRef ref
;
4331 ref
.handler
= handler
;
4334 result
= addMatchingNotification(type
, matching
, &_IOServiceMatchingNotificationHandler
,
4335 target
, &ref
, priority
);
4338 matching
->release();
4343 IONotifier
* IOService::addMatchingNotification(
4344 const OSSymbol
* type
, OSDictionary
* matching
,
4345 IOServiceMatchingNotificationHandler handler
,
4346 void * target
, void * ref
,
4349 OSIterator
* existing
= NULL
;
4350 _IOServiceNotifier
* notify
;
4353 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
4354 handler
, target
, ref
, priority
, &existing
);
4356 // send notifications for existing set
4359 notify
->retain(); // in case handler remove()s
4360 while( (next
= (IOService
*) existing
->getNextObject())) {
4362 next
->lockForArbitration();
4363 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
4364 next
->invokeNotifer( notify
);
4365 next
->unlockForArbitration();
4368 existing
->release();
4374 bool IOService::syncNotificationHandler(
4375 void * /* target */, void * ref
,
4376 IOService
* newService
,
4377 IONotifier
* notifier
)
4381 if (!*((IOService
**) ref
))
4383 newService
->retain();
4384 (*(IOService
**) ref
) = newService
;
4392 IOService
* IOService::waitForMatchingService( OSDictionary
* matching
,
4395 IONotifier
* notify
= 0;
4396 // priority doesn't help us much since we need a thread wakeup
4397 SInt32 priority
= 0;
4408 result
= (IOService
*) copyExistingServices( matching
,
4409 kIOServiceMatchedState
, kIONotifyOnce
);
4412 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
4413 &IOService::syncNotificationHandler
, (void *) 0,
4414 &result
, priority
);
4417 if (UINT64_MAX
!= timeout
)
4419 AbsoluteTime deadline
;
4420 nanoseconds_to_absolutetime(timeout
, &deadline
);
4421 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
4422 SLEEPNOTIFYTO(&result
, deadline
);
4426 SLEEPNOTIFY(&result
);
4434 notify
->remove(); // dequeues
4439 IOService
* IOService::waitForService( OSDictionary
* matching
,
4440 mach_timespec_t
* timeout
)
4447 timeoutNS
= timeout
->tv_sec
;
4448 timeoutNS
*= kSecondScale
;
4449 timeoutNS
+= timeout
->tv_nsec
;
4452 timeoutNS
= UINT64_MAX
;
4454 result
= waitForMatchingService(matching
, timeoutNS
);
4456 matching
->release();
4463 void IOService::deliverNotification( const OSSymbol
* type
,
4464 IOOptionBits orNewState
, IOOptionBits andNewState
)
4466 _IOServiceNotifier
* notify
;
4468 OSArray
* willSend
= 0;
4470 lockForArbitration();
4472 if( (0 == (__state
[0] & kIOServiceInactiveState
))
4473 || (type
== gIOTerminatedNotification
)) {
4477 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
4478 gNotifications
->getObject( type
) );
4481 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
4483 if( matchPassive(notify
->matching
, 0)
4484 && (kIOServiceNotifyEnable
& notify
->state
)) {
4486 willSend
= OSArray::withCapacity(8);
4488 willSend
->setObject( notify
);
4494 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
4500 for( unsigned int idx
= 0;
4501 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
4503 invokeNotifer( notify
);
4505 willSend
->release();
4507 unlockForArbitration();
4510 IOOptionBits
IOService::getState( void ) const
4512 return( __state
[0] );
4516 * Helpers to make matching objects for simple cases
4519 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
4520 OSDictionary
* table
)
4523 const OSString
* str
;
4525 str
= OSSymbol::withString(name
);
4530 table
= OSDictionary::withCapacity( 2 );
4532 table
->setObject(gIOProviderClassKey
, (OSObject
*)str
);
4538 OSDictionary
* IOService::serviceMatching( const char * name
,
4539 OSDictionary
* table
)
4541 const OSString
* str
;
4543 str
= OSSymbol::withCString( name
);
4547 table
= serviceMatching( str
, table
);
4552 OSDictionary
* IOService::nameMatching( const OSString
* name
,
4553 OSDictionary
* table
)
4556 table
= OSDictionary::withCapacity( 2 );
4558 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
4563 OSDictionary
* IOService::nameMatching( const char * name
,
4564 OSDictionary
* table
)
4566 const OSString
* str
;
4568 str
= OSSymbol::withCString( name
);
4572 table
= nameMatching( str
, table
);
4577 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
4578 OSDictionary
* table
)
4580 table
= serviceMatching( gIOResourcesKey
, table
);
4582 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
4587 OSDictionary
* IOService::resourceMatching( const char * name
,
4588 OSDictionary
* table
)
4590 const OSSymbol
* str
;
4592 str
= OSSymbol::withCString( name
);
4596 table
= resourceMatching( str
, table
);
4602 OSDictionary
* IOService::propertyMatching( const OSSymbol
* key
, const OSObject
* value
,
4603 OSDictionary
* table
)
4605 OSDictionary
* properties
;
4607 properties
= OSDictionary::withCapacity( 2 );
4610 properties
->setObject( key
, value
);
4613 table
= OSDictionary::withCapacity( 2 );
4615 table
->setObject( gIOPropertyMatchKey
, properties
);
4617 properties
->release();
4622 OSDictionary
* IOService::registryEntryIDMatching( uint64_t entryID
,
4623 OSDictionary
* table
)
4627 num
= OSNumber::withNumber( entryID
, 64 );
4632 table
= OSDictionary::withCapacity( 2 );
4634 table
->setObject( gIORegistryEntryIDKey
, num
);
4644 * _IOServiceNotifier
4647 // wait for all threads, other than the current one,
4648 // to exit the handler
4650 void _IOServiceNotifier::wait()
4652 _IOServiceNotifierInvocation
* next
;
4657 queue_iterate( &handlerInvocations
, next
,
4658 _IOServiceNotifierInvocation
*, link
) {
4659 if( next
->thread
!= current_thread() ) {
4665 state
|= kIOServiceNotifyWaiter
;
4672 void _IOServiceNotifier::free()
4674 assert( queue_empty( &handlerInvocations
));
4678 void _IOServiceNotifier::remove()
4683 whence
->removeObject( (OSObject
*) this );
4687 matching
->release();
4691 state
&= ~kIOServiceNotifyEnable
;
4700 bool _IOServiceNotifier::disable()
4706 ret
= (0 != (kIOServiceNotifyEnable
& state
));
4707 state
&= ~kIOServiceNotifyEnable
;
4716 void _IOServiceNotifier::enable( bool was
)
4720 state
|= kIOServiceNotifyEnable
;
4722 state
&= ~kIOServiceNotifyEnable
;
4730 IOService
* IOResources::resources( void )
4734 inst
= new IOResources
;
4735 if( inst
&& !inst
->init()) {
4743 bool IOResources::init( OSDictionary
* dictionary
)
4745 // Do super init first
4746 if ( !super::init() )
4749 // Allow PAL layer to publish a value
4750 const char *property_name
;
4753 pal_get_resource_property( &property_name
, &property_value
);
4755 if( property_name
) {
4757 const OSSymbol
* sym
;
4759 if( (num
= OSNumber::withNumber(property_value
, 32)) != 0 ) {
4760 if( (sym
= OSSymbol::withCString( property_name
)) != 0 ) {
4761 this->setProperty( sym
, num
);
4771 IOReturn
IOResources::newUserClient(task_t owningTask
, void * securityID
,
4772 UInt32 type
, OSDictionary
* properties
,
4773 IOUserClient
** handler
)
4775 return( kIOReturnUnsupported
);
4778 IOWorkLoop
* IOResources::getWorkLoop() const
4780 // If we are the resource root
4781 // then use the platform's workloop
4782 if (this == (IOResources
*) gIOResources
)
4783 return getPlatform()->getWorkLoop();
4785 return IOService::getWorkLoop();
4788 bool IOResources::matchPropertyTable( OSDictionary
* table
)
4796 prop
= table
->getObject( gIOResourceMatchKey
);
4797 str
= OSDynamicCast( OSString
, prop
);
4799 ok
= (0 != getProperty( str
));
4801 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
4803 iter
= OSCollectionIterator::withCollection( set
);
4805 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
4806 ok
= (0 != getProperty( str
));
4815 void IOService::consoleLockTimer(thread_call_param_t p0
, thread_call_param_t p1
)
4817 IOService::updateConsoleUsers(NULL
, 0);
4820 void IOService::updateConsoleUsers(OSArray
* consoleUsers
, IOMessage systemMessage
)
4822 IORegistryEntry
* regEntry
;
4823 OSObject
* locked
= kOSBooleanFalse
;
4826 OSDictionary
* user
;
4827 static IOMessage sSystemPower
;
4829 regEntry
= IORegistryEntry::getRegistryRoot();
4831 if (!gIOChosenEntry
)
4832 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
4834 IOLockLock(gIOConsoleUsersLock
);
4838 sSystemPower
= systemMessage
;
4840 if ((kIOMessageSystemHasPoweredOn
== systemMessage
) && IOHibernateWasScreenLocked())
4842 locked
= kOSBooleanTrue
;
4844 #endif /* HIBERNATION */
4850 gIOConsoleLoggedIn
= false;
4852 (user
= OSDynamicCast(OSDictionary
, consoleUsers
->getObject(idx
)));
4855 gIOConsoleLoggedIn
|= ((kOSBooleanTrue
== user
->getObject(gIOConsoleSessionOnConsoleKey
))
4856 && (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionLoginDoneKey
)));
4859 num
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionScreenLockedTimeKey
));
4862 gIOConsoleLockTime
= num
? num
->unsigned32BitValue() : 0;
4865 if (!gIOConsoleLoggedIn
4866 || (kIOMessageSystemWillSleep
== sSystemPower
)
4867 || (kIOMessageSystemPagingOff
== sSystemPower
))
4869 locked
= kOSBooleanTrue
;
4871 else if (gIOConsoleLockTime
)
4874 clock_usec_t microsecs
;
4876 clock_get_calendar_microtime(&now
, µsecs
);
4877 if (gIOConsoleLockTime
> now
)
4879 AbsoluteTime deadline
;
4880 clock_interval_to_deadline(gIOConsoleLockTime
- now
, kSecondScale
, &deadline
);
4881 thread_call_enter_delayed(gIOConsoleLockCallout
, deadline
);
4885 locked
= kOSBooleanTrue
;
4889 publish
= (consoleUsers
|| (locked
!= regEntry
->getProperty(gIOConsoleLockedKey
)));
4892 regEntry
->setProperty(gIOConsoleLockedKey
, locked
);
4895 regEntry
->setProperty(gIOConsoleUsersKey
, consoleUsers
);
4897 OSIncrementAtomic( &gIOConsoleUsersSeed
);
4903 if (locked
== kOSBooleanTrue
) gIOScreenLockState
= kIOScreenLockLocked
;
4904 else if (gIOConsoleLockTime
) gIOScreenLockState
= kIOScreenLockUnlocked
;
4905 else gIOScreenLockState
= kIOScreenLockNoLock
;
4906 gIOChosenEntry
->setProperty(kIOScreenLockStateKey
, &gIOScreenLockState
, sizeof(gIOScreenLockState
));
4908 #endif /* HIBERNATION */
4910 IOLockUnlock(gIOConsoleUsersLock
);
4914 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
4916 MessageClientsContext context
;
4918 context
.service
= getServiceRoot();
4919 context
.type
= kIOMessageConsoleSecurityChange
;
4920 context
.argument
= (void *) regEntry
;
4921 context
.argSize
= 0;
4923 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest
,
4924 &messageClientsApplier
, &context
);
4928 IOReturn
IOResources::setProperties( OSObject
* properties
)
4931 const OSSymbol
* key
;
4932 OSDictionary
* dict
;
4933 OSCollectionIterator
* iter
;
4935 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
4936 if ( kIOReturnSuccess
!= err
)
4939 dict
= OSDynamicCast(OSDictionary
, properties
);
4941 return( kIOReturnBadArgument
);
4943 iter
= OSCollectionIterator::withCollection( dict
);
4945 return( kIOReturnBadArgument
);
4947 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
4949 if (gIOConsoleUsersKey
== key
) do
4951 OSArray
* consoleUsers
;
4952 consoleUsers
= OSDynamicCast(OSArray
, dict
->getObject(key
));
4955 IOService::updateConsoleUsers(consoleUsers
, 0);
4959 publishResource( key
, dict
->getObject(key
) );
4964 return( kIOReturnSuccess
);
4968 * Helpers for matching dictionaries.
4969 * Keys existing in matching are checked in properties.
4970 * Keys may be a string or OSCollection of IOStrings
4973 bool IOService::compareProperty( OSDictionary
* matching
,
4979 value
= matching
->getObject( key
);
4981 ok
= value
->isEqualTo( getProperty( key
));
4989 bool IOService::compareProperty( OSDictionary
* matching
,
4990 const OSString
* key
)
4995 value
= matching
->getObject( key
);
4997 ok
= value
->isEqualTo( getProperty( key
));
5004 bool IOService::compareProperties( OSDictionary
* matching
,
5005 OSCollection
* keys
)
5007 OSCollectionIterator
* iter
;
5008 const OSString
* key
;
5011 if( !matching
|| !keys
)
5014 iter
= OSCollectionIterator::withCollection( keys
);
5017 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
5018 ok
= compareProperty( matching
, key
);
5022 keys
->release(); // !! consume a ref !!
5027 /* Helper to add a location matching dict to the table */
5029 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
5031 OSDictionary
* dict
;
5036 dict
= OSDictionary::withCapacity( 1 );
5038 table
->setObject( gIOLocationMatchKey
, dict
);
5046 * Go looking for a provider to match a location dict.
5049 IOService
* IOService::matchLocation( IOService
* /* client */ )
5053 parent
= getProvider();
5056 parent
= parent
->matchLocation( this );
5061 bool IOService::matchInternal(OSDictionary
* table
, uint32_t options
, uint32_t * did
)
5066 IORegistryEntry
* entry
;
5069 bool changesOK
= (0 != (kIOServiceChangesOK
& options
));
5075 count
= table
->getCount();
5077 str
= OSDynamicCast(OSString
, table
->getObject(gIOProviderClassKey
));
5081 match
= ((kIOServiceClassDone
& options
) || (0 != metaCast(str
)));
5083 match
= (0 != metaCast( str
));
5084 if ((kIOServiceClassDone
& options
) && !match
) panic("classDone");
5086 if ((!match
) || (done
== count
)) break;
5089 obj
= table
->getObject( gIONameMatchKey
);
5092 match
= compareNames( obj
, changesOK
? &matched
: 0 );
5094 if( changesOK
&& matched
) {
5095 // leave a hint as to which name matched
5096 table
->setObject( gIONameMatchedKey
, matched
);
5099 if (done
== count
) break;
5102 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
5105 const OSSymbol
* sym
;
5108 sym
= copyLocation();
5110 match
= sym
->isEqualTo( str
);
5113 if ((!match
) || (done
== count
)) break;
5116 obj
= table
->getObject( gIOPropertyMatchKey
);
5119 OSDictionary
* dict
;
5120 OSDictionary
* nextDict
;
5124 dict
= dictionaryWithProperties();
5126 nextDict
= OSDynamicCast( OSDictionary
, obj
);
5130 iter
= OSCollectionIterator::withCollection(
5131 OSDynamicCast(OSCollection
, obj
));
5134 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
5135 iter
->getNextObject()))))) {
5136 match
= dict
->isEqualTo( nextDict
, nextDict
);
5145 if ((!match
) || (done
== count
)) break;
5148 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
5151 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
5152 match
= (this == entry
);
5155 if ((!match
) || (done
== count
)) break;
5158 num
= OSDynamicCast( OSNumber
, table
->getObject( gIORegistryEntryIDKey
));
5161 match
= (getRegistryEntryID() == num
->unsigned64BitValue());
5162 if ((!match
) || (done
== count
)) break;
5165 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
5169 IOService
* service
= 0;
5170 UInt32 serviceCount
= 0;
5173 iter
= getClientIterator();
5175 while( (service
= (IOService
*) iter
->getNextObject())) {
5176 if( kIOServiceInactiveState
& service
->__state
[0])
5178 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
5184 match
= (serviceCount
== num
->unsigned32BitValue());
5185 if ((!match
) || (done
== count
)) break;
5188 #define propMatch(key) \
5189 obj = table->getObject(key); \
5194 prop = copyProperty(key); \
5195 match = obj->isEqualTo(prop); \
5196 if (prop) prop->release(); \
5197 if ((!match) || (done == count)) break; \
5199 propMatch(kIOBSDNameKey
)
5200 propMatch(kIOBSDMajorKey
)
5201 propMatch(kIOBSDMinorKey
)
5202 propMatch(kIOBSDUnitKey
)
5207 if (did
) *did
= done
;
5211 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
5213 return (matchPassive(table
, changesOK
? kIOServiceChangesOK
: 0));
5216 bool IOService::matchPassive(OSDictionary
* table
, uint32_t options
)
5219 OSDictionary
* nextTable
;
5223 bool matchParent
= false;
5229 OSArray
* aliasServiceRegIds
= NULL
;
5230 IOService
* foundAlternateService
= NULL
;
5233 OSDictionary
* root
= table
;
5241 count
= table
->getCount();
5243 if (!(kIOServiceInternalDone
& options
))
5245 match
= where
->matchInternal(table
, options
, &done
);
5246 // don't call family if we've done all the entries in the table
5247 if ((!match
) || (done
== count
)) break;
5250 // pass in score from property table
5251 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
5253 // do family specific matching
5254 match
= where
->matchPropertyTable( table
, &score
);
5258 if( kIOLogMatch
& getDebugFlags( table
))
5259 LOG("%s: family specific matching fails\n", where
->getName());
5264 if (kIOServiceChangesOK
& options
) {
5266 newPri
= OSNumber::withNumber( score
, 32 );
5268 table
->setObject( gIOProbeScoreKey
, newPri
);
5274 matchParent
= false;
5276 nextTable
= OSDynamicCast(OSDictionary
,
5277 table
->getObject( gIOParentMatchKey
));
5279 // look for a matching entry anywhere up to root
5286 table
= OSDynamicCast(OSDictionary
,
5287 table
->getObject( gIOLocationMatchKey
));
5289 // look for a matching entry at matchLocation()
5291 where
= where
->getProvider();
5292 if (where
&& (where
= where
->matchLocation(where
))) continue;
5302 if(matchParent
== true) {
5303 // check if service has an alias to search its other "parents" if a parent match isn't found
5304 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, where
->getProperty(kIOServiceLegacyMatchingRegistryIDKey
));
5305 if(alternateRegistryID
!= NULL
) {
5306 if(aliasServiceRegIds
== NULL
)
5308 aliasServiceRegIds
= OSArray::withCapacity(sizeof(alternateRegistryID
));
5310 aliasServiceRegIds
->setObject(alternateRegistryID
);
5317 where
= where
->getProvider();
5319 // there were no matching parent services, check to see if there are aliased services that have a matching parent
5320 if(aliasServiceRegIds
!= NULL
) {
5321 unsigned int numAliasedServices
= aliasServiceRegIds
->getCount();
5322 if(numAliasedServices
!= 0) {
5323 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, aliasServiceRegIds
->getObject(numAliasedServices
- 1));
5324 if(alternateRegistryID
!= NULL
) {
5325 OSDictionary
* alternateMatchingDict
= IOService::registryEntryIDMatching(alternateRegistryID
->unsigned64BitValue());
5326 aliasServiceRegIds
->removeObject(numAliasedServices
- 1);
5327 if(alternateMatchingDict
!= NULL
) {
5328 OSSafeReleaseNULL(foundAlternateService
);
5329 foundAlternateService
= IOService::copyMatchingService(alternateMatchingDict
);
5330 alternateMatchingDict
->release();
5331 if(foundAlternateService
!= NULL
) {
5332 where
= foundAlternateService
;
5340 while( where
!= NULL
);
5342 OSSafeRelease(foundAlternateService
);
5343 OSSafeRelease(aliasServiceRegIds
);
5348 OSSerialize
* s
= OSSerialize::withCapacity(128);
5350 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match
, s
->text());
5359 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
5360 UInt32 type
, OSDictionary
* properties
,
5361 IOUserClient
** handler
)
5363 const OSSymbol
*userClientClass
= 0;
5364 IOUserClient
*client
;
5367 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
))
5368 return kIOReturnSuccess
;
5370 // First try my own properties for a user client class name
5371 temp
= getProperty(gIOUserClientClassKey
);
5373 if (OSDynamicCast(OSSymbol
, temp
))
5374 userClientClass
= (const OSSymbol
*) temp
;
5375 else if (OSDynamicCast(OSString
, temp
)) {
5376 userClientClass
= OSSymbol::withString((OSString
*) temp
);
5377 if (userClientClass
)
5378 setProperty(kIOUserClientClassKey
,
5379 (OSObject
*) userClientClass
);
5383 // Didn't find one so lets just bomb out now without further ado.
5384 if (!userClientClass
)
5385 return kIOReturnUnsupported
;
5387 // This reference is consumed by the IOServiceOpen call
5388 temp
= OSMetaClass::allocClassWithName(userClientClass
);
5390 return kIOReturnNoMemory
;
5392 if (OSDynamicCast(IOUserClient
, temp
))
5393 client
= (IOUserClient
*) temp
;
5396 return kIOReturnUnsupported
;
5399 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
5401 return kIOReturnBadArgument
;
5404 if ( !client
->attach(this) ) {
5406 return kIOReturnUnsupported
;
5409 if ( !client
->start(this) ) {
5410 client
->detach(this);
5412 return kIOReturnUnsupported
;
5416 return kIOReturnSuccess
;
5419 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
5420 UInt32 type
, IOUserClient
** handler
)
5422 return( kIOReturnUnsupported
);
5425 IOReturn
IOService::requestProbe( IOOptionBits options
)
5427 return( kIOReturnUnsupported
);
5431 * Convert an IOReturn to text. Subclasses which add additional
5432 * IOReturn's should override this method and call
5433 * super::stringFromReturn if the desired value is not found.
5436 const char * IOService::stringFromReturn( IOReturn rtn
)
5438 static const IONamedValue IOReturn_values
[] = {
5439 {kIOReturnSuccess
, "success" },
5440 {kIOReturnError
, "general error" },
5441 {kIOReturnNoMemory
, "memory allocation error" },
5442 {kIOReturnNoResources
, "resource shortage" },
5443 {kIOReturnIPCError
, "Mach IPC failure" },
5444 {kIOReturnNoDevice
, "no such device" },
5445 {kIOReturnNotPrivileged
, "privilege violation" },
5446 {kIOReturnBadArgument
, "invalid argument" },
5447 {kIOReturnLockedRead
, "device is read locked" },
5448 {kIOReturnLockedWrite
, "device is write locked" },
5449 {kIOReturnExclusiveAccess
, "device is exclusive access" },
5450 {kIOReturnBadMessageID
, "bad IPC message ID" },
5451 {kIOReturnUnsupported
, "unsupported function" },
5452 {kIOReturnVMError
, "virtual memory error" },
5453 {kIOReturnInternalError
, "internal driver error" },
5454 {kIOReturnIOError
, "I/O error" },
5455 {kIOReturnCannotLock
, "cannot acquire lock" },
5456 {kIOReturnNotOpen
, "device is not open" },
5457 {kIOReturnNotReadable
, "device is not readable" },
5458 {kIOReturnNotWritable
, "device is not writeable" },
5459 {kIOReturnNotAligned
, "alignment error" },
5460 {kIOReturnBadMedia
, "media error" },
5461 {kIOReturnStillOpen
, "device is still open" },
5462 {kIOReturnRLDError
, "rld failure" },
5463 {kIOReturnDMAError
, "DMA failure" },
5464 {kIOReturnBusy
, "device is busy" },
5465 {kIOReturnTimeout
, "I/O timeout" },
5466 {kIOReturnOffline
, "device is offline" },
5467 {kIOReturnNotReady
, "device is not ready" },
5468 {kIOReturnNotAttached
, "device/channel is not attached" },
5469 {kIOReturnNoChannels
, "no DMA channels available" },
5470 {kIOReturnNoSpace
, "no space for data" },
5471 {kIOReturnPortExists
, "device port already exists" },
5472 {kIOReturnCannotWire
, "cannot wire physical memory" },
5473 {kIOReturnNoInterrupt
, "no interrupt attached" },
5474 {kIOReturnNoFrames
, "no DMA frames enqueued" },
5475 {kIOReturnMessageTooLarge
, "message is too large" },
5476 {kIOReturnNotPermitted
, "operation is not permitted" },
5477 {kIOReturnNoPower
, "device is without power" },
5478 {kIOReturnNoMedia
, "media is not present" },
5479 {kIOReturnUnformattedMedia
, "media is not formatted" },
5480 {kIOReturnUnsupportedMode
, "unsupported mode" },
5481 {kIOReturnUnderrun
, "data underrun" },
5482 {kIOReturnOverrun
, "data overrun" },
5483 {kIOReturnDeviceError
, "device error" },
5484 {kIOReturnNoCompletion
, "no completion routine" },
5485 {kIOReturnAborted
, "operation was aborted" },
5486 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
5487 {kIOReturnNotResponding
, "device is not responding" },
5488 {kIOReturnInvalid
, "unanticipated driver error" },
5492 return IOFindNameForValue(rtn
, IOReturn_values
);
5496 * Convert an IOReturn to an errno.
5498 int IOService::errnoFromReturn( IOReturn rtn
)
5500 if (unix_err(err_get_code(rtn
)) == rtn
)
5501 return err_get_code(rtn
);
5505 case kIOReturnSuccess
:
5507 case kIOReturnNoMemory
:
5509 case kIOReturnNoDevice
:
5511 case kIOReturnVMError
:
5513 case kIOReturnNotPermitted
:
5515 case kIOReturnNotPrivileged
:
5517 case kIOReturnIOError
:
5519 case kIOReturnNotWritable
:
5521 case kIOReturnBadArgument
:
5523 case kIOReturnUnsupported
:
5527 case kIOReturnNoPower
:
5529 case kIOReturnDeviceError
:
5531 case kIOReturnTimeout
:
5533 case kIOReturnMessageTooLarge
:
5535 case kIOReturnNoSpace
:
5537 case kIOReturnCannotLock
:
5541 case kIOReturnBadMessageID
:
5542 case kIOReturnNoCompletion
:
5543 case kIOReturnNotAligned
:
5545 case kIOReturnNotReady
:
5547 case kIOReturnRLDError
:
5549 case kIOReturnPortExists
:
5550 case kIOReturnStillOpen
:
5552 case kIOReturnExclusiveAccess
:
5553 case kIOReturnLockedRead
:
5554 case kIOReturnLockedWrite
:
5555 case kIOReturnNotOpen
:
5556 case kIOReturnNotReadable
:
5558 case kIOReturnCannotWire
:
5559 case kIOReturnNoResources
:
5561 case kIOReturnAborted
:
5562 case kIOReturnOffline
:
5563 case kIOReturnNotResponding
:
5565 case kIOReturnBadMedia
:
5566 case kIOReturnNoMedia
:
5567 case kIOReturnNotAttached
:
5568 case kIOReturnUnformattedMedia
:
5569 return(ENXIO
); // (media error)
5570 case kIOReturnDMAError
:
5571 case kIOReturnOverrun
:
5572 case kIOReturnUnderrun
:
5573 return(EIO
); // (transfer error)
5574 case kIOReturnNoBandwidth
:
5575 case kIOReturnNoChannels
:
5576 case kIOReturnNoFrames
:
5577 case kIOReturnNoInterrupt
:
5578 return(EIO
); // (hardware error)
5579 case kIOReturnError
:
5580 case kIOReturnInternalError
:
5581 case kIOReturnInvalid
:
5582 return(EIO
); // (generic error)
5583 case kIOReturnIPCError
:
5584 return(EIO
); // (ipc error)
5586 return(EIO
); // (all other errors)
5590 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
5594 * Generic entry point for calls from the provider. A return value of
5595 * kIOReturnSuccess indicates that the message was received, and where
5596 * applicable, that it was successful.
5599 return kIOReturnUnsupported
;
5606 IOItemCount
IOService::getDeviceMemoryCount( void )
5611 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
5613 count
= array
->getCount();
5620 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
5623 IODeviceMemory
* range
;
5625 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
5627 range
= (IODeviceMemory
*) array
->getObject( index
);
5634 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
5635 IOOptionBits options
)
5637 IODeviceMemory
* range
;
5640 range
= getDeviceMemoryWithIndex( index
);
5642 map
= range
->map( options
);
5649 OSArray
* IOService::getDeviceMemory( void )
5651 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
5655 void IOService::setDeviceMemory( OSArray
* array
)
5657 setProperty( gIODeviceMemoryKey
, array
);
5661 * For machines where the transfers on an I/O bus can stall because
5662 * the CPU is in an idle mode, These APIs allow a driver to specify
5663 * the maximum bus stall that they can handle. 0 indicates no limit.
5666 setCPUSnoopDelay(UInt32 __unused ns
)
5668 #if defined(__i386__) || defined(__x86_64__)
5669 ml_set_maxsnoop(ns
);
5670 #endif /* defined(__i386__) || defined(__x86_64__) */
5676 #if defined(__i386__) || defined(__x86_64__)
5677 return ml_get_maxsnoop();
5680 #endif /* defined(__i386__) || defined(__x86_64__) */
5683 #if defined(__i386__) || defined(__x86_64__)
5685 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
)
5687 static const UInt kNoReplace
= -1U; // Must be an illegal index
5688 UInt replace
= kNoReplace
;
5689 bool setCpuDelay
= false;
5691 IORecursiveLockLock(sCpuDelayLock
);
5693 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
5694 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
5695 IOService
* holder
= NULL
;
5698 const CpuDelayEntry ne
= {service
, ns
, delayType
};
5700 // Set maximum delay.
5701 for (UInt i
= 0; i
< count
; i
++) {
5702 IOService
*thisService
= entries
[i
].fService
;
5703 bool sameType
= (delayType
== entries
[i
].fDelayType
);
5704 if ((service
== thisService
) && sameType
)
5706 else if (!thisService
) {
5707 if (kNoReplace
== replace
)
5710 else if (sameType
) {
5711 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
5715 holder
= thisService
;
5721 if (kNoReplace
== replace
)
5722 sCpuDelayData
->appendBytes(&ne
, sizeof(ne
));
5724 entries
[replace
] = ne
;
5727 ns
= -1U; // Set to max unsigned, i.e. no restriction
5729 for (UInt i
= 0; i
< count
; i
++) {
5730 // Clear a maximum delay.
5731 IOService
*thisService
= entries
[i
].fService
;
5732 if (thisService
&& (delayType
== entries
[i
].fDelayType
)) {
5733 UInt32 thisMax
= entries
[i
].fMaxDelay
;
5734 if (service
== thisService
)
5736 else if (thisMax
< ns
) {
5738 holder
= thisService
;
5743 // Check if entry found
5744 if (kNoReplace
!= replace
) {
5745 entries
[replace
].fService
= 0; // Null the entry
5752 if (holder
&& debug_boot_arg
) {
5753 strlcpy(sCPULatencyHolderName
[delayType
], holder
->getName(), sizeof(sCPULatencyHolderName
[delayType
]));
5756 // Must be safe to call from locked context
5757 if (delayType
== kCpuDelayBusStall
)
5759 ml_set_maxbusdelay(ns
);
5761 else if (delayType
== kCpuDelayInterrupt
)
5763 ml_set_maxintdelay(ns
);
5765 sCPULatencyHolder
[delayType
]->setValue(holder
? holder
->getRegistryEntryID() : 0);
5766 sCPULatencySet
[delayType
]->setValue(ns
);
5768 OSArray
* handlers
= sCpuLatencyHandlers
[delayType
];
5770 if (handlers
) for (unsigned int idx
= 0;
5771 (target
= (IOService
*) handlers
->getObject(idx
));
5774 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
5775 (void *) (uintptr_t) ns
, holder
,
5780 IORecursiveLockUnlock(sCpuDelayLock
);
5784 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
)
5786 IOReturn result
= kIOReturnNotFound
;
5790 IORecursiveLockLock(sCpuDelayLock
);
5794 if (enable
&& !sCpuLatencyHandlers
[delayType
])
5795 sCpuLatencyHandlers
[delayType
] = OSArray::withCapacity(4);
5796 array
= sCpuLatencyHandlers
[delayType
];
5799 idx
= array
->getNextIndexOfObject(target
, 0);
5804 array
->removeObject(idx
);
5805 result
= kIOReturnSuccess
;
5811 result
= kIOReturnExclusiveAccess
;
5814 array
->setObject(target
);
5816 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
5817 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
5818 UInt32 ns
= -1U; // Set to max unsigned, i.e. no restriction
5819 IOService
* holder
= NULL
;
5821 for (UInt i
= 0; i
< count
; i
++) {
5822 if (entries
[i
].fService
5823 && (delayType
== entries
[i
].fDelayType
)
5824 && (entries
[i
].fMaxDelay
< ns
)) {
5825 ns
= entries
[i
].fMaxDelay
;
5826 holder
= entries
[i
].fService
;
5829 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
5830 (void *) (uintptr_t) ns
, holder
,
5832 result
= kIOReturnSuccess
;
5837 IORecursiveLockUnlock(sCpuDelayLock
);
5842 #endif /* defined(__i386__) || defined(__x86_64__) */
5845 requireMaxBusStall(UInt32 __unused ns
)
5847 #if defined(__i386__) || defined(__x86_64__)
5848 requireMaxCpuDelay(this, ns
, kCpuDelayBusStall
);
5853 requireMaxInterruptDelay(uint32_t __unused ns
)
5855 #if defined(__i386__) || defined(__x86_64__)
5856 requireMaxCpuDelay(this, ns
, kCpuDelayInterrupt
);
5864 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
5866 IOInterruptController
*interruptController
;
5869 OSSymbol
*interruptControllerName
;
5871 IOInterruptSource
*interruptSources
;
5873 // Get the parents list from the nub.
5874 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
5875 if (array
== 0) return kIOReturnNoResources
;
5877 // Allocate space for the IOInterruptSources if needed... then return early.
5878 if (nub
->_interruptSources
== 0) {
5879 numSources
= array
->getCount();
5880 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
5881 if (interruptSources
== 0) return kIOReturnNoMemory
;
5883 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
5885 nub
->_numInterruptSources
= numSources
;
5886 nub
->_interruptSources
= interruptSources
;
5887 return kIOReturnSuccess
;
5890 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
5891 if (interruptControllerName
== 0) return kIOReturnNoResources
;
5893 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
5894 if (interruptController
== 0) return kIOReturnNoResources
;
5896 // Get the interrupt numbers from the nub.
5897 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
5898 if (array
== 0) return kIOReturnNoResources
;
5899 data
= OSDynamicCast(OSData
, array
->getObject(source
));
5900 if (data
== 0) return kIOReturnNoResources
;
5902 // Set the interruptController and interruptSource in the nub's table.
5903 interruptSources
= nub
->_interruptSources
;
5904 interruptSources
[source
].interruptController
= interruptController
;
5905 interruptSources
[source
].vectorData
= data
;
5907 return kIOReturnSuccess
;
5910 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
5914 /* Make sure the _interruptSources are set */
5915 if (_interruptSources
== 0) {
5916 ret
= resolveInterrupt(this, source
);
5917 if (ret
!= kIOReturnSuccess
) return ret
;
5920 /* Make sure the local source number is valid */
5921 if ((source
< 0) || (source
>= _numInterruptSources
))
5922 return kIOReturnNoInterrupt
;
5924 /* Look up the contoller for the local source */
5925 *interruptController
= _interruptSources
[source
].interruptController
;
5927 if (*interruptController
== NULL
) {
5928 if (!resolve
) return kIOReturnNoInterrupt
;
5930 /* Try to reslove the interrupt */
5931 ret
= resolveInterrupt(this, source
);
5932 if (ret
!= kIOReturnSuccess
) return ret
;
5934 *interruptController
= _interruptSources
[source
].interruptController
;
5937 return kIOReturnSuccess
;
5940 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
5941 IOInterruptAction handler
,
5944 IOInterruptController
*interruptController
;
5947 ret
= lookupInterrupt(source
, true, &interruptController
);
5948 if (ret
!= kIOReturnSuccess
) return ret
;
5950 /* Register the source */
5951 return interruptController
->registerInterrupt(this, source
, target
,
5952 (IOInterruptHandler
)handler
,
5956 IOReturn
IOService::unregisterInterrupt(int source
)
5958 IOInterruptController
*interruptController
;
5961 ret
= lookupInterrupt(source
, false, &interruptController
);
5962 if (ret
!= kIOReturnSuccess
) return ret
;
5964 /* Unregister the source */
5965 return interruptController
->unregisterInterrupt(this, source
);
5968 IOReturn
IOService::addInterruptStatistics(IOInterruptAccountingData
* statistics
, int source
)
5970 IOReportLegend
* legend
= NULL
;
5971 IOInterruptAccountingData
* oldValue
= NULL
;
5972 IOInterruptAccountingReporter
* newArray
= NULL
;
5973 char subgroupName
[64];
5974 int newArraySize
= 0;
5978 return kIOReturnBadArgument
;
5982 * We support statistics on a maximum of 256 interrupts per nub; if a nub
5983 * has more than 256 interrupt specifiers associated with it, and tries
5984 * to register a high interrupt index with interrupt accounting, panic.
5985 * Having more than 256 interrupts associated with a single nub is
5986 * probably a sign that something fishy is going on.
5988 if (source
> IA_INDEX_MAX
) {
5989 panic("addInterruptStatistics called for an excessively large index (%d)", source
);
5993 * TODO: This is ugly (wrapping a lock around an allocation). I'm only
5994 * leaving it as is because the likelihood of contention where we are
5995 * actually growing the array is minimal (we would realistically need
5996 * to be starting a driver for the first time, with an IOReporting
5997 * client already in place). Nonetheless, cleanup that can be done
5998 * to adhere to best practices; it'll make the code more complicated,
6001 IOLockLock(reserved
->interruptStatisticsLock
);
6004 * Lazily allocate the statistics array.
6006 if (!reserved
->interruptStatisticsArray
) {
6007 reserved
->interruptStatisticsArray
= IONew(IOInterruptAccountingReporter
, 1);
6008 assert(reserved
->interruptStatisticsArray
);
6009 reserved
->interruptStatisticsArrayCount
= 1;
6010 bzero(reserved
->interruptStatisticsArray
, sizeof(*reserved
->interruptStatisticsArray
));
6013 if (source
>= reserved
->interruptStatisticsArrayCount
) {
6015 * We're still within the range of supported indices, but we are out
6016 * of space in the current array. Do a nasty realloc (because
6017 * IORealloc isn't a thing) here. We'll double the size with each
6020 * Yes, the "next power of 2" could be more efficient; but this will
6021 * be invoked incredibly rarely. Who cares.
6023 newArraySize
= (reserved
->interruptStatisticsArrayCount
<< 1);
6025 while (newArraySize
<= source
)
6026 newArraySize
= (newArraySize
<< 1);
6027 newArray
= IONew(IOInterruptAccountingReporter
, newArraySize
);
6032 * TODO: This even zeroes the memory it is about to overwrite.
6033 * Shameful; fix it. Not particularly high impact, however.
6035 bzero(newArray
, newArraySize
* sizeof(*newArray
));
6036 memcpy(newArray
, reserved
->interruptStatisticsArray
, reserved
->interruptStatisticsArrayCount
* sizeof(*newArray
));
6037 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
6038 reserved
->interruptStatisticsArray
= newArray
;
6039 reserved
->interruptStatisticsArrayCount
= newArraySize
;
6042 if (!reserved
->interruptStatisticsArray
[source
].reporter
) {
6044 * We don't have a reporter associated with this index yet, so we
6045 * need to create one.
6048 * TODO: Some statistics do in fact have common units (time); should this be
6049 * split into separate reporters to communicate this?
6051 reserved
->interruptStatisticsArray
[source
].reporter
= IOSimpleReporter::with(this, kIOReportCategoryPower
, kIOReportUnitNone
);
6054 * Each statistic is given an identifier based on the interrupt index (which
6055 * should be unique relative to any single nub) and the statistic involved.
6056 * We should now have a sane (small and positive) index, so start
6057 * constructing the channels for statistics.
6059 for (i
= 0; i
< IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS
; i
++) {
6061 * TODO: Currently, this does not add channels for disabled statistics.
6062 * Will this be confusing for clients? If so, we should just add the
6063 * channels; we can avoid updating the channels even if they exist.
6065 if (IA_GET_STATISTIC_ENABLED(i
))
6066 reserved
->interruptStatisticsArray
[source
].reporter
->addChannel(IA_GET_CHANNEL_ID(source
, i
), kInterruptAccountingStatisticNameArray
[i
]);
6070 * We now need to add the legend for this reporter to the registry.
6072 legend
= IOReportLegend::with(OSDynamicCast(OSArray
, getProperty(kIOReportLegendKey
)));
6075 * Note that while we compose the subgroup name, we do not need to
6076 * manage its lifecycle (the reporter will handle this).
6078 snprintf(subgroupName
, sizeof(subgroupName
), "%s %d", getName(), source
);
6079 subgroupName
[sizeof(subgroupName
) - 1] = 0;
6080 legend
->addReporterLegend(reserved
->interruptStatisticsArray
[source
].reporter
, kInterruptAccountingGroupName
, subgroupName
);
6081 setProperty(kIOReportLegendKey
, legend
->getLegend());
6085 * TODO: Is this a good idea? Probably not; my assumption is it opts
6086 * all entities who register interrupts into public disclosure of all
6087 * IOReporting channels. Unfortunately, this appears to be as fine
6090 setProperty(kIOReportLegendPublicKey
, true);
6094 * Don't stomp existing entries. If we are about to, panic; this
6095 * probably means we failed to tear down our old interrupt source
6098 oldValue
= reserved
->interruptStatisticsArray
[source
].statistics
;
6101 panic("addInterruptStatistics call for index %d would have clobbered existing statistics", source
);
6104 reserved
->interruptStatisticsArray
[source
].statistics
= statistics
;
6107 * Inherit the reporter values for each statistic. The target may
6108 * be torn down as part of the runtime of the service (especially
6109 * for sleep/wake), so we inherit in order to avoid having values
6110 * reset for no apparent reason. Our statistics are ultimately
6111 * tied to the index and the sevice, not to an individual target,
6112 * so we should maintain them accordingly.
6114 interruptAccountingDataInheritChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
6116 IOLockUnlock(reserved
->interruptStatisticsLock
);
6118 return kIOReturnSuccess
;
6121 IOReturn
IOService::removeInterruptStatistics(int source
)
6123 IOInterruptAccountingData
* value
= NULL
;
6126 return kIOReturnBadArgument
;
6129 IOLockLock(reserved
->interruptStatisticsLock
);
6132 * We dynamically grow the statistics array, so an excessively
6133 * large index value has NEVER been registered. This either
6134 * means our cap on the array size is too small (unlikely), or
6135 * that we have been passed a corrupt index (this must be passed
6136 * the plain index into the interrupt specifier list).
6138 if (source
>= reserved
->interruptStatisticsArrayCount
) {
6139 panic("removeInterruptStatistics called for index %d, which was never registered", source
);
6142 assert(reserved
->interruptStatisticsArray
);
6145 * If there is no existing entry, we are most likely trying to
6146 * free an interrupt owner twice, or we have corrupted the
6149 value
= reserved
->interruptStatisticsArray
[source
].statistics
;
6152 panic("removeInterruptStatistics called for empty index %d", source
);
6156 * We update the statistics, so that any delta with the reporter
6157 * state is not lost.
6159 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
6160 reserved
->interruptStatisticsArray
[source
].statistics
= NULL
;
6161 IOLockUnlock(reserved
->interruptStatisticsLock
);
6163 return kIOReturnSuccess
;
6166 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
6168 IOInterruptController
*interruptController
;
6171 ret
= lookupInterrupt(source
, true, &interruptController
);
6172 if (ret
!= kIOReturnSuccess
) return ret
;
6174 /* Return the type */
6175 return interruptController
->getInterruptType(this, source
, interruptType
);
6178 IOReturn
IOService::enableInterrupt(int source
)
6180 IOInterruptController
*interruptController
;
6183 ret
= lookupInterrupt(source
, false, &interruptController
);
6184 if (ret
!= kIOReturnSuccess
) return ret
;
6186 /* Enable the source */
6187 return interruptController
->enableInterrupt(this, source
);
6190 IOReturn
IOService::disableInterrupt(int source
)
6192 IOInterruptController
*interruptController
;
6195 ret
= lookupInterrupt(source
, false, &interruptController
);
6196 if (ret
!= kIOReturnSuccess
) return ret
;
6198 /* Disable the source */
6199 return interruptController
->disableInterrupt(this, source
);
6202 IOReturn
IOService::causeInterrupt(int source
)
6204 IOInterruptController
*interruptController
;
6207 ret
= lookupInterrupt(source
, false, &interruptController
);
6208 if (ret
!= kIOReturnSuccess
) return ret
;
6210 /* Cause an interrupt for the source */
6211 return interruptController
->causeInterrupt(this, source
);
6214 IOReturn
IOService::configureReport(IOReportChannelList
*channelList
,
6215 IOReportConfigureAction action
,
6221 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
6222 if ( channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
6223 if (pwrMgt
) configurePowerStatesReport(action
, result
);
6224 else return kIOReturnUnsupported
;
6226 else if ( channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
6227 if (pwrMgt
) configureSimplePowerReport(action
, result
);
6228 else return kIOReturnUnsupported
;
6232 IOLockLock(reserved
->interruptStatisticsLock
);
6234 /* The array count is signed (because the interrupt indices are signed), hence the cast */
6235 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
6236 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
6238 * If the reporter is currently associated with the statistics
6239 * for an event source, we may need to update the reporter.
6241 if (reserved
->interruptStatisticsArray
[cnt
].statistics
)
6242 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
6244 reserved
->interruptStatisticsArray
[cnt
].reporter
->configureReport(channelList
, action
, result
, destination
);
6248 IOLockUnlock(reserved
->interruptStatisticsLock
);
6250 return kIOReturnSuccess
;
6253 IOReturn
IOService::updateReport(IOReportChannelList
*channelList
,
6254 IOReportUpdateAction action
,
6260 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
6261 if ( channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
6262 if (pwrMgt
) updatePowerStatesReport(action
, result
, destination
);
6263 else return kIOReturnUnsupported
;
6265 else if ( channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
6266 if (pwrMgt
) updateSimplePowerReport(action
, result
, destination
);
6267 else return kIOReturnUnsupported
;
6271 IOLockLock(reserved
->interruptStatisticsLock
);
6273 /* The array count is signed (because the interrupt indices are signed), hence the cast */
6274 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
6275 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
6277 * If the reporter is currently associated with the statistics
6278 * for an event source, we need to update the reporter.
6280 if (reserved
->interruptStatisticsArray
[cnt
].statistics
)
6281 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
6283 reserved
->interruptStatisticsArray
[cnt
].reporter
->updateReport(channelList
, action
, result
, destination
);
6287 IOLockUnlock(reserved
->interruptStatisticsLock
);
6289 return kIOReturnSuccess
;
6292 uint64_t IOService::getAuthorizationID( void )
6294 return reserved
->authorizationID
;
6297 IOReturn
IOService::setAuthorizationID( uint64_t authorizationID
)
6299 OSObject
* entitlement
;
6302 entitlement
= IOUserClient::copyClientEntitlement( current_task( ), "com.apple.private.iokit.IOServiceSetAuthorizationID" );
6306 if ( entitlement
== kOSBooleanTrue
)
6308 reserved
->authorizationID
= authorizationID
;
6310 status
= kIOReturnSuccess
;
6314 status
= kIOReturnNotPrivileged
;
6317 entitlement
->release( );
6321 status
= kIOReturnNotPrivileged
;
6328 OSMetaClassDefineReservedUsed(IOService
, 0);
6329 OSMetaClassDefineReservedUsed(IOService
, 1);
6330 OSMetaClassDefineReservedUnused(IOService
, 2);
6331 OSMetaClassDefineReservedUnused(IOService
, 3);
6332 OSMetaClassDefineReservedUnused(IOService
, 4);
6333 OSMetaClassDefineReservedUnused(IOService
, 5);
6334 OSMetaClassDefineReservedUnused(IOService
, 6);
6335 OSMetaClassDefineReservedUnused(IOService
, 7);
6337 OSMetaClassDefineReservedUsed(IOService
, 0);
6338 OSMetaClassDefineReservedUsed(IOService
, 1);
6339 OSMetaClassDefineReservedUsed(IOService
, 2);
6340 OSMetaClassDefineReservedUsed(IOService
, 3);
6341 OSMetaClassDefineReservedUsed(IOService
, 4);
6342 OSMetaClassDefineReservedUsed(IOService
, 5);
6343 OSMetaClassDefineReservedUsed(IOService
, 6);
6344 OSMetaClassDefineReservedUsed(IOService
, 7);
6346 OSMetaClassDefineReservedUnused(IOService
, 8);
6347 OSMetaClassDefineReservedUnused(IOService
, 9);
6348 OSMetaClassDefineReservedUnused(IOService
, 10);
6349 OSMetaClassDefineReservedUnused(IOService
, 11);
6350 OSMetaClassDefineReservedUnused(IOService
, 12);
6351 OSMetaClassDefineReservedUnused(IOService
, 13);
6352 OSMetaClassDefineReservedUnused(IOService
, 14);
6353 OSMetaClassDefineReservedUnused(IOService
, 15);
6354 OSMetaClassDefineReservedUnused(IOService
, 16);
6355 OSMetaClassDefineReservedUnused(IOService
, 17);
6356 OSMetaClassDefineReservedUnused(IOService
, 18);
6357 OSMetaClassDefineReservedUnused(IOService
, 19);
6358 OSMetaClassDefineReservedUnused(IOService
, 20);
6359 OSMetaClassDefineReservedUnused(IOService
, 21);
6360 OSMetaClassDefineReservedUnused(IOService
, 22);
6361 OSMetaClassDefineReservedUnused(IOService
, 23);
6362 OSMetaClassDefineReservedUnused(IOService
, 24);
6363 OSMetaClassDefineReservedUnused(IOService
, 25);
6364 OSMetaClassDefineReservedUnused(IOService
, 26);
6365 OSMetaClassDefineReservedUnused(IOService
, 27);
6366 OSMetaClassDefineReservedUnused(IOService
, 28);
6367 OSMetaClassDefineReservedUnused(IOService
, 29);
6368 OSMetaClassDefineReservedUnused(IOService
, 30);
6369 OSMetaClassDefineReservedUnused(IOService
, 31);
6370 OSMetaClassDefineReservedUnused(IOService
, 32);
6371 OSMetaClassDefineReservedUnused(IOService
, 33);
6372 OSMetaClassDefineReservedUnused(IOService
, 34);
6373 OSMetaClassDefineReservedUnused(IOService
, 35);
6374 OSMetaClassDefineReservedUnused(IOService
, 36);
6375 OSMetaClassDefineReservedUnused(IOService
, 37);
6376 OSMetaClassDefineReservedUnused(IOService
, 38);
6377 OSMetaClassDefineReservedUnused(IOService
, 39);
6378 OSMetaClassDefineReservedUnused(IOService
, 40);
6379 OSMetaClassDefineReservedUnused(IOService
, 41);
6380 OSMetaClassDefineReservedUnused(IOService
, 42);
6381 OSMetaClassDefineReservedUnused(IOService
, 43);
6382 OSMetaClassDefineReservedUnused(IOService
, 44);
6383 OSMetaClassDefineReservedUnused(IOService
, 45);
6384 OSMetaClassDefineReservedUnused(IOService
, 46);
6385 OSMetaClassDefineReservedUnused(IOService
, 47);