2 * Copyright (c) 1998-2009 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/IODeviceMemory.h>
39 #include <IOKit/IOInterrupts.h>
40 #include <IOKit/IOInterruptController.h>
41 #include <IOKit/IOPlatformExpert.h>
42 #include <IOKit/IOMessage.h>
43 #include <IOKit/IOLib.h>
44 #include <IOKit/IOKitKeysPrivate.h>
45 #include <IOKit/IOBSD.h>
46 #include <IOKit/IOUserClient.h>
47 #include <IOKit/IOWorkLoop.h>
48 #include <IOKit/IOTimeStamp.h>
49 #include <mach/sync_policy.h>
50 #include <IOKit/assert.h>
51 #include <sys/errno.h>
53 #include <machine/pal_routines.h>
58 #include "IOServicePrivate.h"
59 #include "IOKitKernelInternal.h"
61 // take lockForArbitration before LOCKNOTIFY
63 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
65 #define super IORegistryEntry
67 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
69 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
71 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
73 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
75 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
77 OSDefineMetaClassAndStructors(IOResources
, IOService
)
79 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
81 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
83 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
85 static IOPlatformExpert
* gIOPlatform
;
86 static class IOPMrootDomain
* gIOPMRootDomain
;
87 const IORegistryPlane
* gIOServicePlane
;
88 const IORegistryPlane
* gIOPowerPlane
;
89 const OSSymbol
* gIODeviceMemoryKey
;
90 const OSSymbol
* gIOInterruptControllersKey
;
91 const OSSymbol
* gIOInterruptSpecifiersKey
;
93 const OSSymbol
* gIOResourcesKey
;
94 const OSSymbol
* gIOResourceMatchKey
;
95 const OSSymbol
* gIOProviderClassKey
;
96 const OSSymbol
* gIONameMatchKey
;
97 const OSSymbol
* gIONameMatchedKey
;
98 const OSSymbol
* gIOPropertyMatchKey
;
99 const OSSymbol
* gIOLocationMatchKey
;
100 const OSSymbol
* gIOParentMatchKey
;
101 const OSSymbol
* gIOPathMatchKey
;
102 const OSSymbol
* gIOMatchCategoryKey
;
103 const OSSymbol
* gIODefaultMatchCategoryKey
;
104 const OSSymbol
* gIOMatchedServiceCountKey
;
106 const OSSymbol
* gIOMapperIDKey
;
107 const OSSymbol
* gIOUserClientClassKey
;
108 const OSSymbol
* gIOKitDebugKey
;
110 const OSSymbol
* gIOCommandPoolSizeKey
;
112 const OSSymbol
* gIOConsoleLockedKey
;
113 const OSSymbol
* gIOConsoleUsersKey
;
114 const OSSymbol
* gIOConsoleSessionUIDKey
;
115 const OSSymbol
* gIOConsoleSessionAuditIDKey
;
116 const OSSymbol
* gIOConsoleUsersSeedKey
;
117 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
118 const OSSymbol
* gIOConsoleSessionLoginDoneKey
;
119 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
120 const OSSymbol
* gIOConsoleSessionScreenLockedTimeKey
;
122 static clock_sec_t gIOConsoleLockTime
;
124 static int gIOResourceGenerationCount
;
126 const OSSymbol
* gIOServiceKey
;
127 const OSSymbol
* gIOPublishNotification
;
128 const OSSymbol
* gIOFirstPublishNotification
;
129 const OSSymbol
* gIOMatchedNotification
;
130 const OSSymbol
* gIOFirstMatchNotification
;
131 const OSSymbol
* gIOTerminatedNotification
;
133 const OSSymbol
* gIOGeneralInterest
;
134 const OSSymbol
* gIOBusyInterest
;
135 const OSSymbol
* gIOAppPowerStateInterest
;
136 const OSSymbol
* gIOPriorityPowerStateInterest
;
137 const OSSymbol
* gIOConsoleSecurityInterest
;
139 static OSDictionary
* gNotifications
;
140 static IORecursiveLock
* gNotificationLock
;
142 static IOService
* gIOResources
;
143 static IOService
* gIOServiceRoot
;
145 static OSOrderedSet
* gJobs
;
146 static semaphore_port_t gJobsSemaphore
;
147 static IOLock
* gJobsLock
;
148 static int gOutstandingJobs
;
149 static int gNumConfigThreads
;
150 static int gNumWaitingThreads
;
151 static IOLock
* gIOServiceBusyLock
;
153 static thread_t gIOTerminateThread
;
154 static UInt32 gIOTerminateWork
;
155 static OSArray
* gIOTerminatePhase2List
;
156 static OSArray
* gIOStopList
;
157 static OSArray
* gIOStopProviderList
;
158 static OSArray
* gIOFinalizeList
;
160 static SInt32 gIOConsoleUsersSeed
;
161 static OSData
* gIOConsoleUsersSeedValue
;
163 extern const OSSymbol
* gIODTPHandleKey
;
165 const OSSymbol
* gIOPlatformSleepActionKey
;
166 const OSSymbol
* gIOPlatformWakeActionKey
;
167 const OSSymbol
* gIOPlatformQuiesceActionKey
;
168 const OSSymbol
* gIOPlatformActiveActionKey
;
170 const OSSymbol
* gIOPlatformFunctionHandlerSet
;
172 static IOLock
* gIOConsoleUsersLock
;
173 static thread_call_t gIOConsoleLockCallout
;
175 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
177 #define LOCKREADNOTIFY() \
178 IORecursiveLockLock( gNotificationLock )
179 #define LOCKWRITENOTIFY() \
180 IORecursiveLockLock( gNotificationLock )
181 #define LOCKWRITE2READNOTIFY()
182 #define UNLOCKNOTIFY() \
183 IORecursiveLockUnlock( gNotificationLock )
184 #define SLEEPNOTIFY(event) \
185 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
186 #define SLEEPNOTIFYTO(event, deadline) \
187 IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT )
188 #define WAKEUPNOTIFY(event) \
189 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
191 #define randomDelay() \
192 int del = read_processor_clock(); \
193 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
196 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
198 #define queue_element(entry, element, type, field) do { \
199 vm_address_t __ele = (vm_address_t) (entry); \
200 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
201 (element) = (type) __ele; \
204 #define iterqueue(que, elt) \
205 for (queue_entry_t elt = queue_first(que); \
206 !queue_end(que, elt); \
207 elt = queue_next(elt))
209 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
211 struct ArbitrationLockQueueElement
{
220 static queue_head_t gArbitrationLockQueueActive
;
221 static queue_head_t gArbitrationLockQueueWaiting
;
222 static queue_head_t gArbitrationLockQueueFree
;
223 static IOLock
* gArbitrationLockQueueLock
;
225 bool IOService::isInactive( void ) const
226 { return( 0 != (kIOServiceInactiveState
& getState())); }
229 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
231 #if defined(__i386__) || defined(__x86_64__)
233 // Only used by the intel implementation of
234 // IOService::requireMaxBusStall(UInt32 ns)
235 // IOService::requireMaxInterruptDelay(uint32_t ns)
238 IOService
* fService
;
244 kCpuDelayBusStall
, kCpuDelayInterrupt
,
248 static OSData
*sCpuDelayData
= OSData::withCapacity(8 * sizeof(CpuDelayEntry
));
249 static IORecursiveLock
*sCpuDelayLock
= IORecursiveLockAlloc();
250 static OSArray
*sCpuLatencyHandlers
[kCpuNumDelayTypes
];
251 const OSSymbol
*sCPULatencyFunctionName
[kCpuNumDelayTypes
];
254 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
);
256 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
);
258 #endif /* defined(__i386__) || defined(__x86_64__) */
260 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
262 void IOService::initialize( void )
266 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
267 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
269 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
270 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
271 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
272 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
273 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
274 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
275 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
277 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
278 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
279 kIODefaultMatchCategoryKey
);
280 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
281 kIOMatchedServiceCountKey
);
283 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
285 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
286 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
288 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
289 gIOInterruptControllersKey
290 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
291 gIOInterruptSpecifiersKey
292 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
294 gIOMapperIDKey
= OSSymbol::withCStringNoCopy(kIOMapperIDKey
);
296 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
298 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
300 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
301 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
302 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
303 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
304 gIOConsoleSecurityInterest
= OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest
);
306 gNotifications
= OSDictionary::withCapacity( 1 );
307 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
308 kIOPublishNotification
);
309 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
310 kIOFirstPublishNotification
);
311 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
312 kIOMatchedNotification
);
313 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
314 kIOFirstMatchNotification
);
315 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
316 kIOTerminatedNotification
);
317 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
319 gIOConsoleLockedKey
= OSSymbol::withCStringNoCopy( kIOConsoleLockedKey
);
320 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
321 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
322 gIOConsoleSessionAuditIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey
);
324 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey
);
325 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey
);
326 gIOConsoleSessionLoginDoneKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey
);
327 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey
);
328 gIOConsoleSessionScreenLockedTimeKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey
);
330 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
332 gIOPlatformSleepActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformSleepActionKey
);
333 gIOPlatformWakeActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformWakeActionKey
);
334 gIOPlatformQuiesceActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformQuiesceActionKey
);
335 gIOPlatformActiveActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformActiveActionKey
);
337 gIOPlatformFunctionHandlerSet
= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet
);
338 #if defined(__i386__) || defined(__x86_64__)
339 sCPULatencyFunctionName
[kCpuDelayBusStall
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay
);
340 sCPULatencyFunctionName
[kCpuDelayInterrupt
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay
);
342 gNotificationLock
= IORecursiveLockAlloc();
344 assert( gIOServicePlane
&& gIODeviceMemoryKey
345 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
346 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
347 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
348 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
349 && gIOPublishNotification
&& gIOMatchedNotification
350 && gIOTerminatedNotification
&& gIOServiceKey
351 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
352 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
353 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
355 gJobsLock
= IOLockAlloc();
356 gJobs
= OSOrderedSet::withCapacity( 10 );
358 gIOServiceBusyLock
= IOLockAlloc();
360 gIOConsoleUsersLock
= IOLockAlloc();
362 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
364 gIOConsoleLockCallout
= thread_call_allocate(&IOService::consoleLockTimer
, NULL
);
366 IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey
, kOSBooleanTrue
);
368 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& gIOConsoleUsersLock
369 && gIOConsoleLockCallout
&& (err
== KERN_SUCCESS
) );
371 gIOResources
= IOResources::resources();
372 assert( gIOResources
);
374 gArbitrationLockQueueLock
= IOLockAlloc();
375 queue_init(&gArbitrationLockQueueActive
);
376 queue_init(&gArbitrationLockQueueWaiting
);
377 queue_init(&gArbitrationLockQueueFree
);
379 assert( gArbitrationLockQueueLock
);
381 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
382 gIOStopList
= OSArray::withCapacity( 16 );
383 gIOStopProviderList
= OSArray::withCapacity( 16 );
384 gIOFinalizeList
= OSArray::withCapacity( 16 );
385 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
388 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
391 static UInt64
getDebugFlags( OSDictionary
* props
)
393 OSNumber
* debugProp
;
396 debugProp
= OSDynamicCast( OSNumber
,
397 props
->getObject( gIOKitDebugKey
));
399 debugFlags
= debugProp
->unsigned64BitValue();
401 debugFlags
= gIOKitDebug
;
403 return( debugFlags
);
407 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
409 // Probe a matched service and return an instance to be started.
410 // The default score is from the property table, & may be altered
411 // during probe to change the start order.
413 IOService
* IOService::probe( IOService
* provider
,
419 bool IOService::start( IOService
* provider
)
424 void IOService::stop( IOService
* provider
)
428 void IOService::free( void )
430 requireMaxBusStall(0);
431 requireMaxInterruptDelay(0);
432 if( getPropertyTable())
433 unregisterAllInterest();
439 * Attach in service plane
441 bool IOService::attach( IOService
* provider
)
447 if( gIOKitDebug
& kIOLogAttach
)
448 LOG( "%s::attach(%s)\n", getName(),
449 provider
->getName());
451 provider
->lockForArbitration();
452 if( provider
->__state
[0] & kIOServiceInactiveState
)
455 ok
= attachToParent( provider
, gIOServicePlane
);
456 provider
->unlockForArbitration();
459 gIOServiceRoot
= this;
460 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
466 IOService
* IOService::getServiceRoot( void )
468 return( gIOServiceRoot
);
471 void IOService::detach( IOService
* provider
)
473 IOService
* newProvider
= 0;
477 if( gIOKitDebug
& kIOLogAttach
)
478 LOG("%s::detach(%s)\n", getName(), provider
->getName());
480 lockForArbitration();
482 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
483 && (provider
== getProvider()));
485 detachFromParent( provider
, gIOServicePlane
);
488 newProvider
= getProvider();
489 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
490 _adjustBusy( -busy
);
493 unlockForArbitration();
496 newProvider
->lockForArbitration();
497 newProvider
->_adjustBusy(1);
498 newProvider
->unlockForArbitration();
501 // check for last client detach from a terminated service
502 if( provider
->lockForArbitration( true )) {
504 provider
->_adjustBusy( -1 );
505 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
506 && (0 == provider
->getClient())) {
507 provider
->scheduleFinalize();
509 provider
->unlockForArbitration();
514 * Register instance - publish it for matching
517 void IOService::registerService( IOOptionBits options
)
523 enum { kMaxPathLen
= 256 };
524 enum { kMaxChars
= 63 };
526 IORegistryEntry
* parent
= this;
527 IORegistryEntry
* root
= getRegistryRoot();
528 while( parent
&& (parent
!= root
))
529 parent
= parent
->getParentEntry( gIOServicePlane
);
531 if( parent
!= root
) {
532 IOLog("%s: not registry member at registerService()\n", getName());
536 // Allow the Platform Expert to adjust this node.
537 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
540 if( (this != gIOResources
)
541 && (kIOLogRegister
& gIOKitDebug
)) {
543 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
545 IOLog( "Registering: " );
548 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
551 if( len
> kMaxChars
) {
555 if( (skip
= strchr( path
, '/')))
561 IOLog( "%s\n", path
);
564 IOFree( pathBuf
, kMaxPathLen
);
567 startMatching( options
);
570 void IOService::startMatching( IOOptionBits options
)
572 IOService
* provider
;
575 bool needWake
= false;
580 lockForArbitration();
582 sync
= (options
& kIOServiceSynchronous
)
583 || ((provider
= getProvider())
584 && (provider
->__state
[1] & kIOServiceSynchronousState
));
586 if ( options
& kIOServiceAsynchronous
)
589 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
590 && (0 == (__state
[0] & kIOServiceInactiveState
));
592 __state
[1] |= kIOServiceNeedConfigState
;
594 // __state[0] &= ~kIOServiceInactiveState;
596 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
597 // OSKernelStackRemaining(), getName());
600 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
604 __state
[1] |= kIOServiceSynchronousState
;
606 __state
[1] &= ~kIOServiceSynchronousState
;
608 unlockForArbitration();
612 prevBusy
= _adjustBusy( 1 );
615 IOLockLock( gIOServiceBusyLock
);
616 thread_wakeup( (event_t
) this/*&__state[1]*/ );
617 IOLockUnlock( gIOServiceBusyLock
);
619 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
621 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
625 if( (__state
[1] & kIOServiceNeedConfigState
))
626 doServiceMatch( options
);
628 lockForArbitration();
629 IOLockLock( gIOServiceBusyLock
);
631 waitAgain
= (prevBusy
< (__state
[1] & kIOServiceBusyStateMask
));
633 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
635 __state
[1] &= ~kIOServiceSyncPubState
;
637 unlockForArbitration();
640 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
642 IOLockUnlock( gIOServiceBusyLock
);
644 thread_block(THREAD_CONTINUE_NULL
);
646 } while( waitAgain
);
650 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
652 OSDictionary
* table
;
662 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
665 set
= (OSSet
*) copyExistingServices( table
,
666 kIOServiceRegisteredState
,
667 kIOServiceExistingSet
);
672 count
+= set
->getCount();
675 allSet
->merge((const OSSet
*) set
);
683 if( getDebugFlags( table
) & kIOLogMatch
)
684 LOG("Matching service count = %ld\n", (long)count
);
686 newTables
->removeObject(table
);
690 while( (service
= (IOService
*) allSet
->getAnyObject())) {
691 service
->startMatching(kIOServiceAsynchronous
);
692 allSet
->removeObject(service
);
697 newTables
->release();
699 return( kIOReturnSuccess
);
702 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
703 IOOptionBits options
)
707 job
= new _IOServiceJob
;
708 if( job
&& !job
->init()) {
716 job
->options
= options
;
717 nub
->retain(); // thread will release()
725 * Called on a registered service to see if it matches
729 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
731 return( matchPropertyTable(table
) );
734 bool IOService::matchPropertyTable( OSDictionary
* table
)
740 * Called on a matched service to allocate resources
741 * before first driver is attached.
744 IOReturn
IOService::getResources( void )
746 return( kIOReturnSuccess
);
750 * Client/provider accessors
753 IOService
* IOService::getProvider( void ) const
755 IOService
* self
= (IOService
*) this;
760 generation
= getGenerationCount();
761 if( __providerGeneration
== generation
)
764 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
765 if( parent
== IORegistryEntry::getRegistryRoot())
766 /* root is not an IOService */
769 self
->__provider
= parent
;
770 // save the count before getParentEntry()
771 self
->__providerGeneration
= generation
;
776 IOWorkLoop
* IOService::getWorkLoop() const
778 IOService
*provider
= getProvider();
781 return provider
->getWorkLoop();
786 OSIterator
* IOService::getProviderIterator( void ) const
788 return( getParentIterator( gIOServicePlane
));
791 IOService
* IOService::getClient( void ) const
793 return( (IOService
*) getChildEntry( gIOServicePlane
));
796 OSIterator
* IOService::getClientIterator( void ) const
798 return( getChildIterator( gIOServicePlane
));
801 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
802 const IOService
* client
,
803 const IOService
* provider
)
805 _IOOpenServiceIterator
* inst
;
810 inst
= new _IOOpenServiceIterator
;
812 if( inst
&& !inst
->init()) {
818 inst
->client
= client
;
819 inst
->provider
= provider
;
825 void _IOOpenServiceIterator::free()
829 last
->unlockForArbitration();
833 OSObject
* _IOOpenServiceIterator::getNextObject()
838 last
->unlockForArbitration();
840 while( (next
= (IOService
*) iter
->getNextObject())) {
842 next
->lockForArbitration();
843 if( (client
&& (next
->isOpen( client
)))
844 || (provider
&& (provider
->isOpen( next
))) )
846 next
->unlockForArbitration();
854 bool _IOOpenServiceIterator::isValid()
856 return( iter
->isValid() );
859 void _IOOpenServiceIterator::reset()
862 last
->unlockForArbitration();
868 OSIterator
* IOService::getOpenProviderIterator( void ) const
870 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
873 OSIterator
* IOService::getOpenClientIterator( void ) const
875 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
879 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
880 bool waitForFunction
,
881 void *param1
, void *param2
,
882 void *param3
, void *param4
)
884 IOReturn result
= kIOReturnUnsupported
;
887 if (gIOPlatformFunctionHandlerSet
== functionName
)
889 #if defined(__i386__) || defined(__x86_64__)
890 const OSSymbol
* functionHandlerName
= (const OSSymbol
*) param1
;
891 IOService
* target
= (IOService
*) param2
;
892 bool enable
= (param3
!= 0);
894 if (sCPULatencyFunctionName
[kCpuDelayBusStall
] == functionHandlerName
)
895 result
= setLatencyHandler(kCpuDelayBusStall
, target
, enable
);
896 else if (sCPULatencyFunctionName
[kCpuDelayInterrupt
] == param1
)
897 result
= setLatencyHandler(kCpuDelayInterrupt
, target
, enable
);
898 #endif /* defined(__i386__) || defined(__x86_64__) */
901 if ((kIOReturnUnsupported
== result
) && (provider
= getProvider())) {
902 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
903 param1
, param2
, param3
, param4
);
909 IOReturn
IOService::callPlatformFunction( const char * functionName
,
910 bool waitForFunction
,
911 void *param1
, void *param2
,
912 void *param3
, void *param4
)
914 IOReturn result
= kIOReturnNoMemory
;
915 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
917 if (functionSymbol
!= 0) {
918 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
919 param1
, param2
, param3
, param4
);
920 functionSymbol
->release();
928 * Accessors for global services
931 IOPlatformExpert
* IOService::getPlatform( void )
933 return( gIOPlatform
);
936 class IOPMrootDomain
* IOService::getPMRootDomain( void )
938 return( gIOPMRootDomain
);
941 IOService
* IOService::getResourceService( void )
943 return( gIOResources
);
946 void IOService::setPlatform( IOPlatformExpert
* platform
)
948 gIOPlatform
= platform
;
949 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
952 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
954 gIOPMRootDomain
= rootDomain
;
955 publishResource("IOKit");
962 bool IOService::lockForArbitration( bool isSuccessRequired
)
966 ArbitrationLockQueueElement
* element
;
967 ArbitrationLockQueueElement
* active
;
968 ArbitrationLockQueueElement
* waiting
;
970 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
972 // lock global access
973 IOTakeLock( gArbitrationLockQueueLock
);
975 // obtain an unused queue element
976 if( !queue_empty( &gArbitrationLockQueueFree
)) {
977 queue_remove_first( &gArbitrationLockQueueFree
,
979 ArbitrationLockQueueElement
*,
982 element
= IONew( ArbitrationLockQueueElement
, 1 );
986 // prepare the queue element
987 element
->thread
= IOThreadSelf();
988 element
->service
= this;
990 element
->required
= isSuccessRequired
;
991 element
->aborted
= false;
993 // determine whether this object is already locked (ie. on active queue)
995 queue_iterate( &gArbitrationLockQueueActive
,
997 ArbitrationLockQueueElement
*,
1000 if( active
->service
== element
->service
) {
1006 if( found
) { // this object is already locked
1008 // determine whether it is the same or a different thread trying to lock
1009 if( active
->thread
!= element
->thread
) { // it is a different thread
1011 ArbitrationLockQueueElement
* victim
= 0;
1013 // before placing this new thread on the waiting queue, we look for
1014 // a deadlock cycle...
1017 // determine whether the active thread holding the object we
1018 // want is waiting for another object to be unlocked
1020 queue_iterate( &gArbitrationLockQueueWaiting
,
1022 ArbitrationLockQueueElement
*,
1025 if( waiting
->thread
== active
->thread
) {
1026 assert( false == waiting
->aborted
);
1032 if( found
) { // yes, active thread waiting for another object
1034 // this may be a candidate for rejection if the required
1035 // flag is not set, should we detect a deadlock later on
1036 if( false == waiting
->required
)
1039 // find the thread that is holding this other object, that
1040 // is blocking the active thread from proceeding (fun :-)
1042 queue_iterate( &gArbitrationLockQueueActive
,
1043 active
, // (reuse active queue element)
1044 ArbitrationLockQueueElement
*,
1047 if( active
->service
== waiting
->service
) {
1053 // someone must be holding it or it wouldn't be waiting
1056 if( active
->thread
== element
->thread
) {
1058 // doh, it's waiting for the thread that originated
1059 // this whole lock (ie. current thread) -> deadlock
1060 if( false == element
->required
) { // willing to fail?
1062 // the originating thread doesn't have the required
1063 // flag, so it can fail
1064 success
= false; // (fail originating lock request)
1065 break; // (out of while)
1067 } else { // originating thread is not willing to fail
1069 // see if we came across a waiting thread that did
1070 // not have the 'required' flag set: we'll fail it
1073 // we do have a willing victim, fail it's lock
1074 victim
->aborted
= true;
1076 // take the victim off the waiting queue
1077 queue_remove( &gArbitrationLockQueueWaiting
,
1079 ArbitrationLockQueueElement
*,
1083 IOLockWakeup( gArbitrationLockQueueLock
,
1085 /* one thread */ true );
1087 // allow this thread to proceed (ie. wait)
1088 success
= true; // (put request on wait queue)
1089 break; // (out of while)
1092 // all the waiting threads we came across in
1093 // finding this loop had the 'required' flag
1094 // set, so we've got a deadlock we can't avoid
1095 panic("I/O Kit: Unrecoverable deadlock.");
1099 // repeat while loop, redefining active thread to be the
1100 // thread holding "this other object" (see above), and
1101 // looking for threads waiting on it; note the active
1102 // variable points to "this other object" already... so
1103 // there nothing to do in this else clause.
1105 } else { // no, active thread is not waiting for another object
1107 success
= true; // (put request on wait queue)
1108 break; // (out of while)
1112 if( success
) { // put the request on the waiting queue?
1113 kern_return_t wait_result
;
1115 // place this thread on the waiting queue and put it to sleep;
1116 // we place it at the tail of the queue...
1117 queue_enter( &gArbitrationLockQueueWaiting
,
1119 ArbitrationLockQueueElement
*,
1122 // declare that this thread will wait for a given event
1123 restart_sleep
: wait_result
= assert_wait( element
,
1124 element
->required
? THREAD_UNINT
1125 : THREAD_INTERRUPTIBLE
);
1127 // unlock global access
1128 IOUnlock( gArbitrationLockQueueLock
);
1130 // put thread to sleep, waiting for our event to fire...
1131 if (wait_result
== THREAD_WAITING
)
1132 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1135 // ...and we've been woken up; we might be in one of two states:
1136 // (a) we've been aborted and our queue element is not on
1137 // any of the three queues, but is floating around
1138 // (b) we're allowed to proceed with the lock and we have
1139 // already been moved from the waiting queue to the
1141 // ...plus a 3rd state, should the thread have been interrupted:
1142 // (c) we're still on the waiting queue
1144 // determine whether we were interrupted out of our sleep
1145 if( THREAD_INTERRUPTED
== wait_result
) {
1147 // re-lock global access
1148 IOTakeLock( gArbitrationLockQueueLock
);
1150 // determine whether we're still on the waiting queue
1152 queue_iterate( &gArbitrationLockQueueWaiting
,
1153 waiting
, // (reuse waiting queue element)
1154 ArbitrationLockQueueElement
*,
1157 if( waiting
== element
) {
1163 if( found
) { // yes, we're still on the waiting queue
1165 // determine whether we're willing to fail
1166 if( false == element
->required
) {
1168 // mark us as aborted
1169 element
->aborted
= true;
1171 // take us off the waiting queue
1172 queue_remove( &gArbitrationLockQueueWaiting
,
1174 ArbitrationLockQueueElement
*,
1176 } else { // we are not willing to fail
1178 // ignore interruption, go back to sleep
1183 // unlock global access
1184 IOUnlock( gArbitrationLockQueueLock
);
1186 // proceed as though this were a normal wake up
1187 wait_result
= THREAD_AWAKENED
;
1190 assert( THREAD_AWAKENED
== wait_result
);
1192 // determine whether we've been aborted while we were asleep
1193 if( element
->aborted
) {
1194 assert( false == element
->required
);
1196 // re-lock global access
1197 IOTakeLock( gArbitrationLockQueueLock
);
1199 action
= kPutOnFreeQueue
;
1201 } else { // we weren't aborted, so we must be ready to go :-)
1203 // we've already been moved from waiting to active queue
1207 } else { // the lock request is to be failed
1209 // return unused queue element to queue
1210 action
= kPutOnFreeQueue
;
1212 } else { // it is the same thread, recursive access is allowed
1214 // add one level of recursion
1217 // return unused queue element to queue
1218 action
= kPutOnFreeQueue
;
1221 } else { // this object is not already locked, so let this thread through
1222 action
= kPutOnActiveQueue
;
1226 // put the new element on a queue
1227 if( kPutOnActiveQueue
== action
) {
1228 queue_enter( &gArbitrationLockQueueActive
,
1230 ArbitrationLockQueueElement
*,
1232 } else if( kPutOnFreeQueue
== action
) {
1233 queue_enter( &gArbitrationLockQueueFree
,
1235 ArbitrationLockQueueElement
*,
1238 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1241 // unlock global access
1242 IOUnlock( gArbitrationLockQueueLock
);
1247 void IOService::unlockForArbitration( void )
1250 ArbitrationLockQueueElement
* element
;
1252 // lock global access
1253 IOTakeLock( gArbitrationLockQueueLock
);
1255 // find the lock element for this object (ie. on active queue)
1257 queue_iterate( &gArbitrationLockQueueActive
,
1259 ArbitrationLockQueueElement
*,
1262 if( element
->service
== this ) {
1270 // determine whether the lock has been taken recursively
1271 if( element
->count
> 1 ) {
1272 // undo one level of recursion
1277 // remove it from the active queue
1278 queue_remove( &gArbitrationLockQueueActive
,
1280 ArbitrationLockQueueElement
*,
1283 // put it on the free queue
1284 queue_enter( &gArbitrationLockQueueFree
,
1286 ArbitrationLockQueueElement
*,
1289 // determine whether a thread is waiting for object (head to tail scan)
1291 queue_iterate( &gArbitrationLockQueueWaiting
,
1293 ArbitrationLockQueueElement
*,
1296 if( element
->service
== this ) {
1302 if ( found
) { // we found an interested thread on waiting queue
1304 // remove it from the waiting queue
1305 queue_remove( &gArbitrationLockQueueWaiting
,
1307 ArbitrationLockQueueElement
*,
1310 // put it on the active queue
1311 queue_enter( &gArbitrationLockQueueActive
,
1313 ArbitrationLockQueueElement
*,
1316 // wake the waiting thread
1317 IOLockWakeup( gArbitrationLockQueueLock
,
1319 /* one thread */ true );
1323 // unlock global access
1324 IOUnlock( gArbitrationLockQueueLock
);
1327 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1330 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1331 context
, gIOServicePlane
);
1334 void IOService::applyToClients( IOServiceApplierFunction applier
,
1337 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1338 context
, gIOServicePlane
);
1347 // send a message to a client or interested party of this service
1348 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1349 void * argument
, vm_size_t argSize
)
1352 IOService
* service
;
1353 _IOServiceInterestNotifier
* notify
;
1355 if( (service
= OSDynamicCast( IOService
, client
)))
1356 ret
= service
->message( type
, this, argument
);
1358 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1360 _IOServiceNotifierInvocation invocation
;
1363 invocation
.thread
= current_thread();
1366 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1369 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1370 _IOServiceNotifierInvocation
*, link
);
1376 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1377 type
, this, argument
, argSize
);
1380 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1381 _IOServiceNotifierInvocation
*, link
);
1382 if( kIOServiceNotifyWaiter
& notify
->state
) {
1383 notify
->state
&= ~kIOServiceNotifyWaiter
;
1384 WAKEUPNOTIFY( notify
);
1389 ret
= kIOReturnSuccess
;
1392 ret
= kIOReturnBadArgument
;
1398 applyToInterestNotifiers(const IORegistryEntry
*target
,
1399 const OSSymbol
* typeOfInterest
,
1400 OSObjectApplierFunction applier
,
1403 OSArray
* copyArray
= 0;
1407 IOCommand
*notifyList
=
1408 OSDynamicCast( IOCommand
, target
->getProperty( typeOfInterest
));
1411 copyArray
= OSArray::withCapacity(1);
1413 // iterate over queue, entry is set to each element in the list
1414 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1415 _IOServiceInterestNotifier
* notify
;
1417 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1418 copyArray
->setObject(notify
);
1427 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1428 (*applier
)(next
, context
);
1429 copyArray
->release();
1433 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1434 OSObjectApplierFunction applier
,
1437 if (gIOGeneralInterest
== typeOfInterest
)
1438 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1439 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1442 struct MessageClientsContext
{
1443 IOService
* service
;
1450 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1453 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1455 ret
= context
->service
->messageClient( context
->type
,
1456 object
, context
->argument
, context
->argSize
);
1457 if( kIOReturnSuccess
!= ret
)
1461 // send a message to all clients
1462 IOReturn
IOService::messageClients( UInt32 type
,
1463 void * argument
, vm_size_t argSize
)
1465 MessageClientsContext context
;
1467 context
.service
= this;
1468 context
.type
= type
;
1469 context
.argument
= argument
;
1470 context
.argSize
= argSize
;
1471 context
.ret
= kIOReturnSuccess
;
1473 applyToInterested( gIOGeneralInterest
,
1474 &messageClientsApplier
, &context
);
1476 return( context
.ret
);
1479 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1480 IOOptionBits response
)
1482 return( kIOReturnUnsupported
);
1485 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1486 IOServiceInterestHandler handler
, void * target
, void * ref
)
1488 _IOServiceInterestNotifier
* notify
= 0;
1490 if( (typeOfInterest
!= gIOGeneralInterest
)
1491 && (typeOfInterest
!= gIOBusyInterest
)
1492 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1493 && (typeOfInterest
!= gIOConsoleSecurityInterest
)
1494 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1497 lockForArbitration();
1498 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1500 notify
= new _IOServiceInterestNotifier
;
1501 if( notify
&& !notify
->init()) {
1507 notify
->handler
= handler
;
1508 notify
->target
= target
;
1510 notify
->state
= kIOServiceNotifyEnable
;
1511 queue_init( ¬ify
->handlerInvocations
);
1517 // Get the head of the notifier linked list
1518 IOCommand
*notifyList
= (IOCommand
*) getProperty( typeOfInterest
);
1519 if (!notifyList
|| !OSDynamicCast(IOCommand
, notifyList
)) {
1520 notifyList
= OSTypeAlloc(IOCommand
);
1523 setProperty( typeOfInterest
, notifyList
);
1524 notifyList
->release();
1529 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1530 notify
->retain(); // ref'ed while in list
1536 unlockForArbitration();
1541 static void cleanInterestList( OSObject
* head
)
1543 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1548 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1549 queue_next(entry
) = queue_prev(entry
) = 0;
1551 _IOServiceInterestNotifier
* notify
;
1553 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1559 void IOService::unregisterAllInterest( void )
1561 cleanInterestList( getProperty( gIOGeneralInterest
));
1562 cleanInterestList( getProperty( gIOBusyInterest
));
1563 cleanInterestList( getProperty( gIOAppPowerStateInterest
));
1564 cleanInterestList( getProperty( gIOPriorityPowerStateInterest
));
1565 cleanInterestList( getProperty( gIOConsoleSecurityInterest
));
1569 * _IOServiceInterestNotifier
1572 // wait for all threads, other than the current one,
1573 // to exit the handler
1575 void _IOServiceInterestNotifier::wait()
1577 _IOServiceNotifierInvocation
* next
;
1582 queue_iterate( &handlerInvocations
, next
,
1583 _IOServiceNotifierInvocation
*, link
) {
1584 if( next
->thread
!= current_thread() ) {
1590 state
|= kIOServiceNotifyWaiter
;
1597 void _IOServiceInterestNotifier::free()
1599 assert( queue_empty( &handlerInvocations
));
1603 void _IOServiceInterestNotifier::remove()
1607 if( queue_next( &chain
)) {
1609 queue_next( &chain
) = queue_prev( &chain
) = 0;
1613 state
&= ~kIOServiceNotifyEnable
;
1622 bool _IOServiceInterestNotifier::disable()
1628 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1629 state
&= ~kIOServiceNotifyEnable
;
1638 void _IOServiceInterestNotifier::enable( bool was
)
1642 state
|= kIOServiceNotifyEnable
;
1644 state
&= ~kIOServiceNotifyEnable
;
1648 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1654 #define tailQ(o) setObject(o)
1655 #define headQ(o) setObject(0, o)
1656 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
1658 static void _workLoopAction( IOWorkLoop::Action action
,
1659 IOService
* service
,
1660 void * p0
= 0, void * p1
= 0,
1661 void * p2
= 0, void * p3
= 0 )
1665 if( (wl
= service
->getWorkLoop())) {
1667 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1670 (*action
)( service
, p0
, p1
, p2
, p3
);
1673 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1677 // if its our only provider
1678 ok
= isParent( provider
, gIOServicePlane
, true);
1682 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1683 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1690 bool IOService::terminatePhase1( IOOptionBits options
)
1695 OSArray
* makeInactive
;
1696 int waitResult
= THREAD_AWAKENED
;
1700 bool startPhase2
= false;
1702 TLOG("%s::terminatePhase1(%08llx)\n", getName(), (long long)options
);
1704 uint64_t regID
= getRegistryEntryID();
1706 IOSERVICE_TERMINATE_PHASE1
,
1708 (uintptr_t) (regID
>> 32),
1710 (uintptr_t) options
);
1713 if( options
& kIOServiceRecursing
) {
1714 __state
[1] |= kIOServiceRecursing
;
1719 makeInactive
= OSArray::withCapacity( 16 );
1728 didInactive
= victim
->lockForArbitration( true );
1730 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1732 victim
->__state
[0] |= kIOServiceInactiveState
;
1733 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1734 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1737 victim
->__state
[1] |= kIOServiceTermPhase1State
;
1739 victim
->_adjustBusy( 1 );
1741 } else if (victim
!= this) do {
1743 IOLockLock(gIOServiceBusyLock
);
1744 wait
= (victim
->__state
[1] & kIOServiceTermPhase1State
);
1746 TLOG("%s::waitPhase1(%s)\n", getName(), victim
->getName());
1747 victim
->__state
[1] |= kIOServiceTerm1WaiterState
;
1748 victim
->unlockForArbitration();
1749 assert_wait((event_t
)&victim
->__state
[1], THREAD_UNINT
);
1751 IOLockUnlock(gIOServiceBusyLock
);
1753 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
1754 TLOG("%s::did waitPhase1(%s)\n", getName(), victim
->getName());
1755 victim
->lockForArbitration();
1757 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
1759 victim
->unlockForArbitration();
1762 startPhase2
= didInactive
;
1765 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1766 IOUserClient::destroyUserReferences( victim
);
1768 iter
= victim
->getClientIterator();
1770 while( (client
= (IOService
*) iter
->getNextObject())) {
1771 TLOG("%s::requestTerminate(%s, %08llx)\n",
1772 client
->getName(), victim
->getName(), (long long)options
);
1773 ok
= client
->requestTerminate( victim
, options
);
1774 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1775 client
->getName(), victim
->getName(), ok
);
1777 uint64_t regID1
= client
->getRegistryEntryID();
1778 uint64_t regID2
= victim
->getRegistryEntryID();
1780 (ok
? IOSERVICE_TERMINATE_REQUEST_OK
1781 : IOSERVICE_TERMINATE_REQUEST_FAIL
),
1783 (uintptr_t) (regID1
>> 32),
1785 (uintptr_t) (regID2
>> 32));
1788 makeInactive
->setObject( client
);
1794 victim
= (IOService
*) makeInactive
->getObject(0);
1797 makeInactive
->removeObject(0);
1801 makeInactive
->release();
1805 lockForArbitration();
1806 __state
[1] &= ~kIOServiceTermPhase1State
;
1807 if (kIOServiceTerm1WaiterState
& __state
[1])
1809 __state
[1] &= ~kIOServiceTerm1WaiterState
;
1810 TLOG("%s::wakePhase1\n", getName());
1811 IOLockLock( gIOServiceBusyLock
);
1812 thread_wakeup( (event_t
) &__state
[1]);
1813 IOLockUnlock( gIOServiceBusyLock
);
1815 unlockForArbitration();
1817 scheduleTerminatePhase2( options
);
1822 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
1824 AbsoluteTime deadline
;
1825 int waitResult
= THREAD_AWAKENED
;
1826 bool wait
, haveDeadline
= false;
1828 options
|= kIOServiceRequired
;
1832 IOLockLock( gJobsLock
);
1834 if( (options
& kIOServiceSynchronous
)
1835 && (current_thread() != gIOTerminateThread
)) {
1838 wait
= (gIOTerminateThread
!= 0);
1840 // wait to become the terminate thread
1841 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
1845 gIOTerminateThread
= current_thread();
1846 gIOTerminatePhase2List
->setObject( this );
1850 while( gIOTerminateWork
)
1851 terminateWorker( options
);
1852 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1854 // wait for the victim to go non-busy
1855 if( !haveDeadline
) {
1856 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1857 haveDeadline
= true;
1859 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
1860 deadline
, THREAD_UNINT
);
1861 if( waitResult
== THREAD_TIMED_OUT
) {
1862 IOLog("%s::terminate(kIOServiceSynchronous) timeout\n", getName());
1865 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
1867 gIOTerminateThread
= 0;
1868 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1871 // ! kIOServiceSynchronous
1873 gIOTerminatePhase2List
->setObject( this );
1874 if( 0 == gIOTerminateWork
++) {
1875 if( !gIOTerminateThread
)
1876 kernel_thread_start(&terminateThread
, (void *) options
, &gIOTerminateThread
);
1878 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1882 IOLockUnlock( gJobsLock
);
1887 void IOService::terminateThread( void * arg
, wait_result_t waitResult
)
1889 IOLockLock( gJobsLock
);
1891 while (gIOTerminateWork
)
1892 terminateWorker( (uintptr_t) arg
);
1894 thread_deallocate(gIOTerminateThread
);
1895 gIOTerminateThread
= 0;
1896 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1898 IOLockUnlock( gJobsLock
);
1901 void IOService::scheduleStop( IOService
* provider
)
1903 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1905 uint64_t regID1
= getRegistryEntryID();
1906 uint64_t regID2
= provider
->getRegistryEntryID();
1908 IOSERVICE_TERMINATE_SCHEDULE_STOP
,
1910 (uintptr_t) (regID1
>> 32),
1912 (uintptr_t) (regID2
>> 32));
1914 IOLockLock( gJobsLock
);
1915 gIOStopList
->tailQ( this );
1916 gIOStopProviderList
->tailQ( provider
);
1918 if( 0 == gIOTerminateWork
++) {
1919 if( !gIOTerminateThread
)
1920 kernel_thread_start(&terminateThread
, (void *) 0, &gIOTerminateThread
);
1922 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1925 IOLockUnlock( gJobsLock
);
1928 void IOService::scheduleFinalize( void )
1930 TLOG("%s::scheduleFinalize\n", getName());
1932 uint64_t regID1
= getRegistryEntryID();
1934 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE
,
1936 (uintptr_t) (regID1
>> 32),
1939 IOLockLock( gJobsLock
);
1940 gIOFinalizeList
->tailQ( this );
1942 if( 0 == gIOTerminateWork
++) {
1943 if( !gIOTerminateThread
)
1944 kernel_thread_start(&terminateThread
, (void *) 0, &gIOTerminateThread
);
1946 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1949 IOLockUnlock( gJobsLock
);
1952 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1957 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1959 if( false == *defer
) {
1961 if( lockForArbitration( true )) {
1962 if( false == provider
->handleIsOpen( this ))
1963 scheduleStop( provider
);
1966 message( kIOMessageServiceIsRequestingClose
, provider
, (void *) options
);
1967 if( false == provider
->handleIsOpen( this ))
1968 scheduleStop( provider
);
1971 unlockForArbitration();
1978 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
1979 OSArray
* doPhase2List
,
1980 void *unused2 __unused
,
1981 void *unused3 __unused
)
1987 iter
= victim
->getClientIterator();
1989 while( (client
= (IOService
*) iter
->getNextObject())) {
1990 TLOG("%s::willTerminate(%s, %08llx)\n",
1991 client
->getName(), victim
->getName(), (long long)options
);
1993 uint64_t regID1
= client
->getRegistryEntryID();
1994 uint64_t regID2
= victim
->getRegistryEntryID();
1996 IOSERVICE_TERMINATE_WILL
,
1998 (uintptr_t) (regID1
>> 32),
2000 (uintptr_t) (regID2
>> 32));
2002 ok
= client
->willTerminate( victim
, options
);
2003 doPhase2List
->tailQ( client
);
2009 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
,
2010 void *unused1 __unused
, void *unused2 __unused
,
2011 void *unused3 __unused
)
2017 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *) options
);
2019 iter
= victim
->getClientIterator();
2021 while( (client
= (IOService
*) iter
->getNextObject())) {
2022 TLOG("%s::didTerminate(%s, %08llx)\n",
2023 client
->getName(), victim
->getName(), (long long)options
);
2024 client
->didTerminate( victim
, options
, &defer
);
2026 uint64_t regID1
= client
->getRegistryEntryID();
2027 uint64_t regID2
= victim
->getRegistryEntryID();
2029 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2030 : IOSERVICE_TERMINATE_DID
),
2032 (uintptr_t) (regID1
>> 32),
2034 (uintptr_t) (regID2
>> 32));
2036 TLOG("%s::didTerminate(%s, defer %d)\n",
2037 client
->getName(), victim
->getName(), defer
);
2043 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
,
2044 void *unused1 __unused
, void *unused2 __unused
,
2045 void *unused3 __unused
)
2047 TLOG("%s::finalize(%08llx)\n", victim
->getName(), (long long)options
);
2049 uint64_t regID1
= victim
->getRegistryEntryID();
2051 IOSERVICE_TERMINATE_FINALIZE
,
2053 (uintptr_t) (regID1
>> 32),
2056 victim
->finalize( options
);
2059 void IOService::actionStop( IOService
* provider
, IOService
* client
,
2060 void *unused1 __unused
, void *unused2 __unused
,
2061 void *unused3 __unused
)
2063 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
2065 uint64_t regID1
= provider
->getRegistryEntryID();
2066 uint64_t regID2
= client
->getRegistryEntryID();
2068 IOSERVICE_TERMINATE_STOP
,
2070 (uintptr_t) (regID1
>> 32),
2072 (uintptr_t) (regID2
>> 32));
2074 client
->stop( provider
);
2075 if( provider
->isOpen( client
))
2076 provider
->close( client
);
2077 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
2078 client
->detach( provider
);
2081 void IOService::terminateWorker( IOOptionBits options
)
2083 OSArray
* doPhase2List
;
2084 OSArray
* didPhase2List
;
2089 IOService
* provider
;
2095 options
|= kIOServiceRequired
;
2097 doPhase2List
= OSArray::withCapacity( 16 );
2098 didPhase2List
= OSArray::withCapacity( 16 );
2099 freeList
= OSSet::withCapacity( 16 );
2100 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
2104 workDone
= gIOTerminateWork
;
2106 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
2109 gIOTerminatePhase2List
->removeObject(0);
2110 IOLockUnlock( gJobsLock
);
2114 doPhase2
= victim
->lockForArbitration( true );
2116 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
2118 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
2119 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
2121 victim
->__state
[1] |= kIOServiceTermPhase2State
;
2123 victim
->unlockForArbitration();
2126 if( 0 == victim
->getClient()) {
2127 // no clients - will go to finalize
2128 IOLockLock( gJobsLock
);
2129 gIOFinalizeList
->tailQ( victim
);
2130 IOLockUnlock( gJobsLock
);
2132 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
2133 victim
, (void *) options
, (void *) doPhase2List
);
2135 didPhase2List
->headQ( victim
);
2138 victim
= (IOService
*) doPhase2List
->getObject(0);
2141 doPhase2List
->removeObject(0);
2145 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
2147 if( victim
->lockForArbitration( true )) {
2148 victim
->__state
[1] |= kIOServiceTermPhase3State
;
2149 victim
->unlockForArbitration();
2151 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
2152 victim
, (void *) options
);
2153 didPhase2List
->removeObject(0);
2155 IOLockLock( gJobsLock
);
2162 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
2164 IOLockUnlock( gJobsLock
);
2165 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
2166 victim
, (void *) options
);
2167 IOLockLock( gJobsLock
);
2169 freeList
->setObject( victim
);
2170 // safe if finalize list is append only
2171 gIOFinalizeList
->removeObject(0);
2175 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
2177 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
2180 if( !provider
->isChild( client
, gIOServicePlane
)) {
2181 // may be multiply queued - nop it
2182 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
2184 uint64_t regID1
= provider
->getRegistryEntryID();
2185 uint64_t regID2
= client
->getRegistryEntryID();
2187 IOSERVICE_TERMINATE_STOP_NOP
,
2189 (uintptr_t) (regID1
>> 32),
2191 (uintptr_t) (regID2
>> 32));
2194 // a terminated client is not ready for stop if it has clients, skip it
2195 if( (kIOServiceInactiveState
& client
->__state
[0]) && client
->getClient()) {
2196 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
2198 uint64_t regID1
= provider
->getRegistryEntryID();
2199 uint64_t regID2
= client
->getRegistryEntryID();
2201 IOSERVICE_TERMINATE_STOP_DEFER
,
2203 (uintptr_t) (regID1
>> 32),
2205 (uintptr_t) (regID2
>> 32));
2211 IOLockUnlock( gJobsLock
);
2212 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
2213 provider
, (void *) client
);
2214 IOLockLock( gJobsLock
);
2215 // check the finalize list now
2219 freeList
->setObject( client
);
2220 freeList
->setObject( provider
);
2222 // safe if stop list is append only
2223 gIOStopList
->removeObject( idx
);
2224 gIOStopProviderList
->removeObject( idx
);
2228 } while( doPhase3
);
2230 gIOTerminateWork
-= workDone
;
2231 moreToDo
= (gIOTerminateWork
!= 0);
2234 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
2236 IOSERVICE_TERMINATE_DONE
,
2237 (uintptr_t) gIOStopList
->getCount(), 0, 0, 0);
2240 } while( moreToDo
);
2242 IOLockUnlock( gJobsLock
);
2244 freeList
->release();
2245 doPhase2List
->release();
2246 didPhase2List
->release();
2248 IOLockLock( gJobsLock
);
2251 bool IOService::finalize( IOOptionBits options
)
2254 IOService
* provider
;
2256 iter
= getProviderIterator();
2260 while( (provider
= (IOService
*) iter
->getNextObject())) {
2263 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
2264 /* we come down here on programmatic terminate */
2266 if( provider
->isOpen( this ))
2267 provider
->close( this );
2271 if( provider
->lockForArbitration( true )) {
2272 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2273 scheduleStop( provider
);
2274 provider
->unlockForArbitration();
2291 void IOService::doServiceTerminate( IOOptionBits options
)
2295 // a method in case someone needs to override it
2296 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2300 if( client
->isParent( this, gIOServicePlane
, true))
2301 // we are the clients only provider
2302 ok
= client
->terminate( options
);
2309 bool IOService::terminate( IOOptionBits options
)
2311 options
|= kIOServiceTerminate
;
2313 return( terminatePhase1( options
));
2316 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2322 struct ServiceOpenMessageContext
2324 IOService
* service
;
2326 IOService
* excludeClient
;
2327 IOOptionBits options
;
2330 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2332 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2334 if( object
!= context
->excludeClient
)
2335 context
->service
->messageClient( context
->type
, object
, (void *) context
->options
);
2338 bool IOService::open( IOService
* forClient
,
2339 IOOptionBits options
,
2343 ServiceOpenMessageContext context
;
2345 context
.service
= this;
2346 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2347 context
.excludeClient
= forClient
;
2348 context
.options
= options
;
2350 applyToInterested( gIOGeneralInterest
,
2351 &serviceOpenMessageApplier
, &context
);
2353 if( false == lockForArbitration(false) )
2356 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2358 ok
= handleOpen( forClient
, options
, arg
);
2360 unlockForArbitration();
2365 void IOService::close( IOService
* forClient
,
2366 IOOptionBits options
)
2371 lockForArbitration();
2373 wasClosed
= handleIsOpen( forClient
);
2375 handleClose( forClient
, options
);
2376 last
= (__state
[1] & kIOServiceTermPhase3State
);
2379 unlockForArbitration();
2382 forClient
->scheduleStop( this );
2384 else if( wasClosed
) {
2386 ServiceOpenMessageContext context
;
2388 context
.service
= this;
2389 context
.type
= kIOMessageServiceWasClosed
;
2390 context
.excludeClient
= forClient
;
2391 context
.options
= options
;
2393 applyToInterested( gIOGeneralInterest
,
2394 &serviceOpenMessageApplier
, &context
);
2398 bool IOService::isOpen( const IOService
* forClient
) const
2400 IOService
* self
= (IOService
*) this;
2403 self
->lockForArbitration();
2405 ok
= handleIsOpen( forClient
);
2407 self
->unlockForArbitration();
2412 bool IOService::handleOpen( IOService
* forClient
,
2413 IOOptionBits options
,
2418 ok
= (0 == __owner
);
2420 __owner
= forClient
;
2422 else if( options
& kIOServiceSeize
) {
2423 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2424 __owner
, (void *) options
));
2425 if( ok
&& (0 == __owner
))
2426 __owner
= forClient
;
2433 void IOService::handleClose( IOService
* forClient
,
2434 IOOptionBits options
)
2436 if( __owner
== forClient
)
2440 bool IOService::handleIsOpen( const IOService
* forClient
) const
2443 return( __owner
== forClient
);
2445 return( __owner
!= forClient
);
2449 * Probing & starting
2451 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2453 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2454 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2462 val1
= obj1
->priority
;
2465 val2
= obj2
->priority
;
2467 return ( val1
- val2
);
2470 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2472 OSDictionary
* dict
;
2473 IOService
* service
;
2474 _IOServiceNotifier
* notify
;
2475 OSSymbol
* key
= (OSSymbol
*) ref
;
2478 if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2479 return( notify
->priority
);
2481 else if( (service
= OSDynamicCast( IOService
, entry
)))
2482 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2483 else if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2484 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2491 return( (SInt32
) offset
->unsigned32BitValue());
2493 return( kIODefaultProbeScore
);
2496 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2498 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2499 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2507 val1
= IOServiceObjectOrder( obj1
, ref
);
2510 val2
= IOServiceObjectOrder( obj2
, ref
);
2512 return ( val1
- val2
);
2515 IOService
* IOService::copyClientWithCategory( const OSSymbol
* category
)
2517 IOService
* service
= 0;
2519 const OSSymbol
* nextCat
;
2521 iter
= getClientIterator();
2523 while( (service
= (IOService
*) iter
->getNextObject())) {
2524 if( kIOServiceInactiveState
& service
->__state
[0])
2526 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2527 service
->getProperty( gIOMatchCategoryKey
));
2528 if( category
== nextCat
)
2539 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2542 service
= copyClientWithCategory(category
);
2548 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2550 _IOServiceNotifierInvocation invocation
;
2554 invocation
.thread
= current_thread();
2557 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2560 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2561 _IOServiceNotifierInvocation
*, link
);
2567 ret
= (*notify
->handler
)(notify
->target
, notify
->ref
, this, notify
);
2570 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2571 _IOServiceNotifierInvocation
*, link
);
2572 if( kIOServiceNotifyWaiter
& notify
->state
) {
2573 notify
->state
&= ~kIOServiceNotifyWaiter
;
2574 WAKEUPNOTIFY( notify
);
2583 * Alloc and probe matching classes,
2584 * called on the provider instance
2587 void IOService::probeCandidates( OSOrderedSet
* matches
)
2589 OSDictionary
* match
= 0;
2592 IOService
* newInst
;
2593 OSDictionary
* props
;
2596 OSOrderedSet
* familyMatches
= 0;
2597 OSOrderedSet
* startList
;
2598 OSDictionary
* startDict
= 0;
2599 const OSSymbol
* category
;
2601 _IOServiceNotifier
* notify
;
2602 OSObject
* nextMatch
= 0;
2604 bool needReloc
= false;
2605 #if CONFIG_MACF_KEXT
2606 OSBoolean
* isSandbox
= 0;
2607 bool useSandbox
= false;
2612 IOService
* client
= NULL
;
2616 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2618 nextMatch
->retain();
2619 matches
->removeObject(nextMatch
);
2621 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2623 lockForArbitration();
2624 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2625 invokeNotifer( notify
);
2626 unlockForArbitration();
2627 nextMatch
->release();
2631 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2632 nextMatch
->release();
2639 debugFlags
= getDebugFlags( match
);
2643 category
= OSDynamicCast( OSSymbol
,
2644 match
->getObject( gIOMatchCategoryKey
));
2646 category
= gIODefaultMatchCategoryKey
;
2648 if( (client
= copyClientWithCategory(category
)) ) {
2650 if( debugFlags
& kIOLogMatch
)
2651 LOG("%s: match category %s exists\n", getName(),
2652 category
->getCStringNoCopy());
2654 nextMatch
->release();
2663 // create a copy now in case its modified during matching
2664 props
= OSDictionary::withDictionary( match
, match
->getCount());
2667 props
->setCapacityIncrement(1);
2669 // check the nub matches
2670 if( false == passiveMatch( props
, true ))
2673 // Check to see if driver reloc has been loaded.
2674 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2677 if( debugFlags
& kIOLogCatalogue
)
2678 LOG("%s: stalling for module\n", getName());
2680 // If reloc hasn't been loaded, exit;
2681 // reprobing will occur after reloc has been loaded.
2685 // reorder on family matchPropertyTable score.
2686 if( 0 == familyMatches
)
2687 familyMatches
= OSOrderedSet::withCapacity( 1,
2688 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2690 familyMatches
->setObject( props
);
2695 nextMatch
->release();
2704 if( familyMatches
) {
2707 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2710 familyMatches
->removeObject( props
);
2715 debugFlags
= getDebugFlags( props
);
2718 symbol
= OSDynamicCast( OSSymbol
,
2719 props
->getObject( gIOClassKey
));
2723 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), symbol, props);
2725 // alloc the driver instance
2726 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2729 IOLog("Couldn't alloc class \"%s\"\n",
2730 symbol
->getCStringNoCopy());
2734 // init driver instance
2735 if( !(inst
->init( props
))) {
2737 if( debugFlags
& kIOLogStart
)
2738 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2742 if( __state
[1] & kIOServiceSynchronousState
)
2743 inst
->__state
[1] |= kIOServiceSynchronousState
;
2745 // give the driver the default match category if not specified
2746 category
= OSDynamicCast( OSSymbol
,
2747 props
->getObject( gIOMatchCategoryKey
));
2749 category
= gIODefaultMatchCategoryKey
;
2750 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2751 #if CONFIG_MACF_KEXT
2752 isSandbox
= OSDynamicCast(OSBoolean
,
2753 props
->getObject("IOKitForceMatch"));
2755 // attach driver instance
2756 if( !(inst
->attach( this )))
2759 // pass in score from property table
2760 score
= familyMatches
->orderObject( props
);
2762 // & probe the new driver instance
2764 if( debugFlags
& kIOLogProbe
)
2765 LOG("%s::probe(%s)\n",
2766 inst
->getMetaClass()->getClassName(), getName());
2769 newInst
= inst
->probe( this, &score
);
2770 inst
->detach( this );
2771 #if CONFIG_MACF_KEXT
2773 * If this is the Sandbox driver and it matched, this is a
2774 * disallowed device; toss any drivers that were already
2777 if (isSandbox
&& isSandbox
->isTrue() && newInst
!= 0) {
2778 if (startDict
!= 0) {
2779 startDict
->flushCollection();
2780 startDict
->release();
2788 if( debugFlags
& kIOLogProbe
)
2789 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2795 newPri
= OSNumber::withNumber( score
, 32 );
2797 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2801 // add to start list for the match category
2803 startDict
= OSDictionary::withCapacity( 1 );
2804 assert( startDict
);
2805 startList
= (OSOrderedSet
*)
2806 startDict
->getObject( category
);
2807 if( 0 == startList
) {
2808 startList
= OSOrderedSet::withCapacity( 1,
2809 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2810 if( startDict
&& startList
) {
2811 startDict
->setObject( category
, startList
);
2812 startList
->release();
2815 assert( startList
);
2817 startList
->setObject( newInst
);
2824 #if CONFIG_MACF_KEXT
2826 * If we're forcing the sandbox, drop out of the loop.
2828 if (isSandbox
&& isSandbox
->isTrue() && useSandbox
)
2832 familyMatches
->release();
2836 // start the best (until success) of each category
2838 iter
= OSCollectionIterator::withCollection( startDict
);
2840 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2842 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2843 assert( startList
);
2848 while( true // (!started)
2849 && (inst
= (IOService
*)startList
->getFirstObject())) {
2852 startList
->removeObject(inst
);
2855 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2857 if( debugFlags
& kIOLogStart
) {
2859 LOG( "match category exists, skipping " );
2860 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2861 getName(), inst
->getRetainCount());
2864 if( false == started
)
2865 started
= startCandidate( inst
);
2867 if( (debugFlags
& kIOLogStart
) && (false == started
))
2868 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2869 inst
->getRetainCount());
2878 // adjust the busy count by +1 if matching is stalled for a module,
2879 // or -1 if a previously stalled matching is complete.
2880 lockForArbitration();
2882 uint64_t regID
= getRegistryEntryID();
2885 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2889 IOSERVICE_MODULESTALL
,
2891 (uintptr_t) (regID
>> 32),
2895 __state
[1] |= kIOServiceModuleStallState
;
2898 } else if( __state
[1] & kIOServiceModuleStallState
) {
2901 IOSERVICE_MODULEUNSTALL
,
2903 (uintptr_t) (regID
>> 32),
2907 __state
[1] &= ~kIOServiceModuleStallState
;
2911 _adjustBusy( adjBusy
);
2912 unlockForArbitration();
2915 startDict
->release();
2919 * Start a previously attached & probed instance,
2920 * called on exporting object instance
2923 bool IOService::startCandidate( IOService
* service
)
2927 ok
= service
->attach( this );
2931 if (this != gIOResources
)
2933 // stall for any nub resources
2935 // stall for any driver resources
2936 service
->checkResources();
2939 AbsoluteTime startTime
;
2940 AbsoluteTime endTime
;
2943 if (kIOLogStart
& gIOKitDebug
)
2944 clock_get_uptime(&startTime
);
2946 ok
= service
->start(this);
2948 if (kIOLogStart
& gIOKitDebug
)
2950 clock_get_uptime(&endTime
);
2952 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2954 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2955 absolutetime_to_nanoseconds(endTime
, &nano
);
2956 if (nano
> 500000000ULL)
2957 IOLog("%s::start took %ld ms\n", service
->getName(), (long)(UInt32
)(nano
/ 1000000ULL));
2961 service
->detach( this );
2966 void IOService::publishResource( const char * key
, OSObject
* value
)
2968 const OSSymbol
* sym
;
2970 if( (sym
= OSSymbol::withCString( key
))) {
2971 publishResource( sym
, value
);
2976 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
2979 value
= (OSObject
*) gIOServiceKey
;
2981 gIOResources
->setProperty( key
, value
);
2983 if( IORecursiveLockHaveLock( gNotificationLock
))
2986 gIOResourceGenerationCount
++;
2987 gIOResources
->registerService();
2990 bool IOService::addNeededResource( const char * key
)
2992 OSObject
* resourcesProp
;
2997 resourcesProp
= getProperty( gIOResourceMatchKey
);
2999 newKey
= OSString::withCString( key
);
3000 if( (0 == resourcesProp
) || (0 == newKey
))
3003 set
= OSDynamicCast( OSSet
, resourcesProp
);
3005 set
= OSSet::withCapacity( 1 );
3007 set
->setObject( resourcesProp
);
3012 set
->setObject( newKey
);
3014 ret
= setProperty( gIOResourceMatchKey
, set
);
3020 bool IOService::checkResource( OSObject
* matching
)
3023 OSDictionary
* table
;
3025 if( (str
= OSDynamicCast( OSString
, matching
))) {
3026 if( gIOResources
->getProperty( str
))
3031 table
= resourceMatching( str
);
3032 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
3035 IOLog("%s: Can't match using: %s\n", getName(),
3036 matching
->getMetaClass()->getClassName());
3037 /* false would stall forever */
3041 if( gIOKitDebug
& kIOLogConfig
)
3042 LOG("config(%p): stalling %s\n", IOThreadSelf(), getName());
3044 waitForService( table
);
3046 if( gIOKitDebug
& kIOLogConfig
)
3047 LOG("config(%p): waking\n", IOThreadSelf() );
3052 bool IOService::checkResources( void )
3054 OSObject
* resourcesProp
;
3059 resourcesProp
= getProperty( gIOResourceMatchKey
);
3060 if( 0 == resourcesProp
)
3063 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
3065 iter
= OSCollectionIterator::withCollection( set
);
3067 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
3068 ok
= checkResource( resourcesProp
);
3073 ok
= checkResource( resourcesProp
);
3079 void _IOConfigThread::configThread( void )
3081 _IOConfigThread
* inst
;
3084 if( !(inst
= new _IOConfigThread
))
3089 if (KERN_SUCCESS
!= kernel_thread_start(&_IOConfigThread::main
, inst
, &unused
))
3102 void _IOConfigThread::free( void )
3104 thread_deallocate(current_thread());
3108 void IOService::doServiceMatch( IOOptionBits options
)
3110 _IOServiceNotifier
* notify
;
3112 OSOrderedSet
* matches
;
3113 SInt32 catalogGeneration
;
3114 bool keepGuessing
= true;
3115 bool reRegistered
= true;
3117 // job->nub->deliverNotification( gIOPublishNotification,
3118 // kIOServiceRegisteredState, 0xffffffff );
3120 while( keepGuessing
) {
3122 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
3123 // the matches list should always be created by findDrivers()
3126 lockForArbitration();
3127 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
3128 deliverNotification( gIOFirstPublishNotification
,
3129 kIOServiceFirstPublishState
, 0xffffffff );
3131 __state
[1] &= ~kIOServiceNeedConfigState
;
3132 __state
[1] |= kIOServiceConfigState
;
3133 __state
[0] |= kIOServiceRegisteredState
;
3135 keepGuessing
&= (0 == (__state
[0] & kIOServiceInactiveState
));
3136 if (reRegistered
&& keepGuessing
) {
3137 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3138 gNotifications
->getObject( gIOPublishNotification
) );
3140 while((notify
= (_IOServiceNotifier
*)
3141 iter
->getNextObject())) {
3143 if( passiveMatch( notify
->matching
)
3144 && (kIOServiceNotifyEnable
& notify
->state
))
3145 matches
->setObject( notify
);
3152 unlockForArbitration();
3154 if (keepGuessing
&& matches
->getCount() && (kIOReturnSuccess
== getResources()))
3155 probeCandidates( matches
);
3160 lockForArbitration();
3161 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
3163 (reRegistered
|| (catalogGeneration
!=
3164 gIOCatalogue
->getGenerationCount()))
3165 && (0 == (__state
[0] & kIOServiceInactiveState
));
3168 unlockForArbitration();
3171 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3172 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
3173 deliverNotification( gIOMatchedNotification
,
3174 kIOServiceMatchedState
, 0xffffffff );
3175 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
3176 deliverNotification( gIOFirstMatchNotification
,
3177 kIOServiceFirstMatchState
, 0xffffffff );
3180 __state
[1] &= ~kIOServiceConfigState
;
3181 if( __state
[0] & kIOServiceInactiveState
)
3182 scheduleTerminatePhase2();
3185 unlockForArbitration();
3188 UInt32
IOService::_adjustBusy( SInt32 delta
)
3193 bool wasQuiet
, nowQuiet
, needWake
;
3196 result
= __state
[1] & kIOServiceBusyStateMask
;
3200 next
->lockForArbitration();
3201 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
3202 wasQuiet
= (0 == count
);
3203 if (((delta
< 0) && wasQuiet
) || ((delta
> 0) && (kIOServiceBusyMax
== count
)))
3204 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next
->getName(), count
, delta
);
3207 next
->__state
[1] = (next
->__state
[1] & ~kIOServiceBusyStateMask
) | count
;
3208 nowQuiet
= (0 == count
);
3209 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
3212 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
3213 IOLockLock( gIOServiceBusyLock
);
3214 thread_wakeup( (event_t
) next
);
3215 IOLockUnlock( gIOServiceBusyLock
);
3218 next
->unlockForArbitration();
3220 if( (wasQuiet
|| nowQuiet
) ) {
3221 uint64_t regID
= next
->getRegistryEntryID();
3224 ((wasQuiet
/*nowBusy*/) ? IOSERVICE_BUSY
: IOSERVICE_NONBUSY
),
3226 (uintptr_t) (regID
>> 32),
3232 next
->__timeBusy
= mach_absolute_time();
3236 next
->__accumBusy
+= mach_absolute_time() - next
->__timeBusy
;
3237 next
->__timeBusy
= 0;
3240 MessageClientsContext context
;
3242 context
.service
= next
;
3243 context
.type
= kIOMessageServiceBusyStateChange
;
3244 context
.argument
= (void *) wasQuiet
; /*nowBusy*/
3245 context
.argSize
= 0;
3247 applyToInterestNotifiers( next
, gIOBusyInterest
,
3248 &messageClientsApplier
, &context
);
3251 if( nowQuiet
&& (next
== gIOServiceRoot
)) {
3252 OSKext::considerUnloads();
3253 IOServiceTrace(IOSERVICE_REGISTRY_QUIET
, 0, 0, 0, 0);
3258 delta
= nowQuiet
? -1 : +1;
3260 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
3265 void IOService::adjustBusy( SInt32 delta
)
3267 lockForArbitration();
3268 _adjustBusy( delta
);
3269 unlockForArbitration();
3272 uint64_t IOService::getAccumulatedBusyTime( void )
3274 uint64_t accumBusy
= __accumBusy
;
3275 uint64_t timeBusy
= __timeBusy
;
3280 accumBusy
= __accumBusy
;
3281 timeBusy
= __timeBusy
;
3283 accumBusy
+= mach_absolute_time() - timeBusy
;
3285 while (timeBusy
!= __timeBusy
);
3287 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&accumBusy
, &nano
);
3292 UInt32
IOService::getBusyState( void )
3294 return( __state
[1] & kIOServiceBusyStateMask
);
3297 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3298 mach_timespec_t
* timeout
)
3300 panic("waitForState");
3301 return (kIOReturnUnsupported
);
3304 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3308 int waitResult
= THREAD_AWAKENED
;
3309 bool computeDeadline
= true;
3310 AbsoluteTime abstime
;
3313 lockForArbitration();
3314 IOLockLock( gIOServiceBusyLock
);
3315 wait
= (value
!= (__state
[1] & mask
));
3317 __state
[1] |= kIOServiceBusyWaiterState
;
3318 unlockForArbitration();
3319 if( timeout
!= UINT64_MAX
) {
3320 if( computeDeadline
) {
3321 AbsoluteTime nsinterval
;
3322 nanoseconds_to_absolutetime(timeout
, &nsinterval
);
3323 clock_absolutetime_interval_to_deadline(nsinterval
, &abstime
);
3324 computeDeadline
= false;
3326 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
3329 assert_wait((event_t
)this, THREAD_UNINT
);
3331 unlockForArbitration();
3332 IOLockUnlock( gIOServiceBusyLock
);
3334 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
3336 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3338 if( waitResult
== THREAD_TIMED_OUT
)
3339 return( kIOReturnTimeout
);
3341 return( kIOReturnSuccess
);
3344 IOReturn
IOService::waitQuiet( uint64_t timeout
)
3346 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
3349 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
3355 timeoutNS
= timeout
->tv_sec
;
3356 timeoutNS
*= kSecondScale
;
3357 timeoutNS
+= timeout
->tv_nsec
;
3360 timeoutNS
= UINT64_MAX
;
3362 return( waitForState( kIOServiceBusyStateMask
, 0, timeoutNS
));
3365 bool IOService::serializeProperties( OSSerialize
* s
) const
3368 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
3369 sizeof( __state
), "__state");
3371 return( super::serializeProperties(s
) );
3375 void _IOConfigThread::main(void * arg
, wait_result_t result
)
3377 _IOConfigThread
* self
= (_IOConfigThread
*) arg
;
3378 _IOServiceJob
* job
;
3382 thread_precedence_policy_data_t precedence
= { -1 };
3384 kr
= thread_policy_set(current_thread(),
3385 THREAD_PRECEDENCE_POLICY
,
3386 (thread_policy_t
) &precedence
,
3387 THREAD_PRECEDENCE_POLICY_COUNT
);
3388 if (KERN_SUCCESS
!= kr
)
3389 IOLog("thread_policy_set(%d)\n", kr
);
3395 semaphore_wait( gJobsSemaphore
);
3397 IOTakeLock( gJobsLock
);
3398 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
3400 gJobs
->removeObject(job
);
3403 // gNumConfigThreads--; // we're out of service
3404 gNumWaitingThreads
--; // we're out of service
3406 IOUnlock( gJobsLock
);
3412 if( gIOKitDebug
& kIOLogConfig
)
3413 LOG("config(%p): starting on %s, %d\n",
3414 IOThreadSelf(), job
->nub
->getName(), job
->type
);
3416 switch( job
->type
) {
3419 nub
->doServiceMatch( job
->options
);
3423 LOG("config(%p): strange type (%d)\n",
3424 IOThreadSelf(), job
->type
);
3431 IOTakeLock( gJobsLock
);
3432 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
3434 gNumWaitingThreads
++; // back in service
3435 // gNumConfigThreads++;
3437 if( 0 == --gNumConfigThreads
) {
3438 // IOLog("MATCH IDLE\n");
3439 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3442 IOUnlock( gJobsLock
);
3447 if( gIOKitDebug
& kIOLogConfig
)
3448 LOG("config(%p): terminating\n", IOThreadSelf() );
3453 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3456 int waitResult
= THREAD_AWAKENED
;
3457 bool computeDeadline
= true;
3458 AbsoluteTime deadline
;
3460 IOLockLock( gJobsLock
);
3462 wait
= (0 != gNumConfigThreads
);
3465 if( computeDeadline
) {
3466 clock_interval_to_deadline(
3467 msToWait
, kMillisecondScale
, &deadline
);
3468 computeDeadline
= false;
3470 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
3471 deadline
, THREAD_UNINT
);
3473 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3477 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3478 IOLockUnlock( gJobsLock
);
3480 if( waitResult
== THREAD_TIMED_OUT
)
3481 return( kIOReturnTimeout
);
3483 return( kIOReturnSuccess
);
3486 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3493 IOTakeLock( gJobsLock
);
3496 gJobs
->setLastObject( job
);
3498 count
= gNumWaitingThreads
;
3499 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3501 create
= ( (gOutstandingJobs
> count
)
3502 && (gNumConfigThreads
< kMaxConfigThreads
) );
3504 gNumConfigThreads
++;
3505 gNumWaitingThreads
++;
3508 IOUnlock( gJobsLock
);
3513 if( gIOKitDebug
& kIOLogConfig
)
3514 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3515 _IOConfigThread::configThread();
3518 semaphore_signal( gJobsSemaphore
);
3521 // internal - call with gNotificationLock
3522 OSObject
* IOService::copyExistingServices( OSDictionary
* matching
,
3523 IOOptionBits inState
, IOOptionBits options
)
3525 OSObject
* current
= 0;
3527 IOService
* service
;
3534 && (obj
= matching
->getObject(gIOProviderClassKey
))
3536 && gIOResourcesKey
->isEqualTo(obj
)
3537 && (service
= gIOResources
))
3539 if( (inState
== (service
->__state
[0] & inState
))
3540 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3541 && service
->passiveMatch( matching
))
3543 if( options
& kIONotifyOnce
)
3549 current
= OSSet::withObjects(
3550 (const OSObject
**) &service
, 1, 1 );
3555 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3556 kIORegistryIterateRecursively
);
3560 while( (service
= (IOService
*) iter
->getNextObject())) {
3561 if( (inState
== (service
->__state
[0] & inState
))
3562 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3563 && service
->passiveMatch( matching
)) {
3565 if( options
& kIONotifyOnce
) {
3571 ((OSSet
*)current
)->setObject( service
);
3573 current
= OSSet::withObjects(
3574 (const OSObject
**) &service
, 1, 1 );
3577 } while( !service
&& !iter
->isValid());
3582 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
3583 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3592 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3596 // is a lock even needed?
3599 iter
= (OSIterator
*) copyExistingServices( matching
,
3600 kIOServiceMatchedState
);
3607 struct _IOServiceMatchingNotificationHandlerRef
3609 IOServiceNotificationHandler handler
;
3613 static bool _IOServiceMatchingNotificationHandler( void * target
, void * refCon
,
3614 IOService
* newService
,
3615 IONotifier
* notifier
)
3617 return ((*((_IOServiceNotifier
*) notifier
)->compatHandler
)(target
, refCon
, newService
));
3620 // internal - call with gNotificationLock
3621 IONotifier
* IOService::setNotification(
3622 const OSSymbol
* type
, OSDictionary
* matching
,
3623 IOServiceMatchingNotificationHandler handler
, void * target
, void * ref
,
3626 _IOServiceNotifier
* notify
= 0;
3632 notify
= new _IOServiceNotifier
;
3633 if( notify
&& !notify
->init()) {
3639 notify
->handler
= handler
;
3640 notify
->target
= target
;
3641 notify
->matching
= matching
;
3643 if (handler
== &_IOServiceMatchingNotificationHandler
)
3645 notify
->compatHandler
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->handler
;
3646 notify
->ref
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->ref
;
3650 notify
->priority
= priority
;
3651 notify
->state
= kIOServiceNotifyEnable
;
3652 queue_init( ¬ify
->handlerInvocations
);
3656 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3657 set
= OSOrderedSet::withCapacity( 1,
3658 IONotifyOrdering
, 0 );
3660 gNotifications
->setObject( type
, set
);
3664 notify
->whence
= set
;
3666 set
->setObject( notify
);
3672 // internal - call with gNotificationLock
3673 IONotifier
* IOService::doInstallNotification(
3674 const OSSymbol
* type
, OSDictionary
* matching
,
3675 IOServiceMatchingNotificationHandler handler
,
3676 void * target
, void * ref
,
3677 SInt32 priority
, OSIterator
** existing
)
3680 IONotifier
* notify
;
3681 IOOptionBits inState
;
3686 if( type
== gIOPublishNotification
)
3687 inState
= kIOServiceRegisteredState
;
3689 else if( type
== gIOFirstPublishNotification
)
3690 inState
= kIOServiceFirstPublishState
;
3692 else if( (type
== gIOMatchedNotification
)
3693 || (type
== gIOFirstMatchNotification
))
3694 inState
= kIOServiceMatchedState
;
3695 else if( type
== gIOTerminatedNotification
)
3700 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3703 // get the current set
3704 exist
= (OSIterator
*) copyExistingServices( matching
, inState
);
3713 #if !defined(__LP64__)
3714 IONotifier
* IOService::installNotification(const OSSymbol
* type
, OSDictionary
* matching
,
3715 IOServiceNotificationHandler handler
,
3716 void * target
, void * refCon
,
3717 SInt32 priority
, OSIterator
** existing
)
3719 IONotifier
* result
;
3720 _IOServiceMatchingNotificationHandlerRef ref
;
3721 ref
.handler
= handler
;
3724 result
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3725 &_IOServiceMatchingNotificationHandler
,
3726 target
, &ref
, priority
, existing
);
3728 matching
->release();
3732 #endif /* !defined(__LP64__) */
3735 IONotifier
* IOService::installNotification(
3736 const OSSymbol
* type
, OSDictionary
* matching
,
3737 IOServiceMatchingNotificationHandler handler
,
3738 void * target
, void * ref
,
3739 SInt32 priority
, OSIterator
** existing
)
3741 IONotifier
* notify
;
3745 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3746 priority
, existing
);
3753 IONotifier
* IOService::addNotification(
3754 const OSSymbol
* type
, OSDictionary
* matching
,
3755 IOServiceNotificationHandler handler
,
3756 void * target
, void * refCon
,
3759 IONotifier
* result
;
3760 _IOServiceMatchingNotificationHandlerRef ref
;
3762 ref
.handler
= handler
;
3765 result
= addMatchingNotification(type
, matching
, &_IOServiceMatchingNotificationHandler
,
3766 target
, &ref
, priority
);
3769 matching
->release();
3774 IONotifier
* IOService::addMatchingNotification(
3775 const OSSymbol
* type
, OSDictionary
* matching
,
3776 IOServiceMatchingNotificationHandler handler
,
3777 void * target
, void * ref
,
3780 OSIterator
* existing
= NULL
;
3781 _IOServiceNotifier
* notify
;
3784 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3785 handler
, target
, ref
, priority
, &existing
);
3787 // send notifications for existing set
3790 notify
->retain(); // in case handler remove()s
3791 while( (next
= (IOService
*) existing
->getNextObject())) {
3793 next
->lockForArbitration();
3794 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3795 next
->invokeNotifer( notify
);
3796 next
->unlockForArbitration();
3799 existing
->release();
3805 bool IOService::syncNotificationHandler(
3806 void * /* target */, void * ref
,
3807 IOService
* newService
,
3808 IONotifier
* notifier
)
3812 if (!*((IOService
**) ref
))
3814 newService
->retain();
3815 (*(IOService
**) ref
) = newService
;
3823 IOService
* IOService::waitForMatchingService( OSDictionary
* matching
,
3826 IONotifier
* notify
= 0;
3827 // priority doesn't help us much since we need a thread wakeup
3828 SInt32 priority
= 0;
3839 result
= (IOService
*) copyExistingServices( matching
,
3840 kIOServiceMatchedState
, kIONotifyOnce
);
3843 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
3844 &IOService::syncNotificationHandler
, (void *) 0,
3845 &result
, priority
);
3848 if (UINT64_MAX
!= timeout
)
3850 AbsoluteTime deadline
;
3851 nanoseconds_to_absolutetime(timeout
, &deadline
);
3852 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
3853 SLEEPNOTIFYTO(&result
, deadline
);
3857 SLEEPNOTIFY(&result
);
3865 notify
->remove(); // dequeues
3870 IOService
* IOService::waitForService( OSDictionary
* matching
,
3871 mach_timespec_t
* timeout
)
3878 timeoutNS
= timeout
->tv_sec
;
3879 timeoutNS
*= kSecondScale
;
3880 timeoutNS
+= timeout
->tv_nsec
;
3883 timeoutNS
= UINT64_MAX
;
3885 result
= waitForMatchingService(matching
, timeoutNS
);
3887 matching
->release();
3894 void IOService::deliverNotification( const OSSymbol
* type
,
3895 IOOptionBits orNewState
, IOOptionBits andNewState
)
3897 _IOServiceNotifier
* notify
;
3899 OSArray
* willSend
= 0;
3901 lockForArbitration();
3903 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3904 || (type
== gIOTerminatedNotification
)) {
3908 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3909 gNotifications
->getObject( type
) );
3912 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
3914 if( passiveMatch( notify
->matching
)
3915 && (kIOServiceNotifyEnable
& notify
->state
)) {
3917 willSend
= OSArray::withCapacity(8);
3919 willSend
->setObject( notify
);
3925 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
3931 for( unsigned int idx
= 0;
3932 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
3934 invokeNotifer( notify
);
3936 willSend
->release();
3938 unlockForArbitration();
3941 IOOptionBits
IOService::getState( void ) const
3943 return( __state
[0] );
3947 * Helpers to make matching objects for simple cases
3950 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
3951 OSDictionary
* table
)
3954 table
= OSDictionary::withCapacity( 2 );
3956 table
->setObject(gIOProviderClassKey
, (OSObject
*)name
);
3961 OSDictionary
* IOService::serviceMatching( const char * name
,
3962 OSDictionary
* table
)
3964 const OSString
* str
;
3966 str
= OSSymbol::withCString( name
);
3970 table
= serviceMatching( str
, table
);
3975 OSDictionary
* IOService::nameMatching( const OSString
* name
,
3976 OSDictionary
* table
)
3979 table
= OSDictionary::withCapacity( 2 );
3981 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
3986 OSDictionary
* IOService::nameMatching( const char * name
,
3987 OSDictionary
* table
)
3989 const OSString
* str
;
3991 str
= OSSymbol::withCString( name
);
3995 table
= nameMatching( str
, table
);
4000 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
4001 OSDictionary
* table
)
4003 table
= serviceMatching( gIOResourcesKey
, table
);
4005 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
4010 OSDictionary
* IOService::resourceMatching( const char * name
,
4011 OSDictionary
* table
)
4013 const OSSymbol
* str
;
4015 str
= OSSymbol::withCString( name
);
4019 table
= resourceMatching( str
, table
);
4025 OSDictionary
* IOService::propertyMatching( const OSSymbol
* key
, const OSObject
* value
,
4026 OSDictionary
* table
)
4028 OSDictionary
* properties
;
4030 properties
= OSDictionary::withCapacity( 2 );
4033 properties
->setObject( key
, value
);
4036 table
= OSDictionary::withCapacity( 2 );
4038 table
->setObject( gIOPropertyMatchKey
, properties
);
4040 properties
->release();
4045 OSDictionary
* IOService::registryEntryIDMatching( uint64_t entryID
,
4046 OSDictionary
* table
)
4050 num
= OSNumber::withNumber( entryID
, 64 );
4055 table
= OSDictionary::withCapacity( 2 );
4057 table
->setObject( gIORegistryEntryIDKey
, num
);
4067 * _IOServiceNotifier
4070 // wait for all threads, other than the current one,
4071 // to exit the handler
4073 void _IOServiceNotifier::wait()
4075 _IOServiceNotifierInvocation
* next
;
4080 queue_iterate( &handlerInvocations
, next
,
4081 _IOServiceNotifierInvocation
*, link
) {
4082 if( next
->thread
!= current_thread() ) {
4088 state
|= kIOServiceNotifyWaiter
;
4095 void _IOServiceNotifier::free()
4097 assert( queue_empty( &handlerInvocations
));
4101 void _IOServiceNotifier::remove()
4106 whence
->removeObject( (OSObject
*) this );
4110 matching
->release();
4114 state
&= ~kIOServiceNotifyEnable
;
4123 bool _IOServiceNotifier::disable()
4129 ret
= (0 != (kIOServiceNotifyEnable
& state
));
4130 state
&= ~kIOServiceNotifyEnable
;
4139 void _IOServiceNotifier::enable( bool was
)
4143 state
|= kIOServiceNotifyEnable
;
4145 state
&= ~kIOServiceNotifyEnable
;
4153 IOService
* IOResources::resources( void )
4157 inst
= new IOResources
;
4158 if( inst
&& !inst
->init()) {
4166 bool IOResources::init( OSDictionary
* dictionary
)
4168 // Do super init first
4169 if ( !super::init() )
4172 // Allow PAL layer to publish a value
4173 const char *property_name
;
4176 pal_get_resource_property( &property_name
, &property_value
);
4178 if( property_name
) {
4180 const OSSymbol
* sym
;
4182 if( (num
= OSNumber::withNumber(property_value
, 32)) != 0 ) {
4183 if( (sym
= OSSymbol::withCString( property_name
)) != 0 ) {
4184 this->setProperty( sym
, num
);
4194 IOWorkLoop
* IOResources::getWorkLoop() const
4196 // If we are the resource root
4197 // then use the platform's workloop
4198 if (this == (IOResources
*) gIOResources
)
4199 return getPlatform()->getWorkLoop();
4201 return IOService::getWorkLoop();
4204 bool IOResources::matchPropertyTable( OSDictionary
* table
)
4212 prop
= table
->getObject( gIOResourceMatchKey
);
4213 str
= OSDynamicCast( OSString
, prop
);
4215 ok
= (0 != getProperty( str
));
4217 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
4219 iter
= OSCollectionIterator::withCollection( set
);
4221 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
4222 ok
= (0 != getProperty( str
));
4231 void IOService::consoleLockTimer(thread_call_param_t p0
, thread_call_param_t p1
)
4233 IOService::updateConsoleUsers(NULL
, 0);
4236 void IOService::updateConsoleUsers(OSArray
* consoleUsers
, IOMessage systemMessage
)
4238 IORegistryEntry
* regEntry
;
4239 OSObject
* locked
= kOSBooleanFalse
;
4243 OSDictionary
* user
;
4244 static IOMessage sSystemPower
;
4246 regEntry
= IORegistryEntry::getRegistryRoot();
4248 IOLockLock(gIOConsoleUsersLock
);
4252 sSystemPower
= systemMessage
;
4259 (user
= OSDynamicCast(OSDictionary
, consoleUsers
->getObject(idx
)));
4262 loggedIn
|= ((kOSBooleanTrue
== user
->getObject(gIOConsoleSessionOnConsoleKey
))
4263 && (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionLoginDoneKey
)));
4266 num
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionScreenLockedTimeKey
));
4269 gIOConsoleLockTime
= num
? num
->unsigned32BitValue() : 0;
4273 || (kIOMessageSystemWillSleep
== sSystemPower
)
4274 || (kIOMessageSystemPagingOff
== sSystemPower
))
4276 locked
= kOSBooleanTrue
;
4278 else if (gIOConsoleLockTime
)
4281 clock_usec_t microsecs
;
4283 clock_get_calendar_microtime(&now
, µsecs
);
4284 if (gIOConsoleLockTime
> now
)
4286 AbsoluteTime deadline
;
4287 clock_interval_to_deadline(gIOConsoleLockTime
- now
, kSecondScale
, &deadline
);
4288 thread_call_enter_delayed(gIOConsoleLockCallout
, deadline
);
4292 locked
= kOSBooleanTrue
;
4296 publish
= (consoleUsers
|| (locked
!= regEntry
->getProperty(gIOConsoleLockedKey
)));
4299 regEntry
->setProperty(gIOConsoleLockedKey
, locked
);
4302 regEntry
->setProperty(gIOConsoleUsersKey
, consoleUsers
);
4304 OSIncrementAtomic( &gIOConsoleUsersSeed
);
4307 IOLockUnlock(gIOConsoleUsersLock
);
4311 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
4313 MessageClientsContext context
;
4315 context
.service
= getServiceRoot();
4316 context
.type
= kIOMessageConsoleSecurityChange
;
4317 context
.argument
= (void *) regEntry
;
4318 context
.argSize
= 0;
4320 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest
,
4321 &messageClientsApplier
, &context
);
4325 IOReturn
IOResources::setProperties( OSObject
* properties
)
4328 const OSSymbol
* key
;
4329 OSDictionary
* dict
;
4330 OSCollectionIterator
* iter
;
4332 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
4333 if ( kIOReturnSuccess
!= err
)
4336 dict
= OSDynamicCast(OSDictionary
, properties
);
4338 return( kIOReturnBadArgument
);
4340 iter
= OSCollectionIterator::withCollection( dict
);
4342 return( kIOReturnBadArgument
);
4344 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
4346 if (gIOConsoleUsersKey
== key
) do
4348 OSArray
* consoleUsers
;
4349 consoleUsers
= OSDynamicCast(OSArray
, dict
->getObject(key
));
4352 IOService::updateConsoleUsers(consoleUsers
, 0);
4356 publishResource( key
, dict
->getObject(key
) );
4361 return( kIOReturnSuccess
);
4365 * Helpers for matching dictionaries.
4366 * Keys existing in matching are checked in properties.
4367 * Keys may be a string or OSCollection of IOStrings
4370 bool IOService::compareProperty( OSDictionary
* matching
,
4376 value
= matching
->getObject( key
);
4378 ok
= value
->isEqualTo( getProperty( key
));
4386 bool IOService::compareProperty( OSDictionary
* matching
,
4387 const OSString
* key
)
4392 value
= matching
->getObject( key
);
4394 ok
= value
->isEqualTo( getProperty( key
));
4401 bool IOService::compareProperties( OSDictionary
* matching
,
4402 OSCollection
* keys
)
4404 OSCollectionIterator
* iter
;
4405 const OSString
* key
;
4408 if( !matching
|| !keys
)
4411 iter
= OSCollectionIterator::withCollection( keys
);
4414 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
4415 ok
= compareProperty( matching
, key
);
4419 keys
->release(); // !! consume a ref !!
4424 /* Helper to add a location matching dict to the table */
4426 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
4428 OSDictionary
* dict
;
4433 dict
= OSDictionary::withCapacity( 1 );
4435 table
->setObject( gIOLocationMatchKey
, dict
);
4443 * Go looking for a provider to match a location dict.
4446 IOService
* IOService::matchLocation( IOService
* /* client */ )
4450 parent
= getProvider();
4453 parent
= parent
->matchLocation( this );
4458 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
4464 IORegistryEntry
* entry
;
4469 bool matchParent
= false;
4480 str
= OSDynamicCast( OSString
, table
->getObject( gIOProviderClassKey
));
4483 match
= (0 != where
->metaCast( str
));
4488 obj
= table
->getObject( gIONameMatchKey
);
4491 match
= where
->compareNames( obj
, changesOK
? &matched
: 0 );
4494 if( changesOK
&& matched
) {
4495 // leave a hint as to which name matched
4496 table
->setObject( gIONameMatchedKey
, matched
);
4501 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
4504 const OSSymbol
* sym
;
4508 sym
= where
->copyLocation();
4510 match
= sym
->isEqualTo( str
);
4517 obj
= table
->getObject( gIOPropertyMatchKey
);
4520 OSDictionary
* dict
;
4521 OSDictionary
* nextDict
;
4526 dict
= where
->dictionaryWithProperties();
4528 nextDict
= OSDynamicCast( OSDictionary
, obj
);
4532 iter
= OSCollectionIterator::withCollection(
4533 OSDynamicCast(OSCollection
, obj
));
4536 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
4537 iter
->getNextObject()))))) {
4538 match
= dict
->isEqualTo( nextDict
, nextDict
);
4551 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
4554 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
4555 match
= (where
== entry
);
4562 num
= OSDynamicCast( OSNumber
, table
->getObject( gIORegistryEntryIDKey
));
4565 match
= (getRegistryEntryID() == num
->unsigned64BitValue());
4568 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
4572 IOService
* service
= 0;
4573 UInt32 serviceCount
= 0;
4576 iter
= where
->getClientIterator();
4578 while( (service
= (IOService
*) iter
->getNextObject())) {
4579 if( kIOServiceInactiveState
& service
->__state
[0])
4581 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
4587 match
= (serviceCount
== num
->unsigned32BitValue());
4592 if( done
== table
->getCount()) {
4593 // don't call family if we've done all the entries in the table
4594 matchParent
= false;
4598 // pass in score from property table
4599 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
4601 // do family specific matching
4602 match
= where
->matchPropertyTable( table
, &score
);
4606 if( kIOLogMatch
& getDebugFlags( table
))
4607 LOG("%s: family specific matching fails\n", where
->getName());
4614 newPri
= OSNumber::withNumber( score
, 32 );
4616 table
->setObject( gIOProbeScoreKey
, newPri
);
4621 if( !(match
= where
->compareProperty( table
, kIOBSDNameKey
)))
4623 if( !(match
= where
->compareProperty( table
, kIOBSDMajorKey
)))
4625 if( !(match
= where
->compareProperty( table
, kIOBSDMinorKey
)))
4627 if( !(match
= where
->compareProperty( table
, kIOBSDUnitKey
)))
4630 matchParent
= false;
4632 obj
= OSDynamicCast( OSDictionary
,
4633 table
->getObject( gIOParentMatchKey
));
4637 table
= (OSDictionary
*) obj
;
4641 table
= OSDynamicCast( OSDictionary
,
4642 table
->getObject( gIOLocationMatchKey
));
4645 where
= where
->getProvider();
4647 where
= where
->matchLocation( where
);
4650 } while( table
&& where
);
4652 } while( matchParent
&& (where
= where
->getProvider()) );
4654 if( kIOLogMatch
& gIOKitDebug
)
4655 if( where
&& (where
!= this) )
4656 LOG("match parent @ %s = %d\n",
4657 where
->getName(), match
);
4663 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4664 UInt32 type
, OSDictionary
* properties
,
4665 IOUserClient
** handler
)
4667 const OSSymbol
*userClientClass
= 0;
4668 IOUserClient
*client
;
4671 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
))
4672 return kIOReturnSuccess
;
4674 // First try my own properties for a user client class name
4675 temp
= getProperty(gIOUserClientClassKey
);
4677 if (OSDynamicCast(OSSymbol
, temp
))
4678 userClientClass
= (const OSSymbol
*) temp
;
4679 else if (OSDynamicCast(OSString
, temp
)) {
4680 userClientClass
= OSSymbol::withString((OSString
*) temp
);
4681 if (userClientClass
)
4682 setProperty(kIOUserClientClassKey
,
4683 (OSObject
*) userClientClass
);
4687 // Didn't find one so lets just bomb out now without further ado.
4688 if (!userClientClass
)
4689 return kIOReturnUnsupported
;
4691 // This reference is consumed by the IOServiceOpen call
4692 temp
= OSMetaClass::allocClassWithName(userClientClass
);
4694 return kIOReturnNoMemory
;
4696 if (OSDynamicCast(IOUserClient
, temp
))
4697 client
= (IOUserClient
*) temp
;
4700 return kIOReturnUnsupported
;
4703 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
4705 return kIOReturnBadArgument
;
4708 if ( !client
->attach(this) ) {
4710 return kIOReturnUnsupported
;
4713 if ( !client
->start(this) ) {
4714 client
->detach(this);
4716 return kIOReturnUnsupported
;
4720 return kIOReturnSuccess
;
4723 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4724 UInt32 type
, IOUserClient
** handler
)
4726 return( kIOReturnUnsupported
);
4729 IOReturn
IOService::requestProbe( IOOptionBits options
)
4731 return( kIOReturnUnsupported
);
4735 * Convert an IOReturn to text. Subclasses which add additional
4736 * IOReturn's should override this method and call
4737 * super::stringFromReturn if the desired value is not found.
4740 const char * IOService::stringFromReturn( IOReturn rtn
)
4742 static const IONamedValue IOReturn_values
[] = {
4743 {kIOReturnSuccess
, "success" },
4744 {kIOReturnError
, "general error" },
4745 {kIOReturnNoMemory
, "memory allocation error" },
4746 {kIOReturnNoResources
, "resource shortage" },
4747 {kIOReturnIPCError
, "Mach IPC failure" },
4748 {kIOReturnNoDevice
, "no such device" },
4749 {kIOReturnNotPrivileged
, "privilege violation" },
4750 {kIOReturnBadArgument
, "invalid argument" },
4751 {kIOReturnLockedRead
, "device is read locked" },
4752 {kIOReturnLockedWrite
, "device is write locked" },
4753 {kIOReturnExclusiveAccess
, "device is exclusive access" },
4754 {kIOReturnBadMessageID
, "bad IPC message ID" },
4755 {kIOReturnUnsupported
, "unsupported function" },
4756 {kIOReturnVMError
, "virtual memory error" },
4757 {kIOReturnInternalError
, "internal driver error" },
4758 {kIOReturnIOError
, "I/O error" },
4759 {kIOReturnCannotLock
, "cannot acquire lock" },
4760 {kIOReturnNotOpen
, "device is not open" },
4761 {kIOReturnNotReadable
, "device is not readable" },
4762 {kIOReturnNotWritable
, "device is not writeable" },
4763 {kIOReturnNotAligned
, "alignment error" },
4764 {kIOReturnBadMedia
, "media error" },
4765 {kIOReturnStillOpen
, "device is still open" },
4766 {kIOReturnRLDError
, "rld failure" },
4767 {kIOReturnDMAError
, "DMA failure" },
4768 {kIOReturnBusy
, "device is busy" },
4769 {kIOReturnTimeout
, "I/O timeout" },
4770 {kIOReturnOffline
, "device is offline" },
4771 {kIOReturnNotReady
, "device is not ready" },
4772 {kIOReturnNotAttached
, "device/channel is not attached" },
4773 {kIOReturnNoChannels
, "no DMA channels available" },
4774 {kIOReturnNoSpace
, "no space for data" },
4775 {kIOReturnPortExists
, "device port already exists" },
4776 {kIOReturnCannotWire
, "cannot wire physical memory" },
4777 {kIOReturnNoInterrupt
, "no interrupt attached" },
4778 {kIOReturnNoFrames
, "no DMA frames enqueued" },
4779 {kIOReturnMessageTooLarge
, "message is too large" },
4780 {kIOReturnNotPermitted
, "operation is not permitted" },
4781 {kIOReturnNoPower
, "device is without power" },
4782 {kIOReturnNoMedia
, "media is not present" },
4783 {kIOReturnUnformattedMedia
, "media is not formatted" },
4784 {kIOReturnUnsupportedMode
, "unsupported mode" },
4785 {kIOReturnUnderrun
, "data underrun" },
4786 {kIOReturnOverrun
, "data overrun" },
4787 {kIOReturnDeviceError
, "device error" },
4788 {kIOReturnNoCompletion
, "no completion routine" },
4789 {kIOReturnAborted
, "operation was aborted" },
4790 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
4791 {kIOReturnNotResponding
, "device is not responding" },
4792 {kIOReturnInvalid
, "unanticipated driver error" },
4796 return IOFindNameForValue(rtn
, IOReturn_values
);
4800 * Convert an IOReturn to an errno.
4802 int IOService::errnoFromReturn( IOReturn rtn
)
4806 case kIOReturnSuccess
:
4808 case kIOReturnNoMemory
:
4810 case kIOReturnNoDevice
:
4812 case kIOReturnVMError
:
4814 case kIOReturnNotPermitted
:
4816 case kIOReturnNotPrivileged
:
4818 case kIOReturnIOError
:
4820 case kIOReturnNotWritable
:
4822 case kIOReturnBadArgument
:
4824 case kIOReturnUnsupported
:
4828 case kIOReturnNoPower
:
4830 case kIOReturnDeviceError
:
4832 case kIOReturnTimeout
:
4834 case kIOReturnMessageTooLarge
:
4836 case kIOReturnNoSpace
:
4838 case kIOReturnCannotLock
:
4842 case kIOReturnBadMessageID
:
4843 case kIOReturnNoCompletion
:
4844 case kIOReturnNotAligned
:
4846 case kIOReturnNotReady
:
4848 case kIOReturnRLDError
:
4850 case kIOReturnPortExists
:
4851 case kIOReturnStillOpen
:
4853 case kIOReturnExclusiveAccess
:
4854 case kIOReturnLockedRead
:
4855 case kIOReturnLockedWrite
:
4856 case kIOReturnNotOpen
:
4857 case kIOReturnNotReadable
:
4859 case kIOReturnCannotWire
:
4860 case kIOReturnNoResources
:
4862 case kIOReturnAborted
:
4863 case kIOReturnOffline
:
4864 case kIOReturnNotResponding
:
4866 case kIOReturnBadMedia
:
4867 case kIOReturnNoMedia
:
4868 case kIOReturnNotAttached
:
4869 case kIOReturnUnformattedMedia
:
4870 return(ENXIO
); // (media error)
4871 case kIOReturnDMAError
:
4872 case kIOReturnOverrun
:
4873 case kIOReturnUnderrun
:
4874 return(EIO
); // (transfer error)
4875 case kIOReturnNoBandwidth
:
4876 case kIOReturnNoChannels
:
4877 case kIOReturnNoFrames
:
4878 case kIOReturnNoInterrupt
:
4879 return(EIO
); // (hardware error)
4880 case kIOReturnError
:
4881 case kIOReturnInternalError
:
4882 case kIOReturnInvalid
:
4883 return(EIO
); // (generic error)
4884 case kIOReturnIPCError
:
4885 return(EIO
); // (ipc error)
4887 return(EIO
); // (all other errors)
4891 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
4895 * Generic entry point for calls from the provider. A return value of
4896 * kIOReturnSuccess indicates that the message was received, and where
4897 * applicable, that it was successful.
4900 return kIOReturnUnsupported
;
4907 IOItemCount
IOService::getDeviceMemoryCount( void )
4912 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4914 count
= array
->getCount();
4921 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
4924 IODeviceMemory
* range
;
4926 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4928 range
= (IODeviceMemory
*) array
->getObject( index
);
4935 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
4936 IOOptionBits options
)
4938 IODeviceMemory
* range
;
4941 range
= getDeviceMemoryWithIndex( index
);
4943 map
= range
->map( options
);
4950 OSArray
* IOService::getDeviceMemory( void )
4952 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
4956 void IOService::setDeviceMemory( OSArray
* array
)
4958 setProperty( gIODeviceMemoryKey
, array
);
4962 * For machines where the transfers on an I/O bus can stall because
4963 * the CPU is in an idle mode, These APIs allow a driver to specify
4964 * the maximum bus stall that they can handle. 0 indicates no limit.
4967 setCPUSnoopDelay(UInt32 __unused ns
)
4969 #if defined(__i386__) || defined(__x86_64__)
4970 ml_set_maxsnoop(ns
);
4971 #endif /* defined(__i386__) || defined(__x86_64__) */
4977 #if defined(__i386__) || defined(__x86_64__)
4978 return ml_get_maxsnoop();
4981 #endif /* defined(__i386__) || defined(__x86_64__) */
4984 #if defined(__i386__) || defined(__x86_64__)
4986 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
)
4988 static const UInt kNoReplace
= -1U; // Must be an illegal index
4989 UInt replace
= kNoReplace
;
4990 bool setCpuDelay
= false;
4992 IORecursiveLockLock(sCpuDelayLock
);
4994 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
4995 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
4996 IOService
* holder
= NULL
;
4999 const CpuDelayEntry ne
= {service
, ns
, delayType
};
5001 // Set maximum delay.
5002 for (UInt i
= 0; i
< count
; i
++) {
5003 IOService
*thisService
= entries
[i
].fService
;
5004 bool sameType
= (delayType
== entries
[i
].fDelayType
);
5005 if ((service
== thisService
) && sameType
)
5007 else if (!thisService
) {
5008 if (kNoReplace
== replace
)
5011 else if (sameType
) {
5012 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
5016 holder
= thisService
;
5022 if (kNoReplace
== replace
)
5023 sCpuDelayData
->appendBytes(&ne
, sizeof(ne
));
5025 entries
[replace
] = ne
;
5028 ns
= -1U; // Set to max unsigned, i.e. no restriction
5030 for (UInt i
= 0; i
< count
; i
++) {
5031 // Clear a maximum delay.
5032 IOService
*thisService
= entries
[i
].fService
;
5033 if (thisService
&& (delayType
== entries
[i
].fDelayType
)) {
5034 UInt32 thisMax
= entries
[i
].fMaxDelay
;
5035 if (service
== thisService
)
5037 else if (thisMax
< ns
) {
5039 holder
= thisService
;
5044 // Check if entry found
5045 if (kNoReplace
!= replace
) {
5046 entries
[replace
].fService
= 0; // Null the entry
5053 // Must be safe to call from locked context
5054 if (delayType
== kCpuDelayBusStall
)
5056 ml_set_maxbusdelay(ns
);
5058 else if (delayType
== kCpuDelayInterrupt
)
5060 ml_set_maxintdelay(ns
);
5063 OSArray
* handlers
= sCpuLatencyHandlers
[delayType
];
5065 if (handlers
) for (unsigned int idx
= 0;
5066 (target
= (IOService
*) handlers
->getObject(idx
));
5069 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
5070 (void *) (uintptr_t) ns
, holder
,
5075 IORecursiveLockUnlock(sCpuDelayLock
);
5079 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
)
5081 IOReturn result
= kIOReturnNotFound
;
5085 IORecursiveLockLock(sCpuDelayLock
);
5089 if (enable
&& !sCpuLatencyHandlers
[delayType
])
5090 sCpuLatencyHandlers
[delayType
] = OSArray::withCapacity(4);
5091 array
= sCpuLatencyHandlers
[delayType
];
5094 idx
= array
->getNextIndexOfObject(target
, 0);
5099 array
->removeObject(idx
);
5100 result
= kIOReturnSuccess
;
5106 result
= kIOReturnExclusiveAccess
;
5109 array
->setObject(target
);
5111 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
5112 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
5113 UInt32 ns
= -1U; // Set to max unsigned, i.e. no restriction
5114 IOService
* holder
= NULL
;
5116 for (UInt i
= 0; i
< count
; i
++) {
5117 if (entries
[i
].fService
5118 && (delayType
== entries
[i
].fDelayType
)
5119 && (entries
[i
].fMaxDelay
< ns
)) {
5120 ns
= entries
[i
].fMaxDelay
;
5121 holder
= entries
[i
].fService
;
5124 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
5125 (void *) (uintptr_t) ns
, holder
,
5127 result
= kIOReturnSuccess
;
5132 IORecursiveLockUnlock(sCpuDelayLock
);
5137 #endif /* defined(__i386__) || defined(__x86_64__) */
5140 requireMaxBusStall(UInt32 __unused ns
)
5142 #if defined(__i386__) || defined(__x86_64__)
5143 requireMaxCpuDelay(this, ns
, kCpuDelayBusStall
);
5148 requireMaxInterruptDelay(uint32_t __unused ns
)
5150 #if defined(__i386__) || defined(__x86_64__)
5151 requireMaxCpuDelay(this, ns
, kCpuDelayInterrupt
);
5159 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
5161 IOInterruptController
*interruptController
;
5164 OSSymbol
*interruptControllerName
;
5166 IOInterruptSource
*interruptSources
;
5168 // Get the parents list from the nub.
5169 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
5170 if (array
== 0) return kIOReturnNoResources
;
5172 // Allocate space for the IOInterruptSources if needed... then return early.
5173 if (nub
->_interruptSources
== 0) {
5174 numSources
= array
->getCount();
5175 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
5176 if (interruptSources
== 0) return kIOReturnNoMemory
;
5178 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
5180 nub
->_numInterruptSources
= numSources
;
5181 nub
->_interruptSources
= interruptSources
;
5182 return kIOReturnSuccess
;
5185 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
5186 if (interruptControllerName
== 0) return kIOReturnNoResources
;
5188 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
5189 if (interruptController
== 0) return kIOReturnNoResources
;
5191 // Get the interrupt numbers from the nub.
5192 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
5193 if (array
== 0) return kIOReturnNoResources
;
5194 data
= OSDynamicCast(OSData
, array
->getObject(source
));
5195 if (data
== 0) return kIOReturnNoResources
;
5197 // Set the interruptController and interruptSource in the nub's table.
5198 interruptSources
= nub
->_interruptSources
;
5199 interruptSources
[source
].interruptController
= interruptController
;
5200 interruptSources
[source
].vectorData
= data
;
5202 return kIOReturnSuccess
;
5205 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
5209 /* Make sure the _interruptSources are set */
5210 if (_interruptSources
== 0) {
5211 ret
= resolveInterrupt(this, source
);
5212 if (ret
!= kIOReturnSuccess
) return ret
;
5215 /* Make sure the local source number is valid */
5216 if ((source
< 0) || (source
>= _numInterruptSources
))
5217 return kIOReturnNoInterrupt
;
5219 /* Look up the contoller for the local source */
5220 *interruptController
= _interruptSources
[source
].interruptController
;
5222 if (*interruptController
== NULL
) {
5223 if (!resolve
) return kIOReturnNoInterrupt
;
5225 /* Try to reslove the interrupt */
5226 ret
= resolveInterrupt(this, source
);
5227 if (ret
!= kIOReturnSuccess
) return ret
;
5229 *interruptController
= _interruptSources
[source
].interruptController
;
5232 return kIOReturnSuccess
;
5235 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
5236 IOInterruptAction handler
,
5239 IOInterruptController
*interruptController
;
5242 ret
= lookupInterrupt(source
, true, &interruptController
);
5243 if (ret
!= kIOReturnSuccess
) return ret
;
5245 /* Register the source */
5246 return interruptController
->registerInterrupt(this, source
, target
,
5247 (IOInterruptHandler
)handler
,
5251 IOReturn
IOService::unregisterInterrupt(int source
)
5253 IOInterruptController
*interruptController
;
5256 ret
= lookupInterrupt(source
, false, &interruptController
);
5257 if (ret
!= kIOReturnSuccess
) return ret
;
5259 /* Unregister the source */
5260 return interruptController
->unregisterInterrupt(this, source
);
5263 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
5265 IOInterruptController
*interruptController
;
5268 ret
= lookupInterrupt(source
, true, &interruptController
);
5269 if (ret
!= kIOReturnSuccess
) return ret
;
5271 /* Return the type */
5272 return interruptController
->getInterruptType(this, source
, interruptType
);
5275 IOReturn
IOService::enableInterrupt(int source
)
5277 IOInterruptController
*interruptController
;
5280 ret
= lookupInterrupt(source
, false, &interruptController
);
5281 if (ret
!= kIOReturnSuccess
) return ret
;
5283 /* Enable the source */
5284 return interruptController
->enableInterrupt(this, source
);
5287 IOReturn
IOService::disableInterrupt(int source
)
5289 IOInterruptController
*interruptController
;
5292 ret
= lookupInterrupt(source
, false, &interruptController
);
5293 if (ret
!= kIOReturnSuccess
) return ret
;
5295 /* Disable the source */
5296 return interruptController
->disableInterrupt(this, source
);
5299 IOReturn
IOService::causeInterrupt(int source
)
5301 IOInterruptController
*interruptController
;
5304 ret
= lookupInterrupt(source
, false, &interruptController
);
5305 if (ret
!= kIOReturnSuccess
) return ret
;
5307 /* Cause an interrupt for the source */
5308 return interruptController
->causeInterrupt(this, source
);
5312 OSMetaClassDefineReservedUnused(IOService
, 0);
5313 OSMetaClassDefineReservedUnused(IOService
, 1);
5314 OSMetaClassDefineReservedUnused(IOService
, 2);
5315 OSMetaClassDefineReservedUnused(IOService
, 3);
5316 OSMetaClassDefineReservedUnused(IOService
, 4);
5317 OSMetaClassDefineReservedUnused(IOService
, 5);
5319 OSMetaClassDefineReservedUsed(IOService
, 0);
5320 OSMetaClassDefineReservedUsed(IOService
, 1);
5321 OSMetaClassDefineReservedUsed(IOService
, 2);
5322 OSMetaClassDefineReservedUsed(IOService
, 3);
5323 OSMetaClassDefineReservedUsed(IOService
, 4);
5324 OSMetaClassDefineReservedUsed(IOService
, 5);
5326 OSMetaClassDefineReservedUnused(IOService
, 6);
5327 OSMetaClassDefineReservedUnused(IOService
, 7);
5328 OSMetaClassDefineReservedUnused(IOService
, 8);
5329 OSMetaClassDefineReservedUnused(IOService
, 9);
5330 OSMetaClassDefineReservedUnused(IOService
, 10);
5331 OSMetaClassDefineReservedUnused(IOService
, 11);
5332 OSMetaClassDefineReservedUnused(IOService
, 12);
5333 OSMetaClassDefineReservedUnused(IOService
, 13);
5334 OSMetaClassDefineReservedUnused(IOService
, 14);
5335 OSMetaClassDefineReservedUnused(IOService
, 15);
5336 OSMetaClassDefineReservedUnused(IOService
, 16);
5337 OSMetaClassDefineReservedUnused(IOService
, 17);
5338 OSMetaClassDefineReservedUnused(IOService
, 18);
5339 OSMetaClassDefineReservedUnused(IOService
, 19);
5340 OSMetaClassDefineReservedUnused(IOService
, 20);
5341 OSMetaClassDefineReservedUnused(IOService
, 21);
5342 OSMetaClassDefineReservedUnused(IOService
, 22);
5343 OSMetaClassDefineReservedUnused(IOService
, 23);
5344 OSMetaClassDefineReservedUnused(IOService
, 24);
5345 OSMetaClassDefineReservedUnused(IOService
, 25);
5346 OSMetaClassDefineReservedUnused(IOService
, 26);
5347 OSMetaClassDefineReservedUnused(IOService
, 27);
5348 OSMetaClassDefineReservedUnused(IOService
, 28);
5349 OSMetaClassDefineReservedUnused(IOService
, 29);
5350 OSMetaClassDefineReservedUnused(IOService
, 30);
5351 OSMetaClassDefineReservedUnused(IOService
, 31);
5352 OSMetaClassDefineReservedUnused(IOService
, 32);
5353 OSMetaClassDefineReservedUnused(IOService
, 33);
5354 OSMetaClassDefineReservedUnused(IOService
, 34);
5355 OSMetaClassDefineReservedUnused(IOService
, 35);
5356 OSMetaClassDefineReservedUnused(IOService
, 36);
5357 OSMetaClassDefineReservedUnused(IOService
, 37);
5358 OSMetaClassDefineReservedUnused(IOService
, 38);
5359 OSMetaClassDefineReservedUnused(IOService
, 39);
5360 OSMetaClassDefineReservedUnused(IOService
, 40);
5361 OSMetaClassDefineReservedUnused(IOService
, 41);
5362 OSMetaClassDefineReservedUnused(IOService
, 42);
5363 OSMetaClassDefineReservedUnused(IOService
, 43);
5364 OSMetaClassDefineReservedUnused(IOService
, 44);
5365 OSMetaClassDefineReservedUnused(IOService
, 45);
5366 OSMetaClassDefineReservedUnused(IOService
, 46);
5367 OSMetaClassDefineReservedUnused(IOService
, 47);