2 * Copyright (c) 1998-2008 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>
56 #include "IOServicePrivate.h"
58 // take lockForArbitration before LOCKNOTIFY
60 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
62 #define super IORegistryEntry
64 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
66 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
68 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
70 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
72 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
74 OSDefineMetaClassAndStructors(IOResources
, IOService
)
76 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
78 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
80 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
82 static IOPlatformExpert
* gIOPlatform
;
83 static class IOPMrootDomain
* gIOPMRootDomain
;
84 const IORegistryPlane
* gIOServicePlane
;
85 const IORegistryPlane
* gIOPowerPlane
;
86 const OSSymbol
* gIODeviceMemoryKey
;
87 const OSSymbol
* gIOInterruptControllersKey
;
88 const OSSymbol
* gIOInterruptSpecifiersKey
;
90 const OSSymbol
* gIOResourcesKey
;
91 const OSSymbol
* gIOResourceMatchKey
;
92 const OSSymbol
* gIOProviderClassKey
;
93 const OSSymbol
* gIONameMatchKey
;
94 const OSSymbol
* gIONameMatchedKey
;
95 const OSSymbol
* gIOPropertyMatchKey
;
96 const OSSymbol
* gIOLocationMatchKey
;
97 const OSSymbol
* gIOParentMatchKey
;
98 const OSSymbol
* gIOPathMatchKey
;
99 const OSSymbol
* gIOMatchCategoryKey
;
100 const OSSymbol
* gIODefaultMatchCategoryKey
;
101 const OSSymbol
* gIOMatchedServiceCountKey
;
103 const OSSymbol
* gIOMapperIDKey
;
104 const OSSymbol
* gIOUserClientClassKey
;
105 const OSSymbol
* gIOKitDebugKey
;
107 const OSSymbol
* gIOCommandPoolSizeKey
;
109 const OSSymbol
* gIOConsoleUsersKey
;
110 const OSSymbol
* gIOConsoleSessionUIDKey
;
111 const OSSymbol
* gIOConsoleUsersSeedKey
;
112 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
113 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
115 static int gIOResourceGenerationCount
;
117 const OSSymbol
* gIOServiceKey
;
118 const OSSymbol
* gIOPublishNotification
;
119 const OSSymbol
* gIOFirstPublishNotification
;
120 const OSSymbol
* gIOMatchedNotification
;
121 const OSSymbol
* gIOFirstMatchNotification
;
122 const OSSymbol
* gIOTerminatedNotification
;
124 const OSSymbol
* gIOGeneralInterest
;
125 const OSSymbol
* gIOBusyInterest
;
126 const OSSymbol
* gIOAppPowerStateInterest
;
127 const OSSymbol
* gIOPriorityPowerStateInterest
;
129 static OSDictionary
* gNotifications
;
130 static IORecursiveLock
* gNotificationLock
;
132 static IOService
* gIOResources
;
133 static IOService
* gIOServiceRoot
;
135 static OSOrderedSet
* gJobs
;
136 static semaphore_port_t gJobsSemaphore
;
137 static IOLock
* gJobsLock
;
138 static int gOutstandingJobs
;
139 static int gNumConfigThreads
;
140 static int gNumWaitingThreads
;
141 static IOLock
* gIOServiceBusyLock
;
143 static thread_t gIOTerminateThread
;
144 static UInt32 gIOTerminateWork
;
145 static OSArray
* gIOTerminatePhase2List
;
146 static OSArray
* gIOStopList
;
147 static OSArray
* gIOStopProviderList
;
148 static OSArray
* gIOFinalizeList
;
150 static SInt32 gIOConsoleUsersSeed
;
151 static OSData
* gIOConsoleUsersSeedValue
;
153 extern const OSSymbol
* gIODTPHandleKey
;
155 const OSSymbol
* gIOPlatformSleepActionKey
;
156 const OSSymbol
* gIOPlatformWakeActionKey
;
157 const OSSymbol
* gIOPlatformQuiesceActionKey
;
158 const OSSymbol
* gIOPlatformActiveActionKey
;
160 const OSSymbol
* gIOPlatformFunctionHandlerSet
;
162 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
164 #define LOCKREADNOTIFY() \
165 IORecursiveLockLock( gNotificationLock )
166 #define LOCKWRITENOTIFY() \
167 IORecursiveLockLock( gNotificationLock )
168 #define LOCKWRITE2READNOTIFY()
169 #define UNLOCKNOTIFY() \
170 IORecursiveLockUnlock( gNotificationLock )
171 #define SLEEPNOTIFY(event) \
172 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
173 #define SLEEPNOTIFYTO(event, deadline) \
174 IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT )
175 #define WAKEUPNOTIFY(event) \
176 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
178 #define randomDelay() \
179 int del = read_processor_clock(); \
180 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
183 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
185 #define queue_element(entry, element, type, field) do { \
186 vm_address_t __ele = (vm_address_t) (entry); \
187 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
188 (element) = (type) __ele; \
191 #define iterqueue(que, elt) \
192 for (queue_entry_t elt = queue_first(que); \
193 !queue_end(que, elt); \
194 elt = queue_next(elt))
196 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
198 struct ArbitrationLockQueueElement
{
207 static queue_head_t gArbitrationLockQueueActive
;
208 static queue_head_t gArbitrationLockQueueWaiting
;
209 static queue_head_t gArbitrationLockQueueFree
;
210 static IOLock
* gArbitrationLockQueueLock
;
212 bool IOService::isInactive( void ) const
213 { return( 0 != (kIOServiceInactiveState
& getState())); }
216 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
218 #define IOServiceTrace(csc, a, b, c, d) { \
219 if(kIOTraceIOService & gIOKitDebug) { \
220 KERNEL_DEBUG_CONSTANT(IODBG_IOSERVICE(csc), a, b, c, d, 0); \
224 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
226 #if defined(__i386__) || defined(__x86_64__)
228 // Only used by the intel implementation of
229 // IOService::requireMaxBusStall(UInt32 ns)
230 // IOService::requireMaxInterruptDelay(uint32_t ns)
233 IOService
* fService
;
239 kCpuDelayBusStall
, kCpuDelayInterrupt
,
243 static OSData
*sCpuDelayData
= OSData::withCapacity(8 * sizeof(CpuDelayEntry
));
244 static IORecursiveLock
*sCpuDelayLock
= IORecursiveLockAlloc();
245 static OSArray
*sCpuLatencyHandlers
[kCpuNumDelayTypes
];
246 const OSSymbol
*sCPULatencyFunctionName
[kCpuNumDelayTypes
];
249 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
);
251 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
);
253 #endif /* defined(__i386__) || defined(__x86_64__) */
255 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
257 void IOService::initialize( void )
261 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
262 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
264 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
265 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
266 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
267 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
268 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
269 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
270 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
272 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
273 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
274 kIODefaultMatchCategoryKey
);
275 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
276 kIOMatchedServiceCountKey
);
278 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
280 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
281 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
283 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
284 gIOInterruptControllersKey
285 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
286 gIOInterruptSpecifiersKey
287 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
289 gIOMapperIDKey
= OSSymbol::withCStringNoCopy(kIOMapperIDKey
);
291 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
293 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
295 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
296 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
297 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
298 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
300 gNotifications
= OSDictionary::withCapacity( 1 );
301 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
302 kIOPublishNotification
);
303 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
304 kIOFirstPublishNotification
);
305 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
306 kIOMatchedNotification
);
307 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
308 kIOFirstMatchNotification
);
309 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
310 kIOTerminatedNotification
);
311 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
313 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
314 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
315 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey
);
316 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionOnConsoleKey
);
317 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionSecureInputPIDKey
);
318 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
320 gIOPlatformSleepActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformSleepActionKey
);
321 gIOPlatformWakeActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformWakeActionKey
);
322 gIOPlatformQuiesceActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformQuiesceActionKey
);
323 gIOPlatformActiveActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformActiveActionKey
);
325 gIOPlatformFunctionHandlerSet
= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet
);
326 #if defined(__i386__) || defined(__x86_64__)
327 sCPULatencyFunctionName
[kCpuDelayBusStall
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay
);
328 sCPULatencyFunctionName
[kCpuDelayInterrupt
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay
);
330 gNotificationLock
= IORecursiveLockAlloc();
332 assert( gIOServicePlane
&& gIODeviceMemoryKey
333 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
334 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
335 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
336 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
337 && gIOPublishNotification
&& gIOMatchedNotification
338 && gIOTerminatedNotification
&& gIOServiceKey
339 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
340 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
341 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
343 gJobsLock
= IOLockAlloc();
344 gJobs
= OSOrderedSet::withCapacity( 10 );
346 gIOServiceBusyLock
= IOLockAlloc();
348 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
350 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& (err
== KERN_SUCCESS
) );
352 gIOResources
= IOResources::resources();
353 assert( gIOResources
);
355 gArbitrationLockQueueLock
= IOLockAlloc();
356 queue_init(&gArbitrationLockQueueActive
);
357 queue_init(&gArbitrationLockQueueWaiting
);
358 queue_init(&gArbitrationLockQueueFree
);
360 assert( gArbitrationLockQueueLock
);
362 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
363 gIOStopList
= OSArray::withCapacity( 16 );
364 gIOStopProviderList
= OSArray::withCapacity( 16 );
365 gIOFinalizeList
= OSArray::withCapacity( 16 );
366 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
369 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
372 static UInt64
getDebugFlags( OSDictionary
* props
)
374 OSNumber
* debugProp
;
377 debugProp
= OSDynamicCast( OSNumber
,
378 props
->getObject( gIOKitDebugKey
));
380 debugFlags
= debugProp
->unsigned64BitValue();
382 debugFlags
= gIOKitDebug
;
384 return( debugFlags
);
388 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
390 // Probe a matched service and return an instance to be started.
391 // The default score is from the property table, & may be altered
392 // during probe to change the start order.
394 IOService
* IOService::probe( IOService
* provider
,
400 bool IOService::start( IOService
* provider
)
405 void IOService::stop( IOService
* provider
)
409 void IOService::free( void )
411 requireMaxBusStall(0);
412 requireMaxInterruptDelay(0);
413 if( getPropertyTable())
414 unregisterAllInterest();
420 * Attach in service plane
422 bool IOService::attach( IOService
* provider
)
428 if( gIOKitDebug
& kIOLogAttach
)
429 LOG( "%s::attach(%s)\n", getName(),
430 provider
->getName());
432 provider
->lockForArbitration();
433 if( provider
->__state
[0] & kIOServiceInactiveState
)
436 ok
= attachToParent( provider
, gIOServicePlane
);
437 provider
->unlockForArbitration();
440 gIOServiceRoot
= this;
441 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
447 IOService
* IOService::getServiceRoot( void )
449 return( gIOServiceRoot
);
452 void IOService::detach( IOService
* provider
)
454 IOService
* newProvider
= 0;
458 if( gIOKitDebug
& kIOLogAttach
)
459 LOG("%s::detach(%s)\n", getName(), provider
->getName());
461 lockForArbitration();
463 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
464 && (provider
== getProvider()));
466 detachFromParent( provider
, gIOServicePlane
);
469 newProvider
= getProvider();
470 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
471 _adjustBusy( -busy
);
474 unlockForArbitration();
477 newProvider
->lockForArbitration();
478 newProvider
->_adjustBusy(1);
479 newProvider
->unlockForArbitration();
482 // check for last client detach from a terminated service
483 if( provider
->lockForArbitration( true )) {
485 provider
->_adjustBusy( -1 );
486 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
487 && (0 == provider
->getClient())) {
488 provider
->scheduleFinalize();
490 provider
->unlockForArbitration();
495 * Register instance - publish it for matching
498 void IOService::registerService( IOOptionBits options
)
504 enum { kMaxPathLen
= 256 };
505 enum { kMaxChars
= 63 };
507 IORegistryEntry
* parent
= this;
508 IORegistryEntry
* root
= getRegistryRoot();
509 while( parent
&& (parent
!= root
))
510 parent
= parent
->getParentEntry( gIOServicePlane
);
512 if( parent
!= root
) {
513 IOLog("%s: not registry member at registerService()\n", getName());
517 // Allow the Platform Expert to adjust this node.
518 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
521 if( (this != gIOResources
)
522 && (kIOLogRegister
& gIOKitDebug
)) {
524 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
526 IOLog( "Registering: " );
529 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
532 if( len
> kMaxChars
) {
536 if( (skip
= strchr( path
, '/')))
542 IOLog( "%s\n", path
);
545 IOFree( pathBuf
, kMaxPathLen
);
548 startMatching( options
);
551 void IOService::startMatching( IOOptionBits options
)
553 IOService
* provider
;
556 bool needWake
= false;
561 lockForArbitration();
563 sync
= (options
& kIOServiceSynchronous
)
564 || ((provider
= getProvider())
565 && (provider
->__state
[1] & kIOServiceSynchronousState
));
567 if ( options
& kIOServiceAsynchronous
)
570 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
571 && (0 == (__state
[0] & kIOServiceInactiveState
));
573 __state
[1] |= kIOServiceNeedConfigState
;
575 // __state[0] &= ~kIOServiceInactiveState;
577 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
578 // OSKernelStackRemaining(), getName());
581 prevBusy
= _adjustBusy( 1 );
582 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
586 __state
[1] |= kIOServiceSynchronousState
;
588 __state
[1] &= ~kIOServiceSynchronousState
;
590 unlockForArbitration();
595 IOLockLock( gIOServiceBusyLock
);
596 thread_wakeup( (event_t
) this/*&__state[1]*/ );
597 IOLockUnlock( gIOServiceBusyLock
);
599 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
601 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
605 if( (__state
[1] & kIOServiceNeedConfigState
))
606 doServiceMatch( options
);
608 lockForArbitration();
609 IOLockLock( gIOServiceBusyLock
);
611 waitAgain
= (prevBusy
< (__state
[1] & kIOServiceBusyStateMask
));
613 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
615 __state
[1] &= ~kIOServiceSyncPubState
;
617 unlockForArbitration();
620 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
622 IOLockUnlock( gIOServiceBusyLock
);
624 thread_block(THREAD_CONTINUE_NULL
);
626 } while( waitAgain
);
630 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
632 OSDictionary
* table
;
642 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
645 set
= (OSSet
*) copyExistingServices( table
,
646 kIOServiceRegisteredState
,
647 kIOServiceExistingSet
);
652 count
+= set
->getCount();
655 allSet
->merge((const OSSet
*) set
);
663 if( getDebugFlags( table
) & kIOLogMatch
)
664 LOG("Matching service count = %ld\n", (long)count
);
666 newTables
->removeObject(table
);
670 while( (service
= (IOService
*) allSet
->getAnyObject())) {
671 service
->startMatching(kIOServiceAsynchronous
);
672 allSet
->removeObject(service
);
677 newTables
->release();
679 return( kIOReturnSuccess
);
682 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
683 IOOptionBits options
)
687 job
= new _IOServiceJob
;
688 if( job
&& !job
->init()) {
696 job
->options
= options
;
697 nub
->retain(); // thread will release()
705 * Called on a registered service to see if it matches
709 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
711 return( matchPropertyTable(table
) );
714 bool IOService::matchPropertyTable( OSDictionary
* table
)
720 * Called on a matched service to allocate resources
721 * before first driver is attached.
724 IOReturn
IOService::getResources( void )
726 return( kIOReturnSuccess
);
730 * Client/provider accessors
733 IOService
* IOService::getProvider( void ) const
735 IOService
* self
= (IOService
*) this;
740 generation
= getGenerationCount();
741 if( __providerGeneration
== generation
)
744 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
745 if( parent
== IORegistryEntry::getRegistryRoot())
746 /* root is not an IOService */
749 self
->__provider
= parent
;
750 // save the count before getParentEntry()
751 self
->__providerGeneration
= generation
;
756 IOWorkLoop
* IOService::getWorkLoop() const
758 IOService
*provider
= getProvider();
761 return provider
->getWorkLoop();
766 OSIterator
* IOService::getProviderIterator( void ) const
768 return( getParentIterator( gIOServicePlane
));
771 IOService
* IOService::getClient( void ) const
773 return( (IOService
*) getChildEntry( gIOServicePlane
));
776 OSIterator
* IOService::getClientIterator( void ) const
778 return( getChildIterator( gIOServicePlane
));
781 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
782 const IOService
* client
,
783 const IOService
* provider
)
785 _IOOpenServiceIterator
* inst
;
790 inst
= new _IOOpenServiceIterator
;
792 if( inst
&& !inst
->init()) {
798 inst
->client
= client
;
799 inst
->provider
= provider
;
805 void _IOOpenServiceIterator::free()
809 last
->unlockForArbitration();
813 OSObject
* _IOOpenServiceIterator::getNextObject()
818 last
->unlockForArbitration();
820 while( (next
= (IOService
*) iter
->getNextObject())) {
822 next
->lockForArbitration();
823 if( (client
&& (next
->isOpen( client
)))
824 || (provider
&& (provider
->isOpen( next
))) )
826 next
->unlockForArbitration();
834 bool _IOOpenServiceIterator::isValid()
836 return( iter
->isValid() );
839 void _IOOpenServiceIterator::reset()
842 last
->unlockForArbitration();
848 OSIterator
* IOService::getOpenProviderIterator( void ) const
850 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
853 OSIterator
* IOService::getOpenClientIterator( void ) const
855 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
859 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
860 bool waitForFunction
,
861 void *param1
, void *param2
,
862 void *param3
, void *param4
)
864 IOReturn result
= kIOReturnUnsupported
;
867 if (gIOPlatformFunctionHandlerSet
== functionName
)
869 #if defined(__i386__) || defined(__x86_64__)
870 const OSSymbol
* functionHandlerName
= (const OSSymbol
*) param1
;
871 IOService
* target
= (IOService
*) param2
;
872 bool enable
= (param3
!= 0);
874 if (sCPULatencyFunctionName
[kCpuDelayBusStall
] == functionHandlerName
)
875 result
= setLatencyHandler(kCpuDelayBusStall
, target
, enable
);
876 else if (sCPULatencyFunctionName
[kCpuDelayInterrupt
] == param1
)
877 result
= setLatencyHandler(kCpuDelayInterrupt
, target
, enable
);
878 #endif /* defined(__i386__) || defined(__x86_64__) */
881 if ((kIOReturnUnsupported
== result
) && (provider
= getProvider())) {
882 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
883 param1
, param2
, param3
, param4
);
889 IOReturn
IOService::callPlatformFunction( const char * functionName
,
890 bool waitForFunction
,
891 void *param1
, void *param2
,
892 void *param3
, void *param4
)
894 IOReturn result
= kIOReturnNoMemory
;
895 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
897 if (functionSymbol
!= 0) {
898 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
899 param1
, param2
, param3
, param4
);
900 functionSymbol
->release();
908 * Accessors for global services
911 IOPlatformExpert
* IOService::getPlatform( void )
913 return( gIOPlatform
);
916 class IOPMrootDomain
* IOService::getPMRootDomain( void )
918 return( gIOPMRootDomain
);
921 IOService
* IOService::getResourceService( void )
923 return( gIOResources
);
926 void IOService::setPlatform( IOPlatformExpert
* platform
)
928 gIOPlatform
= platform
;
929 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
932 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
934 gIOPMRootDomain
= rootDomain
;
935 publishResource("IOKit");
942 bool IOService::lockForArbitration( bool isSuccessRequired
)
946 ArbitrationLockQueueElement
* element
;
947 ArbitrationLockQueueElement
* active
;
948 ArbitrationLockQueueElement
* waiting
;
950 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
952 // lock global access
953 IOTakeLock( gArbitrationLockQueueLock
);
955 // obtain an unused queue element
956 if( !queue_empty( &gArbitrationLockQueueFree
)) {
957 queue_remove_first( &gArbitrationLockQueueFree
,
959 ArbitrationLockQueueElement
*,
962 element
= IONew( ArbitrationLockQueueElement
, 1 );
966 // prepare the queue element
967 element
->thread
= IOThreadSelf();
968 element
->service
= this;
970 element
->required
= isSuccessRequired
;
971 element
->aborted
= false;
973 // determine whether this object is already locked (ie. on active queue)
975 queue_iterate( &gArbitrationLockQueueActive
,
977 ArbitrationLockQueueElement
*,
980 if( active
->service
== element
->service
) {
986 if( found
) { // this object is already locked
988 // determine whether it is the same or a different thread trying to lock
989 if( active
->thread
!= element
->thread
) { // it is a different thread
991 ArbitrationLockQueueElement
* victim
= 0;
993 // before placing this new thread on the waiting queue, we look for
994 // a deadlock cycle...
997 // determine whether the active thread holding the object we
998 // want is waiting for another object to be unlocked
1000 queue_iterate( &gArbitrationLockQueueWaiting
,
1002 ArbitrationLockQueueElement
*,
1005 if( waiting
->thread
== active
->thread
) {
1006 assert( false == waiting
->aborted
);
1012 if( found
) { // yes, active thread waiting for another object
1014 // this may be a candidate for rejection if the required
1015 // flag is not set, should we detect a deadlock later on
1016 if( false == waiting
->required
)
1019 // find the thread that is holding this other object, that
1020 // is blocking the active thread from proceeding (fun :-)
1022 queue_iterate( &gArbitrationLockQueueActive
,
1023 active
, // (reuse active queue element)
1024 ArbitrationLockQueueElement
*,
1027 if( active
->service
== waiting
->service
) {
1033 // someone must be holding it or it wouldn't be waiting
1036 if( active
->thread
== element
->thread
) {
1038 // doh, it's waiting for the thread that originated
1039 // this whole lock (ie. current thread) -> deadlock
1040 if( false == element
->required
) { // willing to fail?
1042 // the originating thread doesn't have the required
1043 // flag, so it can fail
1044 success
= false; // (fail originating lock request)
1045 break; // (out of while)
1047 } else { // originating thread is not willing to fail
1049 // see if we came across a waiting thread that did
1050 // not have the 'required' flag set: we'll fail it
1053 // we do have a willing victim, fail it's lock
1054 victim
->aborted
= true;
1056 // take the victim off the waiting queue
1057 queue_remove( &gArbitrationLockQueueWaiting
,
1059 ArbitrationLockQueueElement
*,
1063 IOLockWakeup( gArbitrationLockQueueLock
,
1065 /* one thread */ true );
1067 // allow this thread to proceed (ie. wait)
1068 success
= true; // (put request on wait queue)
1069 break; // (out of while)
1072 // all the waiting threads we came across in
1073 // finding this loop had the 'required' flag
1074 // set, so we've got a deadlock we can't avoid
1075 panic("I/O Kit: Unrecoverable deadlock.");
1079 // repeat while loop, redefining active thread to be the
1080 // thread holding "this other object" (see above), and
1081 // looking for threads waiting on it; note the active
1082 // variable points to "this other object" already... so
1083 // there nothing to do in this else clause.
1085 } else { // no, active thread is not waiting for another object
1087 success
= true; // (put request on wait queue)
1088 break; // (out of while)
1092 if( success
) { // put the request on the waiting queue?
1093 kern_return_t wait_result
;
1095 // place this thread on the waiting queue and put it to sleep;
1096 // we place it at the tail of the queue...
1097 queue_enter( &gArbitrationLockQueueWaiting
,
1099 ArbitrationLockQueueElement
*,
1102 // declare that this thread will wait for a given event
1103 restart_sleep
: wait_result
= assert_wait( element
,
1104 element
->required
? THREAD_UNINT
1105 : THREAD_INTERRUPTIBLE
);
1107 // unlock global access
1108 IOUnlock( gArbitrationLockQueueLock
);
1110 // put thread to sleep, waiting for our event to fire...
1111 if (wait_result
== THREAD_WAITING
)
1112 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1115 // ...and we've been woken up; we might be in one of two states:
1116 // (a) we've been aborted and our queue element is not on
1117 // any of the three queues, but is floating around
1118 // (b) we're allowed to proceed with the lock and we have
1119 // already been moved from the waiting queue to the
1121 // ...plus a 3rd state, should the thread have been interrupted:
1122 // (c) we're still on the waiting queue
1124 // determine whether we were interrupted out of our sleep
1125 if( THREAD_INTERRUPTED
== wait_result
) {
1127 // re-lock global access
1128 IOTakeLock( gArbitrationLockQueueLock
);
1130 // determine whether we're still on the waiting queue
1132 queue_iterate( &gArbitrationLockQueueWaiting
,
1133 waiting
, // (reuse waiting queue element)
1134 ArbitrationLockQueueElement
*,
1137 if( waiting
== element
) {
1143 if( found
) { // yes, we're still on the waiting queue
1145 // determine whether we're willing to fail
1146 if( false == element
->required
) {
1148 // mark us as aborted
1149 element
->aborted
= true;
1151 // take us off the waiting queue
1152 queue_remove( &gArbitrationLockQueueWaiting
,
1154 ArbitrationLockQueueElement
*,
1156 } else { // we are not willing to fail
1158 // ignore interruption, go back to sleep
1163 // unlock global access
1164 IOUnlock( gArbitrationLockQueueLock
);
1166 // proceed as though this were a normal wake up
1167 wait_result
= THREAD_AWAKENED
;
1170 assert( THREAD_AWAKENED
== wait_result
);
1172 // determine whether we've been aborted while we were asleep
1173 if( element
->aborted
) {
1174 assert( false == element
->required
);
1176 // re-lock global access
1177 IOTakeLock( gArbitrationLockQueueLock
);
1179 action
= kPutOnFreeQueue
;
1181 } else { // we weren't aborted, so we must be ready to go :-)
1183 // we've already been moved from waiting to active queue
1187 } else { // the lock request is to be failed
1189 // return unused queue element to queue
1190 action
= kPutOnFreeQueue
;
1192 } else { // it is the same thread, recursive access is allowed
1194 // add one level of recursion
1197 // return unused queue element to queue
1198 action
= kPutOnFreeQueue
;
1201 } else { // this object is not already locked, so let this thread through
1202 action
= kPutOnActiveQueue
;
1206 // put the new element on a queue
1207 if( kPutOnActiveQueue
== action
) {
1208 queue_enter( &gArbitrationLockQueueActive
,
1210 ArbitrationLockQueueElement
*,
1212 } else if( kPutOnFreeQueue
== action
) {
1213 queue_enter( &gArbitrationLockQueueFree
,
1215 ArbitrationLockQueueElement
*,
1218 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1221 // unlock global access
1222 IOUnlock( gArbitrationLockQueueLock
);
1227 void IOService::unlockForArbitration( void )
1230 ArbitrationLockQueueElement
* element
;
1232 // lock global access
1233 IOTakeLock( gArbitrationLockQueueLock
);
1235 // find the lock element for this object (ie. on active queue)
1237 queue_iterate( &gArbitrationLockQueueActive
,
1239 ArbitrationLockQueueElement
*,
1242 if( element
->service
== this ) {
1250 // determine whether the lock has been taken recursively
1251 if( element
->count
> 1 ) {
1252 // undo one level of recursion
1257 // remove it from the active queue
1258 queue_remove( &gArbitrationLockQueueActive
,
1260 ArbitrationLockQueueElement
*,
1263 // put it on the free queue
1264 queue_enter( &gArbitrationLockQueueFree
,
1266 ArbitrationLockQueueElement
*,
1269 // determine whether a thread is waiting for object (head to tail scan)
1271 queue_iterate( &gArbitrationLockQueueWaiting
,
1273 ArbitrationLockQueueElement
*,
1276 if( element
->service
== this ) {
1282 if ( found
) { // we found an interested thread on waiting queue
1284 // remove it from the waiting queue
1285 queue_remove( &gArbitrationLockQueueWaiting
,
1287 ArbitrationLockQueueElement
*,
1290 // put it on the active queue
1291 queue_enter( &gArbitrationLockQueueActive
,
1293 ArbitrationLockQueueElement
*,
1296 // wake the waiting thread
1297 IOLockWakeup( gArbitrationLockQueueLock
,
1299 /* one thread */ true );
1303 // unlock global access
1304 IOUnlock( gArbitrationLockQueueLock
);
1307 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1310 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1311 context
, gIOServicePlane
);
1314 void IOService::applyToClients( IOServiceApplierFunction applier
,
1317 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1318 context
, gIOServicePlane
);
1327 // send a message to a client or interested party of this service
1328 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1329 void * argument
, vm_size_t argSize
)
1332 IOService
* service
;
1333 _IOServiceInterestNotifier
* notify
;
1335 if( (service
= OSDynamicCast( IOService
, client
)))
1336 ret
= service
->message( type
, this, argument
);
1338 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1340 _IOServiceNotifierInvocation invocation
;
1343 invocation
.thread
= current_thread();
1346 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1349 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1350 _IOServiceNotifierInvocation
*, link
);
1356 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1357 type
, this, argument
, argSize
);
1360 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1361 _IOServiceNotifierInvocation
*, link
);
1362 if( kIOServiceNotifyWaiter
& notify
->state
) {
1363 notify
->state
&= ~kIOServiceNotifyWaiter
;
1364 WAKEUPNOTIFY( notify
);
1369 ret
= kIOReturnSuccess
;
1372 ret
= kIOReturnBadArgument
;
1378 applyToInterestNotifiers(const IORegistryEntry
*target
,
1379 const OSSymbol
* typeOfInterest
,
1380 OSObjectApplierFunction applier
,
1383 OSArray
* copyArray
= 0;
1387 IOCommand
*notifyList
=
1388 OSDynamicCast( IOCommand
, target
->getProperty( typeOfInterest
));
1391 copyArray
= OSArray::withCapacity(1);
1393 // iterate over queue, entry is set to each element in the list
1394 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1395 _IOServiceInterestNotifier
* notify
;
1397 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1398 copyArray
->setObject(notify
);
1407 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1408 (*applier
)(next
, context
);
1409 copyArray
->release();
1413 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1414 OSObjectApplierFunction applier
,
1417 if (gIOGeneralInterest
== typeOfInterest
)
1418 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1419 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1422 struct MessageClientsContext
{
1423 IOService
* service
;
1430 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1433 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1435 ret
= context
->service
->messageClient( context
->type
,
1436 object
, context
->argument
, context
->argSize
);
1437 if( kIOReturnSuccess
!= ret
)
1441 // send a message to all clients
1442 IOReturn
IOService::messageClients( UInt32 type
,
1443 void * argument
, vm_size_t argSize
)
1445 MessageClientsContext context
;
1447 context
.service
= this;
1448 context
.type
= type
;
1449 context
.argument
= argument
;
1450 context
.argSize
= argSize
;
1451 context
.ret
= kIOReturnSuccess
;
1453 applyToInterested( gIOGeneralInterest
,
1454 &messageClientsApplier
, &context
);
1456 return( context
.ret
);
1459 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1460 IOOptionBits response
)
1462 return( kIOReturnUnsupported
);
1465 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1466 IOServiceInterestHandler handler
, void * target
, void * ref
)
1468 _IOServiceInterestNotifier
* notify
= 0;
1470 if( (typeOfInterest
!= gIOGeneralInterest
)
1471 && (typeOfInterest
!= gIOBusyInterest
)
1472 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1473 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1476 lockForArbitration();
1477 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1479 notify
= new _IOServiceInterestNotifier
;
1480 if( notify
&& !notify
->init()) {
1486 notify
->handler
= handler
;
1487 notify
->target
= target
;
1489 notify
->state
= kIOServiceNotifyEnable
;
1490 queue_init( ¬ify
->handlerInvocations
);
1496 // Get the head of the notifier linked list
1497 IOCommand
*notifyList
= (IOCommand
*) getProperty( typeOfInterest
);
1498 if (!notifyList
|| !OSDynamicCast(IOCommand
, notifyList
)) {
1499 notifyList
= OSTypeAlloc(IOCommand
);
1502 setProperty( typeOfInterest
, notifyList
);
1503 notifyList
->release();
1508 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1509 notify
->retain(); // ref'ed while in list
1515 unlockForArbitration();
1520 static void cleanInterestList( OSObject
* head
)
1522 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1527 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1528 queue_next(entry
) = queue_prev(entry
) = 0;
1530 _IOServiceInterestNotifier
* notify
;
1532 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1538 void IOService::unregisterAllInterest( void )
1540 cleanInterestList( getProperty( gIOGeneralInterest
));
1541 cleanInterestList( getProperty( gIOBusyInterest
));
1542 cleanInterestList( getProperty( gIOAppPowerStateInterest
));
1543 cleanInterestList( getProperty( gIOPriorityPowerStateInterest
));
1547 * _IOServiceInterestNotifier
1550 // wait for all threads, other than the current one,
1551 // to exit the handler
1553 void _IOServiceInterestNotifier::wait()
1555 _IOServiceNotifierInvocation
* next
;
1560 queue_iterate( &handlerInvocations
, next
,
1561 _IOServiceNotifierInvocation
*, link
) {
1562 if( next
->thread
!= current_thread() ) {
1568 state
|= kIOServiceNotifyWaiter
;
1575 void _IOServiceInterestNotifier::free()
1577 assert( queue_empty( &handlerInvocations
));
1581 void _IOServiceInterestNotifier::remove()
1585 if( queue_next( &chain
)) {
1586 remqueue( 0, &chain
);
1587 queue_next( &chain
) = queue_prev( &chain
) = 0;
1591 state
&= ~kIOServiceNotifyEnable
;
1600 bool _IOServiceInterestNotifier::disable()
1606 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1607 state
&= ~kIOServiceNotifyEnable
;
1616 void _IOServiceInterestNotifier::enable( bool was
)
1620 state
|= kIOServiceNotifyEnable
;
1622 state
&= ~kIOServiceNotifyEnable
;
1626 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1632 #define tailQ(o) setObject(o)
1633 #define headQ(o) setObject(0, o)
1634 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); }
1636 static void _workLoopAction( IOWorkLoop::Action action
,
1637 IOService
* service
,
1638 void * p0
= 0, void * p1
= 0,
1639 void * p2
= 0, void * p3
= 0 )
1643 if( (wl
= service
->getWorkLoop())) {
1645 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1648 (*action
)( service
, p0
, p1
, p2
, p3
);
1651 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1655 // if its our only provider
1656 ok
= isParent( provider
, gIOServicePlane
, true);
1660 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1661 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1668 bool IOService::terminatePhase1( IOOptionBits options
)
1673 OSArray
* makeInactive
;
1676 bool startPhase2
= false;
1678 TLOG("%s::terminatePhase1(%08llx)\n", getName(), (long long)options
);
1680 uint64_t regID
= getRegistryEntryID();
1682 IOSERVICE_TERMINATE_PHASE1
,
1684 (uintptr_t) (regID
>> 32),
1686 (uintptr_t) options
);
1689 if( options
& kIOServiceRecursing
) {
1690 __state
[1] |= kIOServiceRecursing
;
1695 makeInactive
= OSArray::withCapacity( 16 );
1704 didInactive
= victim
->lockForArbitration( true );
1706 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1708 victim
->__state
[0] |= kIOServiceInactiveState
;
1709 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1710 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1711 victim
->_adjustBusy( 1 );
1713 victim
->unlockForArbitration();
1716 startPhase2
= didInactive
;
1719 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1720 IOUserClient::destroyUserReferences( victim
);
1722 iter
= victim
->getClientIterator();
1724 while( (client
= (IOService
*) iter
->getNextObject())) {
1725 TLOG("%s::requestTerminate(%s, %08llx)\n",
1726 client
->getName(), victim
->getName(), (long long)options
);
1727 ok
= client
->requestTerminate( victim
, options
);
1728 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1729 client
->getName(), victim
->getName(), ok
);
1731 uint64_t regID1
= client
->getRegistryEntryID();
1732 uint64_t regID2
= victim
->getRegistryEntryID();
1734 (ok
? IOSERVICE_TERMINATE_REQUEST_OK
1735 : IOSERVICE_TERMINATE_REQUEST_FAIL
),
1737 (uintptr_t) (regID1
>> 32),
1739 (uintptr_t) (regID2
>> 32));
1742 makeInactive
->setObject( client
);
1748 victim
= (IOService
*) makeInactive
->getObject(0);
1751 makeInactive
->removeObject(0);
1755 makeInactive
->release();
1758 scheduleTerminatePhase2( options
);
1763 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
1765 AbsoluteTime deadline
;
1766 int waitResult
= THREAD_AWAKENED
;
1767 bool wait
, haveDeadline
= false;
1769 options
|= kIOServiceRequired
;
1773 IOLockLock( gJobsLock
);
1775 if( (options
& kIOServiceSynchronous
)
1776 && (current_thread() != gIOTerminateThread
)) {
1779 wait
= (gIOTerminateThread
!= 0);
1781 // wait to become the terminate thread
1782 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
1786 gIOTerminateThread
= current_thread();
1787 gIOTerminatePhase2List
->setObject( this );
1791 while( gIOTerminateWork
)
1792 terminateWorker( options
);
1793 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1795 // wait for the victim to go non-busy
1796 if( !haveDeadline
) {
1797 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1798 haveDeadline
= true;
1800 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
1801 deadline
, THREAD_UNINT
);
1802 if( waitResult
== THREAD_TIMED_OUT
) {
1803 IOLog("%s::terminate(kIOServiceSynchronous) timeout\n", getName());
1806 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
1808 gIOTerminateThread
= 0;
1809 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1812 // ! kIOServiceSynchronous
1814 gIOTerminatePhase2List
->setObject( this );
1815 if( 0 == gIOTerminateWork
++) {
1816 if( !gIOTerminateThread
)
1817 kernel_thread_start(&terminateThread
, (void *) options
, &gIOTerminateThread
);
1819 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1823 IOLockUnlock( gJobsLock
);
1828 void IOService::terminateThread( void * arg
, wait_result_t waitResult
)
1830 IOLockLock( gJobsLock
);
1832 while (gIOTerminateWork
)
1833 terminateWorker( (uintptr_t) arg
);
1835 thread_deallocate(gIOTerminateThread
);
1836 gIOTerminateThread
= 0;
1837 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1839 IOLockUnlock( gJobsLock
);
1842 void IOService::scheduleStop( IOService
* provider
)
1844 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1846 uint64_t regID1
= getRegistryEntryID();
1847 uint64_t regID2
= provider
->getRegistryEntryID();
1849 IOSERVICE_TERMINATE_SCHEDULE_STOP
,
1851 (uintptr_t) (regID1
>> 32),
1853 (uintptr_t) (regID2
>> 32));
1855 IOLockLock( gJobsLock
);
1856 gIOStopList
->tailQ( this );
1857 gIOStopProviderList
->tailQ( provider
);
1859 if( 0 == gIOTerminateWork
++) {
1860 if( !gIOTerminateThread
)
1861 kernel_thread_start(&terminateThread
, (void *) 0, &gIOTerminateThread
);
1863 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1866 IOLockUnlock( gJobsLock
);
1869 void IOService::scheduleFinalize( void )
1871 TLOG("%s::scheduleFinalize\n", getName());
1873 uint64_t regID1
= getRegistryEntryID();
1875 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE
,
1877 (uintptr_t) (regID1
>> 32),
1880 IOLockLock( gJobsLock
);
1881 gIOFinalizeList
->tailQ( this );
1883 if( 0 == gIOTerminateWork
++) {
1884 if( !gIOTerminateThread
)
1885 kernel_thread_start(&terminateThread
, (void *) 0, &gIOTerminateThread
);
1887 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1890 IOLockUnlock( gJobsLock
);
1893 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1898 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1900 if( false == *defer
) {
1902 if( lockForArbitration( true )) {
1903 if( false == provider
->handleIsOpen( this ))
1904 scheduleStop( provider
);
1907 message( kIOMessageServiceIsRequestingClose
, provider
, (void *) options
);
1908 if( false == provider
->handleIsOpen( this ))
1909 scheduleStop( provider
);
1912 unlockForArbitration();
1919 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
1920 OSArray
* doPhase2List
)
1926 iter
= victim
->getClientIterator();
1928 while( (client
= (IOService
*) iter
->getNextObject())) {
1929 TLOG("%s::willTerminate(%s, %08llx)\n",
1930 client
->getName(), victim
->getName(), (long long)options
);
1932 uint64_t regID1
= client
->getRegistryEntryID();
1933 uint64_t regID2
= victim
->getRegistryEntryID();
1935 IOSERVICE_TERMINATE_WILL
,
1937 (uintptr_t) (regID1
>> 32),
1939 (uintptr_t) (regID2
>> 32));
1941 ok
= client
->willTerminate( victim
, options
);
1942 doPhase2List
->tailQ( client
);
1948 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
)
1954 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *) options
);
1956 iter
= victim
->getClientIterator();
1958 while( (client
= (IOService
*) iter
->getNextObject())) {
1959 TLOG("%s::didTerminate(%s, %08llx)\n",
1960 client
->getName(), victim
->getName(), (long long)options
);
1961 client
->didTerminate( victim
, options
, &defer
);
1963 uint64_t regID1
= client
->getRegistryEntryID();
1964 uint64_t regID2
= victim
->getRegistryEntryID();
1966 (defer
? IOSERVICE_TERMINATE_DID_DEFER
1967 : IOSERVICE_TERMINATE_DID
),
1969 (uintptr_t) (regID1
>> 32),
1971 (uintptr_t) (regID2
>> 32));
1973 TLOG("%s::didTerminate(%s, defer %d)\n",
1974 client
->getName(), victim
->getName(), defer
);
1980 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
)
1982 TLOG("%s::finalize(%08llx)\n", victim
->getName(), (long long)options
);
1984 uint64_t regID1
= victim
->getRegistryEntryID();
1986 IOSERVICE_TERMINATE_FINALIZE
,
1988 (uintptr_t) (regID1
>> 32),
1991 victim
->finalize( options
);
1994 void IOService::actionStop( IOService
* provider
, IOService
* client
)
1996 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
1998 uint64_t regID1
= provider
->getRegistryEntryID();
1999 uint64_t regID2
= client
->getRegistryEntryID();
2001 IOSERVICE_TERMINATE_STOP
,
2003 (uintptr_t) (regID1
>> 32),
2005 (uintptr_t) (regID2
>> 32));
2007 client
->stop( provider
);
2008 if( provider
->isOpen( client
))
2009 provider
->close( client
);
2010 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
2011 client
->detach( provider
);
2014 void IOService::terminateWorker( IOOptionBits options
)
2016 OSArray
* doPhase2List
;
2017 OSArray
* didPhase2List
;
2022 IOService
* provider
;
2028 options
|= kIOServiceRequired
;
2030 doPhase2List
= OSArray::withCapacity( 16 );
2031 didPhase2List
= OSArray::withCapacity( 16 );
2032 freeList
= OSSet::withCapacity( 16 );
2033 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
2037 workDone
= gIOTerminateWork
;
2039 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
2042 gIOTerminatePhase2List
->removeObject(0);
2043 IOLockUnlock( gJobsLock
);
2047 doPhase2
= victim
->lockForArbitration( true );
2049 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
2051 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
2052 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
2054 victim
->__state
[1] |= kIOServiceTermPhase2State
;
2056 victim
->unlockForArbitration();
2059 if( 0 == victim
->getClient()) {
2060 // no clients - will go to finalize
2061 IOLockLock( gJobsLock
);
2062 gIOFinalizeList
->tailQ( victim
);
2063 IOLockUnlock( gJobsLock
);
2065 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
2066 victim
, (void *) options
, (void *) doPhase2List
);
2068 didPhase2List
->headQ( victim
);
2071 victim
= (IOService
*) doPhase2List
->getObject(0);
2074 doPhase2List
->removeObject(0);
2078 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
2080 if( victim
->lockForArbitration( true )) {
2081 victim
->__state
[1] |= kIOServiceTermPhase3State
;
2082 victim
->unlockForArbitration();
2084 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
2085 victim
, (void *) options
);
2086 didPhase2List
->removeObject(0);
2088 IOLockLock( gJobsLock
);
2095 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
2097 IOLockUnlock( gJobsLock
);
2098 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
2099 victim
, (void *) options
);
2100 IOLockLock( gJobsLock
);
2102 freeList
->setObject( victim
);
2103 // safe if finalize list is append only
2104 gIOFinalizeList
->removeObject(0);
2108 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
2110 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
2113 if( !provider
->isChild( client
, gIOServicePlane
)) {
2114 // may be multiply queued - nop it
2115 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
2117 uint64_t regID1
= provider
->getRegistryEntryID();
2118 uint64_t regID2
= client
->getRegistryEntryID();
2120 IOSERVICE_TERMINATE_STOP_NOP
,
2122 (uintptr_t) (regID1
>> 32),
2124 (uintptr_t) (regID2
>> 32));
2127 // not ready for stop if it has clients, skip it
2128 if( (client
->__state
[1] & kIOServiceTermPhase3State
) && client
->getClient()) {
2129 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
2131 uint64_t regID1
= provider
->getRegistryEntryID();
2132 uint64_t regID2
= client
->getRegistryEntryID();
2134 IOSERVICE_TERMINATE_STOP_DEFER
,
2136 (uintptr_t) (regID1
>> 32),
2138 (uintptr_t) (regID2
>> 32));
2144 IOLockUnlock( gJobsLock
);
2145 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
2146 provider
, (void *) client
);
2147 IOLockLock( gJobsLock
);
2148 // check the finalize list now
2152 freeList
->setObject( client
);
2153 freeList
->setObject( provider
);
2155 // safe if stop list is append only
2156 gIOStopList
->removeObject( idx
);
2157 gIOStopProviderList
->removeObject( idx
);
2161 } while( doPhase3
);
2163 gIOTerminateWork
-= workDone
;
2164 moreToDo
= (gIOTerminateWork
!= 0);
2167 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
2169 IOSERVICE_TERMINATE_DONE
,
2170 (uintptr_t) gIOStopList
->getCount(), 0, 0, 0);
2173 } while( moreToDo
);
2175 IOLockUnlock( gJobsLock
);
2177 freeList
->release();
2178 doPhase2List
->release();
2179 didPhase2List
->release();
2181 IOLockLock( gJobsLock
);
2184 bool IOService::finalize( IOOptionBits options
)
2187 IOService
* provider
;
2189 iter
= getProviderIterator();
2193 while( (provider
= (IOService
*) iter
->getNextObject())) {
2196 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
2197 /* we come down here on programmatic terminate */
2199 if( provider
->isOpen( this ))
2200 provider
->close( this );
2204 if( provider
->lockForArbitration( true )) {
2205 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2206 scheduleStop( provider
);
2207 provider
->unlockForArbitration();
2224 void IOService::doServiceTerminate( IOOptionBits options
)
2228 // a method in case someone needs to override it
2229 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2233 if( client
->isParent( this, gIOServicePlane
, true))
2234 // we are the clients only provider
2235 ok
= client
->terminate( options
);
2242 bool IOService::terminate( IOOptionBits options
)
2244 options
|= kIOServiceTerminate
;
2246 return( terminatePhase1( options
));
2249 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2255 struct ServiceOpenMessageContext
2257 IOService
* service
;
2259 IOService
* excludeClient
;
2260 IOOptionBits options
;
2263 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2265 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2267 if( object
!= context
->excludeClient
)
2268 context
->service
->messageClient( context
->type
, object
, (void *) context
->options
);
2271 bool IOService::open( IOService
* forClient
,
2272 IOOptionBits options
,
2276 ServiceOpenMessageContext context
;
2278 context
.service
= this;
2279 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2280 context
.excludeClient
= forClient
;
2281 context
.options
= options
;
2283 applyToInterested( gIOGeneralInterest
,
2284 &serviceOpenMessageApplier
, &context
);
2286 if( false == lockForArbitration(false) )
2289 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2291 ok
= handleOpen( forClient
, options
, arg
);
2293 unlockForArbitration();
2298 void IOService::close( IOService
* forClient
,
2299 IOOptionBits options
)
2304 lockForArbitration();
2306 wasClosed
= handleIsOpen( forClient
);
2308 handleClose( forClient
, options
);
2309 last
= (__state
[1] & kIOServiceTermPhase3State
);
2312 unlockForArbitration();
2315 forClient
->scheduleStop( this );
2317 else if( wasClosed
) {
2319 ServiceOpenMessageContext context
;
2321 context
.service
= this;
2322 context
.type
= kIOMessageServiceWasClosed
;
2323 context
.excludeClient
= forClient
;
2324 context
.options
= options
;
2326 applyToInterested( gIOGeneralInterest
,
2327 &serviceOpenMessageApplier
, &context
);
2331 bool IOService::isOpen( const IOService
* forClient
) const
2333 IOService
* self
= (IOService
*) this;
2336 self
->lockForArbitration();
2338 ok
= handleIsOpen( forClient
);
2340 self
->unlockForArbitration();
2345 bool IOService::handleOpen( IOService
* forClient
,
2346 IOOptionBits options
,
2351 ok
= (0 == __owner
);
2353 __owner
= forClient
;
2355 else if( options
& kIOServiceSeize
) {
2356 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2357 __owner
, (void *) options
));
2358 if( ok
&& (0 == __owner
))
2359 __owner
= forClient
;
2366 void IOService::handleClose( IOService
* forClient
,
2367 IOOptionBits options
)
2369 if( __owner
== forClient
)
2373 bool IOService::handleIsOpen( const IOService
* forClient
) const
2376 return( __owner
== forClient
);
2378 return( __owner
!= forClient
);
2382 * Probing & starting
2384 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2386 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2387 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2395 val1
= obj1
->priority
;
2398 val2
= obj2
->priority
;
2400 return ( val1
- val2
);
2403 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2405 OSDictionary
* dict
;
2406 IOService
* service
;
2407 _IOServiceNotifier
* notify
;
2408 OSSymbol
* key
= (OSSymbol
*) ref
;
2411 if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2412 return( notify
->priority
);
2414 else if( (service
= OSDynamicCast( IOService
, entry
)))
2415 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2416 else if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2417 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2424 return( (SInt32
) offset
->unsigned32BitValue());
2426 return( kIODefaultProbeScore
);
2429 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2431 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2432 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2440 val1
= IOServiceObjectOrder( obj1
, ref
);
2443 val2
= IOServiceObjectOrder( obj2
, ref
);
2445 return ( val1
- val2
);
2448 IOService
* IOService::copyClientWithCategory( const OSSymbol
* category
)
2450 IOService
* service
= 0;
2452 const OSSymbol
* nextCat
;
2454 iter
= getClientIterator();
2456 while( (service
= (IOService
*) iter
->getNextObject())) {
2457 if( kIOServiceInactiveState
& service
->__state
[0])
2459 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2460 service
->getProperty( gIOMatchCategoryKey
));
2461 if( category
== nextCat
)
2472 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2475 service
= copyClientWithCategory(category
);
2481 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2483 _IOServiceNotifierInvocation invocation
;
2487 invocation
.thread
= current_thread();
2490 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2493 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2494 _IOServiceNotifierInvocation
*, link
);
2500 ret
= (*notify
->handler
)(notify
->target
, notify
->ref
, this, notify
);
2503 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2504 _IOServiceNotifierInvocation
*, link
);
2505 if( kIOServiceNotifyWaiter
& notify
->state
) {
2506 notify
->state
&= ~kIOServiceNotifyWaiter
;
2507 WAKEUPNOTIFY( notify
);
2516 * Alloc and probe matching classes,
2517 * called on the provider instance
2520 void IOService::probeCandidates( OSOrderedSet
* matches
)
2522 OSDictionary
* match
= 0;
2525 IOService
* newInst
;
2526 OSDictionary
* props
;
2529 OSOrderedSet
* familyMatches
= 0;
2530 OSOrderedSet
* startList
;
2531 OSDictionary
* startDict
= 0;
2532 const OSSymbol
* category
;
2534 _IOServiceNotifier
* notify
;
2535 OSObject
* nextMatch
= 0;
2537 bool needReloc
= false;
2538 #if CONFIG_MACF_KEXT
2539 OSBoolean
* isSandbox
= 0;
2540 bool useSandbox
= false;
2545 IOService
* client
= NULL
;
2549 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2551 nextMatch
->retain();
2552 matches
->removeObject(nextMatch
);
2554 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2556 lockForArbitration();
2557 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2558 invokeNotifer( notify
);
2559 unlockForArbitration();
2560 nextMatch
->release();
2564 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2565 nextMatch
->release();
2572 debugFlags
= getDebugFlags( match
);
2576 category
= OSDynamicCast( OSSymbol
,
2577 match
->getObject( gIOMatchCategoryKey
));
2579 category
= gIODefaultMatchCategoryKey
;
2581 if( (client
= copyClientWithCategory(category
)) ) {
2583 if( debugFlags
& kIOLogMatch
)
2584 LOG("%s: match category %s exists\n", getName(),
2585 category
->getCStringNoCopy());
2587 nextMatch
->release();
2596 // create a copy now in case its modified during matching
2597 props
= OSDictionary::withDictionary( match
, match
->getCount());
2600 props
->setCapacityIncrement(1);
2602 // check the nub matches
2603 if( false == passiveMatch( props
, true ))
2606 // Check to see if driver reloc has been loaded.
2607 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2610 if( debugFlags
& kIOLogCatalogue
)
2611 LOG("%s: stalling for module\n", getName());
2613 // If reloc hasn't been loaded, exit;
2614 // reprobing will occur after reloc has been loaded.
2618 // reorder on family matchPropertyTable score.
2619 if( 0 == familyMatches
)
2620 familyMatches
= OSOrderedSet::withCapacity( 1,
2621 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2623 familyMatches
->setObject( props
);
2628 nextMatch
->release();
2637 if( familyMatches
) {
2640 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2643 familyMatches
->removeObject( props
);
2648 debugFlags
= getDebugFlags( props
);
2651 symbol
= OSDynamicCast( OSSymbol
,
2652 props
->getObject( gIOClassKey
));
2656 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), symbol, props);
2658 // alloc the driver instance
2659 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2662 IOLog("Couldn't alloc class \"%s\"\n",
2663 symbol
->getCStringNoCopy());
2667 // init driver instance
2668 if( !(inst
->init( props
))) {
2670 if( debugFlags
& kIOLogStart
)
2671 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2675 if( __state
[1] & kIOServiceSynchronousState
)
2676 inst
->__state
[1] |= kIOServiceSynchronousState
;
2678 // give the driver the default match category if not specified
2679 category
= OSDynamicCast( OSSymbol
,
2680 props
->getObject( gIOMatchCategoryKey
));
2682 category
= gIODefaultMatchCategoryKey
;
2683 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2684 #if CONFIG_MACF_KEXT
2685 isSandbox
= OSDynamicCast(OSBoolean
,
2686 props
->getObject("IOKitForceMatch"));
2688 // attach driver instance
2689 if( !(inst
->attach( this )))
2692 // pass in score from property table
2693 score
= familyMatches
->orderObject( props
);
2695 // & probe the new driver instance
2697 if( debugFlags
& kIOLogProbe
)
2698 LOG("%s::probe(%s)\n",
2699 inst
->getMetaClass()->getClassName(), getName());
2702 newInst
= inst
->probe( this, &score
);
2703 inst
->detach( this );
2704 #if CONFIG_MACF_KEXT
2706 * If this is the Sandbox driver and it matched, this is a
2707 * disallowed device; toss any drivers that were already
2710 if (isSandbox
&& isSandbox
->isTrue() && newInst
!= 0) {
2711 if (startDict
!= 0) {
2712 startDict
->flushCollection();
2713 startDict
->release();
2721 if( debugFlags
& kIOLogProbe
)
2722 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2728 newPri
= OSNumber::withNumber( score
, 32 );
2730 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2734 // add to start list for the match category
2736 startDict
= OSDictionary::withCapacity( 1 );
2737 assert( startDict
);
2738 startList
= (OSOrderedSet
*)
2739 startDict
->getObject( category
);
2740 if( 0 == startList
) {
2741 startList
= OSOrderedSet::withCapacity( 1,
2742 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2743 if( startDict
&& startList
) {
2744 startDict
->setObject( category
, startList
);
2745 startList
->release();
2748 assert( startList
);
2750 startList
->setObject( newInst
);
2757 #if CONFIG_MACF_KEXT
2759 * If we're forcing the sandbox, drop out of the loop.
2761 if (isSandbox
&& isSandbox
->isTrue() && useSandbox
)
2765 familyMatches
->release();
2769 // start the best (until success) of each category
2771 iter
= OSCollectionIterator::withCollection( startDict
);
2773 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2775 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2776 assert( startList
);
2781 while( true // (!started)
2782 && (inst
= (IOService
*)startList
->getFirstObject())) {
2785 startList
->removeObject(inst
);
2788 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2790 if( debugFlags
& kIOLogStart
) {
2792 LOG( "match category exists, skipping " );
2793 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2794 getName(), inst
->getRetainCount());
2797 if( false == started
)
2798 started
= startCandidate( inst
);
2800 if( (debugFlags
& kIOLogStart
) && (false == started
))
2801 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2802 inst
->getRetainCount());
2811 // adjust the busy count by +1 if matching is stalled for a module,
2812 // or -1 if a previously stalled matching is complete.
2813 lockForArbitration();
2815 uint64_t regID
= getRegistryEntryID();
2818 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2822 IOSERVICE_MODULESTALL
,
2824 (uintptr_t) (regID
>> 32),
2828 __state
[1] |= kIOServiceModuleStallState
;
2831 } else if( __state
[1] & kIOServiceModuleStallState
) {
2834 IOSERVICE_MODULEUNSTALL
,
2836 (uintptr_t) (regID
>> 32),
2840 __state
[1] &= ~kIOServiceModuleStallState
;
2844 _adjustBusy( adjBusy
);
2845 unlockForArbitration();
2848 startDict
->release();
2852 * Start a previously attached & probed instance,
2853 * called on exporting object instance
2856 bool IOService::startCandidate( IOService
* service
)
2860 ok
= service
->attach( this );
2864 if (this != gIOResources
)
2866 // stall for any nub resources
2868 // stall for any driver resources
2869 service
->checkResources();
2872 AbsoluteTime startTime
;
2873 AbsoluteTime endTime
;
2876 if (kIOLogStart
& gIOKitDebug
)
2877 clock_get_uptime(&startTime
);
2879 ok
= service
->start(this);
2881 if (kIOLogStart
& gIOKitDebug
)
2883 clock_get_uptime(&endTime
);
2885 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2887 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2888 absolutetime_to_nanoseconds(endTime
, &nano
);
2889 if (nano
> 500000000ULL)
2890 IOLog("%s::start took %ld ms\n", service
->getName(), (long)(UInt32
)(nano
/ 1000000ULL));
2894 service
->detach( this );
2899 void IOService::publishResource( const char * key
, OSObject
* value
)
2901 const OSSymbol
* sym
;
2903 if( (sym
= OSSymbol::withCString( key
))) {
2904 publishResource( sym
, value
);
2909 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
2912 value
= (OSObject
*) gIOServiceKey
;
2914 gIOResources
->setProperty( key
, value
);
2916 if( IORecursiveLockHaveLock( gNotificationLock
))
2919 gIOResourceGenerationCount
++;
2920 gIOResources
->registerService();
2923 bool IOService::addNeededResource( const char * key
)
2925 OSObject
* resourcesProp
;
2930 resourcesProp
= getProperty( gIOResourceMatchKey
);
2932 newKey
= OSString::withCString( key
);
2933 if( (0 == resourcesProp
) || (0 == newKey
))
2936 set
= OSDynamicCast( OSSet
, resourcesProp
);
2938 set
= OSSet::withCapacity( 1 );
2940 set
->setObject( resourcesProp
);
2945 set
->setObject( newKey
);
2947 ret
= setProperty( gIOResourceMatchKey
, set
);
2953 bool IOService::checkResource( OSObject
* matching
)
2956 OSDictionary
* table
;
2958 if( (str
= OSDynamicCast( OSString
, matching
))) {
2959 if( gIOResources
->getProperty( str
))
2964 table
= resourceMatching( str
);
2965 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
2968 IOLog("%s: Can't match using: %s\n", getName(),
2969 matching
->getMetaClass()->getClassName());
2970 /* false would stall forever */
2974 if( gIOKitDebug
& kIOLogConfig
)
2975 LOG("config(%p): stalling %s\n", IOThreadSelf(), getName());
2977 waitForService( table
);
2979 if( gIOKitDebug
& kIOLogConfig
)
2980 LOG("config(%p): waking\n", IOThreadSelf() );
2985 bool IOService::checkResources( void )
2987 OSObject
* resourcesProp
;
2992 resourcesProp
= getProperty( gIOResourceMatchKey
);
2993 if( 0 == resourcesProp
)
2996 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
2998 iter
= OSCollectionIterator::withCollection( set
);
3000 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
3001 ok
= checkResource( resourcesProp
);
3006 ok
= checkResource( resourcesProp
);
3012 void _IOConfigThread::configThread( void )
3014 _IOConfigThread
* inst
;
3017 if( !(inst
= new _IOConfigThread
))
3022 if (KERN_SUCCESS
!= kernel_thread_start(&_IOConfigThread::main
, inst
, &unused
))
3035 void _IOConfigThread::free( void )
3037 thread_deallocate(current_thread());
3041 void IOService::doServiceMatch( IOOptionBits options
)
3043 _IOServiceNotifier
* notify
;
3045 OSOrderedSet
* matches
;
3046 SInt32 catalogGeneration
;
3047 bool keepGuessing
= true;
3048 bool reRegistered
= true;
3050 // job->nub->deliverNotification( gIOPublishNotification,
3051 // kIOServiceRegisteredState, 0xffffffff );
3053 while( keepGuessing
) {
3055 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
3056 // the matches list should always be created by findDrivers()
3059 lockForArbitration();
3060 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
3061 deliverNotification( gIOFirstPublishNotification
,
3062 kIOServiceFirstPublishState
, 0xffffffff );
3064 __state
[1] &= ~kIOServiceNeedConfigState
;
3065 __state
[1] |= kIOServiceConfigState
;
3066 __state
[0] |= kIOServiceRegisteredState
;
3068 if( reRegistered
&& (0 == (__state
[0] & kIOServiceInactiveState
))) {
3070 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3071 gNotifications
->getObject( gIOPublishNotification
) );
3073 while((notify
= (_IOServiceNotifier
*)
3074 iter
->getNextObject())) {
3076 if( passiveMatch( notify
->matching
)
3077 && (kIOServiceNotifyEnable
& notify
->state
))
3078 matches
->setObject( notify
);
3085 unlockForArbitration();
3087 if( matches
->getCount() && (kIOReturnSuccess
== getResources()))
3088 probeCandidates( matches
);
3093 lockForArbitration();
3094 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
3096 (reRegistered
|| (catalogGeneration
!=
3097 gIOCatalogue
->getGenerationCount()))
3098 && (0 == (__state
[0] & kIOServiceInactiveState
));
3101 unlockForArbitration();
3104 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3105 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
3106 deliverNotification( gIOMatchedNotification
,
3107 kIOServiceMatchedState
, 0xffffffff );
3108 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
3109 deliverNotification( gIOFirstMatchNotification
,
3110 kIOServiceFirstMatchState
, 0xffffffff );
3113 __state
[1] &= ~kIOServiceConfigState
;
3114 if( __state
[0] & kIOServiceInactiveState
)
3115 scheduleTerminatePhase2();
3118 unlockForArbitration();
3121 UInt32
IOService::_adjustBusy( SInt32 delta
)
3126 bool wasQuiet
, nowQuiet
, needWake
;
3129 result
= __state
[1] & kIOServiceBusyStateMask
;
3133 next
->lockForArbitration();
3134 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
3135 wasQuiet
= (0 == count
);
3136 if (((delta
< 0) && wasQuiet
) || ((delta
> 0) && (kIOServiceBusyMax
== count
)))
3137 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next
->getName(), count
, delta
);
3140 next
->__state
[1] = (next
->__state
[1] & ~kIOServiceBusyStateMask
) | count
;
3141 nowQuiet
= (0 == count
);
3142 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
3145 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
3146 IOLockLock( gIOServiceBusyLock
);
3147 thread_wakeup( (event_t
) next
);
3148 IOLockUnlock( gIOServiceBusyLock
);
3151 next
->unlockForArbitration();
3153 if( (wasQuiet
|| nowQuiet
) ) {
3154 uint64_t regID
= next
->getRegistryEntryID();
3157 ((wasQuiet
/*nowBusy*/) ? IOSERVICE_BUSY
: IOSERVICE_NONBUSY
),
3159 (uintptr_t) (regID
>> 32),
3165 next
->__timeBusy
= mach_absolute_time();
3169 next
->__accumBusy
+= mach_absolute_time() - next
->__timeBusy
;
3170 next
->__timeBusy
= 0;
3173 MessageClientsContext context
;
3175 context
.service
= next
;
3176 context
.type
= kIOMessageServiceBusyStateChange
;
3177 context
.argument
= (void *) wasQuiet
; /*nowBusy*/
3178 context
.argSize
= 0;
3180 applyToInterestNotifiers( next
, gIOBusyInterest
,
3181 &messageClientsApplier
, &context
);
3184 if( nowQuiet
&& (next
== gIOServiceRoot
))
3185 OSKext::considerUnloads();
3189 delta
= nowQuiet
? -1 : +1;
3191 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
3196 void IOService::adjustBusy( SInt32 delta
)
3198 lockForArbitration();
3199 _adjustBusy( delta
);
3200 unlockForArbitration();
3203 uint64_t IOService::getAccumulatedBusyTime( void )
3205 uint64_t accumBusy
= __accumBusy
;
3206 uint64_t timeBusy
= __timeBusy
;
3211 accumBusy
= __accumBusy
;
3212 timeBusy
= __timeBusy
;
3214 accumBusy
+= mach_absolute_time() - timeBusy
;
3216 while (timeBusy
!= __timeBusy
);
3218 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&accumBusy
, &nano
);
3223 UInt32
IOService::getBusyState( void )
3225 return( __state
[1] & kIOServiceBusyStateMask
);
3228 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3229 mach_timespec_t
* timeout
)
3231 panic("waitForState");
3232 return (kIOReturnUnsupported
);
3235 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3239 int waitResult
= THREAD_AWAKENED
;
3240 bool computeDeadline
= true;
3241 AbsoluteTime abstime
;
3244 lockForArbitration();
3245 IOLockLock( gIOServiceBusyLock
);
3246 wait
= (value
!= (__state
[1] & mask
));
3248 __state
[1] |= kIOServiceBusyWaiterState
;
3249 unlockForArbitration();
3250 if( timeout
!= UINT64_MAX
) {
3251 if( computeDeadline
) {
3252 AbsoluteTime nsinterval
;
3253 nanoseconds_to_absolutetime(timeout
, &nsinterval
);
3254 clock_absolutetime_interval_to_deadline(nsinterval
, &abstime
);
3255 computeDeadline
= false;
3257 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
3260 assert_wait((event_t
)this, THREAD_UNINT
);
3262 unlockForArbitration();
3263 IOLockUnlock( gIOServiceBusyLock
);
3265 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
3267 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3269 if( waitResult
== THREAD_TIMED_OUT
)
3270 return( kIOReturnTimeout
);
3272 return( kIOReturnSuccess
);
3275 IOReturn
IOService::waitQuiet( uint64_t timeout
)
3277 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
3280 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
3286 timeoutNS
= timeout
->tv_sec
;
3287 timeoutNS
*= kSecondScale
;
3288 timeoutNS
+= timeout
->tv_nsec
;
3291 timeoutNS
= UINT64_MAX
;
3293 return( waitForState( kIOServiceBusyStateMask
, 0, timeoutNS
));
3296 bool IOService::serializeProperties( OSSerialize
* s
) const
3299 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
3300 sizeof( __state
), "__state");
3302 return( super::serializeProperties(s
) );
3306 void _IOConfigThread::main(void * arg
, wait_result_t result
)
3308 _IOConfigThread
* self
= (_IOConfigThread
*) arg
;
3309 _IOServiceJob
* job
;
3313 thread_precedence_policy_data_t precedence
= { -1 };
3315 kr
= thread_policy_set(current_thread(),
3316 THREAD_PRECEDENCE_POLICY
,
3317 (thread_policy_t
) &precedence
,
3318 THREAD_PRECEDENCE_POLICY_COUNT
);
3319 if (KERN_SUCCESS
!= kr
)
3320 IOLog("thread_policy_set(%d)\n", kr
);
3326 semaphore_wait( gJobsSemaphore
);
3328 IOTakeLock( gJobsLock
);
3329 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
3331 gJobs
->removeObject(job
);
3334 // gNumConfigThreads--; // we're out of service
3335 gNumWaitingThreads
--; // we're out of service
3337 IOUnlock( gJobsLock
);
3343 if( gIOKitDebug
& kIOLogConfig
)
3344 LOG("config(%p): starting on %s, %d\n",
3345 IOThreadSelf(), job
->nub
->getName(), job
->type
);
3347 switch( job
->type
) {
3350 nub
->doServiceMatch( job
->options
);
3354 LOG("config(%p): strange type (%d)\n",
3355 IOThreadSelf(), job
->type
);
3362 IOTakeLock( gJobsLock
);
3363 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
3365 gNumWaitingThreads
++; // back in service
3366 // gNumConfigThreads++;
3368 if( 0 == --gNumConfigThreads
) {
3369 // IOLog("MATCH IDLE\n");
3370 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3373 IOUnlock( gJobsLock
);
3378 if( gIOKitDebug
& kIOLogConfig
)
3379 LOG("config(%p): terminating\n", IOThreadSelf() );
3384 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3387 int waitResult
= THREAD_AWAKENED
;
3388 bool computeDeadline
= true;
3389 AbsoluteTime abstime
;
3391 IOLockLock( gJobsLock
);
3393 wait
= (0 != gNumConfigThreads
);
3396 if( computeDeadline
) {
3397 clock_interval_to_absolutetime_interval(
3398 msToWait
, kMillisecondScale
, &abstime
);
3399 clock_absolutetime_interval_to_deadline(
3400 abstime
, &abstime
);
3401 computeDeadline
= false;
3403 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
3404 abstime
, THREAD_UNINT
);
3406 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3410 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3411 IOLockUnlock( gJobsLock
);
3413 if( waitResult
== THREAD_TIMED_OUT
)
3414 return( kIOReturnTimeout
);
3416 return( kIOReturnSuccess
);
3419 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3426 IOTakeLock( gJobsLock
);
3429 gJobs
->setLastObject( job
);
3431 count
= gNumWaitingThreads
;
3432 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3434 create
= ( (gOutstandingJobs
> count
)
3435 && (gNumConfigThreads
< kMaxConfigThreads
) );
3437 gNumConfigThreads
++;
3438 gNumWaitingThreads
++;
3441 IOUnlock( gJobsLock
);
3446 if( gIOKitDebug
& kIOLogConfig
)
3447 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3448 _IOConfigThread::configThread();
3451 semaphore_signal( gJobsSemaphore
);
3454 // internal - call with gNotificationLock
3455 OSObject
* IOService::copyExistingServices( OSDictionary
* matching
,
3456 IOOptionBits inState
, IOOptionBits options
)
3458 OSObject
* current
= 0;
3460 IOService
* service
;
3467 && (obj
= matching
->getObject(gIOProviderClassKey
))
3469 && gIOResourcesKey
->isEqualTo(obj
)
3470 && (service
= gIOResources
))
3472 if( (inState
== (service
->__state
[0] & inState
))
3473 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3474 && service
->passiveMatch( matching
))
3476 if( options
& kIONotifyOnce
)
3482 current
= OSSet::withObjects(
3483 (const OSObject
**) &service
, 1, 1 );
3488 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3489 kIORegistryIterateRecursively
);
3493 while( (service
= (IOService
*) iter
->getNextObject())) {
3494 if( (inState
== (service
->__state
[0] & inState
))
3495 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3496 && service
->passiveMatch( matching
)) {
3498 if( options
& kIONotifyOnce
) {
3504 ((OSSet
*)current
)->setObject( service
);
3506 current
= OSSet::withObjects(
3507 (const OSObject
**) &service
, 1, 1 );
3510 } while( !service
&& !iter
->isValid());
3515 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
3516 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3525 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3529 // is a lock even needed?
3532 iter
= (OSIterator
*) copyExistingServices( matching
,
3533 kIOServiceMatchedState
);
3540 struct _IOServiceMatchingNotificationHandlerRef
3542 IOServiceNotificationHandler handler
;
3546 static bool _IOServiceMatchingNotificationHandler( void * target
, void * refCon
,
3547 IOService
* newService
,
3548 IONotifier
* notifier
)
3550 return ((*((_IOServiceNotifier
*) notifier
)->compatHandler
)(target
, refCon
, newService
));
3553 // internal - call with gNotificationLock
3554 IONotifier
* IOService::setNotification(
3555 const OSSymbol
* type
, OSDictionary
* matching
,
3556 IOServiceMatchingNotificationHandler handler
, void * target
, void * ref
,
3559 _IOServiceNotifier
* notify
= 0;
3565 notify
= new _IOServiceNotifier
;
3566 if( notify
&& !notify
->init()) {
3572 notify
->handler
= handler
;
3573 notify
->target
= target
;
3574 notify
->matching
= matching
;
3576 if (handler
== &_IOServiceMatchingNotificationHandler
)
3578 notify
->compatHandler
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->handler
;
3579 notify
->ref
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->ref
;
3583 notify
->priority
= priority
;
3584 notify
->state
= kIOServiceNotifyEnable
;
3585 queue_init( ¬ify
->handlerInvocations
);
3589 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3590 set
= OSOrderedSet::withCapacity( 1,
3591 IONotifyOrdering
, 0 );
3593 gNotifications
->setObject( type
, set
);
3597 notify
->whence
= set
;
3599 set
->setObject( notify
);
3605 // internal - call with gNotificationLock
3606 IONotifier
* IOService::doInstallNotification(
3607 const OSSymbol
* type
, OSDictionary
* matching
,
3608 IOServiceMatchingNotificationHandler handler
,
3609 void * target
, void * ref
,
3610 SInt32 priority
, OSIterator
** existing
)
3613 IONotifier
* notify
;
3614 IOOptionBits inState
;
3619 if( type
== gIOPublishNotification
)
3620 inState
= kIOServiceRegisteredState
;
3622 else if( type
== gIOFirstPublishNotification
)
3623 inState
= kIOServiceFirstPublishState
;
3625 else if( (type
== gIOMatchedNotification
)
3626 || (type
== gIOFirstMatchNotification
))
3627 inState
= kIOServiceMatchedState
;
3628 else if( type
== gIOTerminatedNotification
)
3633 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3636 // get the current set
3637 exist
= (OSIterator
*) copyExistingServices( matching
, inState
);
3646 #if !defined(__LP64__)
3647 IONotifier
* IOService::installNotification(const OSSymbol
* type
, OSDictionary
* matching
,
3648 IOServiceNotificationHandler handler
,
3649 void * target
, void * refCon
,
3650 SInt32 priority
, OSIterator
** existing
)
3652 IONotifier
* result
;
3653 _IOServiceMatchingNotificationHandlerRef ref
;
3654 ref
.handler
= handler
;
3657 result
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3658 &_IOServiceMatchingNotificationHandler
,
3659 target
, &ref
, priority
, existing
);
3661 matching
->release();
3665 #endif /* !defined(__LP64__) */
3668 IONotifier
* IOService::installNotification(
3669 const OSSymbol
* type
, OSDictionary
* matching
,
3670 IOServiceMatchingNotificationHandler handler
,
3671 void * target
, void * ref
,
3672 SInt32 priority
, OSIterator
** existing
)
3674 IONotifier
* notify
;
3678 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3679 priority
, existing
);
3686 IONotifier
* IOService::addNotification(
3687 const OSSymbol
* type
, OSDictionary
* matching
,
3688 IOServiceNotificationHandler handler
,
3689 void * target
, void * refCon
,
3692 IONotifier
* result
;
3693 _IOServiceMatchingNotificationHandlerRef ref
;
3695 ref
.handler
= handler
;
3698 result
= addMatchingNotification(type
, matching
, &_IOServiceMatchingNotificationHandler
,
3699 target
, &ref
, priority
);
3702 matching
->release();
3707 IONotifier
* IOService::addMatchingNotification(
3708 const OSSymbol
* type
, OSDictionary
* matching
,
3709 IOServiceMatchingNotificationHandler handler
,
3710 void * target
, void * ref
,
3713 OSIterator
* existing
= NULL
;
3714 _IOServiceNotifier
* notify
;
3717 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3718 handler
, target
, ref
, priority
, &existing
);
3720 // send notifications for existing set
3723 notify
->retain(); // in case handler remove()s
3724 while( (next
= (IOService
*) existing
->getNextObject())) {
3726 next
->lockForArbitration();
3727 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3728 next
->invokeNotifer( notify
);
3729 next
->unlockForArbitration();
3732 existing
->release();
3738 bool IOService::syncNotificationHandler(
3739 void * /* target */, void * ref
,
3740 IOService
* newService
,
3741 IONotifier
* notifier
)
3745 if (!*((IOService
**) ref
))
3747 newService
->retain();
3748 (*(IOService
**) ref
) = newService
;
3756 IOService
* IOService::waitForMatchingService( OSDictionary
* matching
,
3759 IONotifier
* notify
= 0;
3760 // priority doesn't help us much since we need a thread wakeup
3761 SInt32 priority
= 0;
3772 result
= (IOService
*) copyExistingServices( matching
,
3773 kIOServiceMatchedState
, kIONotifyOnce
);
3776 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
3777 &IOService::syncNotificationHandler
, (void *) 0,
3778 &result
, priority
);
3781 if (UINT64_MAX
!= timeout
)
3783 AbsoluteTime deadline
;
3784 nanoseconds_to_absolutetime(timeout
, &deadline
);
3785 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
3786 SLEEPNOTIFYTO(&result
, deadline
);
3790 SLEEPNOTIFY(&result
);
3798 notify
->remove(); // dequeues
3803 IOService
* IOService::waitForService( OSDictionary
* matching
,
3804 mach_timespec_t
* timeout
)
3811 timeoutNS
= timeout
->tv_sec
;
3812 timeoutNS
*= kSecondScale
;
3813 timeoutNS
+= timeout
->tv_nsec
;
3816 timeoutNS
= UINT64_MAX
;
3818 result
= waitForMatchingService(matching
, timeoutNS
);
3820 matching
->release();
3827 void IOService::deliverNotification( const OSSymbol
* type
,
3828 IOOptionBits orNewState
, IOOptionBits andNewState
)
3830 _IOServiceNotifier
* notify
;
3832 OSArray
* willSend
= 0;
3834 lockForArbitration();
3836 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3837 || (type
== gIOTerminatedNotification
)) {
3841 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3842 gNotifications
->getObject( type
) );
3845 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
3847 if( passiveMatch( notify
->matching
)
3848 && (kIOServiceNotifyEnable
& notify
->state
)) {
3850 willSend
= OSArray::withCapacity(8);
3852 willSend
->setObject( notify
);
3858 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
3864 for( unsigned int idx
= 0;
3865 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
3867 invokeNotifer( notify
);
3869 willSend
->release();
3871 unlockForArbitration();
3874 IOOptionBits
IOService::getState( void ) const
3876 return( __state
[0] );
3880 * Helpers to make matching objects for simple cases
3883 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
3884 OSDictionary
* table
)
3887 table
= OSDictionary::withCapacity( 2 );
3889 table
->setObject(gIOProviderClassKey
, (OSObject
*)name
);
3894 OSDictionary
* IOService::serviceMatching( const char * name
,
3895 OSDictionary
* table
)
3897 const OSString
* str
;
3899 str
= OSSymbol::withCString( name
);
3903 table
= serviceMatching( str
, table
);
3908 OSDictionary
* IOService::nameMatching( const OSString
* name
,
3909 OSDictionary
* table
)
3912 table
= OSDictionary::withCapacity( 2 );
3914 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
3919 OSDictionary
* IOService::nameMatching( const char * name
,
3920 OSDictionary
* table
)
3922 const OSString
* str
;
3924 str
= OSSymbol::withCString( name
);
3928 table
= nameMatching( str
, table
);
3933 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
3934 OSDictionary
* table
)
3936 table
= serviceMatching( gIOResourcesKey
, table
);
3938 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
3943 OSDictionary
* IOService::resourceMatching( const char * name
,
3944 OSDictionary
* table
)
3946 const OSSymbol
* str
;
3948 str
= OSSymbol::withCString( name
);
3952 table
= resourceMatching( str
, table
);
3958 OSDictionary
* IOService::propertyMatching( const OSSymbol
* key
, const OSObject
* value
,
3959 OSDictionary
* table
)
3961 OSDictionary
* properties
;
3963 properties
= OSDictionary::withCapacity( 2 );
3966 properties
->setObject( key
, value
);
3969 table
= OSDictionary::withCapacity( 2 );
3971 table
->setObject( gIOPropertyMatchKey
, properties
);
3973 properties
->release();
3978 OSDictionary
* IOService::registryEntryIDMatching( uint64_t entryID
,
3979 OSDictionary
* table
)
3983 num
= OSNumber::withNumber( entryID
, 64 );
3988 table
= OSDictionary::withCapacity( 2 );
3990 table
->setObject( gIORegistryEntryIDKey
, num
);
4000 * _IOServiceNotifier
4003 // wait for all threads, other than the current one,
4004 // to exit the handler
4006 void _IOServiceNotifier::wait()
4008 _IOServiceNotifierInvocation
* next
;
4013 queue_iterate( &handlerInvocations
, next
,
4014 _IOServiceNotifierInvocation
*, link
) {
4015 if( next
->thread
!= current_thread() ) {
4021 state
|= kIOServiceNotifyWaiter
;
4028 void _IOServiceNotifier::free()
4030 assert( queue_empty( &handlerInvocations
));
4034 void _IOServiceNotifier::remove()
4039 whence
->removeObject( (OSObject
*) this );
4043 matching
->release();
4047 state
&= ~kIOServiceNotifyEnable
;
4056 bool _IOServiceNotifier::disable()
4062 ret
= (0 != (kIOServiceNotifyEnable
& state
));
4063 state
&= ~kIOServiceNotifyEnable
;
4072 void _IOServiceNotifier::enable( bool was
)
4076 state
|= kIOServiceNotifyEnable
;
4078 state
&= ~kIOServiceNotifyEnable
;
4086 IOService
* IOResources::resources( void )
4090 inst
= new IOResources
;
4091 if( inst
&& !inst
->init()) {
4099 IOWorkLoop
* IOResources::getWorkLoop() const
4101 // If we are the resource root
4102 // then use the platform's workloop
4103 if (this == (IOResources
*) gIOResources
)
4104 return getPlatform()->getWorkLoop();
4106 return IOService::getWorkLoop();
4109 bool IOResources::matchPropertyTable( OSDictionary
* table
)
4117 prop
= table
->getObject( gIOResourceMatchKey
);
4118 str
= OSDynamicCast( OSString
, prop
);
4120 ok
= (0 != getProperty( str
));
4122 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
4124 iter
= OSCollectionIterator::withCollection( set
);
4126 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
4127 ok
= (0 != getProperty( str
));
4136 IOReturn
IOResources::setProperties( OSObject
* properties
)
4139 const OSSymbol
* key
;
4140 OSDictionary
* dict
;
4141 OSCollectionIterator
* iter
;
4143 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
4144 if ( kIOReturnSuccess
!= err
)
4147 dict
= OSDynamicCast(OSDictionary
, properties
);
4149 return( kIOReturnBadArgument
);
4151 iter
= OSCollectionIterator::withCollection( dict
);
4153 return( kIOReturnBadArgument
);
4155 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
4157 if (gIOConsoleUsersKey
== key
)
4159 IORegistryEntry::getRegistryRoot()->setProperty(key
, dict
->getObject(key
));
4160 OSIncrementAtomic( &gIOConsoleUsersSeed
);
4161 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
4165 publishResource( key
, dict
->getObject(key
) );
4170 return( kIOReturnSuccess
);
4174 * Helpers for matching dictionaries.
4175 * Keys existing in matching are checked in properties.
4176 * Keys may be a string or OSCollection of IOStrings
4179 bool IOService::compareProperty( OSDictionary
* matching
,
4185 value
= matching
->getObject( key
);
4187 ok
= value
->isEqualTo( getProperty( key
));
4195 bool IOService::compareProperty( OSDictionary
* matching
,
4196 const OSString
* key
)
4201 value
= matching
->getObject( key
);
4203 ok
= value
->isEqualTo( getProperty( key
));
4210 bool IOService::compareProperties( OSDictionary
* matching
,
4211 OSCollection
* keys
)
4213 OSCollectionIterator
* iter
;
4214 const OSString
* key
;
4217 if( !matching
|| !keys
)
4220 iter
= OSCollectionIterator::withCollection( keys
);
4223 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
4224 ok
= compareProperty( matching
, key
);
4228 keys
->release(); // !! consume a ref !!
4233 /* Helper to add a location matching dict to the table */
4235 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
4237 OSDictionary
* dict
;
4242 dict
= OSDictionary::withCapacity( 1 );
4244 table
->setObject( gIOLocationMatchKey
, dict
);
4252 * Go looking for a provider to match a location dict.
4255 IOService
* IOService::matchLocation( IOService
* /* client */ )
4259 parent
= getProvider();
4262 parent
= parent
->matchLocation( this );
4267 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
4273 IORegistryEntry
* entry
;
4278 bool matchParent
= false;
4289 str
= OSDynamicCast( OSString
, table
->getObject( gIOProviderClassKey
));
4292 match
= (0 != where
->metaCast( str
));
4297 obj
= table
->getObject( gIONameMatchKey
);
4300 match
= where
->compareNames( obj
, changesOK
? &matched
: 0 );
4303 if( changesOK
&& matched
) {
4304 // leave a hint as to which name matched
4305 table
->setObject( gIONameMatchedKey
, matched
);
4310 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
4313 const OSSymbol
* sym
;
4317 sym
= where
->copyLocation();
4319 match
= sym
->isEqualTo( str
);
4326 obj
= table
->getObject( gIOPropertyMatchKey
);
4329 OSDictionary
* dict
;
4330 OSDictionary
* nextDict
;
4335 dict
= where
->dictionaryWithProperties();
4337 nextDict
= OSDynamicCast( OSDictionary
, obj
);
4341 iter
= OSCollectionIterator::withCollection(
4342 OSDynamicCast(OSCollection
, obj
));
4345 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
4346 iter
->getNextObject()))))) {
4347 match
= dict
->isEqualTo( nextDict
, nextDict
);
4360 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
4363 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
4364 match
= (where
== entry
);
4371 num
= OSDynamicCast( OSNumber
, table
->getObject( gIORegistryEntryIDKey
));
4374 match
= (getRegistryEntryID() == num
->unsigned64BitValue());
4377 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
4381 IOService
* service
= 0;
4382 UInt32 serviceCount
= 0;
4385 iter
= where
->getClientIterator();
4387 while( (service
= (IOService
*) iter
->getNextObject())) {
4388 if( kIOServiceInactiveState
& service
->__state
[0])
4390 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
4396 match
= (serviceCount
== num
->unsigned32BitValue());
4401 if( done
== table
->getCount()) {
4402 // don't call family if we've done all the entries in the table
4403 matchParent
= false;
4407 // pass in score from property table
4408 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
4410 // do family specific matching
4411 match
= where
->matchPropertyTable( table
, &score
);
4415 if( kIOLogMatch
& getDebugFlags( table
))
4416 LOG("%s: family specific matching fails\n", where
->getName());
4423 newPri
= OSNumber::withNumber( score
, 32 );
4425 table
->setObject( gIOProbeScoreKey
, newPri
);
4430 if( !(match
= where
->compareProperty( table
, kIOBSDNameKey
)))
4432 if( !(match
= where
->compareProperty( table
, kIOBSDMajorKey
)))
4434 if( !(match
= where
->compareProperty( table
, kIOBSDMinorKey
)))
4436 if( !(match
= where
->compareProperty( table
, kIOBSDUnitKey
)))
4439 matchParent
= false;
4441 obj
= OSDynamicCast( OSDictionary
,
4442 table
->getObject( gIOParentMatchKey
));
4446 table
= (OSDictionary
*) obj
;
4450 table
= OSDynamicCast( OSDictionary
,
4451 table
->getObject( gIOLocationMatchKey
));
4454 where
= where
->getProvider();
4456 where
= where
->matchLocation( where
);
4459 } while( table
&& where
);
4461 } while( matchParent
&& (where
= where
->getProvider()) );
4463 if( kIOLogMatch
& gIOKitDebug
)
4465 LOG("match parent @ %s = %d\n",
4466 where
->getName(), match
);
4472 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4473 UInt32 type
, OSDictionary
* properties
,
4474 IOUserClient
** handler
)
4476 const OSSymbol
*userClientClass
= 0;
4477 IOUserClient
*client
;
4480 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
))
4481 return kIOReturnSuccess
;
4483 // First try my own properties for a user client class name
4484 temp
= getProperty(gIOUserClientClassKey
);
4486 if (OSDynamicCast(OSSymbol
, temp
))
4487 userClientClass
= (const OSSymbol
*) temp
;
4488 else if (OSDynamicCast(OSString
, temp
)) {
4489 userClientClass
= OSSymbol::withString((OSString
*) temp
);
4490 if (userClientClass
)
4491 setProperty(kIOUserClientClassKey
,
4492 (OSObject
*) userClientClass
);
4496 // Didn't find one so lets just bomb out now without further ado.
4497 if (!userClientClass
)
4498 return kIOReturnUnsupported
;
4500 // This reference is consumed by the IOServiceOpen call
4501 temp
= OSMetaClass::allocClassWithName(userClientClass
);
4503 return kIOReturnNoMemory
;
4505 if (OSDynamicCast(IOUserClient
, temp
))
4506 client
= (IOUserClient
*) temp
;
4509 return kIOReturnUnsupported
;
4512 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
4514 return kIOReturnBadArgument
;
4517 if ( !client
->attach(this) ) {
4519 return kIOReturnUnsupported
;
4522 if ( !client
->start(this) ) {
4523 client
->detach(this);
4525 return kIOReturnUnsupported
;
4529 return kIOReturnSuccess
;
4532 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4533 UInt32 type
, IOUserClient
** handler
)
4535 return( kIOReturnUnsupported
);
4538 IOReturn
IOService::requestProbe( IOOptionBits options
)
4540 return( kIOReturnUnsupported
);
4544 * Convert an IOReturn to text. Subclasses which add additional
4545 * IOReturn's should override this method and call
4546 * super::stringFromReturn if the desired value is not found.
4549 const char * IOService::stringFromReturn( IOReturn rtn
)
4551 static const IONamedValue IOReturn_values
[] = {
4552 {kIOReturnSuccess
, "success" },
4553 {kIOReturnError
, "general error" },
4554 {kIOReturnNoMemory
, "memory allocation error" },
4555 {kIOReturnNoResources
, "resource shortage" },
4556 {kIOReturnIPCError
, "Mach IPC failure" },
4557 {kIOReturnNoDevice
, "no such device" },
4558 {kIOReturnNotPrivileged
, "privilege violation" },
4559 {kIOReturnBadArgument
, "invalid argument" },
4560 {kIOReturnLockedRead
, "device is read locked" },
4561 {kIOReturnLockedWrite
, "device is write locked" },
4562 {kIOReturnExclusiveAccess
, "device is exclusive access" },
4563 {kIOReturnBadMessageID
, "bad IPC message ID" },
4564 {kIOReturnUnsupported
, "unsupported function" },
4565 {kIOReturnVMError
, "virtual memory error" },
4566 {kIOReturnInternalError
, "internal driver error" },
4567 {kIOReturnIOError
, "I/O error" },
4568 {kIOReturnCannotLock
, "cannot acquire lock" },
4569 {kIOReturnNotOpen
, "device is not open" },
4570 {kIOReturnNotReadable
, "device is not readable" },
4571 {kIOReturnNotWritable
, "device is not writeable" },
4572 {kIOReturnNotAligned
, "alignment error" },
4573 {kIOReturnBadMedia
, "media error" },
4574 {kIOReturnStillOpen
, "device is still open" },
4575 {kIOReturnRLDError
, "rld failure" },
4576 {kIOReturnDMAError
, "DMA failure" },
4577 {kIOReturnBusy
, "device is busy" },
4578 {kIOReturnTimeout
, "I/O timeout" },
4579 {kIOReturnOffline
, "device is offline" },
4580 {kIOReturnNotReady
, "device is not ready" },
4581 {kIOReturnNotAttached
, "device/channel is not attached" },
4582 {kIOReturnNoChannels
, "no DMA channels available" },
4583 {kIOReturnNoSpace
, "no space for data" },
4584 {kIOReturnPortExists
, "device port already exists" },
4585 {kIOReturnCannotWire
, "cannot wire physical memory" },
4586 {kIOReturnNoInterrupt
, "no interrupt attached" },
4587 {kIOReturnNoFrames
, "no DMA frames enqueued" },
4588 {kIOReturnMessageTooLarge
, "message is too large" },
4589 {kIOReturnNotPermitted
, "operation is not permitted" },
4590 {kIOReturnNoPower
, "device is without power" },
4591 {kIOReturnNoMedia
, "media is not present" },
4592 {kIOReturnUnformattedMedia
, "media is not formatted" },
4593 {kIOReturnUnsupportedMode
, "unsupported mode" },
4594 {kIOReturnUnderrun
, "data underrun" },
4595 {kIOReturnOverrun
, "data overrun" },
4596 {kIOReturnDeviceError
, "device error" },
4597 {kIOReturnNoCompletion
, "no completion routine" },
4598 {kIOReturnAborted
, "operation was aborted" },
4599 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
4600 {kIOReturnNotResponding
, "device is not responding" },
4601 {kIOReturnInvalid
, "unanticipated driver error" },
4605 return IOFindNameForValue(rtn
, IOReturn_values
);
4609 * Convert an IOReturn to an errno.
4611 int IOService::errnoFromReturn( IOReturn rtn
)
4615 case kIOReturnSuccess
:
4617 case kIOReturnNoMemory
:
4619 case kIOReturnNoDevice
:
4621 case kIOReturnVMError
:
4623 case kIOReturnNotPermitted
:
4625 case kIOReturnNotPrivileged
:
4627 case kIOReturnIOError
:
4629 case kIOReturnNotWritable
:
4631 case kIOReturnBadArgument
:
4633 case kIOReturnUnsupported
:
4637 case kIOReturnNoPower
:
4639 case kIOReturnDeviceError
:
4641 case kIOReturnTimeout
:
4643 case kIOReturnMessageTooLarge
:
4645 case kIOReturnNoSpace
:
4647 case kIOReturnCannotLock
:
4651 case kIOReturnBadMessageID
:
4652 case kIOReturnNoCompletion
:
4653 case kIOReturnNotAligned
:
4655 case kIOReturnNotReady
:
4657 case kIOReturnRLDError
:
4659 case kIOReturnPortExists
:
4660 case kIOReturnStillOpen
:
4662 case kIOReturnExclusiveAccess
:
4663 case kIOReturnLockedRead
:
4664 case kIOReturnLockedWrite
:
4665 case kIOReturnNotOpen
:
4666 case kIOReturnNotReadable
:
4668 case kIOReturnCannotWire
:
4669 case kIOReturnNoResources
:
4671 case kIOReturnAborted
:
4672 case kIOReturnOffline
:
4673 case kIOReturnNotResponding
:
4675 case kIOReturnBadMedia
:
4676 case kIOReturnNoMedia
:
4677 case kIOReturnNotAttached
:
4678 case kIOReturnUnformattedMedia
:
4679 return(ENXIO
); // (media error)
4680 case kIOReturnDMAError
:
4681 case kIOReturnOverrun
:
4682 case kIOReturnUnderrun
:
4683 return(EIO
); // (transfer error)
4684 case kIOReturnNoBandwidth
:
4685 case kIOReturnNoChannels
:
4686 case kIOReturnNoFrames
:
4687 case kIOReturnNoInterrupt
:
4688 return(EIO
); // (hardware error)
4689 case kIOReturnError
:
4690 case kIOReturnInternalError
:
4691 case kIOReturnInvalid
:
4692 return(EIO
); // (generic error)
4693 case kIOReturnIPCError
:
4694 return(EIO
); // (ipc error)
4696 return(EIO
); // (all other errors)
4700 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
4704 * Generic entry point for calls from the provider. A return value of
4705 * kIOReturnSuccess indicates that the message was received, and where
4706 * applicable, that it was successful.
4709 return kIOReturnUnsupported
;
4716 IOItemCount
IOService::getDeviceMemoryCount( void )
4721 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4723 count
= array
->getCount();
4730 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
4733 IODeviceMemory
* range
;
4735 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4737 range
= (IODeviceMemory
*) array
->getObject( index
);
4744 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
4745 IOOptionBits options
)
4747 IODeviceMemory
* range
;
4750 range
= getDeviceMemoryWithIndex( index
);
4752 map
= range
->map( options
);
4759 OSArray
* IOService::getDeviceMemory( void )
4761 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
4765 void IOService::setDeviceMemory( OSArray
* array
)
4767 setProperty( gIODeviceMemoryKey
, array
);
4771 * For machines where the transfers on an I/O bus can stall because
4772 * the CPU is in an idle mode, These APIs allow a driver to specify
4773 * the maximum bus stall that they can handle. 0 indicates no limit.
4776 setCPUSnoopDelay(UInt32 __unused ns
)
4778 #if defined(__i386__) || defined(__x86_64__)
4779 ml_set_maxsnoop(ns
);
4780 #endif /* defined(__i386__) || defined(__x86_64__) */
4786 #if defined(__i386__) || defined(__x86_64__)
4787 return ml_get_maxsnoop();
4790 #endif /* defined(__i386__) || defined(__x86_64__) */
4793 #if defined(__i386__) || defined(__x86_64__)
4795 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
)
4797 static const UInt kNoReplace
= -1U; // Must be an illegal index
4798 UInt replace
= kNoReplace
;
4799 bool setCpuDelay
= false;
4801 IORecursiveLockLock(sCpuDelayLock
);
4803 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
4804 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
4805 IOService
* holder
= NULL
;
4808 const CpuDelayEntry ne
= {service
, ns
, delayType
};
4810 // Set maximum delay.
4811 for (UInt i
= 0; i
< count
; i
++) {
4812 IOService
*thisService
= entries
[i
].fService
;
4813 bool sameType
= (delayType
== entries
[i
].fDelayType
);
4814 if ((service
== thisService
) && sameType
)
4816 else if (!thisService
) {
4817 if (kNoReplace
== replace
)
4820 else if (sameType
) {
4821 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
4825 holder
= thisService
;
4831 if (kNoReplace
== replace
)
4832 sCpuDelayData
->appendBytes(&ne
, sizeof(ne
));
4834 entries
[replace
] = ne
;
4837 ns
= -1U; // Set to max unsigned, i.e. no restriction
4839 for (UInt i
= 0; i
< count
; i
++) {
4840 // Clear a maximum delay.
4841 IOService
*thisService
= entries
[i
].fService
;
4842 if (thisService
&& (delayType
== entries
[i
].fDelayType
)) {
4843 UInt32 thisMax
= entries
[i
].fMaxDelay
;
4844 if (service
== thisService
)
4846 else if (thisMax
< ns
) {
4848 holder
= thisService
;
4853 // Check if entry found
4854 if (kNoReplace
!= replace
) {
4855 entries
[replace
].fService
= 0; // Null the entry
4862 // Must be safe to call from locked context
4863 if (delayType
== kCpuDelayBusStall
)
4865 ml_set_maxbusdelay(ns
);
4867 else if (delayType
== kCpuDelayInterrupt
)
4869 ml_set_maxintdelay(ns
);
4872 OSArray
* handlers
= sCpuLatencyHandlers
[delayType
];
4874 if (handlers
) for (unsigned int idx
= 0;
4875 (target
= (IOService
*) handlers
->getObject(idx
));
4878 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
4879 (void *) (uintptr_t) ns
, holder
,
4884 IORecursiveLockUnlock(sCpuDelayLock
);
4888 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
)
4890 IOReturn result
= kIOReturnNotFound
;
4894 IORecursiveLockLock(sCpuDelayLock
);
4898 if (enable
&& !sCpuLatencyHandlers
[delayType
])
4899 sCpuLatencyHandlers
[delayType
] = OSArray::withCapacity(4);
4900 array
= sCpuLatencyHandlers
[delayType
];
4903 idx
= array
->getNextIndexOfObject(target
, 0);
4908 array
->removeObject(idx
);
4909 result
= kIOReturnSuccess
;
4915 result
= kIOReturnExclusiveAccess
;
4918 array
->setObject(target
);
4920 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
4921 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
4922 UInt32 ns
= -1U; // Set to max unsigned, i.e. no restriction
4923 IOService
* holder
= NULL
;
4925 for (UInt i
= 0; i
< count
; i
++) {
4926 if (entries
[i
].fService
4927 && (delayType
== entries
[i
].fDelayType
)
4928 && (entries
[i
].fMaxDelay
< ns
)) {
4929 ns
= entries
[i
].fMaxDelay
;
4930 holder
= entries
[i
].fService
;
4933 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
4934 (void *) (uintptr_t) ns
, holder
,
4936 result
= kIOReturnSuccess
;
4941 IORecursiveLockUnlock(sCpuDelayLock
);
4946 #endif /* defined(__i386__) || defined(__x86_64__) */
4949 requireMaxBusStall(UInt32 __unused ns
)
4951 #if defined(__i386__) || defined(__x86_64__)
4952 requireMaxCpuDelay(this, ns
, kCpuDelayBusStall
);
4957 requireMaxInterruptDelay(uint32_t __unused ns
)
4959 #if defined(__i386__) || defined(__x86_64__)
4960 requireMaxCpuDelay(this, ns
, kCpuDelayInterrupt
);
4968 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
4970 IOInterruptController
*interruptController
;
4973 OSSymbol
*interruptControllerName
;
4975 IOInterruptSource
*interruptSources
;
4977 // Get the parents list from the nub.
4978 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
4979 if (array
== 0) return kIOReturnNoResources
;
4981 // Allocate space for the IOInterruptSources if needed... then return early.
4982 if (nub
->_interruptSources
== 0) {
4983 numSources
= array
->getCount();
4984 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
4985 if (interruptSources
== 0) return kIOReturnNoMemory
;
4987 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
4989 nub
->_numInterruptSources
= numSources
;
4990 nub
->_interruptSources
= interruptSources
;
4991 return kIOReturnSuccess
;
4994 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
4995 if (interruptControllerName
== 0) return kIOReturnNoResources
;
4997 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
4998 if (interruptController
== 0) return kIOReturnNoResources
;
5000 // Get the interrupt numbers from the nub.
5001 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
5002 if (array
== 0) return kIOReturnNoResources
;
5003 data
= OSDynamicCast(OSData
, array
->getObject(source
));
5004 if (data
== 0) return kIOReturnNoResources
;
5006 // Set the interruptController and interruptSource in the nub's table.
5007 interruptSources
= nub
->_interruptSources
;
5008 interruptSources
[source
].interruptController
= interruptController
;
5009 interruptSources
[source
].vectorData
= data
;
5011 return kIOReturnSuccess
;
5014 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
5018 /* Make sure the _interruptSources are set */
5019 if (_interruptSources
== 0) {
5020 ret
= resolveInterrupt(this, source
);
5021 if (ret
!= kIOReturnSuccess
) return ret
;
5024 /* Make sure the local source number is valid */
5025 if ((source
< 0) || (source
>= _numInterruptSources
))
5026 return kIOReturnNoInterrupt
;
5028 /* Look up the contoller for the local source */
5029 *interruptController
= _interruptSources
[source
].interruptController
;
5031 if (*interruptController
== NULL
) {
5032 if (!resolve
) return kIOReturnNoInterrupt
;
5034 /* Try to reslove the interrupt */
5035 ret
= resolveInterrupt(this, source
);
5036 if (ret
!= kIOReturnSuccess
) return ret
;
5038 *interruptController
= _interruptSources
[source
].interruptController
;
5041 return kIOReturnSuccess
;
5044 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
5045 IOInterruptAction handler
,
5048 IOInterruptController
*interruptController
;
5051 ret
= lookupInterrupt(source
, true, &interruptController
);
5052 if (ret
!= kIOReturnSuccess
) return ret
;
5054 /* Register the source */
5055 return interruptController
->registerInterrupt(this, source
, target
,
5056 (IOInterruptHandler
)handler
,
5060 IOReturn
IOService::unregisterInterrupt(int source
)
5062 IOInterruptController
*interruptController
;
5065 ret
= lookupInterrupt(source
, false, &interruptController
);
5066 if (ret
!= kIOReturnSuccess
) return ret
;
5068 /* Unregister the source */
5069 return interruptController
->unregisterInterrupt(this, source
);
5072 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
5074 IOInterruptController
*interruptController
;
5077 ret
= lookupInterrupt(source
, true, &interruptController
);
5078 if (ret
!= kIOReturnSuccess
) return ret
;
5080 /* Return the type */
5081 return interruptController
->getInterruptType(this, source
, interruptType
);
5084 IOReturn
IOService::enableInterrupt(int source
)
5086 IOInterruptController
*interruptController
;
5089 ret
= lookupInterrupt(source
, false, &interruptController
);
5090 if (ret
!= kIOReturnSuccess
) return ret
;
5092 /* Enable the source */
5093 return interruptController
->enableInterrupt(this, source
);
5096 IOReturn
IOService::disableInterrupt(int source
)
5098 IOInterruptController
*interruptController
;
5101 ret
= lookupInterrupt(source
, false, &interruptController
);
5102 if (ret
!= kIOReturnSuccess
) return ret
;
5104 /* Disable the source */
5105 return interruptController
->disableInterrupt(this, source
);
5108 IOReturn
IOService::causeInterrupt(int source
)
5110 IOInterruptController
*interruptController
;
5113 ret
= lookupInterrupt(source
, false, &interruptController
);
5114 if (ret
!= kIOReturnSuccess
) return ret
;
5116 /* Cause an interrupt for the source */
5117 return interruptController
->causeInterrupt(this, source
);
5121 OSMetaClassDefineReservedUnused(IOService
, 0);
5122 OSMetaClassDefineReservedUnused(IOService
, 1);
5123 OSMetaClassDefineReservedUnused(IOService
, 2);
5124 OSMetaClassDefineReservedUnused(IOService
, 3);
5125 OSMetaClassDefineReservedUnused(IOService
, 4);
5126 OSMetaClassDefineReservedUnused(IOService
, 5);
5128 OSMetaClassDefineReservedUsed(IOService
, 0);
5129 OSMetaClassDefineReservedUsed(IOService
, 1);
5130 OSMetaClassDefineReservedUsed(IOService
, 2);
5131 OSMetaClassDefineReservedUsed(IOService
, 3);
5132 OSMetaClassDefineReservedUsed(IOService
, 4);
5133 OSMetaClassDefineReservedUsed(IOService
, 5);
5135 OSMetaClassDefineReservedUnused(IOService
, 6);
5136 OSMetaClassDefineReservedUnused(IOService
, 7);
5137 OSMetaClassDefineReservedUnused(IOService
, 8);
5138 OSMetaClassDefineReservedUnused(IOService
, 9);
5139 OSMetaClassDefineReservedUnused(IOService
, 10);
5140 OSMetaClassDefineReservedUnused(IOService
, 11);
5141 OSMetaClassDefineReservedUnused(IOService
, 12);
5142 OSMetaClassDefineReservedUnused(IOService
, 13);
5143 OSMetaClassDefineReservedUnused(IOService
, 14);
5144 OSMetaClassDefineReservedUnused(IOService
, 15);
5145 OSMetaClassDefineReservedUnused(IOService
, 16);
5146 OSMetaClassDefineReservedUnused(IOService
, 17);
5147 OSMetaClassDefineReservedUnused(IOService
, 18);
5148 OSMetaClassDefineReservedUnused(IOService
, 19);
5149 OSMetaClassDefineReservedUnused(IOService
, 20);
5150 OSMetaClassDefineReservedUnused(IOService
, 21);
5151 OSMetaClassDefineReservedUnused(IOService
, 22);
5152 OSMetaClassDefineReservedUnused(IOService
, 23);
5153 OSMetaClassDefineReservedUnused(IOService
, 24);
5154 OSMetaClassDefineReservedUnused(IOService
, 25);
5155 OSMetaClassDefineReservedUnused(IOService
, 26);
5156 OSMetaClassDefineReservedUnused(IOService
, 27);
5157 OSMetaClassDefineReservedUnused(IOService
, 28);
5158 OSMetaClassDefineReservedUnused(IOService
, 29);
5159 OSMetaClassDefineReservedUnused(IOService
, 30);
5160 OSMetaClassDefineReservedUnused(IOService
, 31);
5161 OSMetaClassDefineReservedUnused(IOService
, 32);
5162 OSMetaClassDefineReservedUnused(IOService
, 33);
5163 OSMetaClassDefineReservedUnused(IOService
, 34);
5164 OSMetaClassDefineReservedUnused(IOService
, 35);
5165 OSMetaClassDefineReservedUnused(IOService
, 36);
5166 OSMetaClassDefineReservedUnused(IOService
, 37);
5167 OSMetaClassDefineReservedUnused(IOService
, 38);
5168 OSMetaClassDefineReservedUnused(IOService
, 39);
5169 OSMetaClassDefineReservedUnused(IOService
, 40);
5170 OSMetaClassDefineReservedUnused(IOService
, 41);
5171 OSMetaClassDefineReservedUnused(IOService
, 42);
5172 OSMetaClassDefineReservedUnused(IOService
, 43);
5173 OSMetaClassDefineReservedUnused(IOService
, 44);
5174 OSMetaClassDefineReservedUnused(IOService
, 45);
5175 OSMetaClassDefineReservedUnused(IOService
, 46);
5176 OSMetaClassDefineReservedUnused(IOService
, 47);
5179 OSMetaClassDefineReservedUnused(IOService
, 48);
5180 OSMetaClassDefineReservedUnused(IOService
, 49);
5181 OSMetaClassDefineReservedUnused(IOService
, 50);
5182 OSMetaClassDefineReservedUnused(IOService
, 51);
5183 OSMetaClassDefineReservedUnused(IOService
, 52);
5184 OSMetaClassDefineReservedUnused(IOService
, 53);
5185 OSMetaClassDefineReservedUnused(IOService
, 54);
5186 OSMetaClassDefineReservedUnused(IOService
, 55);
5187 OSMetaClassDefineReservedUnused(IOService
, 56);
5188 OSMetaClassDefineReservedUnused(IOService
, 57);
5189 OSMetaClassDefineReservedUnused(IOService
, 58);
5190 OSMetaClassDefineReservedUnused(IOService
, 59);
5191 OSMetaClassDefineReservedUnused(IOService
, 60);
5192 OSMetaClassDefineReservedUnused(IOService
, 61);
5193 OSMetaClassDefineReservedUnused(IOService
, 62);
5194 OSMetaClassDefineReservedUnused(IOService
, 63);