2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include <IOKit/system.h>
25 #include <IOKit/IOService.h>
26 #include <libkern/c++/OSContainers.h>
27 #include <libkern/c++/OSUnserialize.h>
28 #include <IOKit/IOCatalogue.h>
29 #include <IOKit/IOCommand.h>
30 #include <IOKit/IODeviceMemory.h>
31 #include <IOKit/IOInterrupts.h>
32 #include <IOKit/IOInterruptController.h>
33 #include <IOKit/IOPlatformExpert.h>
34 #include <IOKit/IOMessage.h>
35 #include <IOKit/IOLib.h>
36 #include <IOKit/IOKitKeysPrivate.h>
37 #include <IOKit/IOBSD.h>
38 #include <IOKit/IOUserClient.h>
39 #include <IOKit/IOWorkLoop.h>
40 #include <mach/sync_policy.h>
41 #include <IOKit/assert.h>
42 #include <sys/errno.h>
47 #include "IOServicePrivate.h"
49 // take lockForArbitration before LOCKNOTIFY
51 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
53 #define super IORegistryEntry
55 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
57 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
59 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
61 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
63 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
65 OSDefineMetaClassAndStructors(IOResources
, IOService
)
67 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
69 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
71 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
73 static IOPlatformExpert
* gIOPlatform
;
74 static class IOPMrootDomain
* gIOPMRootDomain
;
75 const IORegistryPlane
* gIOServicePlane
;
76 const IORegistryPlane
* gIOPowerPlane
;
77 const OSSymbol
* gIODeviceMemoryKey
;
78 const OSSymbol
* gIOInterruptControllersKey
;
79 const OSSymbol
* gIOInterruptSpecifiersKey
;
81 const OSSymbol
* gIOResourcesKey
;
82 const OSSymbol
* gIOResourceMatchKey
;
83 const OSSymbol
* gIOProviderClassKey
;
84 const OSSymbol
* gIONameMatchKey
;
85 const OSSymbol
* gIONameMatchedKey
;
86 const OSSymbol
* gIOPropertyMatchKey
;
87 const OSSymbol
* gIOLocationMatchKey
;
88 const OSSymbol
* gIOParentMatchKey
;
89 const OSSymbol
* gIOPathMatchKey
;
90 const OSSymbol
* gIOMatchCategoryKey
;
91 const OSSymbol
* gIODefaultMatchCategoryKey
;
92 const OSSymbol
* gIOMatchedServiceCountKey
;
94 const OSSymbol
* gIOUserClientClassKey
;
95 const OSSymbol
* gIOKitDebugKey
;
97 const OSSymbol
* gIOCommandPoolSizeKey
;
99 const OSSymbol
* gIOConsoleUsersKey
;
100 const OSSymbol
* gIOConsoleSessionUIDKey
;
101 const OSSymbol
* gIOConsoleUsersSeedKey
;
102 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
103 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
105 static int gIOResourceGenerationCount
;
107 const OSSymbol
* gIOServiceKey
;
108 const OSSymbol
* gIOPublishNotification
;
109 const OSSymbol
* gIOFirstPublishNotification
;
110 const OSSymbol
* gIOMatchedNotification
;
111 const OSSymbol
* gIOFirstMatchNotification
;
112 const OSSymbol
* gIOTerminatedNotification
;
114 const OSSymbol
* gIOGeneralInterest
;
115 const OSSymbol
* gIOBusyInterest
;
116 const OSSymbol
* gIOAppPowerStateInterest
;
117 const OSSymbol
* gIOPriorityPowerStateInterest
;
119 static OSDictionary
* gNotifications
;
120 static IORecursiveLock
* gNotificationLock
;
122 static IOService
* gIOResources
;
123 static IOService
* gIOServiceRoot
;
125 static OSOrderedSet
* gJobs
;
126 static semaphore_port_t gJobsSemaphore
;
127 static IOLock
* gJobsLock
;
128 static int gOutstandingJobs
;
129 static int gNumConfigThreads
;
130 static int gNumWaitingThreads
;
131 static IOLock
* gIOServiceBusyLock
;
133 static thread_t gIOTerminateThread
;
134 static UInt32 gIOTerminateWork
;
135 static OSArray
* gIOTerminatePhase2List
;
136 static OSArray
* gIOStopList
;
137 static OSArray
* gIOStopProviderList
;
138 static OSArray
* gIOFinalizeList
;
140 static SInt32 gIOConsoleUsersSeed
;
141 static OSData
* gIOConsoleUsersSeedValue
;
143 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
145 #define LOCKREADNOTIFY() \
146 IORecursiveLockLock( gNotificationLock )
147 #define LOCKWRITENOTIFY() \
148 IORecursiveLockLock( gNotificationLock )
149 #define LOCKWRITE2READNOTIFY()
150 #define UNLOCKNOTIFY() \
151 IORecursiveLockUnlock( gNotificationLock )
152 #define SLEEPNOTIFY(event) \
153 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
154 #define WAKEUPNOTIFY(event) \
155 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
157 #define randomDelay() \
158 int del = read_processor_clock(); \
159 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
162 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
164 #define queue_element(entry, element, type, field) do { \
165 vm_address_t __ele = (vm_address_t) (entry); \
166 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
167 (element) = (type) __ele; \
170 #define iterqueue(que, elt) \
171 for (queue_entry_t elt = queue_first(que); \
172 !queue_end(que, elt); \
173 elt = queue_next(elt))
175 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
177 struct ArbitrationLockQueueElement
{
186 static queue_head_t gArbitrationLockQueueActive
;
187 static queue_head_t gArbitrationLockQueueWaiting
;
188 static queue_head_t gArbitrationLockQueueFree
;
189 static IOLock
* gArbitrationLockQueueLock
;
191 bool IOService::isInactive( void ) const
192 { return( 0 != (kIOServiceInactiveState
& getState())); }
194 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
198 // Only used by the intel implementation of
199 // IOService::requireMaxBusStall(UInt32 __unused ns)
202 const IOService
*fService
;
206 static OSData
*sBusStall
= OSData::withCapacity(8 * sizeof(BusStallEntry
));
207 static IOLock
*sBusStallLock
= IOLockAlloc();
208 #endif /* __i386__ */
210 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
212 void IOService::initialize( void )
216 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
217 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
219 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
220 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
221 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
222 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
223 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
224 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
225 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
227 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
228 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
229 kIODefaultMatchCategoryKey
);
230 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
231 kIOMatchedServiceCountKey
);
233 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
235 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
236 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
238 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
239 gIOInterruptControllersKey
240 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
241 gIOInterruptSpecifiersKey
242 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
244 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
246 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
248 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
249 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
250 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
251 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
253 gNotifications
= OSDictionary::withCapacity( 1 );
254 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
255 kIOPublishNotification
);
256 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
257 kIOFirstPublishNotification
);
258 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
259 kIOMatchedNotification
);
260 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
261 kIOFirstMatchNotification
);
262 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
263 kIOTerminatedNotification
);
264 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
266 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
267 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
268 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey
);
269 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionOnConsoleKey
);
270 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionSecureInputPIDKey
);
271 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
273 gNotificationLock
= IORecursiveLockAlloc();
275 assert( gIOServicePlane
&& gIODeviceMemoryKey
276 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
277 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
278 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
279 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
280 && gIOPublishNotification
&& gIOMatchedNotification
281 && gIOTerminatedNotification
&& gIOServiceKey
282 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
283 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
284 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
286 gJobsLock
= IOLockAlloc();
287 gJobs
= OSOrderedSet::withCapacity( 10 );
289 gIOServiceBusyLock
= IOLockAlloc();
291 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
293 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& (err
== KERN_SUCCESS
) );
295 gIOResources
= IOResources::resources();
296 assert( gIOResources
);
298 gArbitrationLockQueueLock
= IOLockAlloc();
299 queue_init(&gArbitrationLockQueueActive
);
300 queue_init(&gArbitrationLockQueueWaiting
);
301 queue_init(&gArbitrationLockQueueFree
);
303 assert( gArbitrationLockQueueLock
);
305 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
306 gIOStopList
= OSArray::withCapacity( 16 );
307 gIOStopProviderList
= OSArray::withCapacity( 16 );
308 gIOFinalizeList
= OSArray::withCapacity( 16 );
309 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
312 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
315 static UInt64
getDebugFlags( OSDictionary
* props
)
317 OSNumber
* debugProp
;
320 debugProp
= OSDynamicCast( OSNumber
,
321 props
->getObject( gIOKitDebugKey
));
323 debugFlags
= debugProp
->unsigned64BitValue();
325 debugFlags
= gIOKitDebug
;
327 return( debugFlags
);
331 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
333 // Probe a matched service and return an instance to be started.
334 // The default score is from the property table, & may be altered
335 // during probe to change the start order.
337 IOService
* IOService::probe( IOService
* provider
,
343 bool IOService::start( IOService
* provider
)
348 void IOService::stop( IOService
* provider
)
352 void IOService::free( void )
354 requireMaxBusStall(0);
355 if( getPropertyTable())
356 unregisterAllInterest();
362 * Attach in service plane
364 bool IOService::attach( IOService
* provider
)
370 if( gIOKitDebug
& kIOLogAttach
)
371 LOG( "%s::attach(%s)\n", getName(),
372 provider
->getName());
374 provider
->lockForArbitration();
375 if( provider
->__state
[0] & kIOServiceInactiveState
)
378 ok
= attachToParent( provider
, gIOServicePlane
);
379 provider
->unlockForArbitration();
382 gIOServiceRoot
= this;
383 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
389 IOService
* IOService::getServiceRoot( void )
391 return( gIOServiceRoot
);
394 void IOService::detach( IOService
* provider
)
396 IOService
* newProvider
= 0;
400 if( gIOKitDebug
& kIOLogAttach
)
401 LOG("%s::detach(%s)\n", getName(), provider
->getName());
403 lockForArbitration();
405 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
406 && (provider
== getProvider()));
408 detachFromParent( provider
, gIOServicePlane
);
411 newProvider
= getProvider();
412 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
413 _adjustBusy( -busy
);
416 unlockForArbitration();
419 newProvider
->lockForArbitration();
420 newProvider
->_adjustBusy(1);
421 newProvider
->unlockForArbitration();
424 // check for last client detach from a terminated service
425 if( provider
->lockForArbitration( true )) {
427 provider
->_adjustBusy( -1 );
428 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
429 && (0 == provider
->getClient())) {
430 provider
->scheduleFinalize();
432 provider
->unlockForArbitration();
437 * Register instance - publish it for matching
440 void IOService::registerService( IOOptionBits options
)
446 enum { kMaxPathLen
= 256 };
447 enum { kMaxChars
= 63 };
449 IORegistryEntry
* parent
= this;
450 IORegistryEntry
* root
= getRegistryRoot();
451 while( parent
&& (parent
!= root
))
452 parent
= parent
->getParentEntry( gIOServicePlane
);
454 if( parent
!= root
) {
455 IOLog("%s: not registry member at registerService()\n", getName());
459 // Allow the Platform Expert to adjust this node.
460 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
463 if( (this != gIOResources
)
464 && (kIOLogRegister
& gIOKitDebug
)) {
466 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
468 IOLog( "Registering: " );
471 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
474 if( len
> kMaxChars
) {
478 if( (skip
= strchr( path
, '/')))
484 IOLog( "%s\n", path
);
487 IOFree( pathBuf
, kMaxPathLen
);
490 startMatching( options
);
493 void IOService::startMatching( IOOptionBits options
)
495 IOService
* provider
;
498 bool needWake
= false;
503 lockForArbitration();
505 sync
= (options
& kIOServiceSynchronous
)
506 || ((provider
= getProvider())
507 && (provider
->__state
[1] & kIOServiceSynchronousState
));
509 if ( options
& kIOServiceAsynchronous
)
512 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
513 && (0 == (__state
[0] & kIOServiceInactiveState
));
515 __state
[1] |= kIOServiceNeedConfigState
;
517 // __state[0] &= ~kIOServiceInactiveState;
519 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
520 // OSKernelStackRemaining(), getName());
523 prevBusy
= _adjustBusy( 1 );
524 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
528 __state
[1] |= kIOServiceSynchronousState
;
530 __state
[1] &= ~kIOServiceSynchronousState
;
532 unlockForArbitration();
537 IOLockLock( gIOServiceBusyLock
);
538 thread_wakeup( (event_t
) this/*&__state[1]*/ );
539 IOLockUnlock( gIOServiceBusyLock
);
541 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
543 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
547 if( (__state
[1] & kIOServiceNeedConfigState
))
548 doServiceMatch( options
);
550 lockForArbitration();
551 IOLockLock( gIOServiceBusyLock
);
553 waitAgain
= (prevBusy
< (__state
[1] & kIOServiceBusyStateMask
));
555 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
557 __state
[1] &= ~kIOServiceSyncPubState
;
559 unlockForArbitration();
562 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
564 IOLockUnlock( gIOServiceBusyLock
);
566 thread_block(THREAD_CONTINUE_NULL
);
568 } while( waitAgain
);
572 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
574 OSDictionary
* table
;
584 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
587 set
= (OSSet
*) getExistingServices( table
,
588 kIOServiceRegisteredState
,
589 kIOServiceExistingSet
);
594 count
+= set
->getCount();
597 allSet
->merge((const OSSet
*) set
);
605 if( getDebugFlags( table
) & kIOLogMatch
)
606 LOG("Matching service count = %ld\n", count
);
608 newTables
->removeObject(table
);
612 while( (service
= (IOService
*) allSet
->getAnyObject())) {
613 service
->startMatching(kIOServiceAsynchronous
);
614 allSet
->removeObject(service
);
619 newTables
->release();
621 return( kIOReturnSuccess
);
624 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
625 IOOptionBits options
)
629 job
= new _IOServiceJob
;
630 if( job
&& !job
->init()) {
638 job
->options
= options
;
639 nub
->retain(); // thread will release()
647 * Called on a registered service to see if it matches
651 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
653 return( matchPropertyTable(table
) );
656 bool IOService::matchPropertyTable( OSDictionary
* table
)
662 * Called on a matched service to allocate resources
663 * before first driver is attached.
666 IOReturn
IOService::getResources( void )
668 return( kIOReturnSuccess
);
672 * Client/provider accessors
675 IOService
* IOService::getProvider( void ) const
677 IOService
* self
= (IOService
*) this;
682 generation
= getGenerationCount();
683 if( __providerGeneration
== generation
)
686 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
687 if( parent
== IORegistryEntry::getRegistryRoot())
688 /* root is not an IOService */
691 self
->__provider
= parent
;
692 // save the count before getParentEntry()
693 self
->__providerGeneration
= generation
;
698 IOWorkLoop
* IOService::getWorkLoop() const
700 IOService
*provider
= getProvider();
703 return provider
->getWorkLoop();
708 OSIterator
* IOService::getProviderIterator( void ) const
710 return( getParentIterator( gIOServicePlane
));
713 IOService
* IOService::getClient( void ) const
715 return( (IOService
*) getChildEntry( gIOServicePlane
));
718 OSIterator
* IOService::getClientIterator( void ) const
720 return( getChildIterator( gIOServicePlane
));
723 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
724 const IOService
* client
,
725 const IOService
* provider
)
727 _IOOpenServiceIterator
* inst
;
732 inst
= new _IOOpenServiceIterator
;
734 if( inst
&& !inst
->init()) {
740 inst
->client
= client
;
741 inst
->provider
= provider
;
747 void _IOOpenServiceIterator::free()
751 last
->unlockForArbitration();
755 OSObject
* _IOOpenServiceIterator::getNextObject()
760 last
->unlockForArbitration();
762 while( (next
= (IOService
*) iter
->getNextObject())) {
764 next
->lockForArbitration();
765 if( (client
&& (next
->isOpen( client
)))
766 || (provider
&& (provider
->isOpen( next
))) )
768 next
->unlockForArbitration();
776 bool _IOOpenServiceIterator::isValid()
778 return( iter
->isValid() );
781 void _IOOpenServiceIterator::reset()
784 last
->unlockForArbitration();
790 OSIterator
* IOService::getOpenProviderIterator( void ) const
792 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
795 OSIterator
* IOService::getOpenClientIterator( void ) const
797 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
801 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
802 bool waitForFunction
,
803 void *param1
, void *param2
,
804 void *param3
, void *param4
)
806 IOReturn result
= kIOReturnUnsupported
;
807 IOService
*provider
= getProvider();
810 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
811 param1
, param2
, param3
, param4
);
817 IOReturn
IOService::callPlatformFunction( const char * functionName
,
818 bool waitForFunction
,
819 void *param1
, void *param2
,
820 void *param3
, void *param4
)
822 IOReturn result
= kIOReturnNoMemory
;
823 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
825 if (functionSymbol
!= 0) {
826 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
827 param1
, param2
, param3
, param4
);
828 functionSymbol
->release();
836 * Accessors for global services
839 IOPlatformExpert
* IOService::getPlatform( void )
841 return( gIOPlatform
);
844 class IOPMrootDomain
* IOService::getPMRootDomain( void )
846 return( gIOPMRootDomain
);
849 IOService
* IOService::getResourceService( void )
851 return( gIOResources
);
854 void IOService::setPlatform( IOPlatformExpert
* platform
)
856 gIOPlatform
= platform
;
857 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
860 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
862 gIOPMRootDomain
= rootDomain
;
863 publishResource("IOKit");
870 bool IOService::lockForArbitration( bool isSuccessRequired
)
874 ArbitrationLockQueueElement
* element
;
875 ArbitrationLockQueueElement
* active
;
876 ArbitrationLockQueueElement
* waiting
;
878 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
880 // lock global access
881 IOTakeLock( gArbitrationLockQueueLock
);
883 // obtain an unused queue element
884 if( !queue_empty( &gArbitrationLockQueueFree
)) {
885 queue_remove_first( &gArbitrationLockQueueFree
,
887 ArbitrationLockQueueElement
*,
890 element
= IONew( ArbitrationLockQueueElement
, 1 );
894 // prepare the queue element
895 element
->thread
= IOThreadSelf();
896 element
->service
= this;
898 element
->required
= isSuccessRequired
;
899 element
->aborted
= false;
901 // determine whether this object is already locked (ie. on active queue)
903 queue_iterate( &gArbitrationLockQueueActive
,
905 ArbitrationLockQueueElement
*,
908 if( active
->service
== element
->service
) {
914 if( found
) { // this object is already locked
916 // determine whether it is the same or a different thread trying to lock
917 if( active
->thread
!= element
->thread
) { // it is a different thread
919 ArbitrationLockQueueElement
* victim
= 0;
921 // before placing this new thread on the waiting queue, we look for
922 // a deadlock cycle...
925 // determine whether the active thread holding the object we
926 // want is waiting for another object to be unlocked
928 queue_iterate( &gArbitrationLockQueueWaiting
,
930 ArbitrationLockQueueElement
*,
933 if( waiting
->thread
== active
->thread
) {
934 assert( false == waiting
->aborted
);
940 if( found
) { // yes, active thread waiting for another object
942 // this may be a candidate for rejection if the required
943 // flag is not set, should we detect a deadlock later on
944 if( false == waiting
->required
)
947 // find the thread that is holding this other object, that
948 // is blocking the active thread from proceeding (fun :-)
950 queue_iterate( &gArbitrationLockQueueActive
,
951 active
, // (reuse active queue element)
952 ArbitrationLockQueueElement
*,
955 if( active
->service
== waiting
->service
) {
961 // someone must be holding it or it wouldn't be waiting
964 if( active
->thread
== element
->thread
) {
966 // doh, it's waiting for the thread that originated
967 // this whole lock (ie. current thread) -> deadlock
968 if( false == element
->required
) { // willing to fail?
970 // the originating thread doesn't have the required
971 // flag, so it can fail
972 success
= false; // (fail originating lock request)
973 break; // (out of while)
975 } else { // originating thread is not willing to fail
977 // see if we came across a waiting thread that did
978 // not have the 'required' flag set: we'll fail it
981 // we do have a willing victim, fail it's lock
982 victim
->aborted
= true;
984 // take the victim off the waiting queue
985 queue_remove( &gArbitrationLockQueueWaiting
,
987 ArbitrationLockQueueElement
*,
991 IOLockWakeup( gArbitrationLockQueueLock
,
993 /* one thread */ true );
995 // allow this thread to proceed (ie. wait)
996 success
= true; // (put request on wait queue)
997 break; // (out of while)
1000 // all the waiting threads we came across in
1001 // finding this loop had the 'required' flag
1002 // set, so we've got a deadlock we can't avoid
1003 panic("I/O Kit: Unrecoverable deadlock.");
1007 // repeat while loop, redefining active thread to be the
1008 // thread holding "this other object" (see above), and
1009 // looking for threads waiting on it; note the active
1010 // variable points to "this other object" already... so
1011 // there nothing to do in this else clause.
1013 } else { // no, active thread is not waiting for another object
1015 success
= true; // (put request on wait queue)
1016 break; // (out of while)
1020 if( success
) { // put the request on the waiting queue?
1021 kern_return_t wait_result
;
1023 // place this thread on the waiting queue and put it to sleep;
1024 // we place it at the tail of the queue...
1025 queue_enter( &gArbitrationLockQueueWaiting
,
1027 ArbitrationLockQueueElement
*,
1030 // declare that this thread will wait for a given event
1031 restart_sleep
: wait_result
= assert_wait( element
,
1032 element
->required
? THREAD_UNINT
1033 : THREAD_INTERRUPTIBLE
);
1035 // unlock global access
1036 IOUnlock( gArbitrationLockQueueLock
);
1038 // put thread to sleep, waiting for our event to fire...
1039 if (wait_result
== THREAD_WAITING
)
1040 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1043 // ...and we've been woken up; we might be in one of two states:
1044 // (a) we've been aborted and our queue element is not on
1045 // any of the three queues, but is floating around
1046 // (b) we're allowed to proceed with the lock and we have
1047 // already been moved from the waiting queue to the
1049 // ...plus a 3rd state, should the thread have been interrupted:
1050 // (c) we're still on the waiting queue
1052 // determine whether we were interrupted out of our sleep
1053 if( THREAD_INTERRUPTED
== wait_result
) {
1055 // re-lock global access
1056 IOTakeLock( gArbitrationLockQueueLock
);
1058 // determine whether we're still on the waiting queue
1060 queue_iterate( &gArbitrationLockQueueWaiting
,
1061 waiting
, // (reuse waiting queue element)
1062 ArbitrationLockQueueElement
*,
1065 if( waiting
== element
) {
1071 if( found
) { // yes, we're still on the waiting queue
1073 // determine whether we're willing to fail
1074 if( false == element
->required
) {
1076 // mark us as aborted
1077 element
->aborted
= true;
1079 // take us off the waiting queue
1080 queue_remove( &gArbitrationLockQueueWaiting
,
1082 ArbitrationLockQueueElement
*,
1084 } else { // we are not willing to fail
1086 // ignore interruption, go back to sleep
1091 // unlock global access
1092 IOUnlock( gArbitrationLockQueueLock
);
1094 // proceed as though this were a normal wake up
1095 wait_result
= THREAD_AWAKENED
;
1098 assert( THREAD_AWAKENED
== wait_result
);
1100 // determine whether we've been aborted while we were asleep
1101 if( element
->aborted
) {
1102 assert( false == element
->required
);
1104 // re-lock global access
1105 IOTakeLock( gArbitrationLockQueueLock
);
1107 action
= kPutOnFreeQueue
;
1109 } else { // we weren't aborted, so we must be ready to go :-)
1111 // we've already been moved from waiting to active queue
1115 } else { // the lock request is to be failed
1117 // return unused queue element to queue
1118 action
= kPutOnFreeQueue
;
1120 } else { // it is the same thread, recursive access is allowed
1122 // add one level of recursion
1125 // return unused queue element to queue
1126 action
= kPutOnFreeQueue
;
1129 } else { // this object is not already locked, so let this thread through
1130 action
= kPutOnActiveQueue
;
1134 // put the new element on a queue
1135 if( kPutOnActiveQueue
== action
) {
1136 queue_enter( &gArbitrationLockQueueActive
,
1138 ArbitrationLockQueueElement
*,
1140 } else if( kPutOnFreeQueue
== action
) {
1141 queue_enter( &gArbitrationLockQueueFree
,
1143 ArbitrationLockQueueElement
*,
1146 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1149 // unlock global access
1150 IOUnlock( gArbitrationLockQueueLock
);
1155 void IOService::unlockForArbitration( void )
1158 ArbitrationLockQueueElement
* element
;
1160 // lock global access
1161 IOTakeLock( gArbitrationLockQueueLock
);
1163 // find the lock element for this object (ie. on active queue)
1165 queue_iterate( &gArbitrationLockQueueActive
,
1167 ArbitrationLockQueueElement
*,
1170 if( element
->service
== this ) {
1178 // determine whether the lock has been taken recursively
1179 if( element
->count
> 1 ) {
1180 // undo one level of recursion
1185 // remove it from the active queue
1186 queue_remove( &gArbitrationLockQueueActive
,
1188 ArbitrationLockQueueElement
*,
1191 // put it on the free queue
1192 queue_enter( &gArbitrationLockQueueFree
,
1194 ArbitrationLockQueueElement
*,
1197 // determine whether a thread is waiting for object (head to tail scan)
1199 queue_iterate( &gArbitrationLockQueueWaiting
,
1201 ArbitrationLockQueueElement
*,
1204 if( element
->service
== this ) {
1210 if ( found
) { // we found an interested thread on waiting queue
1212 // remove it from the waiting queue
1213 queue_remove( &gArbitrationLockQueueWaiting
,
1215 ArbitrationLockQueueElement
*,
1218 // put it on the active queue
1219 queue_enter( &gArbitrationLockQueueActive
,
1221 ArbitrationLockQueueElement
*,
1224 // wake the waiting thread
1225 IOLockWakeup( gArbitrationLockQueueLock
,
1227 /* one thread */ true );
1231 // unlock global access
1232 IOUnlock( gArbitrationLockQueueLock
);
1235 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1238 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1239 context
, gIOServicePlane
);
1242 void IOService::applyToClients( IOServiceApplierFunction applier
,
1245 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1246 context
, gIOServicePlane
);
1255 // send a message to a client or interested party of this service
1256 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1257 void * argument
, vm_size_t argSize
)
1260 IOService
* service
;
1261 _IOServiceInterestNotifier
* notify
;
1263 if( (service
= OSDynamicCast( IOService
, client
)))
1264 ret
= service
->message( type
, this, argument
);
1266 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1268 _IOServiceNotifierInvocation invocation
;
1271 invocation
.thread
= current_thread();
1274 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1277 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1278 _IOServiceNotifierInvocation
*, link
);
1284 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1285 type
, this, argument
, argSize
);
1288 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1289 _IOServiceNotifierInvocation
*, link
);
1290 if( kIOServiceNotifyWaiter
& notify
->state
) {
1291 notify
->state
&= ~kIOServiceNotifyWaiter
;
1292 WAKEUPNOTIFY( notify
);
1297 ret
= kIOReturnSuccess
;
1300 ret
= kIOReturnBadArgument
;
1306 applyToInterestNotifiers(const IORegistryEntry
*target
,
1307 const OSSymbol
* typeOfInterest
,
1308 OSObjectApplierFunction applier
,
1311 OSArray
* copyArray
= 0;
1315 IOCommand
*notifyList
=
1316 OSDynamicCast( IOCommand
, target
->getProperty( typeOfInterest
));
1319 copyArray
= OSArray::withCapacity(1);
1321 // iterate over queue, entry is set to each element in the list
1322 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1323 _IOServiceInterestNotifier
* notify
;
1325 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1326 copyArray
->setObject(notify
);
1335 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1336 (*applier
)(next
, context
);
1337 copyArray
->release();
1341 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1342 OSObjectApplierFunction applier
,
1345 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1346 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1349 struct MessageClientsContext
{
1350 IOService
* service
;
1357 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1360 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1362 ret
= context
->service
->messageClient( context
->type
,
1363 object
, context
->argument
, context
->argSize
);
1364 if( kIOReturnSuccess
!= ret
)
1368 // send a message to all clients
1369 IOReturn
IOService::messageClients( UInt32 type
,
1370 void * argument
, vm_size_t argSize
)
1372 MessageClientsContext context
;
1374 context
.service
= this;
1375 context
.type
= type
;
1376 context
.argument
= argument
;
1377 context
.argSize
= argSize
;
1378 context
.ret
= kIOReturnSuccess
;
1380 applyToInterested( gIOGeneralInterest
,
1381 &messageClientsApplier
, &context
);
1383 return( context
.ret
);
1386 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1387 IOOptionBits response
)
1389 return( kIOReturnUnsupported
);
1392 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1393 IOServiceInterestHandler handler
, void * target
, void * ref
)
1395 _IOServiceInterestNotifier
* notify
= 0;
1397 if( (typeOfInterest
!= gIOGeneralInterest
)
1398 && (typeOfInterest
!= gIOBusyInterest
)
1399 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1400 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1403 lockForArbitration();
1404 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1406 notify
= new _IOServiceInterestNotifier
;
1407 if( notify
&& !notify
->init()) {
1413 notify
->handler
= handler
;
1414 notify
->target
= target
;
1416 notify
->state
= kIOServiceNotifyEnable
;
1417 queue_init( ¬ify
->handlerInvocations
);
1423 // Get the head of the notifier linked list
1424 IOCommand
*notifyList
= (IOCommand
*) getProperty( typeOfInterest
);
1425 if (!notifyList
|| !OSDynamicCast(IOCommand
, notifyList
)) {
1426 notifyList
= OSTypeAlloc(IOCommand
);
1429 setProperty( typeOfInterest
, notifyList
);
1430 notifyList
->release();
1435 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1436 notify
->retain(); // ref'ed while in list
1442 unlockForArbitration();
1447 static void cleanInterestList( OSObject
* head
)
1449 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1454 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1455 queue_next(entry
) = queue_prev(entry
) = 0;
1457 _IOServiceInterestNotifier
* notify
;
1459 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1465 void IOService::unregisterAllInterest( void )
1467 cleanInterestList( getProperty( gIOGeneralInterest
));
1468 cleanInterestList( getProperty( gIOBusyInterest
));
1469 cleanInterestList( getProperty( gIOAppPowerStateInterest
));
1470 cleanInterestList( getProperty( gIOPriorityPowerStateInterest
));
1474 * _IOServiceInterestNotifier
1477 // wait for all threads, other than the current one,
1478 // to exit the handler
1480 void _IOServiceInterestNotifier::wait()
1482 _IOServiceNotifierInvocation
* next
;
1487 queue_iterate( &handlerInvocations
, next
,
1488 _IOServiceNotifierInvocation
*, link
) {
1489 if( next
->thread
!= current_thread() ) {
1495 state
|= kIOServiceNotifyWaiter
;
1502 void _IOServiceInterestNotifier::free()
1504 assert( queue_empty( &handlerInvocations
));
1508 void _IOServiceInterestNotifier::remove()
1512 if( queue_next( &chain
)) {
1513 remqueue( 0, &chain
);
1514 queue_next( &chain
) = queue_prev( &chain
) = 0;
1518 state
&= ~kIOServiceNotifyEnable
;
1527 bool _IOServiceInterestNotifier::disable()
1533 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1534 state
&= ~kIOServiceNotifyEnable
;
1543 void _IOServiceInterestNotifier::enable( bool was
)
1547 state
|= kIOServiceNotifyEnable
;
1549 state
&= ~kIOServiceNotifyEnable
;
1553 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1559 #define tailQ(o) setObject(o)
1560 #define headQ(o) setObject(0, o)
1561 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); }
1563 inline void _workLoopAction( IOWorkLoop::Action action
,
1564 IOService
* service
,
1565 void * p0
= 0, void * p1
= 0,
1566 void * p2
= 0, void * p3
= 0 )
1570 if( (wl
= service
->getWorkLoop())) {
1572 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1575 (*action
)( service
, p0
, p1
, p2
, p3
);
1578 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1582 // if its our only provider
1583 ok
= isParent( provider
, gIOServicePlane
, true);
1587 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1588 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1595 bool IOService::terminatePhase1( IOOptionBits options
)
1600 OSArray
* makeInactive
;
1603 bool startPhase2
= false;
1605 TLOG("%s::terminatePhase1(%08lx)\n", getName(), options
);
1608 if( options
& kIOServiceRecursing
) {
1609 __state
[1] |= kIOServiceRecursing
;
1614 makeInactive
= OSArray::withCapacity( 16 );
1623 didInactive
= victim
->lockForArbitration( true );
1625 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1627 victim
->__state
[0] |= kIOServiceInactiveState
;
1628 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1629 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1630 victim
->_adjustBusy( 1 );
1632 victim
->unlockForArbitration();
1635 startPhase2
= didInactive
;
1638 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1639 IOUserClient::destroyUserReferences( victim
);
1641 iter
= victim
->getClientIterator();
1643 while( (client
= (IOService
*) iter
->getNextObject())) {
1644 TLOG("%s::requestTerminate(%s, %08lx)\n",
1645 client
->getName(), victim
->getName(), options
);
1646 ok
= client
->requestTerminate( victim
, options
);
1647 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1648 client
->getName(), victim
->getName(), ok
);
1650 makeInactive
->setObject( client
);
1656 victim
= (IOService
*) makeInactive
->getObject(0);
1659 makeInactive
->removeObject(0);
1663 makeInactive
->release();
1666 scheduleTerminatePhase2( options
);
1671 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
1673 AbsoluteTime deadline
;
1674 int waitResult
= THREAD_AWAKENED
;
1675 bool wait
, haveDeadline
= false;
1677 options
|= kIOServiceRequired
;
1681 IOLockLock( gJobsLock
);
1683 if( (options
& kIOServiceSynchronous
)
1684 && (current_thread() != gIOTerminateThread
)) {
1687 wait
= (gIOTerminateThread
!= 0);
1689 // wait to become the terminate thread
1690 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
1694 gIOTerminateThread
= current_thread();
1695 gIOTerminatePhase2List
->setObject( this );
1699 while( gIOTerminateWork
)
1700 terminateWorker( options
);
1701 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1703 // wait for the victim to go non-busy
1704 if( !haveDeadline
) {
1705 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1706 haveDeadline
= true;
1708 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
1709 deadline
, THREAD_UNINT
);
1710 if( waitResult
== THREAD_TIMED_OUT
) {
1711 TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName());
1714 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
1716 gIOTerminateThread
= 0;
1717 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1720 // ! kIOServiceSynchronous
1722 gIOTerminatePhase2List
->setObject( this );
1723 if( 0 == gIOTerminateWork
++) {
1724 if( !gIOTerminateThread
)
1725 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) options
);
1727 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1731 IOLockUnlock( gJobsLock
);
1736 void IOService::terminateThread( void * arg
)
1738 IOLockLock( gJobsLock
);
1740 while (gIOTerminateWork
)
1741 terminateWorker( (IOOptionBits
) arg
);
1743 gIOTerminateThread
= 0;
1744 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1746 IOLockUnlock( gJobsLock
);
1749 void IOService::scheduleStop( IOService
* provider
)
1751 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1753 IOLockLock( gJobsLock
);
1754 gIOStopList
->tailQ( this );
1755 gIOStopProviderList
->tailQ( provider
);
1757 if( 0 == gIOTerminateWork
++) {
1758 if( !gIOTerminateThread
)
1759 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1761 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1764 IOLockUnlock( gJobsLock
);
1767 void IOService::scheduleFinalize( void )
1769 TLOG("%s::scheduleFinalize\n", getName());
1771 IOLockLock( gJobsLock
);
1772 gIOFinalizeList
->tailQ( this );
1774 if( 0 == gIOTerminateWork
++) {
1775 if( !gIOTerminateThread
)
1776 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1778 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1781 IOLockUnlock( gJobsLock
);
1784 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1789 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1791 if( false == *defer
) {
1793 if( lockForArbitration( true )) {
1794 if( false == provider
->handleIsOpen( this ))
1795 scheduleStop( provider
);
1798 message( kIOMessageServiceIsRequestingClose
, provider
, (void *) options
);
1799 if( false == provider
->handleIsOpen( this ))
1800 scheduleStop( provider
);
1803 unlockForArbitration();
1810 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
1811 OSArray
* doPhase2List
)
1817 iter
= victim
->getClientIterator();
1819 while( (client
= (IOService
*) iter
->getNextObject())) {
1820 TLOG("%s::willTerminate(%s, %08lx)\n",
1821 client
->getName(), victim
->getName(), options
);
1822 ok
= client
->willTerminate( victim
, options
);
1823 doPhase2List
->tailQ( client
);
1829 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
)
1835 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *) options
);
1837 iter
= victim
->getClientIterator();
1839 while( (client
= (IOService
*) iter
->getNextObject())) {
1840 TLOG("%s::didTerminate(%s, %08lx)\n",
1841 client
->getName(), victim
->getName(), options
);
1842 client
->didTerminate( victim
, options
, &defer
);
1843 TLOG("%s::didTerminate(%s, defer %d)\n",
1844 client
->getName(), victim
->getName(), defer
);
1850 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
)
1852 TLOG("%s::finalize(%08lx)\n", victim
->getName(), options
);
1853 victim
->finalize( options
);
1856 void IOService::actionStop( IOService
* provider
, IOService
* client
)
1858 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
1859 client
->stop( provider
);
1860 if( provider
->isOpen( client
))
1861 provider
->close( client
);
1862 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
1863 client
->detach( provider
);
1866 void IOService::terminateWorker( IOOptionBits options
)
1868 OSArray
* doPhase2List
;
1869 OSArray
* didPhase2List
;
1874 IOService
* provider
;
1880 options
|= kIOServiceRequired
;
1882 doPhase2List
= OSArray::withCapacity( 16 );
1883 didPhase2List
= OSArray::withCapacity( 16 );
1884 freeList
= OSSet::withCapacity( 16 );
1885 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
1889 workDone
= gIOTerminateWork
;
1891 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
1894 gIOTerminatePhase2List
->removeObject(0);
1895 IOLockUnlock( gJobsLock
);
1899 doPhase2
= victim
->lockForArbitration( true );
1901 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
1903 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
1904 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
1906 victim
->__state
[1] |= kIOServiceTermPhase2State
;
1908 victim
->unlockForArbitration();
1911 if( 0 == victim
->getClient()) {
1912 // no clients - will go to finalize
1913 IOLockLock( gJobsLock
);
1914 gIOFinalizeList
->tailQ( victim
);
1915 IOLockUnlock( gJobsLock
);
1917 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
1918 victim
, (void *) options
, (void *) doPhase2List
);
1920 didPhase2List
->headQ( victim
);
1923 victim
= (IOService
*) doPhase2List
->getObject(0);
1926 doPhase2List
->removeObject(0);
1930 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
1932 if( victim
->lockForArbitration( true )) {
1933 victim
->__state
[1] |= kIOServiceTermPhase3State
;
1934 victim
->unlockForArbitration();
1936 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
1937 victim
, (void *) options
);
1938 didPhase2List
->removeObject(0);
1940 IOLockLock( gJobsLock
);
1947 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
1949 IOLockUnlock( gJobsLock
);
1950 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
1951 victim
, (void *) options
);
1952 IOLockLock( gJobsLock
);
1954 freeList
->setObject( victim
);
1955 // safe if finalize list is append only
1956 gIOFinalizeList
->removeObject(0);
1960 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
1962 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
1965 if( !provider
->isChild( client
, gIOServicePlane
)) {
1966 // may be multiply queued - nop it
1967 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
1969 // not ready for stop if it has clients, skip it
1970 if( (client
->__state
[1] & kIOServiceTermPhase3State
) && client
->getClient()) {
1971 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
1976 IOLockUnlock( gJobsLock
);
1977 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
1978 provider
, (void *) client
);
1979 IOLockLock( gJobsLock
);
1980 // check the finalize list now
1984 freeList
->setObject( client
);
1985 freeList
->setObject( provider
);
1987 // safe if stop list is append only
1988 gIOStopList
->removeObject( idx
);
1989 gIOStopProviderList
->removeObject( idx
);
1993 } while( doPhase3
);
1995 gIOTerminateWork
-= workDone
;
1996 moreToDo
= (gIOTerminateWork
!= 0);
1999 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
2002 } while( moreToDo
);
2004 IOLockUnlock( gJobsLock
);
2006 freeList
->release();
2007 doPhase2List
->release();
2008 didPhase2List
->release();
2010 IOLockLock( gJobsLock
);
2013 bool IOService::finalize( IOOptionBits options
)
2016 IOService
* provider
;
2018 iter
= getProviderIterator();
2022 while( (provider
= (IOService
*) iter
->getNextObject())) {
2025 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
2026 /* we come down here on programmatic terminate */
2028 if( provider
->isOpen( this ))
2029 provider
->close( this );
2033 if( provider
->lockForArbitration( true )) {
2034 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2035 scheduleStop( provider
);
2036 provider
->unlockForArbitration();
2053 void IOService::doServiceTerminate( IOOptionBits options
)
2057 // a method in case someone needs to override it
2058 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2062 if( client
->isParent( this, gIOServicePlane
, true))
2063 // we are the clients only provider
2064 ok
= client
->terminate( options
);
2071 bool IOService::terminate( IOOptionBits options
)
2073 options
|= kIOServiceTerminate
;
2075 return( terminatePhase1( options
));
2078 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2084 struct ServiceOpenMessageContext
2086 IOService
* service
;
2088 IOService
* excludeClient
;
2089 IOOptionBits options
;
2092 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2094 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2096 if( object
!= context
->excludeClient
)
2097 context
->service
->messageClient( context
->type
, object
, (void *) context
->options
);
2100 bool IOService::open( IOService
* forClient
,
2101 IOOptionBits options
,
2105 ServiceOpenMessageContext context
;
2107 context
.service
= this;
2108 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2109 context
.excludeClient
= forClient
;
2110 context
.options
= options
;
2112 applyToInterested( gIOGeneralInterest
,
2113 &serviceOpenMessageApplier
, &context
);
2115 if( false == lockForArbitration(false) )
2118 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2120 ok
= handleOpen( forClient
, options
, arg
);
2122 unlockForArbitration();
2127 void IOService::close( IOService
* forClient
,
2128 IOOptionBits options
)
2133 lockForArbitration();
2135 wasClosed
= handleIsOpen( forClient
);
2137 handleClose( forClient
, options
);
2138 last
= (__state
[1] & kIOServiceTermPhase3State
);
2141 unlockForArbitration();
2144 forClient
->scheduleStop( this );
2146 else if( wasClosed
) {
2148 ServiceOpenMessageContext context
;
2150 context
.service
= this;
2151 context
.type
= kIOMessageServiceWasClosed
;
2152 context
.excludeClient
= forClient
;
2153 context
.options
= options
;
2155 applyToInterested( gIOGeneralInterest
,
2156 &serviceOpenMessageApplier
, &context
);
2160 bool IOService::isOpen( const IOService
* forClient
) const
2162 IOService
* self
= (IOService
*) this;
2165 self
->lockForArbitration();
2167 ok
= handleIsOpen( forClient
);
2169 self
->unlockForArbitration();
2174 bool IOService::handleOpen( IOService
* forClient
,
2175 IOOptionBits options
,
2180 ok
= (0 == __owner
);
2182 __owner
= forClient
;
2184 else if( options
& kIOServiceSeize
) {
2185 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2186 __owner
, (void *) options
));
2187 if( ok
&& (0 == __owner
))
2188 __owner
= forClient
;
2195 void IOService::handleClose( IOService
* forClient
,
2196 IOOptionBits options
)
2198 if( __owner
== forClient
)
2202 bool IOService::handleIsOpen( const IOService
* forClient
) const
2205 return( __owner
== forClient
);
2207 return( __owner
!= forClient
);
2211 * Probing & starting
2213 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2215 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2216 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2224 val1
= obj1
->priority
;
2227 val2
= obj2
->priority
;
2229 return ( val1
- val2
);
2232 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2234 OSDictionary
* dict
;
2235 IOService
* service
;
2236 _IOServiceNotifier
* notify
;
2237 OSSymbol
* key
= (OSSymbol
*) ref
;
2240 if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2241 return( notify
->priority
);
2243 else if( (service
= OSDynamicCast( IOService
, entry
)))
2244 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2245 else if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2246 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2253 return( (SInt32
) offset
->unsigned32BitValue());
2255 return( kIODefaultProbeScore
);
2258 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2260 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2261 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2269 val1
= IOServiceObjectOrder( obj1
, ref
);
2272 val2
= IOServiceObjectOrder( obj2
, ref
);
2274 return ( val1
- val2
);
2277 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2279 IOService
* service
= 0;
2281 const OSSymbol
* nextCat
;
2283 iter
= getClientIterator();
2285 while( (service
= (IOService
*) iter
->getNextObject())) {
2286 if( kIOServiceInactiveState
& service
->__state
[0])
2288 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2289 service
->getProperty( gIOMatchCategoryKey
));
2290 if( category
== nextCat
)
2298 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2300 _IOServiceNotifierInvocation invocation
;
2304 invocation
.thread
= current_thread();
2307 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2310 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2311 _IOServiceNotifierInvocation
*, link
);
2317 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
, this );
2320 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2321 _IOServiceNotifierInvocation
*, link
);
2322 if( kIOServiceNotifyWaiter
& notify
->state
) {
2323 notify
->state
&= ~kIOServiceNotifyWaiter
;
2324 WAKEUPNOTIFY( notify
);
2333 * Alloc and probe matching classes,
2334 * called on the provider instance
2337 void IOService::probeCandidates( OSOrderedSet
* matches
)
2339 OSDictionary
* match
= 0;
2342 IOService
* newInst
;
2343 OSDictionary
* props
;
2346 OSOrderedSet
* familyMatches
= 0;
2347 OSOrderedSet
* startList
;
2348 OSDictionary
* startDict
= 0;
2349 const OSSymbol
* category
;
2351 _IOServiceNotifier
* notify
;
2352 OSObject
* nextMatch
= 0;
2354 bool needReloc
= false;
2360 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2362 nextMatch
->retain();
2363 matches
->removeObject(nextMatch
);
2365 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2367 lockForArbitration();
2368 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2369 invokeNotifer( notify
);
2370 unlockForArbitration();
2371 nextMatch
->release();
2375 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2376 nextMatch
->release();
2383 debugFlags
= getDebugFlags( match
);
2387 category
= OSDynamicCast( OSSymbol
,
2388 match
->getObject( gIOMatchCategoryKey
));
2390 category
= gIODefaultMatchCategoryKey
;
2392 if( getClientWithCategory( category
)) {
2394 if( debugFlags
& kIOLogMatch
)
2395 LOG("%s: match category %s exists\n", getName(),
2396 category
->getCStringNoCopy());
2398 nextMatch
->release();
2403 // create a copy now in case its modified during matching
2404 props
= OSDictionary::withDictionary( match
, match
->getCount());
2407 props
->setCapacityIncrement(1);
2409 // check the nub matches
2410 if( false == passiveMatch( props
, true ))
2413 // Check to see if driver reloc has been loaded.
2414 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2417 if( debugFlags
& kIOLogCatalogue
)
2418 LOG("%s: stalling for module\n", getName());
2420 // If reloc hasn't been loaded, exit;
2421 // reprobing will occur after reloc has been loaded.
2425 // reorder on family matchPropertyTable score.
2426 if( 0 == familyMatches
)
2427 familyMatches
= OSOrderedSet::withCapacity( 1,
2428 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2430 familyMatches
->setObject( props
);
2435 nextMatch
->release();
2444 if( familyMatches
) {
2447 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2450 familyMatches
->removeObject( props
);
2455 debugFlags
= getDebugFlags( props
);
2458 symbol
= OSDynamicCast( OSSymbol
,
2459 props
->getObject( gIOClassKey
));
2463 // alloc the driver instance
2464 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2467 IOLog("Couldn't alloc class \"%s\"\n",
2468 symbol
->getCStringNoCopy());
2472 // init driver instance
2473 if( !(inst
->init( props
))) {
2475 if( debugFlags
& kIOLogStart
)
2476 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2480 if( __state
[1] & kIOServiceSynchronousState
)
2481 inst
->__state
[1] |= kIOServiceSynchronousState
;
2483 // give the driver the default match category if not specified
2484 category
= OSDynamicCast( OSSymbol
,
2485 props
->getObject( gIOMatchCategoryKey
));
2487 category
= gIODefaultMatchCategoryKey
;
2488 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2490 // attach driver instance
2491 if( !(inst
->attach( this )))
2494 // pass in score from property table
2495 score
= familyMatches
->orderObject( props
);
2497 // & probe the new driver instance
2499 if( debugFlags
& kIOLogProbe
)
2500 LOG("%s::probe(%s)\n",
2501 inst
->getMetaClass()->getClassName(), getName());
2504 newInst
= inst
->probe( this, &score
);
2505 inst
->detach( this );
2508 if( debugFlags
& kIOLogProbe
)
2509 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2515 newPri
= OSNumber::withNumber( score
, 32 );
2517 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2521 // add to start list for the match category
2523 startDict
= OSDictionary::withCapacity( 1 );
2524 assert( startDict
);
2525 startList
= (OSOrderedSet
*)
2526 startDict
->getObject( category
);
2527 if( 0 == startList
) {
2528 startList
= OSOrderedSet::withCapacity( 1,
2529 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2530 if( startDict
&& startList
) {
2531 startDict
->setObject( category
, startList
);
2532 startList
->release();
2535 assert( startList
);
2537 startList
->setObject( newInst
);
2545 familyMatches
->release();
2549 // start the best (until success) of each category
2551 iter
= OSCollectionIterator::withCollection( startDict
);
2553 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2555 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2556 assert( startList
);
2561 while( true // (!started)
2562 && (inst
= (IOService
*)startList
->getFirstObject())) {
2565 startList
->removeObject(inst
);
2568 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2570 if( debugFlags
& kIOLogStart
) {
2572 LOG( "match category exists, skipping " );
2573 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2574 getName(), inst
->getRetainCount());
2577 if( false == started
)
2578 started
= startCandidate( inst
);
2580 if( (debugFlags
& kIOLogStart
) && (false == started
))
2581 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2582 inst
->getRetainCount());
2591 // adjust the busy count by -1 if matching is stalled for a module,
2592 // or +1 if a previously stalled matching is complete.
2593 lockForArbitration();
2596 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2598 __state
[1] |= kIOServiceModuleStallState
;
2600 } else if( __state
[1] & kIOServiceModuleStallState
) {
2601 __state
[1] &= ~kIOServiceModuleStallState
;
2605 _adjustBusy( adjBusy
);
2606 unlockForArbitration();
2609 startDict
->release();
2613 * Start a previously attached & probed instance,
2614 * called on exporting object instance
2617 bool IOService::startCandidate( IOService
* service
)
2621 ok
= service
->attach( this );
2625 if (this != gIOResources
)
2627 // stall for any nub resources
2629 // stall for any driver resources
2630 service
->checkResources();
2633 AbsoluteTime startTime
;
2634 AbsoluteTime endTime
;
2637 if (kIOLogStart
& gIOKitDebug
)
2638 clock_get_uptime(&startTime
);
2640 ok
= service
->start(this);
2642 if (kIOLogStart
& gIOKitDebug
)
2644 clock_get_uptime(&endTime
);
2646 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2648 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2649 absolutetime_to_nanoseconds(endTime
, &nano
);
2650 if (nano
> 500000000ULL)
2651 IOLog("%s::start took %ld ms\n", service
->getName(), (UInt32
)(nano
/ 1000000ULL));
2655 service
->detach( this );
2660 IOService
* IOService::resources( void )
2662 return( gIOResources
);
2665 void IOService::publishResource( const char * key
, OSObject
* value
)
2667 const OSSymbol
* sym
;
2669 if( (sym
= OSSymbol::withCString( key
))) {
2670 publishResource( sym
, value
);
2675 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
2678 value
= (OSObject
*) gIOServiceKey
;
2680 gIOResources
->setProperty( key
, value
);
2682 if( IORecursiveLockHaveLock( gNotificationLock
))
2685 gIOResourceGenerationCount
++;
2686 gIOResources
->registerService();
2689 bool IOService::addNeededResource( const char * key
)
2691 OSObject
* resourcesProp
;
2696 resourcesProp
= getProperty( gIOResourceMatchKey
);
2698 newKey
= OSString::withCString( key
);
2699 if( (0 == resourcesProp
) || (0 == newKey
))
2702 set
= OSDynamicCast( OSSet
, resourcesProp
);
2704 set
= OSSet::withCapacity( 1 );
2706 set
->setObject( resourcesProp
);
2711 set
->setObject( newKey
);
2713 ret
= setProperty( gIOResourceMatchKey
, set
);
2719 bool IOService::checkResource( OSObject
* matching
)
2722 OSDictionary
* table
;
2724 if( (str
= OSDynamicCast( OSString
, matching
))) {
2725 if( gIOResources
->getProperty( str
))
2730 table
= resourceMatching( str
);
2731 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
2734 IOLog("%s: Can't match using: %s\n", getName(),
2735 matching
->getMetaClass()->getClassName());
2736 /* false would stall forever */
2740 if( gIOKitDebug
& kIOLogConfig
)
2741 LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName());
2743 waitForService( table
);
2745 if( gIOKitDebug
& kIOLogConfig
)
2746 LOG("config(%x): waking\n", (int) IOThreadSelf() );
2751 bool IOService::checkResources( void )
2753 OSObject
* resourcesProp
;
2758 resourcesProp
= getProperty( gIOResourceMatchKey
);
2759 if( 0 == resourcesProp
)
2762 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
2764 iter
= OSCollectionIterator::withCollection( set
);
2766 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
2767 ok
= checkResource( resourcesProp
);
2772 ok
= checkResource( resourcesProp
);
2778 void _IOConfigThread::configThread( void )
2780 _IOConfigThread
* inst
;
2783 if( !(inst
= new _IOConfigThread
))
2787 if( !(IOCreateThread((IOThreadFunc
) &_IOConfigThread::main
, inst
)))
2800 void _IOConfigThread::free( void )
2805 void IOService::doServiceMatch( IOOptionBits options
)
2807 _IOServiceNotifier
* notify
;
2809 OSOrderedSet
* matches
;
2810 SInt32 catalogGeneration
;
2811 bool keepGuessing
= true;
2812 bool reRegistered
= true;
2814 // job->nub->deliverNotification( gIOPublishNotification,
2815 // kIOServiceRegisteredState, 0xffffffff );
2817 while( keepGuessing
) {
2819 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
2820 // the matches list should always be created by findDrivers()
2823 lockForArbitration();
2824 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
2825 deliverNotification( gIOFirstPublishNotification
,
2826 kIOServiceFirstPublishState
, 0xffffffff );
2828 __state
[1] &= ~kIOServiceNeedConfigState
;
2829 __state
[1] |= kIOServiceConfigState
;
2830 __state
[0] |= kIOServiceRegisteredState
;
2832 if( reRegistered
&& (0 == (__state
[0] & kIOServiceInactiveState
))) {
2834 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
2835 gNotifications
->getObject( gIOPublishNotification
) );
2837 while((notify
= (_IOServiceNotifier
*)
2838 iter
->getNextObject())) {
2840 if( passiveMatch( notify
->matching
)
2841 && (kIOServiceNotifyEnable
& notify
->state
))
2842 matches
->setObject( notify
);
2849 unlockForArbitration();
2851 if( matches
->getCount() && (kIOReturnSuccess
== getResources()))
2852 probeCandidates( matches
);
2857 lockForArbitration();
2858 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
2860 (reRegistered
|| (catalogGeneration
!=
2861 gIOCatalogue
->getGenerationCount()))
2862 && (0 == (__state
[0] & kIOServiceInactiveState
));
2865 unlockForArbitration();
2868 if( (0 == (__state
[0] & kIOServiceInactiveState
))
2869 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
2870 deliverNotification( gIOMatchedNotification
,
2871 kIOServiceMatchedState
, 0xffffffff );
2872 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
2873 deliverNotification( gIOFirstMatchNotification
,
2874 kIOServiceFirstMatchState
, 0xffffffff );
2877 __state
[1] &= ~kIOServiceConfigState
;
2878 if( __state
[0] & kIOServiceInactiveState
)
2879 scheduleTerminatePhase2();
2882 unlockForArbitration();
2885 UInt32
IOService::_adjustBusy( SInt32 delta
)
2890 bool wasQuiet
, nowQuiet
, needWake
;
2893 result
= __state
[1] & kIOServiceBusyStateMask
;
2897 next
->lockForArbitration();
2898 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
2899 assert( count
< kIOServiceBusyMax
);
2900 wasQuiet
= (0 == count
);
2901 assert( (!wasQuiet
) || (delta
> 0));
2902 next
->__state
[1] += delta
;
2903 nowQuiet
= (0 == (next
->__state
[1] & kIOServiceBusyStateMask
));
2904 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
2907 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
2908 IOLockLock( gIOServiceBusyLock
);
2909 thread_wakeup( (event_t
) next
);
2910 IOLockUnlock( gIOServiceBusyLock
);
2913 next
->unlockForArbitration();
2915 if( (wasQuiet
|| nowQuiet
) ) {
2916 MessageClientsContext context
;
2918 context
.service
= next
;
2919 context
.type
= kIOMessageServiceBusyStateChange
;
2920 context
.argument
= (void *) wasQuiet
; // busy now
2921 context
.argSize
= 0;
2923 applyToInterestNotifiers( next
, gIOBusyInterest
,
2924 &messageClientsApplier
, &context
);
2926 if( nowQuiet
&& (next
== gIOServiceRoot
))
2927 OSMetaClass::considerUnloads();
2930 delta
= nowQuiet
? -1 : +1;
2932 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
2937 void IOService::adjustBusy( SInt32 delta
)
2939 lockForArbitration();
2940 _adjustBusy( delta
);
2941 unlockForArbitration();
2944 UInt32
IOService::getBusyState( void )
2946 return( __state
[1] & kIOServiceBusyStateMask
);
2949 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
2950 mach_timespec_t
* timeout
)
2953 int waitResult
= THREAD_AWAKENED
;
2954 bool computeDeadline
= true;
2955 AbsoluteTime abstime
;
2958 lockForArbitration();
2959 IOLockLock( gIOServiceBusyLock
);
2960 wait
= (value
!= (__state
[1] & mask
));
2962 __state
[1] |= kIOServiceBusyWaiterState
;
2963 unlockForArbitration();
2965 if( computeDeadline
) {
2966 AbsoluteTime nsinterval
;
2967 clock_interval_to_absolutetime_interval(
2968 timeout
->tv_sec
, kSecondScale
, &abstime
);
2969 clock_interval_to_absolutetime_interval(
2970 timeout
->tv_nsec
, kNanosecondScale
, &nsinterval
);
2971 ADD_ABSOLUTETIME( &abstime
, &nsinterval
);
2972 clock_absolutetime_interval_to_deadline(
2973 abstime
, &abstime
);
2974 computeDeadline
= false;
2977 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
2980 assert_wait((event_t
)this, THREAD_UNINT
);
2982 unlockForArbitration();
2983 IOLockUnlock( gIOServiceBusyLock
);
2985 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2987 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2989 if( waitResult
== THREAD_TIMED_OUT
)
2990 return( kIOReturnTimeout
);
2992 return( kIOReturnSuccess
);
2995 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
2997 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
3000 bool IOService::serializeProperties( OSSerialize
* s
) const
3003 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
3004 sizeof( __state
), "__state");
3006 return( super::serializeProperties(s
) );
3010 void _IOConfigThread::main( _IOConfigThread
* self
)
3012 _IOServiceJob
* job
;
3020 semaphore_wait( gJobsSemaphore
);
3022 IOTakeLock( gJobsLock
);
3023 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
3025 gJobs
->removeObject(job
);
3028 // gNumConfigThreads--; // we're out of service
3029 gNumWaitingThreads
--; // we're out of service
3031 IOUnlock( gJobsLock
);
3037 if( gIOKitDebug
& kIOLogConfig
)
3038 LOG("config(%x): starting on %s, %d\n",
3039 (int) IOThreadSelf(), job
->nub
->getName(), job
->type
);
3041 switch( job
->type
) {
3044 nub
->doServiceMatch( job
->options
);
3048 LOG("config(%x): strange type (%d)\n",
3049 (int) IOThreadSelf(), job
->type
);
3056 IOTakeLock( gJobsLock
);
3057 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
3059 gNumWaitingThreads
++; // back in service
3060 // gNumConfigThreads++;
3062 if( 0 == --gNumConfigThreads
) {
3063 // IOLog("MATCH IDLE\n");
3064 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3067 IOUnlock( gJobsLock
);
3072 if( gIOKitDebug
& kIOLogConfig
)
3073 LOG("config(%x): terminating\n", (int) IOThreadSelf() );
3078 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3081 int waitResult
= THREAD_AWAKENED
;
3082 bool computeDeadline
= true;
3083 AbsoluteTime abstime
;
3085 IOLockLock( gJobsLock
);
3087 wait
= (0 != gNumConfigThreads
);
3090 if( computeDeadline
) {
3091 clock_interval_to_absolutetime_interval(
3092 msToWait
, kMillisecondScale
, &abstime
);
3093 clock_absolutetime_interval_to_deadline(
3094 abstime
, &abstime
);
3095 computeDeadline
= false;
3097 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
3098 abstime
, THREAD_UNINT
);
3100 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3104 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3105 IOLockUnlock( gJobsLock
);
3107 if( waitResult
== THREAD_TIMED_OUT
)
3108 return( kIOReturnTimeout
);
3110 return( kIOReturnSuccess
);
3113 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3120 IOTakeLock( gJobsLock
);
3123 gJobs
->setLastObject( job
);
3125 count
= gNumWaitingThreads
;
3126 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3128 create
= ( (gOutstandingJobs
> count
)
3129 && (gNumConfigThreads
< kMaxConfigThreads
) );
3131 gNumConfigThreads
++;
3132 gNumWaitingThreads
++;
3135 IOUnlock( gJobsLock
);
3140 if( gIOKitDebug
& kIOLogConfig
)
3141 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3142 _IOConfigThread::configThread();
3145 semaphore_signal( gJobsSemaphore
);
3148 // internal - call with gNotificationLock
3149 OSObject
* IOService::getExistingServices( OSDictionary
* matching
,
3150 IOOptionBits inState
, IOOptionBits options
)
3152 OSObject
* current
= 0;
3154 IOService
* service
;
3161 && (obj
= matching
->getObject(gIOProviderClassKey
))
3163 && gIOResourcesKey
->isEqualTo(obj
)
3164 && (service
= gIOResources
))
3166 if( (inState
== (service
->__state
[0] & inState
))
3167 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3168 && service
->passiveMatch( matching
))
3170 if( options
& kIONotifyOnce
)
3173 current
= OSSet::withObjects(
3174 (const OSObject
**) &service
, 1, 1 );
3179 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3180 kIORegistryIterateRecursively
);
3184 while( (service
= (IOService
*) iter
->getNextObject())) {
3185 if( (inState
== (service
->__state
[0] & inState
))
3186 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3187 && service
->passiveMatch( matching
)) {
3189 if( options
& kIONotifyOnce
) {
3194 ((OSSet
*)current
)->setObject( service
);
3196 current
= OSSet::withObjects(
3197 (const OSObject
**) &service
, 1, 1 );
3200 } while( !service
&& !iter
->isValid());
3205 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
3206 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3215 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3219 // is a lock even needed?
3222 iter
= (OSIterator
*) getExistingServices( matching
,
3223 kIOServiceMatchedState
);
3231 // internal - call with gNotificationLock
3232 IONotifier
* IOService::setNotification(
3233 const OSSymbol
* type
, OSDictionary
* matching
,
3234 IOServiceNotificationHandler handler
, void * target
, void * ref
,
3237 _IOServiceNotifier
* notify
= 0;
3243 notify
= new _IOServiceNotifier
;
3244 if( notify
&& !notify
->init()) {
3250 notify
->matching
= matching
;
3251 notify
->handler
= handler
;
3252 notify
->target
= target
;
3254 notify
->priority
= priority
;
3255 notify
->state
= kIOServiceNotifyEnable
;
3256 queue_init( ¬ify
->handlerInvocations
);
3260 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3261 set
= OSOrderedSet::withCapacity( 1,
3262 IONotifyOrdering
, 0 );
3264 gNotifications
->setObject( type
, set
);
3268 notify
->whence
= set
;
3270 set
->setObject( notify
);
3276 // internal - call with gNotificationLock
3277 IONotifier
* IOService::doInstallNotification(
3278 const OSSymbol
* type
, OSDictionary
* matching
,
3279 IOServiceNotificationHandler handler
,
3280 void * target
, void * ref
,
3281 SInt32 priority
, OSIterator
** existing
)
3284 IONotifier
* notify
;
3285 IOOptionBits inState
;
3290 if( type
== gIOPublishNotification
)
3291 inState
= kIOServiceRegisteredState
;
3293 else if( type
== gIOFirstPublishNotification
)
3294 inState
= kIOServiceFirstPublishState
;
3296 else if( (type
== gIOMatchedNotification
)
3297 || (type
== gIOFirstMatchNotification
))
3298 inState
= kIOServiceMatchedState
;
3299 else if( type
== gIOTerminatedNotification
)
3304 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3307 // get the current set
3308 exist
= (OSIterator
*) getExistingServices( matching
, inState
);
3318 IONotifier
* IOService::installNotification(
3319 const OSSymbol
* type
, OSDictionary
* matching
,
3320 IOServiceNotificationHandler handler
,
3321 void * target
, void * ref
,
3322 SInt32 priority
, OSIterator
** existing
)
3324 IONotifier
* notify
;
3328 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3329 priority
, existing
);
3336 IONotifier
* IOService::addNotification(
3337 const OSSymbol
* type
, OSDictionary
* matching
,
3338 IOServiceNotificationHandler handler
,
3339 void * target
, void * ref
,
3342 OSIterator
* existing
;
3343 _IOServiceNotifier
* notify
;
3346 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3347 handler
, target
, ref
, priority
, &existing
);
3349 // send notifications for existing set
3352 notify
->retain(); // in case handler remove()s
3353 while( (next
= (IOService
*) existing
->getNextObject())) {
3355 next
->lockForArbitration();
3356 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3357 next
->invokeNotifer( notify
);
3358 next
->unlockForArbitration();
3361 existing
->release();
3367 struct SyncNotifyVars
{
3368 semaphore_port_t waitHere
;
3372 bool IOService::syncNotificationHandler(
3373 void * /* target */, void * ref
,
3374 IOService
* newService
)
3377 // result may get written more than once before the
3378 // notification is removed!
3379 ((SyncNotifyVars
*) ref
)->result
= newService
;
3380 semaphore_signal( ((SyncNotifyVars
*) ref
)->waitHere
);
3385 IOService
* IOService::waitForService( OSDictionary
* matching
,
3386 mach_timespec_t
* timeout
)
3388 IONotifier
* notify
= 0;
3389 // priority doesn't help us much since we need a thread wakeup
3390 SInt32 priority
= 0;
3391 SyncNotifyVars state
;
3392 kern_return_t err
= kIOReturnBadArgument
;
3404 state
.result
= (IOService
*) getExistingServices( matching
,
3405 kIOServiceMatchedState
, kIONotifyOnce
);
3409 err
= semaphore_create( kernel_task
, &state
.waitHere
,
3410 SYNC_POLICY_FIFO
, 0 );
3411 if( KERN_SUCCESS
!= err
)
3414 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
3415 &IOService::syncNotificationHandler
, (void *) 0,
3416 (void *) &state
, priority
);
3424 err
= semaphore_timedwait( state
.waitHere
, *timeout
);
3426 err
= semaphore_wait( state
.waitHere
);
3430 notify
->remove(); // dequeues
3432 matching
->release();
3434 semaphore_destroy( kernel_task
, state
.waitHere
);
3436 return( state
.result
);
3439 void IOService::deliverNotification( const OSSymbol
* type
,
3440 IOOptionBits orNewState
, IOOptionBits andNewState
)
3442 _IOServiceNotifier
* notify
;
3444 OSArray
* willSend
= 0;
3446 lockForArbitration();
3448 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3449 || (type
== gIOTerminatedNotification
)) {
3453 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3454 gNotifications
->getObject( type
) );
3457 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
3459 if( passiveMatch( notify
->matching
)
3460 && (kIOServiceNotifyEnable
& notify
->state
)) {
3462 willSend
= OSArray::withCapacity(8);
3464 willSend
->setObject( notify
);
3470 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
3476 for( unsigned int idx
= 0;
3477 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
3479 invokeNotifer( notify
);
3481 willSend
->release();
3483 unlockForArbitration();
3486 IOOptionBits
IOService::getState( void ) const
3488 return( __state
[0] );
3492 * Helpers to make matching objects for simple cases
3495 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
3496 OSDictionary
* table
)
3499 table
= OSDictionary::withCapacity( 2 );
3501 table
->setObject(gIOProviderClassKey
, (OSObject
*)name
);
3506 OSDictionary
* IOService::serviceMatching( const char * name
,
3507 OSDictionary
* table
)
3509 const OSString
* str
;
3511 str
= OSSymbol::withCString( name
);
3515 table
= serviceMatching( str
, table
);
3520 OSDictionary
* IOService::nameMatching( const OSString
* name
,
3521 OSDictionary
* table
)
3524 table
= OSDictionary::withCapacity( 2 );
3526 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
3531 OSDictionary
* IOService::nameMatching( const char * name
,
3532 OSDictionary
* table
)
3534 const OSString
* str
;
3536 str
= OSSymbol::withCString( name
);
3540 table
= nameMatching( str
, table
);
3545 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
3546 OSDictionary
* table
)
3548 table
= serviceMatching( gIOResourcesKey
, table
);
3550 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
3555 OSDictionary
* IOService::resourceMatching( const char * name
,
3556 OSDictionary
* table
)
3558 const OSSymbol
* str
;
3560 str
= OSSymbol::withCString( name
);
3564 table
= resourceMatching( str
, table
);
3571 * _IOServiceNotifier
3574 // wait for all threads, other than the current one,
3575 // to exit the handler
3577 void _IOServiceNotifier::wait()
3579 _IOServiceNotifierInvocation
* next
;
3584 queue_iterate( &handlerInvocations
, next
,
3585 _IOServiceNotifierInvocation
*, link
) {
3586 if( next
->thread
!= current_thread() ) {
3592 state
|= kIOServiceNotifyWaiter
;
3599 void _IOServiceNotifier::free()
3601 assert( queue_empty( &handlerInvocations
));
3605 void _IOServiceNotifier::remove()
3610 whence
->removeObject( (OSObject
*) this );
3614 matching
->release();
3618 state
&= ~kIOServiceNotifyEnable
;
3627 bool _IOServiceNotifier::disable()
3633 ret
= (0 != (kIOServiceNotifyEnable
& state
));
3634 state
&= ~kIOServiceNotifyEnable
;
3643 void _IOServiceNotifier::enable( bool was
)
3647 state
|= kIOServiceNotifyEnable
;
3649 state
&= ~kIOServiceNotifyEnable
;
3657 IOService
* IOResources::resources( void )
3661 inst
= new IOResources
;
3662 if( inst
&& !inst
->init()) {
3670 IOWorkLoop
* IOResources::getWorkLoop() const
3672 // If we are the resource root then bringe over to the
3673 // platform to get its workloop
3674 if (this == (IOResources
*) gIOResources
)
3675 return getPlatform()->getWorkLoop();
3677 return IOService::getWorkLoop();
3680 bool IOResources::matchPropertyTable( OSDictionary
* table
)
3688 prop
= table
->getObject( gIOResourceMatchKey
);
3689 str
= OSDynamicCast( OSString
, prop
);
3691 ok
= (0 != getProperty( str
));
3693 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
3695 iter
= OSCollectionIterator::withCollection( set
);
3697 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
3698 ok
= (0 != getProperty( str
));
3707 IOReturn
IOResources::setProperties( OSObject
* properties
)
3710 const OSSymbol
* key
;
3711 OSDictionary
* dict
;
3712 OSCollectionIterator
* iter
;
3714 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
3715 if ( kIOReturnSuccess
!= err
)
3718 dict
= OSDynamicCast(OSDictionary
, properties
);
3720 return( kIOReturnBadArgument
);
3722 iter
= OSCollectionIterator::withCollection( dict
);
3724 return( kIOReturnBadArgument
);
3726 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
3728 if (gIOConsoleUsersKey
== key
)
3730 IORegistryEntry::getRegistryRoot()->setProperty(key
, dict
->getObject(key
));
3731 OSIncrementAtomic( &gIOConsoleUsersSeed
);
3732 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
3736 publishResource( key
, dict
->getObject(key
) );
3741 return( kIOReturnSuccess
);
3745 * Helpers for matching dictionaries.
3746 * Keys existing in matching are checked in properties.
3747 * Keys may be a string or OSCollection of IOStrings
3750 bool IOService::compareProperty( OSDictionary
* matching
,
3756 value
= matching
->getObject( key
);
3758 ok
= value
->isEqualTo( getProperty( key
));
3766 bool IOService::compareProperty( OSDictionary
* matching
,
3767 const OSString
* key
)
3772 value
= matching
->getObject( key
);
3774 ok
= value
->isEqualTo( getProperty( key
));
3781 bool IOService::compareProperties( OSDictionary
* matching
,
3782 OSCollection
* keys
)
3784 OSCollectionIterator
* iter
;
3785 const OSString
* key
;
3788 if( !matching
|| !keys
)
3791 iter
= OSCollectionIterator::withCollection( keys
);
3794 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
3795 ok
= compareProperty( matching
, key
);
3799 keys
->release(); // !! consume a ref !!
3804 /* Helper to add a location matching dict to the table */
3806 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
3808 OSDictionary
* dict
;
3813 dict
= OSDictionary::withCapacity( 1 );
3815 table
->setObject( gIOLocationMatchKey
, dict
);
3823 * Go looking for a provider to match a location dict.
3826 IOService
* IOService::matchLocation( IOService
* /* client */ )
3830 parent
= getProvider();
3833 parent
= parent
->matchLocation( this );
3838 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
3844 IORegistryEntry
* entry
;
3849 bool matchParent
= false;
3860 str
= OSDynamicCast( OSString
, table
->getObject( gIOProviderClassKey
));
3863 match
= (0 != where
->metaCast( str
));
3868 obj
= table
->getObject( gIONameMatchKey
);
3871 match
= where
->compareNames( obj
, changesOK
? &matched
: 0 );
3874 if( changesOK
&& matched
) {
3875 // leave a hint as to which name matched
3876 table
->setObject( gIONameMatchedKey
, matched
);
3881 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
3884 const OSSymbol
* sym
;
3888 sym
= where
->copyLocation();
3890 match
= sym
->isEqualTo( str
);
3897 obj
= table
->getObject( gIOPropertyMatchKey
);
3900 OSDictionary
* dict
;
3901 OSDictionary
* nextDict
;
3906 dict
= where
->dictionaryWithProperties();
3908 nextDict
= OSDynamicCast( OSDictionary
, obj
);
3912 iter
= OSCollectionIterator::withCollection(
3913 OSDynamicCast(OSCollection
, obj
));
3916 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
3917 iter
->getNextObject()))))) {
3918 match
= dict
->isEqualTo( nextDict
, nextDict
);
3931 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
3934 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
3935 match
= (where
== entry
);
3942 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
3946 IOService
* service
= 0;
3947 UInt32 serviceCount
= 0;
3950 iter
= where
->getClientIterator();
3952 while( (service
= (IOService
*) iter
->getNextObject())) {
3953 if( kIOServiceInactiveState
& service
->__state
[0])
3955 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
3961 match
= (serviceCount
== num
->unsigned32BitValue());
3966 if( done
== table
->getCount()) {
3967 // don't call family if we've done all the entries in the table
3968 matchParent
= false;
3972 // pass in score from property table
3973 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
3975 // do family specific matching
3976 match
= where
->matchPropertyTable( table
, &score
);
3980 if( kIOLogMatch
& getDebugFlags( table
))
3981 LOG("%s: family specific matching fails\n", where
->getName());
3988 newPri
= OSNumber::withNumber( score
, 32 );
3990 table
->setObject( gIOProbeScoreKey
, newPri
);
3995 if( !(match
= where
->compareProperty( table
, kIOBSDNameKey
)))
3998 matchParent
= false;
4000 obj
= OSDynamicCast( OSDictionary
,
4001 table
->getObject( gIOParentMatchKey
));
4005 table
= (OSDictionary
*) obj
;
4009 table
= OSDynamicCast( OSDictionary
,
4010 table
->getObject( gIOLocationMatchKey
));
4013 where
= where
->getProvider();
4015 where
= where
->matchLocation( where
);
4018 } while( table
&& where
);
4020 } while( matchParent
&& (where
= where
->getProvider()) );
4022 if( kIOLogMatch
& gIOKitDebug
)
4024 LOG("match parent @ %s = %d\n",
4025 where
->getName(), match
);
4031 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4032 UInt32 type
, OSDictionary
* properties
,
4033 IOUserClient
** handler
)
4035 const OSSymbol
*userClientClass
= 0;
4036 IOUserClient
*client
;
4039 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
))
4040 return kIOReturnSuccess
;
4042 // First try my own properties for a user client class name
4043 temp
= getProperty(gIOUserClientClassKey
);
4045 if (OSDynamicCast(OSSymbol
, temp
))
4046 userClientClass
= (const OSSymbol
*) temp
;
4047 else if (OSDynamicCast(OSString
, temp
)) {
4048 userClientClass
= OSSymbol::withString((OSString
*) temp
);
4049 if (userClientClass
)
4050 setProperty(kIOUserClientClassKey
,
4051 (OSObject
*) userClientClass
);
4055 // Didn't find one so lets just bomb out now without further ado.
4056 if (!userClientClass
)
4057 return kIOReturnUnsupported
;
4059 // This reference is consumed by the IOServiceOpen call
4060 temp
= OSMetaClass::allocClassWithName(userClientClass
);
4062 return kIOReturnNoMemory
;
4064 if (OSDynamicCast(IOUserClient
, temp
))
4065 client
= (IOUserClient
*) temp
;
4068 return kIOReturnUnsupported
;
4071 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
4073 return kIOReturnBadArgument
;
4076 if ( !client
->attach(this) ) {
4078 return kIOReturnUnsupported
;
4081 if ( !client
->start(this) ) {
4082 client
->detach(this);
4084 return kIOReturnUnsupported
;
4088 return kIOReturnSuccess
;
4091 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4092 UInt32 type
, IOUserClient
** handler
)
4094 return( kIOReturnUnsupported
);
4097 IOReturn
IOService::requestProbe( IOOptionBits options
)
4099 return( kIOReturnUnsupported
);
4103 * Convert an IOReturn to text. Subclasses which add additional
4104 * IOReturn's should override this method and call
4105 * super::stringFromReturn if the desired value is not found.
4108 const char * IOService::stringFromReturn( IOReturn rtn
)
4110 static const IONamedValue IOReturn_values
[] = {
4111 {kIOReturnSuccess
, "success" },
4112 {kIOReturnError
, "general error" },
4113 {kIOReturnNoMemory
, "memory allocation error" },
4114 {kIOReturnNoResources
, "resource shortage" },
4115 {kIOReturnIPCError
, "Mach IPC failure" },
4116 {kIOReturnNoDevice
, "no such device" },
4117 {kIOReturnNotPrivileged
, "privilege violation" },
4118 {kIOReturnBadArgument
, "invalid argument" },
4119 {kIOReturnLockedRead
, "device is read locked" },
4120 {kIOReturnLockedWrite
, "device is write locked" },
4121 {kIOReturnExclusiveAccess
, "device is exclusive access" },
4122 {kIOReturnBadMessageID
, "bad IPC message ID" },
4123 {kIOReturnUnsupported
, "unsupported function" },
4124 {kIOReturnVMError
, "virtual memory error" },
4125 {kIOReturnInternalError
, "internal driver error" },
4126 {kIOReturnIOError
, "I/O error" },
4127 {kIOReturnCannotLock
, "cannot acquire lock" },
4128 {kIOReturnNotOpen
, "device is not open" },
4129 {kIOReturnNotReadable
, "device is not readable" },
4130 {kIOReturnNotWritable
, "device is not writeable" },
4131 {kIOReturnNotAligned
, "alignment error" },
4132 {kIOReturnBadMedia
, "media error" },
4133 {kIOReturnStillOpen
, "device is still open" },
4134 {kIOReturnRLDError
, "rld failure" },
4135 {kIOReturnDMAError
, "DMA failure" },
4136 {kIOReturnBusy
, "device is busy" },
4137 {kIOReturnTimeout
, "I/O timeout" },
4138 {kIOReturnOffline
, "device is offline" },
4139 {kIOReturnNotReady
, "device is not ready" },
4140 {kIOReturnNotAttached
, "device/channel is not attached" },
4141 {kIOReturnNoChannels
, "no DMA channels available" },
4142 {kIOReturnNoSpace
, "no space for data" },
4143 {kIOReturnPortExists
, "device port already exists" },
4144 {kIOReturnCannotWire
, "cannot wire physical memory" },
4145 {kIOReturnNoInterrupt
, "no interrupt attached" },
4146 {kIOReturnNoFrames
, "no DMA frames enqueued" },
4147 {kIOReturnMessageTooLarge
, "message is too large" },
4148 {kIOReturnNotPermitted
, "operation is not permitted" },
4149 {kIOReturnNoPower
, "device is without power" },
4150 {kIOReturnNoMedia
, "media is not present" },
4151 {kIOReturnUnformattedMedia
, "media is not formatted" },
4152 {kIOReturnUnsupportedMode
, "unsupported mode" },
4153 {kIOReturnUnderrun
, "data underrun" },
4154 {kIOReturnOverrun
, "data overrun" },
4155 {kIOReturnDeviceError
, "device error" },
4156 {kIOReturnNoCompletion
, "no completion routine" },
4157 {kIOReturnAborted
, "operation was aborted" },
4158 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
4159 {kIOReturnNotResponding
, "device is not responding" },
4160 {kIOReturnInvalid
, "unanticipated driver error" },
4164 return IOFindNameForValue(rtn
, IOReturn_values
);
4168 * Convert an IOReturn to an errno.
4170 int IOService::errnoFromReturn( IOReturn rtn
)
4174 case kIOReturnSuccess
:
4176 case kIOReturnNoMemory
:
4178 case kIOReturnNoDevice
:
4180 case kIOReturnVMError
:
4182 case kIOReturnNotPermitted
:
4184 case kIOReturnNotPrivileged
:
4186 case kIOReturnIOError
:
4188 case kIOReturnNotWritable
:
4190 case kIOReturnBadArgument
:
4192 case kIOReturnUnsupported
:
4196 case kIOReturnNoPower
:
4198 case kIOReturnDeviceError
:
4200 case kIOReturnTimeout
:
4202 case kIOReturnMessageTooLarge
:
4204 case kIOReturnNoSpace
:
4206 case kIOReturnCannotLock
:
4210 case kIOReturnBadMessageID
:
4211 case kIOReturnNoCompletion
:
4212 case kIOReturnNotAligned
:
4214 case kIOReturnNotReady
:
4216 case kIOReturnRLDError
:
4218 case kIOReturnPortExists
:
4219 case kIOReturnStillOpen
:
4221 case kIOReturnExclusiveAccess
:
4222 case kIOReturnLockedRead
:
4223 case kIOReturnLockedWrite
:
4224 case kIOReturnNotAttached
:
4225 case kIOReturnNotOpen
:
4226 case kIOReturnNotReadable
:
4228 case kIOReturnCannotWire
:
4229 case kIOReturnNoResources
:
4231 case kIOReturnAborted
:
4232 case kIOReturnOffline
:
4233 case kIOReturnNotResponding
:
4235 case kIOReturnBadMedia
:
4236 case kIOReturnNoMedia
:
4237 case kIOReturnUnformattedMedia
:
4238 return(ENXIO
); // (media error)
4239 case kIOReturnDMAError
:
4240 case kIOReturnOverrun
:
4241 case kIOReturnUnderrun
:
4242 return(EIO
); // (transfer error)
4243 case kIOReturnNoBandwidth
:
4244 case kIOReturnNoChannels
:
4245 case kIOReturnNoFrames
:
4246 case kIOReturnNoInterrupt
:
4247 return(EIO
); // (hardware error)
4248 case kIOReturnError
:
4249 case kIOReturnInternalError
:
4250 case kIOReturnInvalid
:
4251 return(EIO
); // (generic error)
4252 case kIOReturnIPCError
:
4253 return(EIO
); // (ipc error)
4255 return(EIO
); // (all other errors)
4259 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
4263 * Generic entry point for calls from the provider. A return value of
4264 * kIOReturnSuccess indicates that the message was received, and where
4265 * applicable, that it was successful.
4268 return kIOReturnUnsupported
;
4275 IOItemCount
IOService::getDeviceMemoryCount( void )
4280 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4282 count
= array
->getCount();
4289 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
4292 IODeviceMemory
* range
;
4294 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4296 range
= (IODeviceMemory
*) array
->getObject( index
);
4303 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
4304 IOOptionBits options
)
4306 IODeviceMemory
* range
;
4309 range
= getDeviceMemoryWithIndex( index
);
4311 map
= range
->map( options
);
4318 OSArray
* IOService::getDeviceMemory( void )
4320 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
4324 void IOService::setDeviceMemory( OSArray
* array
)
4326 setProperty( gIODeviceMemoryKey
, array
);
4330 * For machines where the transfers on an I/O bus can stall because
4331 * the CPU is in an idle mode, These APIs allow a driver to specify
4332 * the maximum bus stall that they can handle. 0 indicates no limit.
4335 setCPUSnoopDelay(UInt32 __unused ns
)
4338 ml_set_maxsnoop(ns
);
4339 #endif /* __i386__ */
4346 return ml_get_maxsnoop();
4349 #endif /* __i386__ */
4353 requireMaxBusStall(UInt32 __unused ns
)
4356 static const UInt kNoReplace
= -1U; // Must be an illegal index
4357 UInt replace
= kNoReplace
;
4359 IOLockLock(sBusStallLock
);
4361 UInt count
= sBusStall
->getLength() / sizeof(BusStallEntry
);
4362 BusStallEntry
*entries
= (BusStallEntry
*) sBusStall
->getBytesNoCopy();
4365 const BusStallEntry ne
= {this, ns
};
4367 // Set Maximum bus delay.
4368 for (UInt i
= 0; i
< count
; i
++) {
4369 const IOService
*thisService
= entries
[i
].fService
;
4370 if (this == thisService
)
4372 else if (!thisService
) {
4373 if (kNoReplace
== replace
)
4377 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
4383 // Must be safe to call from locked context
4384 ml_set_maxbusdelay(ns
);
4386 if (kNoReplace
== replace
)
4387 sBusStall
->appendBytes(&ne
, sizeof(ne
));
4389 entries
[replace
] = ne
;
4392 ns
= -1U; // Set to max unsigned, i.e. no restriction
4394 for (UInt i
= 0; i
< count
; i
++) {
4395 // Clear a maximum bus delay.
4396 const IOService
*thisService
= entries
[i
].fService
;
4397 UInt32 thisMax
= entries
[i
].fMaxDelay
;
4398 if (this == thisService
)
4400 else if (thisService
&& thisMax
< ns
)
4404 // Check if entry found
4405 if (kNoReplace
!= replace
) {
4406 entries
[replace
].fService
= 0; // Null the entry
4407 ml_set_maxbusdelay(ns
);
4411 IOLockUnlock(sBusStallLock
);
4412 #endif /* __i386__ */
4419 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
4421 IOInterruptController
*interruptController
;
4424 OSSymbol
*interruptControllerName
;
4426 IOInterruptSource
*interruptSources
;
4428 // Get the parents list from the nub.
4429 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
4430 if (array
== 0) return kIOReturnNoResources
;
4432 // Allocate space for the IOInterruptSources if needed... then return early.
4433 if (nub
->_interruptSources
== 0) {
4434 numSources
= array
->getCount();
4435 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
4436 if (interruptSources
== 0) return kIOReturnNoMemory
;
4438 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
4440 nub
->_numInterruptSources
= numSources
;
4441 nub
->_interruptSources
= interruptSources
;
4442 return kIOReturnSuccess
;
4445 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
4446 if (interruptControllerName
== 0) return kIOReturnNoResources
;
4448 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
4449 if (interruptController
== 0) return kIOReturnNoResources
;
4451 // Get the interrupt numbers from the nub.
4452 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
4453 if (array
== 0) return kIOReturnNoResources
;
4454 data
= OSDynamicCast(OSData
, array
->getObject(source
));
4455 if (data
== 0) return kIOReturnNoResources
;
4457 // Set the interruptController and interruptSource in the nub's table.
4458 interruptSources
= nub
->_interruptSources
;
4459 interruptSources
[source
].interruptController
= interruptController
;
4460 interruptSources
[source
].vectorData
= data
;
4462 return kIOReturnSuccess
;
4465 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
4469 /* Make sure the _interruptSources are set */
4470 if (_interruptSources
== 0) {
4471 ret
= resolveInterrupt(this, source
);
4472 if (ret
!= kIOReturnSuccess
) return ret
;
4475 /* Make sure the local source number is valid */
4476 if ((source
< 0) || (source
>= _numInterruptSources
))
4477 return kIOReturnNoInterrupt
;
4479 /* Look up the contoller for the local source */
4480 *interruptController
= _interruptSources
[source
].interruptController
;
4482 if (*interruptController
== NULL
) {
4483 if (!resolve
) return kIOReturnNoInterrupt
;
4485 /* Try to reslove the interrupt */
4486 ret
= resolveInterrupt(this, source
);
4487 if (ret
!= kIOReturnSuccess
) return ret
;
4489 *interruptController
= _interruptSources
[source
].interruptController
;
4492 return kIOReturnSuccess
;
4495 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
4496 IOInterruptAction handler
,
4499 IOInterruptController
*interruptController
;
4502 ret
= lookupInterrupt(source
, true, &interruptController
);
4503 if (ret
!= kIOReturnSuccess
) return ret
;
4505 /* Register the source */
4506 return interruptController
->registerInterrupt(this, source
, target
,
4507 (IOInterruptHandler
)handler
,
4511 IOReturn
IOService::unregisterInterrupt(int source
)
4513 IOInterruptController
*interruptController
;
4516 ret
= lookupInterrupt(source
, false, &interruptController
);
4517 if (ret
!= kIOReturnSuccess
) return ret
;
4519 /* Unregister the source */
4520 return interruptController
->unregisterInterrupt(this, source
);
4523 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
4525 IOInterruptController
*interruptController
;
4528 ret
= lookupInterrupt(source
, true, &interruptController
);
4529 if (ret
!= kIOReturnSuccess
) return ret
;
4531 /* Return the type */
4532 return interruptController
->getInterruptType(this, source
, interruptType
);
4535 IOReturn
IOService::enableInterrupt(int source
)
4537 IOInterruptController
*interruptController
;
4540 ret
= lookupInterrupt(source
, false, &interruptController
);
4541 if (ret
!= kIOReturnSuccess
) return ret
;
4543 /* Enable the source */
4544 return interruptController
->enableInterrupt(this, source
);
4547 IOReturn
IOService::disableInterrupt(int source
)
4549 IOInterruptController
*interruptController
;
4552 ret
= lookupInterrupt(source
, false, &interruptController
);
4553 if (ret
!= kIOReturnSuccess
) return ret
;
4555 /* Disable the source */
4556 return interruptController
->disableInterrupt(this, source
);
4559 IOReturn
IOService::causeInterrupt(int source
)
4561 IOInterruptController
*interruptController
;
4564 ret
= lookupInterrupt(source
, false, &interruptController
);
4565 if (ret
!= kIOReturnSuccess
) return ret
;
4567 /* Cause an interrupt for the source */
4568 return interruptController
->causeInterrupt(this, source
);
4571 OSMetaClassDefineReservedUsed(IOService
, 0);
4572 OSMetaClassDefineReservedUsed(IOService
, 1);
4573 OSMetaClassDefineReservedUsed(IOService
, 2);
4574 OSMetaClassDefineReservedUsed(IOService
, 3);
4576 OSMetaClassDefineReservedUnused(IOService
, 4);
4577 OSMetaClassDefineReservedUnused(IOService
, 5);
4578 OSMetaClassDefineReservedUnused(IOService
, 6);
4579 OSMetaClassDefineReservedUnused(IOService
, 7);
4580 OSMetaClassDefineReservedUnused(IOService
, 8);
4581 OSMetaClassDefineReservedUnused(IOService
, 9);
4582 OSMetaClassDefineReservedUnused(IOService
, 10);
4583 OSMetaClassDefineReservedUnused(IOService
, 11);
4584 OSMetaClassDefineReservedUnused(IOService
, 12);
4585 OSMetaClassDefineReservedUnused(IOService
, 13);
4586 OSMetaClassDefineReservedUnused(IOService
, 14);
4587 OSMetaClassDefineReservedUnused(IOService
, 15);
4588 OSMetaClassDefineReservedUnused(IOService
, 16);
4589 OSMetaClassDefineReservedUnused(IOService
, 17);
4590 OSMetaClassDefineReservedUnused(IOService
, 18);
4591 OSMetaClassDefineReservedUnused(IOService
, 19);
4592 OSMetaClassDefineReservedUnused(IOService
, 20);
4593 OSMetaClassDefineReservedUnused(IOService
, 21);
4594 OSMetaClassDefineReservedUnused(IOService
, 22);
4595 OSMetaClassDefineReservedUnused(IOService
, 23);
4596 OSMetaClassDefineReservedUnused(IOService
, 24);
4597 OSMetaClassDefineReservedUnused(IOService
, 25);
4598 OSMetaClassDefineReservedUnused(IOService
, 26);
4599 OSMetaClassDefineReservedUnused(IOService
, 27);
4600 OSMetaClassDefineReservedUnused(IOService
, 28);
4601 OSMetaClassDefineReservedUnused(IOService
, 29);
4602 OSMetaClassDefineReservedUnused(IOService
, 30);
4603 OSMetaClassDefineReservedUnused(IOService
, 31);
4604 OSMetaClassDefineReservedUnused(IOService
, 32);
4605 OSMetaClassDefineReservedUnused(IOService
, 33);
4606 OSMetaClassDefineReservedUnused(IOService
, 34);
4607 OSMetaClassDefineReservedUnused(IOService
, 35);
4608 OSMetaClassDefineReservedUnused(IOService
, 36);
4609 OSMetaClassDefineReservedUnused(IOService
, 37);
4610 OSMetaClassDefineReservedUnused(IOService
, 38);
4611 OSMetaClassDefineReservedUnused(IOService
, 39);
4612 OSMetaClassDefineReservedUnused(IOService
, 40);
4613 OSMetaClassDefineReservedUnused(IOService
, 41);
4614 OSMetaClassDefineReservedUnused(IOService
, 42);
4615 OSMetaClassDefineReservedUnused(IOService
, 43);
4616 OSMetaClassDefineReservedUnused(IOService
, 44);
4617 OSMetaClassDefineReservedUnused(IOService
, 45);
4618 OSMetaClassDefineReservedUnused(IOService
, 46);
4619 OSMetaClassDefineReservedUnused(IOService
, 47);
4622 OSMetaClassDefineReservedUnused(IOService
, 48);
4623 OSMetaClassDefineReservedUnused(IOService
, 49);
4624 OSMetaClassDefineReservedUnused(IOService
, 50);
4625 OSMetaClassDefineReservedUnused(IOService
, 51);
4626 OSMetaClassDefineReservedUnused(IOService
, 52);
4627 OSMetaClassDefineReservedUnused(IOService
, 53);
4628 OSMetaClassDefineReservedUnused(IOService
, 54);
4629 OSMetaClassDefineReservedUnused(IOService
, 55);
4630 OSMetaClassDefineReservedUnused(IOService
, 56);
4631 OSMetaClassDefineReservedUnused(IOService
, 57);
4632 OSMetaClassDefineReservedUnused(IOService
, 58);
4633 OSMetaClassDefineReservedUnused(IOService
, 59);
4634 OSMetaClassDefineReservedUnused(IOService
, 60);
4635 OSMetaClassDefineReservedUnused(IOService
, 61);
4636 OSMetaClassDefineReservedUnused(IOService
, 62);
4637 OSMetaClassDefineReservedUnused(IOService
, 63);