2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <IOKit/system.h>
26 #include <IOKit/IOService.h>
27 #include <libkern/c++/OSContainers.h>
28 #include <libkern/c++/OSUnserialize.h>
29 #include <IOKit/IOCatalogue.h>
30 #include <IOKit/IOCommand.h>
31 #include <IOKit/IODeviceMemory.h>
32 #include <IOKit/IOInterrupts.h>
33 #include <IOKit/IOInterruptController.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOMessage.h>
36 #include <IOKit/IOLib.h>
37 #include <IOKit/IOKitKeysPrivate.h>
38 #include <IOKit/IOBSD.h>
39 #include <IOKit/IOUserClient.h>
40 #include <IOKit/IOWorkLoop.h>
41 #include <mach/sync_policy.h>
42 #include <IOKit/assert.h>
43 #include <sys/errno.h>
48 #include "IOServicePrivate.h"
50 // take lockForArbitration before LOCKNOTIFY
52 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
54 #define super IORegistryEntry
56 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
58 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
60 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
62 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
64 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
66 OSDefineMetaClassAndStructors(IOResources
, IOService
)
68 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
70 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
72 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
74 static IOPlatformExpert
* gIOPlatform
;
75 static class IOPMrootDomain
* gIOPMRootDomain
;
76 const IORegistryPlane
* gIOServicePlane
;
77 const IORegistryPlane
* gIOPowerPlane
;
78 const OSSymbol
* gIODeviceMemoryKey
;
79 const OSSymbol
* gIOInterruptControllersKey
;
80 const OSSymbol
* gIOInterruptSpecifiersKey
;
82 const OSSymbol
* gIOResourcesKey
;
83 const OSSymbol
* gIOResourceMatchKey
;
84 const OSSymbol
* gIOProviderClassKey
;
85 const OSSymbol
* gIONameMatchKey
;
86 const OSSymbol
* gIONameMatchedKey
;
87 const OSSymbol
* gIOPropertyMatchKey
;
88 const OSSymbol
* gIOLocationMatchKey
;
89 const OSSymbol
* gIOParentMatchKey
;
90 const OSSymbol
* gIOPathMatchKey
;
91 const OSSymbol
* gIOMatchCategoryKey
;
92 const OSSymbol
* gIODefaultMatchCategoryKey
;
93 const OSSymbol
* gIOMatchedServiceCountKey
;
95 const OSSymbol
* gIOUserClientClassKey
;
96 const OSSymbol
* gIOKitDebugKey
;
98 const OSSymbol
* gIOCommandPoolSizeKey
;
100 const OSSymbol
* gIOConsoleUsersKey
;
101 const OSSymbol
* gIOConsoleSessionUIDKey
;
102 const OSSymbol
* gIOConsoleUsersSeedKey
;
104 static int gIOResourceGenerationCount
;
106 const OSSymbol
* gIOServiceKey
;
107 const OSSymbol
* gIOPublishNotification
;
108 const OSSymbol
* gIOFirstPublishNotification
;
109 const OSSymbol
* gIOMatchedNotification
;
110 const OSSymbol
* gIOFirstMatchNotification
;
111 const OSSymbol
* gIOTerminatedNotification
;
113 const OSSymbol
* gIOGeneralInterest
;
114 const OSSymbol
* gIOBusyInterest
;
115 const OSSymbol
* gIOAppPowerStateInterest
;
116 const OSSymbol
* gIOPriorityPowerStateInterest
;
118 static OSDictionary
* gNotifications
;
119 static IORecursiveLock
* gNotificationLock
;
121 static IOService
* gIOResources
;
122 static IOService
* gIOServiceRoot
;
124 static OSOrderedSet
* gJobs
;
125 static semaphore_port_t gJobsSemaphore
;
126 static IOLock
* gJobsLock
;
127 static int gOutstandingJobs
;
128 static int gNumConfigThreads
;
129 static int gNumWaitingThreads
;
130 static IOLock
* gIOServiceBusyLock
;
132 static thread_t gIOTerminateThread
;
133 static UInt32 gIOTerminateWork
;
134 static OSArray
* gIOTerminatePhase2List
;
135 static OSArray
* gIOStopList
;
136 static OSArray
* gIOStopProviderList
;
137 static OSArray
* gIOFinalizeList
;
139 static SInt32 gIOConsoleUsersSeed
;
140 static OSData
* gIOConsoleUsersSeedValue
;
142 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
144 #define LOCKREADNOTIFY() \
145 IORecursiveLockLock( gNotificationLock )
146 #define LOCKWRITENOTIFY() \
147 IORecursiveLockLock( gNotificationLock )
148 #define LOCKWRITE2READNOTIFY()
149 #define UNLOCKNOTIFY() \
150 IORecursiveLockUnlock( gNotificationLock )
151 #define SLEEPNOTIFY(event) \
152 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
153 #define WAKEUPNOTIFY(event) \
154 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
156 #define randomDelay() \
157 int del = read_processor_clock(); \
158 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
161 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
163 #define queue_element(entry, element, type, field) do { \
164 vm_address_t __ele = (vm_address_t) (entry); \
165 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
166 (element) = (type) __ele; \
169 #define iterqueue(que, elt) \
170 for (queue_entry_t elt = queue_first(que); \
171 !queue_end(que, elt); \
172 elt = queue_next(elt))
174 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
176 struct ArbitrationLockQueueElement
{
185 static queue_head_t gArbitrationLockQueueActive
;
186 static queue_head_t gArbitrationLockQueueWaiting
;
187 static queue_head_t gArbitrationLockQueueFree
;
188 static IOLock
* gArbitrationLockQueueLock
;
190 bool IOService::isInactive( void ) const
191 { return( 0 != (kIOServiceInactiveState
& getState())); }
193 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
195 void IOService::initialize( void )
199 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
200 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
202 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
203 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
204 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
205 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
206 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
207 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
208 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
210 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
211 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
212 kIODefaultMatchCategoryKey
);
213 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
214 kIOMatchedServiceCountKey
);
216 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
218 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
219 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
221 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
222 gIOInterruptControllersKey
223 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
224 gIOInterruptSpecifiersKey
225 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
227 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
229 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
231 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
232 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
233 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
234 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
236 gNotifications
= OSDictionary::withCapacity( 1 );
237 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
238 kIOPublishNotification
);
239 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
240 kIOFirstPublishNotification
);
241 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
242 kIOMatchedNotification
);
243 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
244 kIOFirstMatchNotification
);
245 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
246 kIOTerminatedNotification
);
247 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
249 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
250 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
251 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey
);
252 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
254 gNotificationLock
= IORecursiveLockAlloc();
256 assert( gIOServicePlane
&& gIODeviceMemoryKey
257 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
258 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
259 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
260 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
261 && gIOPublishNotification
&& gIOMatchedNotification
262 && gIOTerminatedNotification
&& gIOServiceKey
263 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
264 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
266 gJobsLock
= IOLockAlloc();
267 gJobs
= OSOrderedSet::withCapacity( 10 );
269 gIOServiceBusyLock
= IOLockAlloc();
271 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
273 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& (err
== KERN_SUCCESS
) );
275 gIOResources
= IOResources::resources();
276 assert( gIOResources
);
278 gArbitrationLockQueueLock
= IOLockAlloc();
279 queue_init(&gArbitrationLockQueueActive
);
280 queue_init(&gArbitrationLockQueueWaiting
);
281 queue_init(&gArbitrationLockQueueFree
);
283 assert( gArbitrationLockQueueLock
);
285 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
286 gIOStopList
= OSArray::withCapacity( 16 );
287 gIOStopProviderList
= OSArray::withCapacity( 16 );
288 gIOFinalizeList
= OSArray::withCapacity( 16 );
289 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
292 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
295 static UInt64
getDebugFlags( OSDictionary
* props
)
297 OSNumber
* debugProp
;
300 debugProp
= OSDynamicCast( OSNumber
,
301 props
->getObject( gIOKitDebugKey
));
303 debugFlags
= debugProp
->unsigned64BitValue();
305 debugFlags
= gIOKitDebug
;
307 return( debugFlags
);
311 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
313 // Probe a matched service and return an instance to be started.
314 // The default score is from the property table, & may be altered
315 // during probe to change the start order.
317 IOService
* IOService::probe( IOService
* provider
,
323 bool IOService::start( IOService
* provider
)
328 void IOService::stop( IOService
* provider
)
332 void IOService::free( void )
334 if( getPropertyTable())
335 unregisterAllInterest();
341 * Attach in service plane
343 bool IOService::attach( IOService
* provider
)
349 if( gIOKitDebug
& kIOLogAttach
)
350 LOG( "%s::attach(%s)\n", getName(),
351 provider
->getName());
353 provider
->lockForArbitration();
354 if( provider
->__state
[0] & kIOServiceInactiveState
)
357 ok
= attachToParent( provider
, gIOServicePlane
);
358 provider
->unlockForArbitration();
361 gIOServiceRoot
= this;
362 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
368 IOService
* IOService::getServiceRoot( void )
370 return( gIOServiceRoot
);
373 void IOService::detach( IOService
* provider
)
375 IOService
* newProvider
= 0;
379 if( gIOKitDebug
& kIOLogAttach
)
380 LOG("%s::detach(%s)\n", getName(), provider
->getName());
382 lockForArbitration();
384 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
385 && (provider
== getProvider()));
387 detachFromParent( provider
, gIOServicePlane
);
390 newProvider
= getProvider();
391 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
392 _adjustBusy( -busy
);
395 unlockForArbitration();
398 newProvider
->lockForArbitration();
399 newProvider
->_adjustBusy(1);
400 newProvider
->unlockForArbitration();
403 // check for last client detach from a terminated service
404 if( provider
->lockForArbitration( true )) {
406 provider
->_adjustBusy( -1 );
407 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
408 && (0 == provider
->getClient())) {
409 provider
->scheduleFinalize();
411 provider
->unlockForArbitration();
416 * Register instance - publish it for matching
419 void IOService::registerService( IOOptionBits options
)
425 enum { kMaxPathLen
= 256 };
426 enum { kMaxChars
= 63 };
428 IORegistryEntry
* parent
= this;
429 IORegistryEntry
* root
= getRegistryRoot();
430 while( parent
&& (parent
!= root
))
431 parent
= parent
->getParentEntry( gIOServicePlane
);
433 if( parent
!= root
) {
434 IOLog("%s: not registry member at registerService()\n", getName());
438 // Allow the Platform Expert to adjust this node.
439 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
442 if( (this != gIOResources
)
443 && (kIOLogRegister
& gIOKitDebug
)) {
445 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
447 IOLog( "Registering: " );
450 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
453 if( len
> kMaxChars
) {
457 if( (skip
= strchr( path
, '/')))
463 IOLog( "%s\n", path
);
466 IOFree( pathBuf
, kMaxPathLen
);
469 startMatching( options
);
472 void IOService::startMatching( IOOptionBits options
)
474 IOService
* provider
;
477 bool needWake
= false;
482 lockForArbitration();
484 sync
= (options
& kIOServiceSynchronous
)
485 || ((provider
= getProvider())
486 && (provider
->__state
[1] & kIOServiceSynchronousState
));
489 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
490 && (0 == (__state
[0] & kIOServiceInactiveState
));
492 __state
[1] |= kIOServiceNeedConfigState
;
494 // __state[0] &= ~kIOServiceInactiveState;
496 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
497 // OSKernelStackRemaining(), getName());
500 prevBusy
= _adjustBusy( 1 );
501 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
505 __state
[1] |= kIOServiceSynchronousState
;
507 __state
[1] &= ~kIOServiceSynchronousState
;
509 unlockForArbitration();
514 IOLockLock( gIOServiceBusyLock
);
515 thread_wakeup( (event_t
) this/*&__state[1]*/ );
516 IOLockUnlock( gIOServiceBusyLock
);
518 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
520 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
524 if( (__state
[1] & kIOServiceNeedConfigState
))
525 doServiceMatch( options
);
527 lockForArbitration();
528 IOLockLock( gIOServiceBusyLock
);
530 waitAgain
= (prevBusy
< (__state
[1] & kIOServiceBusyStateMask
));
532 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
534 __state
[1] &= ~kIOServiceSyncPubState
;
536 unlockForArbitration();
539 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
541 IOLockUnlock( gIOServiceBusyLock
);
543 thread_block(THREAD_CONTINUE_NULL
);
545 } while( waitAgain
);
549 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
551 OSDictionary
* table
;
561 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
564 set
= (OSSet
*) getExistingServices( table
,
565 kIOServiceRegisteredState
,
566 kIOServiceExistingSet
);
571 count
+= set
->getCount();
574 allSet
->merge((const OSSet
*) set
);
582 if( getDebugFlags( table
) & kIOLogMatch
)
583 LOG("Matching service count = %ld\n", count
);
585 newTables
->removeObject(table
);
589 while( (service
= (IOService
*) allSet
->getAnyObject())) {
590 service
->startMatching(kIOServiceAsynchronous
);
591 allSet
->removeObject(service
);
596 newTables
->release();
598 return( kIOReturnSuccess
);
601 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
602 IOOptionBits options
)
606 job
= new _IOServiceJob
;
607 if( job
&& !job
->init()) {
615 job
->options
= options
;
616 nub
->retain(); // thread will release()
624 * Called on a registered service to see if it matches
628 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
630 return( matchPropertyTable(table
) );
633 bool IOService::matchPropertyTable( OSDictionary
* table
)
639 * Called on a matched service to allocate resources
640 * before first driver is attached.
643 IOReturn
IOService::getResources( void )
645 return( kIOReturnSuccess
);
649 * Client/provider accessors
652 IOService
* IOService::getProvider( void ) const
654 IOService
* self
= (IOService
*) this;
659 generation
= getGenerationCount();
660 if( __providerGeneration
== generation
)
663 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
664 if( parent
== IORegistryEntry::getRegistryRoot())
665 /* root is not an IOService */
668 self
->__provider
= parent
;
669 // save the count before getParentEntry()
670 self
->__providerGeneration
= generation
;
675 IOWorkLoop
* IOService::getWorkLoop() const
677 IOService
*provider
= getProvider();
680 return provider
->getWorkLoop();
685 OSIterator
* IOService::getProviderIterator( void ) const
687 return( getParentIterator( gIOServicePlane
));
690 IOService
* IOService::getClient( void ) const
692 return( (IOService
*) getChildEntry( gIOServicePlane
));
695 OSIterator
* IOService::getClientIterator( void ) const
697 return( getChildIterator( gIOServicePlane
));
700 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
701 const IOService
* client
,
702 const IOService
* provider
)
704 _IOOpenServiceIterator
* inst
;
709 inst
= new _IOOpenServiceIterator
;
711 if( inst
&& !inst
->init()) {
717 inst
->client
= client
;
718 inst
->provider
= provider
;
724 void _IOOpenServiceIterator::free()
728 last
->unlockForArbitration();
732 OSObject
* _IOOpenServiceIterator::getNextObject()
737 last
->unlockForArbitration();
739 while( (next
= (IOService
*) iter
->getNextObject())) {
741 next
->lockForArbitration();
742 if( (client
&& (next
->isOpen( client
)))
743 || (provider
&& (provider
->isOpen( next
))) )
745 next
->unlockForArbitration();
753 bool _IOOpenServiceIterator::isValid()
755 return( iter
->isValid() );
758 void _IOOpenServiceIterator::reset()
761 last
->unlockForArbitration();
767 OSIterator
* IOService::getOpenProviderIterator( void ) const
769 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
772 OSIterator
* IOService::getOpenClientIterator( void ) const
774 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
778 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
779 bool waitForFunction
,
780 void *param1
, void *param2
,
781 void *param3
, void *param4
)
783 IOReturn result
= kIOReturnUnsupported
;
784 IOService
*provider
= getProvider();
787 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
788 param1
, param2
, param3
, param4
);
794 IOReturn
IOService::callPlatformFunction( const char * functionName
,
795 bool waitForFunction
,
796 void *param1
, void *param2
,
797 void *param3
, void *param4
)
799 IOReturn result
= kIOReturnNoMemory
;
800 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
802 if (functionSymbol
!= 0) {
803 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
804 param1
, param2
, param3
, param4
);
805 functionSymbol
->release();
813 * Accessors for global services
816 IOPlatformExpert
* IOService::getPlatform( void )
818 return( gIOPlatform
);
821 class IOPMrootDomain
* IOService::getPMRootDomain( void )
823 return( gIOPMRootDomain
);
826 IOService
* IOService::getResourceService( void )
828 return( gIOResources
);
831 void IOService::setPlatform( IOPlatformExpert
* platform
)
833 gIOPlatform
= platform
;
834 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
837 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
839 gIOPMRootDomain
= rootDomain
;
840 publishResource("IOKit");
847 bool IOService::lockForArbitration( bool isSuccessRequired
)
851 ArbitrationLockQueueElement
* element
;
852 ArbitrationLockQueueElement
* active
;
853 ArbitrationLockQueueElement
* waiting
;
855 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
857 // lock global access
858 IOTakeLock( gArbitrationLockQueueLock
);
860 // obtain an unused queue element
861 if( !queue_empty( &gArbitrationLockQueueFree
)) {
862 queue_remove_first( &gArbitrationLockQueueFree
,
864 ArbitrationLockQueueElement
*,
867 element
= IONew( ArbitrationLockQueueElement
, 1 );
871 // prepare the queue element
872 element
->thread
= IOThreadSelf();
873 element
->service
= this;
875 element
->required
= isSuccessRequired
;
876 element
->aborted
= false;
878 // determine whether this object is already locked (ie. on active queue)
880 queue_iterate( &gArbitrationLockQueueActive
,
882 ArbitrationLockQueueElement
*,
885 if( active
->service
== element
->service
) {
891 if( found
) { // this object is already locked
893 // determine whether it is the same or a different thread trying to lock
894 if( active
->thread
!= element
->thread
) { // it is a different thread
896 ArbitrationLockQueueElement
* victim
= 0;
898 // before placing this new thread on the waiting queue, we look for
899 // a deadlock cycle...
902 // determine whether the active thread holding the object we
903 // want is waiting for another object to be unlocked
905 queue_iterate( &gArbitrationLockQueueWaiting
,
907 ArbitrationLockQueueElement
*,
910 if( waiting
->thread
== active
->thread
) {
911 assert( false == waiting
->aborted
);
917 if( found
) { // yes, active thread waiting for another object
919 // this may be a candidate for rejection if the required
920 // flag is not set, should we detect a deadlock later on
921 if( false == waiting
->required
)
924 // find the thread that is holding this other object, that
925 // is blocking the active thread from proceeding (fun :-)
927 queue_iterate( &gArbitrationLockQueueActive
,
928 active
, // (reuse active queue element)
929 ArbitrationLockQueueElement
*,
932 if( active
->service
== waiting
->service
) {
938 // someone must be holding it or it wouldn't be waiting
941 if( active
->thread
== element
->thread
) {
943 // doh, it's waiting for the thread that originated
944 // this whole lock (ie. current thread) -> deadlock
945 if( false == element
->required
) { // willing to fail?
947 // the originating thread doesn't have the required
948 // flag, so it can fail
949 success
= false; // (fail originating lock request)
950 break; // (out of while)
952 } else { // originating thread is not willing to fail
954 // see if we came across a waiting thread that did
955 // not have the 'required' flag set: we'll fail it
958 // we do have a willing victim, fail it's lock
959 victim
->aborted
= true;
961 // take the victim off the waiting queue
962 queue_remove( &gArbitrationLockQueueWaiting
,
964 ArbitrationLockQueueElement
*,
968 IOLockWakeup( gArbitrationLockQueueLock
,
970 /* one thread */ true );
972 // allow this thread to proceed (ie. wait)
973 success
= true; // (put request on wait queue)
974 break; // (out of while)
977 // all the waiting threads we came across in
978 // finding this loop had the 'required' flag
979 // set, so we've got a deadlock we can't avoid
980 panic("I/O Kit: Unrecoverable deadlock.");
984 // repeat while loop, redefining active thread to be the
985 // thread holding "this other object" (see above), and
986 // looking for threads waiting on it; note the active
987 // variable points to "this other object" already... so
988 // there nothing to do in this else clause.
990 } else { // no, active thread is not waiting for another object
992 success
= true; // (put request on wait queue)
993 break; // (out of while)
997 if( success
) { // put the request on the waiting queue?
998 kern_return_t wait_result
;
1000 // place this thread on the waiting queue and put it to sleep;
1001 // we place it at the tail of the queue...
1002 queue_enter( &gArbitrationLockQueueWaiting
,
1004 ArbitrationLockQueueElement
*,
1007 // declare that this thread will wait for a given event
1008 restart_sleep
: wait_result
= assert_wait( element
,
1009 element
->required
? THREAD_UNINT
1010 : THREAD_INTERRUPTIBLE
);
1012 // unlock global access
1013 IOUnlock( gArbitrationLockQueueLock
);
1015 // put thread to sleep, waiting for our event to fire...
1016 if (wait_result
== THREAD_WAITING
)
1017 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1020 // ...and we've been woken up; we might be in one of two states:
1021 // (a) we've been aborted and our queue element is not on
1022 // any of the three queues, but is floating around
1023 // (b) we're allowed to proceed with the lock and we have
1024 // already been moved from the waiting queue to the
1026 // ...plus a 3rd state, should the thread have been interrupted:
1027 // (c) we're still on the waiting queue
1029 // determine whether we were interrupted out of our sleep
1030 if( THREAD_INTERRUPTED
== wait_result
) {
1032 // re-lock global access
1033 IOTakeLock( gArbitrationLockQueueLock
);
1035 // determine whether we're still on the waiting queue
1037 queue_iterate( &gArbitrationLockQueueWaiting
,
1038 waiting
, // (reuse waiting queue element)
1039 ArbitrationLockQueueElement
*,
1042 if( waiting
== element
) {
1048 if( found
) { // yes, we're still on the waiting queue
1050 // determine whether we're willing to fail
1051 if( false == element
->required
) {
1053 // mark us as aborted
1054 element
->aborted
= true;
1056 // take us off the waiting queue
1057 queue_remove( &gArbitrationLockQueueWaiting
,
1059 ArbitrationLockQueueElement
*,
1061 } else { // we are not willing to fail
1063 // ignore interruption, go back to sleep
1068 // unlock global access
1069 IOUnlock( gArbitrationLockQueueLock
);
1071 // proceed as though this were a normal wake up
1072 wait_result
= THREAD_AWAKENED
;
1075 assert( THREAD_AWAKENED
== wait_result
);
1077 // determine whether we've been aborted while we were asleep
1078 if( element
->aborted
) {
1079 assert( false == element
->required
);
1081 // re-lock global access
1082 IOTakeLock( gArbitrationLockQueueLock
);
1084 action
= kPutOnFreeQueue
;
1086 } else { // we weren't aborted, so we must be ready to go :-)
1088 // we've already been moved from waiting to active queue
1092 } else { // the lock request is to be failed
1094 // return unused queue element to queue
1095 action
= kPutOnFreeQueue
;
1097 } else { // it is the same thread, recursive access is allowed
1099 // add one level of recursion
1102 // return unused queue element to queue
1103 action
= kPutOnFreeQueue
;
1106 } else { // this object is not already locked, so let this thread through
1107 action
= kPutOnActiveQueue
;
1111 // put the new element on a queue
1112 if( kPutOnActiveQueue
== action
) {
1113 queue_enter( &gArbitrationLockQueueActive
,
1115 ArbitrationLockQueueElement
*,
1117 } else if( kPutOnFreeQueue
== action
) {
1118 queue_enter( &gArbitrationLockQueueFree
,
1120 ArbitrationLockQueueElement
*,
1123 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1126 // unlock global access
1127 IOUnlock( gArbitrationLockQueueLock
);
1132 void IOService::unlockForArbitration( void )
1135 ArbitrationLockQueueElement
* element
;
1137 // lock global access
1138 IOTakeLock( gArbitrationLockQueueLock
);
1140 // find the lock element for this object (ie. on active queue)
1142 queue_iterate( &gArbitrationLockQueueActive
,
1144 ArbitrationLockQueueElement
*,
1147 if( element
->service
== this ) {
1155 // determine whether the lock has been taken recursively
1156 if( element
->count
> 1 ) {
1157 // undo one level of recursion
1162 // remove it from the active queue
1163 queue_remove( &gArbitrationLockQueueActive
,
1165 ArbitrationLockQueueElement
*,
1168 // put it on the free queue
1169 queue_enter( &gArbitrationLockQueueFree
,
1171 ArbitrationLockQueueElement
*,
1174 // determine whether a thread is waiting for object (head to tail scan)
1176 queue_iterate( &gArbitrationLockQueueWaiting
,
1178 ArbitrationLockQueueElement
*,
1181 if( element
->service
== this ) {
1187 if ( found
) { // we found an interested thread on waiting queue
1189 // remove it from the waiting queue
1190 queue_remove( &gArbitrationLockQueueWaiting
,
1192 ArbitrationLockQueueElement
*,
1195 // put it on the active queue
1196 queue_enter( &gArbitrationLockQueueActive
,
1198 ArbitrationLockQueueElement
*,
1201 // wake the waiting thread
1202 IOLockWakeup( gArbitrationLockQueueLock
,
1204 /* one thread */ true );
1208 // unlock global access
1209 IOUnlock( gArbitrationLockQueueLock
);
1212 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1215 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1216 context
, gIOServicePlane
);
1219 void IOService::applyToClients( IOServiceApplierFunction applier
,
1222 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1223 context
, gIOServicePlane
);
1232 // send a message to a client or interested party of this service
1233 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1234 void * argument
, vm_size_t argSize
)
1237 IOService
* service
;
1238 _IOServiceInterestNotifier
* notify
;
1240 if( (service
= OSDynamicCast( IOService
, client
)))
1241 ret
= service
->message( type
, this, argument
);
1243 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1245 _IOServiceNotifierInvocation invocation
;
1248 invocation
.thread
= current_thread();
1251 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1254 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1255 _IOServiceNotifierInvocation
*, link
);
1261 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1262 type
, this, argument
, argSize
);
1265 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1266 _IOServiceNotifierInvocation
*, link
);
1267 if( kIOServiceNotifyWaiter
& notify
->state
) {
1268 notify
->state
&= ~kIOServiceNotifyWaiter
;
1269 WAKEUPNOTIFY( notify
);
1274 ret
= kIOReturnSuccess
;
1277 ret
= kIOReturnBadArgument
;
1282 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1283 OSObjectApplierFunction applier
,
1286 OSArray
* copyArray
= 0;
1288 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1292 IOCommand
*notifyList
=
1293 OSDynamicCast( IOCommand
, getProperty( typeOfInterest
));
1296 copyArray
= OSArray::withCapacity(1);
1298 // iterate over queue, entry is set to each element in the list
1299 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1300 _IOServiceInterestNotifier
* notify
;
1302 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1303 copyArray
->setObject(notify
);
1312 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1313 (*applier
)(next
, context
);
1314 copyArray
->release();
1318 struct MessageClientsContext
{
1319 IOService
* service
;
1326 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1329 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1331 ret
= context
->service
->messageClient( context
->type
,
1332 object
, context
->argument
, context
->argSize
);
1333 if( kIOReturnSuccess
!= ret
)
1337 // send a message to all clients
1338 IOReturn
IOService::messageClients( UInt32 type
,
1339 void * argument
, vm_size_t argSize
)
1341 MessageClientsContext context
;
1343 context
.service
= this;
1344 context
.type
= type
;
1345 context
.argument
= argument
;
1346 context
.argSize
= argSize
;
1347 context
.ret
= kIOReturnSuccess
;
1349 applyToInterested( gIOGeneralInterest
,
1350 &messageClientsApplier
, &context
);
1352 return( context
.ret
);
1355 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1356 IOOptionBits response
)
1358 return( kIOReturnUnsupported
);
1361 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1362 IOServiceInterestHandler handler
, void * target
, void * ref
)
1364 _IOServiceInterestNotifier
* notify
= 0;
1366 if( (typeOfInterest
!= gIOGeneralInterest
)
1367 && (typeOfInterest
!= gIOBusyInterest
)
1368 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1369 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1372 lockForArbitration();
1373 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1375 notify
= new _IOServiceInterestNotifier
;
1376 if( notify
&& !notify
->init()) {
1382 notify
->handler
= handler
;
1383 notify
->target
= target
;
1385 notify
->state
= kIOServiceNotifyEnable
;
1386 queue_init( ¬ify
->handlerInvocations
);
1392 // Get the head of the notifier linked list
1393 IOCommand
*notifyList
= (IOCommand
*) getProperty( typeOfInterest
);
1394 if (!notifyList
|| !OSDynamicCast(IOCommand
, notifyList
)) {
1395 notifyList
= OSTypeAlloc(IOCommand
);
1398 setProperty( typeOfInterest
, notifyList
);
1399 notifyList
->release();
1404 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1405 notify
->retain(); // ref'ed while in list
1411 unlockForArbitration();
1416 static void cleanInterestList( OSObject
* head
)
1418 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1423 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1424 queue_next(entry
) = queue_prev(entry
) = 0;
1426 _IOServiceInterestNotifier
* notify
;
1428 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1434 void IOService::unregisterAllInterest( void )
1436 cleanInterestList( getProperty( gIOGeneralInterest
));
1437 cleanInterestList( getProperty( gIOBusyInterest
));
1438 cleanInterestList( getProperty( gIOAppPowerStateInterest
));
1439 cleanInterestList( getProperty( gIOPriorityPowerStateInterest
));
1443 * _IOServiceInterestNotifier
1446 // wait for all threads, other than the current one,
1447 // to exit the handler
1449 void _IOServiceInterestNotifier::wait()
1451 _IOServiceNotifierInvocation
* next
;
1456 queue_iterate( &handlerInvocations
, next
,
1457 _IOServiceNotifierInvocation
*, link
) {
1458 if( next
->thread
!= current_thread() ) {
1464 state
|= kIOServiceNotifyWaiter
;
1471 void _IOServiceInterestNotifier::free()
1473 assert( queue_empty( &handlerInvocations
));
1477 void _IOServiceInterestNotifier::remove()
1481 if( queue_next( &chain
)) {
1482 remqueue( 0, &chain
);
1483 queue_next( &chain
) = queue_prev( &chain
) = 0;
1487 state
&= ~kIOServiceNotifyEnable
;
1496 bool _IOServiceInterestNotifier::disable()
1502 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1503 state
&= ~kIOServiceNotifyEnable
;
1512 void _IOServiceInterestNotifier::enable( bool was
)
1516 state
|= kIOServiceNotifyEnable
;
1518 state
&= ~kIOServiceNotifyEnable
;
1522 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1528 #define tailQ(o) setObject(o)
1529 #define headQ(o) setObject(0, o)
1530 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); }
1532 inline void _workLoopAction( IOWorkLoop::Action action
,
1533 IOService
* service
,
1534 void * p0
= 0, void * p1
= 0,
1535 void * p2
= 0, void * p3
= 0 )
1539 if( (wl
= service
->getWorkLoop())) {
1541 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1544 (*action
)( service
, p0
, p1
, p2
, p3
);
1547 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1551 // if its our only provider
1552 ok
= isParent( provider
, gIOServicePlane
, true);
1556 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1557 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1564 bool IOService::terminatePhase1( IOOptionBits options
)
1569 OSArray
* makeInactive
;
1572 bool startPhase2
= false;
1574 TLOG("%s::terminatePhase1(%08lx)\n", getName(), options
);
1577 if( options
& kIOServiceRecursing
) {
1578 __state
[1] |= kIOServiceRecursing
;
1583 makeInactive
= OSArray::withCapacity( 16 );
1592 didInactive
= victim
->lockForArbitration( true );
1594 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1596 victim
->__state
[0] |= kIOServiceInactiveState
;
1597 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1598 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1599 victim
->_adjustBusy( 1 );
1601 victim
->unlockForArbitration();
1604 startPhase2
= didInactive
;
1607 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1608 IOUserClient::destroyUserReferences( victim
);
1610 iter
= victim
->getClientIterator();
1612 while( (client
= (IOService
*) iter
->getNextObject())) {
1613 TLOG("%s::requestTerminate(%s, %08lx)\n",
1614 client
->getName(), victim
->getName(), options
);
1615 ok
= client
->requestTerminate( victim
, options
);
1616 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1617 client
->getName(), victim
->getName(), ok
);
1619 makeInactive
->setObject( client
);
1625 victim
= (IOService
*) makeInactive
->getObject(0);
1628 makeInactive
->removeObject(0);
1632 makeInactive
->release();
1635 scheduleTerminatePhase2( options
);
1640 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
1642 AbsoluteTime deadline
;
1643 int waitResult
= THREAD_AWAKENED
;
1644 bool wait
, haveDeadline
= false;
1646 options
|= kIOServiceRequired
;
1650 IOLockLock( gJobsLock
);
1652 if( (options
& kIOServiceSynchronous
)
1653 && (current_thread() != gIOTerminateThread
)) {
1656 wait
= (gIOTerminateThread
!= 0);
1658 // wait to become the terminate thread
1659 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
1663 gIOTerminateThread
= current_thread();
1664 gIOTerminatePhase2List
->setObject( this );
1668 while( gIOTerminateWork
)
1669 terminateWorker( options
);
1670 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1672 // wait for the victim to go non-busy
1673 if( !haveDeadline
) {
1674 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1675 haveDeadline
= true;
1677 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
1678 deadline
, THREAD_UNINT
);
1679 if( waitResult
== THREAD_TIMED_OUT
) {
1680 TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName());
1683 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
1685 gIOTerminateThread
= 0;
1686 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1689 // ! kIOServiceSynchronous
1691 gIOTerminatePhase2List
->setObject( this );
1692 if( 0 == gIOTerminateWork
++) {
1693 if( !gIOTerminateThread
)
1694 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) options
);
1696 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1700 IOLockUnlock( gJobsLock
);
1705 void IOService::terminateThread( void * arg
)
1707 IOLockLock( gJobsLock
);
1709 while (gIOTerminateWork
)
1710 terminateWorker( (IOOptionBits
) arg
);
1712 gIOTerminateThread
= 0;
1713 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1715 IOLockUnlock( gJobsLock
);
1718 void IOService::scheduleStop( IOService
* provider
)
1720 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1722 IOLockLock( gJobsLock
);
1723 gIOStopList
->tailQ( this );
1724 gIOStopProviderList
->tailQ( provider
);
1726 if( 0 == gIOTerminateWork
++) {
1727 if( !gIOTerminateThread
)
1728 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1730 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1733 IOLockUnlock( gJobsLock
);
1736 void IOService::scheduleFinalize( void )
1738 TLOG("%s::scheduleFinalize\n", getName());
1740 IOLockLock( gJobsLock
);
1741 gIOFinalizeList
->tailQ( this );
1743 if( 0 == gIOTerminateWork
++) {
1744 if( !gIOTerminateThread
)
1745 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1747 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1750 IOLockUnlock( gJobsLock
);
1753 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1758 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1760 if( false == *defer
) {
1762 if( lockForArbitration( true )) {
1763 if( false == provider
->handleIsOpen( this ))
1764 scheduleStop( provider
);
1767 message( kIOMessageServiceIsRequestingClose
, provider
, (void *) options
);
1768 if( false == provider
->handleIsOpen( this ))
1769 scheduleStop( provider
);
1772 unlockForArbitration();
1779 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
1780 OSArray
* doPhase2List
)
1786 iter
= victim
->getClientIterator();
1788 while( (client
= (IOService
*) iter
->getNextObject())) {
1789 TLOG("%s::willTerminate(%s, %08lx)\n",
1790 client
->getName(), victim
->getName(), options
);
1791 ok
= client
->willTerminate( victim
, options
);
1792 doPhase2List
->tailQ( client
);
1798 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
)
1804 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *) options
);
1806 iter
= victim
->getClientIterator();
1808 while( (client
= (IOService
*) iter
->getNextObject())) {
1809 TLOG("%s::didTerminate(%s, %08lx)\n",
1810 client
->getName(), victim
->getName(), options
);
1811 client
->didTerminate( victim
, options
, &defer
);
1812 TLOG("%s::didTerminate(%s, defer %d)\n",
1813 client
->getName(), victim
->getName(), defer
);
1819 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
)
1821 TLOG("%s::finalize(%08lx)\n", victim
->getName(), options
);
1822 victim
->finalize( options
);
1825 void IOService::actionStop( IOService
* provider
, IOService
* client
)
1827 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
1828 client
->stop( provider
);
1829 if( provider
->isOpen( client
))
1830 provider
->close( client
);
1831 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
1832 client
->detach( provider
);
1835 void IOService::terminateWorker( IOOptionBits options
)
1837 OSArray
* doPhase2List
;
1838 OSArray
* didPhase2List
;
1843 IOService
* provider
;
1849 options
|= kIOServiceRequired
;
1851 doPhase2List
= OSArray::withCapacity( 16 );
1852 didPhase2List
= OSArray::withCapacity( 16 );
1853 freeList
= OSSet::withCapacity( 16 );
1854 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
1858 workDone
= gIOTerminateWork
;
1860 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
1863 gIOTerminatePhase2List
->removeObject(0);
1864 IOLockUnlock( gJobsLock
);
1868 doPhase2
= victim
->lockForArbitration( true );
1870 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
1872 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
1873 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
1875 victim
->__state
[1] |= kIOServiceTermPhase2State
;
1877 victim
->unlockForArbitration();
1880 if( 0 == victim
->getClient()) {
1881 // no clients - will go to finalize
1882 IOLockLock( gJobsLock
);
1883 gIOFinalizeList
->tailQ( victim
);
1884 IOLockUnlock( gJobsLock
);
1886 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
1887 victim
, (void *) options
, (void *) doPhase2List
);
1889 didPhase2List
->headQ( victim
);
1892 victim
= (IOService
*) doPhase2List
->getObject(0);
1895 doPhase2List
->removeObject(0);
1899 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
1901 if( victim
->lockForArbitration( true )) {
1902 victim
->__state
[1] |= kIOServiceTermPhase3State
;
1903 victim
->unlockForArbitration();
1905 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
1906 victim
, (void *) options
);
1907 didPhase2List
->removeObject(0);
1909 IOLockLock( gJobsLock
);
1916 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
1918 IOLockUnlock( gJobsLock
);
1919 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
1920 victim
, (void *) options
);
1921 IOLockLock( gJobsLock
);
1923 freeList
->setObject( victim
);
1924 // safe if finalize list is append only
1925 gIOFinalizeList
->removeObject(0);
1929 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
1931 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
1934 if( !provider
->isChild( client
, gIOServicePlane
)) {
1935 // may be multiply queued - nop it
1936 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
1938 // not ready for stop if it has clients, skip it
1939 if( (client
->__state
[1] & kIOServiceTermPhase3State
) && client
->getClient()) {
1940 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
1945 IOLockUnlock( gJobsLock
);
1946 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
1947 provider
, (void *) client
);
1948 IOLockLock( gJobsLock
);
1949 // check the finalize list now
1953 freeList
->setObject( client
);
1954 freeList
->setObject( provider
);
1956 // safe if stop list is append only
1957 gIOStopList
->removeObject( idx
);
1958 gIOStopProviderList
->removeObject( idx
);
1962 } while( doPhase3
);
1964 gIOTerminateWork
-= workDone
;
1965 moreToDo
= (gIOTerminateWork
!= 0);
1968 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
1971 } while( moreToDo
);
1973 IOLockUnlock( gJobsLock
);
1975 freeList
->release();
1976 doPhase2List
->release();
1977 didPhase2List
->release();
1979 IOLockLock( gJobsLock
);
1982 bool IOService::finalize( IOOptionBits options
)
1985 IOService
* provider
;
1987 iter
= getProviderIterator();
1991 while( (provider
= (IOService
*) iter
->getNextObject())) {
1994 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
1995 /* we come down here on programmatic terminate */
1997 if( provider
->isOpen( this ))
1998 provider
->close( this );
2002 if( provider
->lockForArbitration( true )) {
2003 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2004 scheduleStop( provider
);
2005 provider
->unlockForArbitration();
2022 void IOService::doServiceTerminate( IOOptionBits options
)
2026 // a method in case someone needs to override it
2027 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2031 if( client
->isParent( this, gIOServicePlane
, true))
2032 // we are the clients only provider
2033 ok
= client
->terminate( options
);
2040 bool IOService::terminate( IOOptionBits options
)
2042 options
|= kIOServiceTerminate
;
2044 return( terminatePhase1( options
));
2047 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2053 struct ServiceOpenMessageContext
2055 IOService
* service
;
2057 IOService
* excludeClient
;
2058 IOOptionBits options
;
2061 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2063 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2065 if( object
!= context
->excludeClient
)
2066 context
->service
->messageClient( context
->type
, object
, (void *) context
->options
);
2069 bool IOService::open( IOService
* forClient
,
2070 IOOptionBits options
,
2074 ServiceOpenMessageContext context
;
2076 context
.service
= this;
2077 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2078 context
.excludeClient
= forClient
;
2079 context
.options
= options
;
2081 applyToInterested( gIOGeneralInterest
,
2082 &serviceOpenMessageApplier
, &context
);
2084 if( false == lockForArbitration(false) )
2087 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2089 ok
= handleOpen( forClient
, options
, arg
);
2091 unlockForArbitration();
2096 void IOService::close( IOService
* forClient
,
2097 IOOptionBits options
)
2102 lockForArbitration();
2104 wasClosed
= handleIsOpen( forClient
);
2106 handleClose( forClient
, options
);
2107 last
= (__state
[1] & kIOServiceTermPhase3State
);
2110 unlockForArbitration();
2113 forClient
->scheduleStop( this );
2115 else if( wasClosed
) {
2117 ServiceOpenMessageContext context
;
2119 context
.service
= this;
2120 context
.type
= kIOMessageServiceWasClosed
;
2121 context
.excludeClient
= forClient
;
2122 context
.options
= options
;
2124 applyToInterested( gIOGeneralInterest
,
2125 &serviceOpenMessageApplier
, &context
);
2129 bool IOService::isOpen( const IOService
* forClient
) const
2131 IOService
* self
= (IOService
*) this;
2134 self
->lockForArbitration();
2136 ok
= handleIsOpen( forClient
);
2138 self
->unlockForArbitration();
2143 bool IOService::handleOpen( IOService
* forClient
,
2144 IOOptionBits options
,
2149 ok
= (0 == __owner
);
2151 __owner
= forClient
;
2153 else if( options
& kIOServiceSeize
) {
2154 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2155 __owner
, (void *) options
));
2156 if( ok
&& (0 == __owner
))
2157 __owner
= forClient
;
2164 void IOService::handleClose( IOService
* forClient
,
2165 IOOptionBits options
)
2167 if( __owner
== forClient
)
2171 bool IOService::handleIsOpen( const IOService
* forClient
) const
2174 return( __owner
== forClient
);
2176 return( __owner
!= forClient
);
2180 * Probing & starting
2182 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2184 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2185 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2193 val1
= obj1
->priority
;
2196 val2
= obj2
->priority
;
2198 return ( val1
- val2
);
2201 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2203 OSDictionary
* dict
;
2204 IOService
* service
;
2205 _IOServiceNotifier
* notify
;
2206 OSSymbol
* key
= (OSSymbol
*) ref
;
2209 if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2210 return( notify
->priority
);
2212 else if( (service
= OSDynamicCast( IOService
, entry
)))
2213 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2214 else if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2215 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2222 return( (SInt32
) offset
->unsigned32BitValue());
2224 return( kIODefaultProbeScore
);
2227 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2229 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2230 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2238 val1
= IOServiceObjectOrder( obj1
, ref
);
2241 val2
= IOServiceObjectOrder( obj2
, ref
);
2243 return ( val1
- val2
);
2246 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2248 IOService
* service
= 0;
2250 const OSSymbol
* nextCat
;
2252 iter
= getClientIterator();
2254 while( (service
= (IOService
*) iter
->getNextObject())) {
2255 if( kIOServiceInactiveState
& service
->__state
[0])
2257 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2258 service
->getProperty( gIOMatchCategoryKey
));
2259 if( category
== nextCat
)
2267 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2269 _IOServiceNotifierInvocation invocation
;
2273 invocation
.thread
= current_thread();
2276 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2279 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2280 _IOServiceNotifierInvocation
*, link
);
2286 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
, this );
2289 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2290 _IOServiceNotifierInvocation
*, link
);
2291 if( kIOServiceNotifyWaiter
& notify
->state
) {
2292 notify
->state
&= ~kIOServiceNotifyWaiter
;
2293 WAKEUPNOTIFY( notify
);
2302 * Alloc and probe matching classes,
2303 * called on the provider instance
2306 void IOService::probeCandidates( OSOrderedSet
* matches
)
2308 OSDictionary
* match
= 0;
2311 IOService
* newInst
;
2312 OSDictionary
* props
;
2315 OSOrderedSet
* familyMatches
= 0;
2316 OSOrderedSet
* startList
;
2317 OSDictionary
* startDict
= 0;
2318 const OSSymbol
* category
;
2320 _IOServiceNotifier
* notify
;
2321 OSObject
* nextMatch
= 0;
2323 bool needReloc
= false;
2329 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2331 nextMatch
->retain();
2332 matches
->removeObject(nextMatch
);
2334 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2336 lockForArbitration();
2337 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2338 invokeNotifer( notify
);
2339 unlockForArbitration();
2340 nextMatch
->release();
2344 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2345 nextMatch
->release();
2352 debugFlags
= getDebugFlags( match
);
2356 category
= OSDynamicCast( OSSymbol
,
2357 match
->getObject( gIOMatchCategoryKey
));
2359 category
= gIODefaultMatchCategoryKey
;
2361 if( getClientWithCategory( category
)) {
2363 if( debugFlags
& kIOLogMatch
)
2364 LOG("%s: match category %s exists\n", getName(),
2365 category
->getCStringNoCopy());
2367 nextMatch
->release();
2372 // create a copy now in case its modified during matching
2373 props
= OSDictionary::withDictionary( match
, match
->getCount());
2376 props
->setCapacityIncrement(1);
2378 // check the nub matches
2379 if( false == passiveMatch( props
, true ))
2382 // Check to see if driver reloc has been loaded.
2383 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2386 if( debugFlags
& kIOLogCatalogue
)
2387 LOG("%s: stalling for module\n", getName());
2389 // If reloc hasn't been loaded, exit;
2390 // reprobing will occur after reloc has been loaded.
2394 // reorder on family matchPropertyTable score.
2395 if( 0 == familyMatches
)
2396 familyMatches
= OSOrderedSet::withCapacity( 1,
2397 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2399 familyMatches
->setObject( props
);
2404 nextMatch
->release();
2413 if( familyMatches
) {
2416 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2419 familyMatches
->removeObject( props
);
2424 debugFlags
= getDebugFlags( props
);
2427 symbol
= OSDynamicCast( OSSymbol
,
2428 props
->getObject( gIOClassKey
));
2432 // alloc the driver instance
2433 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2436 IOLog("Couldn't alloc class \"%s\"\n",
2437 symbol
->getCStringNoCopy());
2441 // init driver instance
2442 if( !(inst
->init( props
))) {
2444 if( debugFlags
& kIOLogStart
)
2445 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2449 if( __state
[1] & kIOServiceSynchronousState
)
2450 inst
->__state
[1] |= kIOServiceSynchronousState
;
2452 // give the driver the default match category if not specified
2453 category
= OSDynamicCast( OSSymbol
,
2454 props
->getObject( gIOMatchCategoryKey
));
2456 category
= gIODefaultMatchCategoryKey
;
2457 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2459 // attach driver instance
2460 if( !(inst
->attach( this )))
2463 // pass in score from property table
2464 score
= familyMatches
->orderObject( props
);
2466 // & probe the new driver instance
2468 if( debugFlags
& kIOLogProbe
)
2469 LOG("%s::probe(%s)\n",
2470 inst
->getMetaClass()->getClassName(), getName());
2473 newInst
= inst
->probe( this, &score
);
2474 inst
->detach( this );
2477 if( debugFlags
& kIOLogProbe
)
2478 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2484 newPri
= OSNumber::withNumber( score
, 32 );
2486 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2490 // add to start list for the match category
2492 startDict
= OSDictionary::withCapacity( 1 );
2493 assert( startDict
);
2494 startList
= (OSOrderedSet
*)
2495 startDict
->getObject( category
);
2496 if( 0 == startList
) {
2497 startList
= OSOrderedSet::withCapacity( 1,
2498 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2499 if( startDict
&& startList
) {
2500 startDict
->setObject( category
, startList
);
2501 startList
->release();
2504 assert( startList
);
2506 startList
->setObject( newInst
);
2514 familyMatches
->release();
2518 // start the best (until success) of each category
2520 iter
= OSCollectionIterator::withCollection( startDict
);
2522 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2524 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2525 assert( startList
);
2530 while( true // (!started)
2531 && (inst
= (IOService
*)startList
->getFirstObject())) {
2534 startList
->removeObject(inst
);
2537 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2539 if( debugFlags
& kIOLogStart
) {
2541 LOG( "match category exists, skipping " );
2542 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2543 getName(), inst
->getRetainCount());
2546 if( false == started
)
2547 started
= startCandidate( inst
);
2549 if( (debugFlags
& kIOLogStart
) && (false == started
))
2550 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2551 inst
->getRetainCount());
2560 // adjust the busy count by -1 if matching is stalled for a module,
2561 // or +1 if a previously stalled matching is complete.
2562 lockForArbitration();
2565 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2567 __state
[1] |= kIOServiceModuleStallState
;
2569 } else if( __state
[1] & kIOServiceModuleStallState
) {
2570 __state
[1] &= ~kIOServiceModuleStallState
;
2574 _adjustBusy( adjBusy
);
2575 unlockForArbitration();
2578 startDict
->release();
2582 * Start a previously attached & probed instance,
2583 * called on exporting object instance
2586 bool IOService::startCandidate( IOService
* service
)
2590 ok
= service
->attach( this );
2594 if (this != gIOResources
)
2596 // stall for any nub resources
2598 // stall for any driver resources
2599 service
->checkResources();
2602 AbsoluteTime startTime
;
2603 AbsoluteTime endTime
;
2606 if (kIOLogStart
& gIOKitDebug
)
2607 clock_get_uptime(&startTime
);
2609 ok
= service
->start(this);
2611 if (kIOLogStart
& gIOKitDebug
)
2613 clock_get_uptime(&endTime
);
2615 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2617 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2618 absolutetime_to_nanoseconds(endTime
, &nano
);
2619 if (nano
> 500000000ULL)
2620 IOLog("%s::start took %ld ms\n", service
->getName(), (UInt32
)(nano
/ 1000000ULL));
2624 service
->detach( this );
2629 IOService
* IOService::resources( void )
2631 return( gIOResources
);
2634 void IOService::publishResource( const char * key
, OSObject
* value
)
2636 const OSSymbol
* sym
;
2638 if( (sym
= OSSymbol::withCString( key
))) {
2639 publishResource( sym
, value
);
2644 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
2647 value
= (OSObject
*) gIOServiceKey
;
2649 gIOResources
->setProperty( key
, value
);
2651 if( IORecursiveLockHaveLock( gNotificationLock
))
2654 gIOResourceGenerationCount
++;
2655 gIOResources
->registerService();
2658 bool IOService::addNeededResource( const char * key
)
2660 OSObject
* resourcesProp
;
2665 resourcesProp
= getProperty( gIOResourceMatchKey
);
2667 newKey
= OSString::withCString( key
);
2668 if( (0 == resourcesProp
) || (0 == newKey
))
2671 set
= OSDynamicCast( OSSet
, resourcesProp
);
2673 set
= OSSet::withCapacity( 1 );
2675 set
->setObject( resourcesProp
);
2680 set
->setObject( newKey
);
2682 ret
= setProperty( gIOResourceMatchKey
, set
);
2688 bool IOService::checkResource( OSObject
* matching
)
2691 OSDictionary
* table
;
2693 if( (str
= OSDynamicCast( OSString
, matching
))) {
2694 if( gIOResources
->getProperty( str
))
2699 table
= resourceMatching( str
);
2700 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
2703 IOLog("%s: Can't match using: %s\n", getName(),
2704 matching
->getMetaClass()->getClassName());
2705 /* false would stall forever */
2709 if( gIOKitDebug
& kIOLogConfig
)
2710 LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName());
2712 waitForService( table
);
2714 if( gIOKitDebug
& kIOLogConfig
)
2715 LOG("config(%x): waking\n", (int) IOThreadSelf() );
2720 bool IOService::checkResources( void )
2722 OSObject
* resourcesProp
;
2727 resourcesProp
= getProperty( gIOResourceMatchKey
);
2728 if( 0 == resourcesProp
)
2731 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
2733 iter
= OSCollectionIterator::withCollection( set
);
2735 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
2736 ok
= checkResource( resourcesProp
);
2741 ok
= checkResource( resourcesProp
);
2747 void _IOConfigThread::configThread( void )
2749 _IOConfigThread
* inst
;
2752 if( !(inst
= new _IOConfigThread
))
2756 if( !(IOCreateThread((IOThreadFunc
) &_IOConfigThread::main
, inst
)))
2769 void _IOConfigThread::free( void )
2774 void IOService::doServiceMatch( IOOptionBits options
)
2776 _IOServiceNotifier
* notify
;
2778 OSOrderedSet
* matches
;
2779 SInt32 catalogGeneration
;
2780 bool keepGuessing
= true;
2781 bool reRegistered
= true;
2783 // job->nub->deliverNotification( gIOPublishNotification,
2784 // kIOServiceRegisteredState, 0xffffffff );
2786 while( keepGuessing
) {
2788 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
2789 // the matches list should always be created by findDrivers()
2792 lockForArbitration();
2793 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
2794 deliverNotification( gIOFirstPublishNotification
,
2795 kIOServiceFirstPublishState
, 0xffffffff );
2797 __state
[1] &= ~kIOServiceNeedConfigState
;
2798 __state
[1] |= kIOServiceConfigState
;
2799 __state
[0] |= kIOServiceRegisteredState
;
2801 if( reRegistered
&& (0 == (__state
[0] & kIOServiceInactiveState
))) {
2803 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
2804 gNotifications
->getObject( gIOPublishNotification
) );
2806 while((notify
= (_IOServiceNotifier
*)
2807 iter
->getNextObject())) {
2809 if( passiveMatch( notify
->matching
)
2810 && (kIOServiceNotifyEnable
& notify
->state
))
2811 matches
->setObject( notify
);
2818 unlockForArbitration();
2820 if( matches
->getCount() && (kIOReturnSuccess
== getResources()))
2821 probeCandidates( matches
);
2826 lockForArbitration();
2827 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
2829 (reRegistered
|| (catalogGeneration
!=
2830 gIOCatalogue
->getGenerationCount()))
2831 && (0 == (__state
[0] & kIOServiceInactiveState
));
2834 unlockForArbitration();
2837 if( (0 == (__state
[0] & kIOServiceInactiveState
))
2838 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
2839 deliverNotification( gIOMatchedNotification
,
2840 kIOServiceMatchedState
, 0xffffffff );
2841 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
2842 deliverNotification( gIOFirstMatchNotification
,
2843 kIOServiceFirstMatchState
, 0xffffffff );
2846 __state
[1] &= ~kIOServiceConfigState
;
2847 if( __state
[0] & kIOServiceInactiveState
)
2848 scheduleTerminatePhase2();
2851 unlockForArbitration();
2854 UInt32
IOService::_adjustBusy( SInt32 delta
)
2859 bool wasQuiet
, nowQuiet
, needWake
;
2862 result
= __state
[1] & kIOServiceBusyStateMask
;
2866 next
->lockForArbitration();
2867 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
2868 assert( count
< kIOServiceBusyMax
);
2869 wasQuiet
= (0 == count
);
2870 assert( (!wasQuiet
) || (delta
> 0));
2871 next
->__state
[1] += delta
;
2872 nowQuiet
= (0 == (next
->__state
[1] & kIOServiceBusyStateMask
));
2873 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
2876 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
2877 IOLockLock( gIOServiceBusyLock
);
2878 thread_wakeup( (event_t
) next
);
2879 IOLockUnlock( gIOServiceBusyLock
);
2882 next
->unlockForArbitration();
2884 if( (wasQuiet
|| nowQuiet
) ) {
2887 OSObject
* interested
;
2889 array
= OSDynamicCast( OSArray
, next
->getProperty( gIOBusyInterest
));
2893 (interested
= array
->getObject( index
));
2895 next
->messageClient(kIOMessageServiceBusyStateChange
,
2896 interested
, (void *) wasQuiet
/* busy now */);
2901 if( nowQuiet
&& (next
== gIOServiceRoot
))
2902 OSMetaClass::considerUnloads();
2905 delta
= nowQuiet
? -1 : +1;
2907 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
2912 void IOService::adjustBusy( SInt32 delta
)
2914 lockForArbitration();
2915 _adjustBusy( delta
);
2916 unlockForArbitration();
2919 UInt32
IOService::getBusyState( void )
2921 return( __state
[1] & kIOServiceBusyStateMask
);
2924 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
2925 mach_timespec_t
* timeout
)
2928 int waitResult
= THREAD_AWAKENED
;
2929 bool computeDeadline
= true;
2930 AbsoluteTime abstime
;
2933 lockForArbitration();
2934 IOLockLock( gIOServiceBusyLock
);
2935 wait
= (value
!= (__state
[1] & mask
));
2937 __state
[1] |= kIOServiceBusyWaiterState
;
2938 unlockForArbitration();
2940 if( computeDeadline
) {
2941 AbsoluteTime nsinterval
;
2942 clock_interval_to_absolutetime_interval(
2943 timeout
->tv_sec
, kSecondScale
, &abstime
);
2944 clock_interval_to_absolutetime_interval(
2945 timeout
->tv_nsec
, kNanosecondScale
, &nsinterval
);
2946 ADD_ABSOLUTETIME( &abstime
, &nsinterval
);
2947 clock_absolutetime_interval_to_deadline(
2948 abstime
, &abstime
);
2949 computeDeadline
= false;
2952 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
2955 assert_wait((event_t
)this, THREAD_UNINT
);
2957 unlockForArbitration();
2958 IOLockUnlock( gIOServiceBusyLock
);
2960 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2962 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2964 if( waitResult
== THREAD_TIMED_OUT
)
2965 return( kIOReturnTimeout
);
2967 return( kIOReturnSuccess
);
2970 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
2972 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
2975 bool IOService::serializeProperties( OSSerialize
* s
) const
2978 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
2979 sizeof( __state
), "__state");
2981 return( super::serializeProperties(s
) );
2985 void _IOConfigThread::main( _IOConfigThread
* self
)
2987 _IOServiceJob
* job
;
2995 semaphore_wait( gJobsSemaphore
);
2997 IOTakeLock( gJobsLock
);
2998 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
3000 gJobs
->removeObject(job
);
3003 // gNumConfigThreads--; // we're out of service
3004 gNumWaitingThreads
--; // we're out of service
3006 IOUnlock( gJobsLock
);
3012 if( gIOKitDebug
& kIOLogConfig
)
3013 LOG("config(%x): starting on %s, %d\n",
3014 (int) IOThreadSelf(), job
->nub
->getName(), job
->type
);
3016 switch( job
->type
) {
3019 nub
->doServiceMatch( job
->options
);
3023 LOG("config(%x): strange type (%d)\n",
3024 (int) IOThreadSelf(), job
->type
);
3031 IOTakeLock( gJobsLock
);
3032 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
3034 gNumWaitingThreads
++; // back in service
3035 // gNumConfigThreads++;
3037 if( 0 == --gNumConfigThreads
) {
3038 // IOLog("MATCH IDLE\n");
3039 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3042 IOUnlock( gJobsLock
);
3047 if( gIOKitDebug
& kIOLogConfig
)
3048 LOG("config(%x): terminating\n", (int) IOThreadSelf() );
3053 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3056 int waitResult
= THREAD_AWAKENED
;
3057 bool computeDeadline
= true;
3058 AbsoluteTime abstime
;
3060 IOLockLock( gJobsLock
);
3062 wait
= (0 != gNumConfigThreads
);
3065 if( computeDeadline
) {
3066 clock_interval_to_absolutetime_interval(
3067 msToWait
, kMillisecondScale
, &abstime
);
3068 clock_absolutetime_interval_to_deadline(
3069 abstime
, &abstime
);
3070 computeDeadline
= false;
3072 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
3073 abstime
, THREAD_UNINT
);
3075 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3079 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3080 IOLockUnlock( gJobsLock
);
3082 if( waitResult
== THREAD_TIMED_OUT
)
3083 return( kIOReturnTimeout
);
3085 return( kIOReturnSuccess
);
3088 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3095 IOTakeLock( gJobsLock
);
3098 gJobs
->setLastObject( job
);
3100 count
= gNumWaitingThreads
;
3101 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3103 create
= ( (gOutstandingJobs
> count
)
3104 && (gNumConfigThreads
< kMaxConfigThreads
) );
3106 gNumConfigThreads
++;
3107 gNumWaitingThreads
++;
3110 IOUnlock( gJobsLock
);
3115 if( gIOKitDebug
& kIOLogConfig
)
3116 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3117 _IOConfigThread::configThread();
3120 semaphore_signal( gJobsSemaphore
);
3123 // internal - call with gNotificationLock
3124 OSObject
* IOService::getExistingServices( OSDictionary
* matching
,
3125 IOOptionBits inState
, IOOptionBits options
)
3127 OSObject
* current
= 0;
3129 IOService
* service
;
3136 && (obj
= matching
->getObject(gIOProviderClassKey
))
3138 && gIOResourcesKey
->isEqualTo(obj
)
3139 && (service
= gIOResources
))
3141 if( (inState
== (service
->__state
[0] & inState
))
3142 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3143 && service
->passiveMatch( matching
))
3145 if( options
& kIONotifyOnce
)
3148 current
= OSSet::withObjects(
3149 (const OSObject
**) &service
, 1, 1 );
3154 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3155 kIORegistryIterateRecursively
);
3159 while( (service
= (IOService
*) iter
->getNextObject())) {
3160 if( (inState
== (service
->__state
[0] & inState
))
3161 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3162 && service
->passiveMatch( matching
)) {
3164 if( options
& kIONotifyOnce
) {
3169 ((OSSet
*)current
)->setObject( service
);
3171 current
= OSSet::withObjects(
3172 (const OSObject
**) &service
, 1, 1 );
3175 } while( !service
&& !iter
->isValid());
3180 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
3181 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3190 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3194 // is a lock even needed?
3197 iter
= (OSIterator
*) getExistingServices( matching
,
3198 kIOServiceMatchedState
);
3206 // internal - call with gNotificationLock
3207 IONotifier
* IOService::setNotification(
3208 const OSSymbol
* type
, OSDictionary
* matching
,
3209 IOServiceNotificationHandler handler
, void * target
, void * ref
,
3212 _IOServiceNotifier
* notify
= 0;
3218 notify
= new _IOServiceNotifier
;
3219 if( notify
&& !notify
->init()) {
3225 notify
->matching
= matching
;
3226 notify
->handler
= handler
;
3227 notify
->target
= target
;
3229 notify
->priority
= priority
;
3230 notify
->state
= kIOServiceNotifyEnable
;
3231 queue_init( ¬ify
->handlerInvocations
);
3235 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3236 set
= OSOrderedSet::withCapacity( 1,
3237 IONotifyOrdering
, 0 );
3239 gNotifications
->setObject( type
, set
);
3243 notify
->whence
= set
;
3245 set
->setObject( notify
);
3251 // internal - call with gNotificationLock
3252 IONotifier
* IOService::doInstallNotification(
3253 const OSSymbol
* type
, OSDictionary
* matching
,
3254 IOServiceNotificationHandler handler
,
3255 void * target
, void * ref
,
3256 SInt32 priority
, OSIterator
** existing
)
3259 IONotifier
* notify
;
3260 IOOptionBits inState
;
3265 if( type
== gIOPublishNotification
)
3266 inState
= kIOServiceRegisteredState
;
3268 else if( type
== gIOFirstPublishNotification
)
3269 inState
= kIOServiceFirstPublishState
;
3271 else if( (type
== gIOMatchedNotification
)
3272 || (type
== gIOFirstMatchNotification
))
3273 inState
= kIOServiceMatchedState
;
3274 else if( type
== gIOTerminatedNotification
)
3279 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3282 // get the current set
3283 exist
= (OSIterator
*) getExistingServices( matching
, inState
);
3293 IONotifier
* IOService::installNotification(
3294 const OSSymbol
* type
, OSDictionary
* matching
,
3295 IOServiceNotificationHandler handler
,
3296 void * target
, void * ref
,
3297 SInt32 priority
, OSIterator
** existing
)
3299 IONotifier
* notify
;
3303 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3304 priority
, existing
);
3311 IONotifier
* IOService::addNotification(
3312 const OSSymbol
* type
, OSDictionary
* matching
,
3313 IOServiceNotificationHandler handler
,
3314 void * target
, void * ref
,
3317 OSIterator
* existing
;
3318 _IOServiceNotifier
* notify
;
3321 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3322 handler
, target
, ref
, priority
, &existing
);
3324 // send notifications for existing set
3327 notify
->retain(); // in case handler remove()s
3328 while( (next
= (IOService
*) existing
->getNextObject())) {
3330 next
->lockForArbitration();
3331 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3332 next
->invokeNotifer( notify
);
3333 next
->unlockForArbitration();
3336 existing
->release();
3342 struct SyncNotifyVars
{
3343 semaphore_port_t waitHere
;
3347 bool IOService::syncNotificationHandler(
3348 void * /* target */, void * ref
,
3349 IOService
* newService
)
3352 // result may get written more than once before the
3353 // notification is removed!
3354 ((SyncNotifyVars
*) ref
)->result
= newService
;
3355 semaphore_signal( ((SyncNotifyVars
*) ref
)->waitHere
);
3360 IOService
* IOService::waitForService( OSDictionary
* matching
,
3361 mach_timespec_t
* timeout
)
3363 IONotifier
* notify
= 0;
3364 // priority doesn't help us much since we need a thread wakeup
3365 SInt32 priority
= 0;
3366 SyncNotifyVars state
;
3367 kern_return_t err
= kIOReturnBadArgument
;
3379 state
.result
= (IOService
*) getExistingServices( matching
,
3380 kIOServiceMatchedState
, kIONotifyOnce
);
3384 err
= semaphore_create( kernel_task
, &state
.waitHere
,
3385 SYNC_POLICY_FIFO
, 0 );
3386 if( KERN_SUCCESS
!= err
)
3389 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
3390 &IOService::syncNotificationHandler
, (void *) 0,
3391 (void *) &state
, priority
);
3399 err
= semaphore_timedwait( state
.waitHere
, *timeout
);
3401 err
= semaphore_wait( state
.waitHere
);
3405 notify
->remove(); // dequeues
3407 matching
->release();
3409 semaphore_destroy( kernel_task
, state
.waitHere
);
3411 return( state
.result
);
3414 void IOService::deliverNotification( const OSSymbol
* type
,
3415 IOOptionBits orNewState
, IOOptionBits andNewState
)
3417 _IOServiceNotifier
* notify
;
3419 OSArray
* willSend
= 0;
3421 lockForArbitration();
3423 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3424 || (type
== gIOTerminatedNotification
)) {
3428 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3429 gNotifications
->getObject( type
) );
3432 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
3434 if( passiveMatch( notify
->matching
)
3435 && (kIOServiceNotifyEnable
& notify
->state
)) {
3437 willSend
= OSArray::withCapacity(8);
3439 willSend
->setObject( notify
);
3445 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
3451 for( unsigned int idx
= 0;
3452 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
3454 invokeNotifer( notify
);
3456 willSend
->release();
3458 unlockForArbitration();
3461 IOOptionBits
IOService::getState( void ) const
3463 return( __state
[0] );
3467 * Helpers to make matching objects for simple cases
3470 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
3471 OSDictionary
* table
)
3474 table
= OSDictionary::withCapacity( 2 );
3476 table
->setObject(gIOProviderClassKey
, (OSObject
*)name
);
3481 OSDictionary
* IOService::serviceMatching( const char * name
,
3482 OSDictionary
* table
)
3484 const OSString
* str
;
3486 str
= OSSymbol::withCString( name
);
3490 table
= serviceMatching( str
, table
);
3495 OSDictionary
* IOService::nameMatching( const OSString
* name
,
3496 OSDictionary
* table
)
3499 table
= OSDictionary::withCapacity( 2 );
3501 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
3506 OSDictionary
* IOService::nameMatching( const char * name
,
3507 OSDictionary
* table
)
3509 const OSString
* str
;
3511 str
= OSSymbol::withCString( name
);
3515 table
= nameMatching( str
, table
);
3520 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
3521 OSDictionary
* table
)
3523 table
= serviceMatching( gIOResourcesKey
, table
);
3525 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
3530 OSDictionary
* IOService::resourceMatching( const char * name
,
3531 OSDictionary
* table
)
3533 const OSSymbol
* str
;
3535 str
= OSSymbol::withCString( name
);
3539 table
= resourceMatching( str
, table
);
3546 * _IOServiceNotifier
3549 // wait for all threads, other than the current one,
3550 // to exit the handler
3552 void _IOServiceNotifier::wait()
3554 _IOServiceNotifierInvocation
* next
;
3559 queue_iterate( &handlerInvocations
, next
,
3560 _IOServiceNotifierInvocation
*, link
) {
3561 if( next
->thread
!= current_thread() ) {
3567 state
|= kIOServiceNotifyWaiter
;
3574 void _IOServiceNotifier::free()
3576 assert( queue_empty( &handlerInvocations
));
3580 void _IOServiceNotifier::remove()
3585 whence
->removeObject( (OSObject
*) this );
3589 matching
->release();
3593 state
&= ~kIOServiceNotifyEnable
;
3602 bool _IOServiceNotifier::disable()
3608 ret
= (0 != (kIOServiceNotifyEnable
& state
));
3609 state
&= ~kIOServiceNotifyEnable
;
3618 void _IOServiceNotifier::enable( bool was
)
3622 state
|= kIOServiceNotifyEnable
;
3624 state
&= ~kIOServiceNotifyEnable
;
3632 IOService
* IOResources::resources( void )
3636 inst
= new IOResources
;
3637 if( inst
&& !inst
->init()) {
3645 IOWorkLoop
* IOResources::getWorkLoop() const
3647 // If we are the resource root then bringe over to the
3648 // platform to get its workloop
3649 if (this == (IOResources
*) gIOResources
)
3650 return getPlatform()->getWorkLoop();
3652 return IOService::getWorkLoop();
3655 bool IOResources::matchPropertyTable( OSDictionary
* table
)
3663 prop
= table
->getObject( gIOResourceMatchKey
);
3664 str
= OSDynamicCast( OSString
, prop
);
3666 ok
= (0 != getProperty( str
));
3668 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
3670 iter
= OSCollectionIterator::withCollection( set
);
3672 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
3673 ok
= (0 != getProperty( str
));
3682 IOReturn
IOResources::setProperties( OSObject
* properties
)
3685 const OSSymbol
* key
;
3686 OSDictionary
* dict
;
3687 OSCollectionIterator
* iter
;
3689 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
3690 if ( kIOReturnSuccess
!= err
)
3693 dict
= OSDynamicCast(OSDictionary
, properties
);
3695 return( kIOReturnBadArgument
);
3697 iter
= OSCollectionIterator::withCollection( dict
);
3699 return( kIOReturnBadArgument
);
3701 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
3703 if (gIOConsoleUsersKey
== key
)
3705 IORegistryEntry::getRegistryRoot()->setProperty(key
, dict
->getObject(key
));
3706 OSIncrementAtomic( &gIOConsoleUsersSeed
);
3707 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
3711 publishResource( key
, dict
->getObject(key
) );
3716 return( kIOReturnSuccess
);
3720 * Helpers for matching dictionaries.
3721 * Keys existing in matching are checked in properties.
3722 * Keys may be a string or OSCollection of IOStrings
3725 bool IOService::compareProperty( OSDictionary
* matching
,
3731 value
= matching
->getObject( key
);
3733 ok
= value
->isEqualTo( getProperty( key
));
3741 bool IOService::compareProperty( OSDictionary
* matching
,
3742 const OSString
* key
)
3747 value
= matching
->getObject( key
);
3749 ok
= value
->isEqualTo( getProperty( key
));
3756 bool IOService::compareProperties( OSDictionary
* matching
,
3757 OSCollection
* keys
)
3759 OSCollectionIterator
* iter
;
3760 const OSString
* key
;
3763 if( !matching
|| !keys
)
3766 iter
= OSCollectionIterator::withCollection( keys
);
3769 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
3770 ok
= compareProperty( matching
, key
);
3774 keys
->release(); // !! consume a ref !!
3779 /* Helper to add a location matching dict to the table */
3781 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
3783 OSDictionary
* dict
;
3788 dict
= OSDictionary::withCapacity( 1 );
3790 table
->setObject( gIOLocationMatchKey
, dict
);
3798 * Go looking for a provider to match a location dict.
3801 IOService
* IOService::matchLocation( IOService
* /* client */ )
3805 parent
= getProvider();
3808 parent
= parent
->matchLocation( this );
3813 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
3819 IORegistryEntry
* entry
;
3824 bool matchParent
= false;
3835 str
= OSDynamicCast( OSString
, table
->getObject( gIOProviderClassKey
));
3838 match
= (0 != where
->metaCast( str
));
3843 obj
= table
->getObject( gIONameMatchKey
);
3846 match
= where
->compareNames( obj
, changesOK
? &matched
: 0 );
3849 if( changesOK
&& matched
) {
3850 // leave a hint as to which name matched
3851 table
->setObject( gIONameMatchedKey
, matched
);
3856 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
3859 const OSSymbol
* sym
;
3863 sym
= where
->copyLocation();
3865 match
= sym
->isEqualTo( str
);
3872 obj
= table
->getObject( gIOPropertyMatchKey
);
3875 OSDictionary
* dict
;
3876 OSDictionary
* nextDict
;
3881 dict
= where
->dictionaryWithProperties();
3883 nextDict
= OSDynamicCast( OSDictionary
, obj
);
3887 iter
= OSCollectionIterator::withCollection(
3888 OSDynamicCast(OSCollection
, obj
));
3891 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
3892 iter
->getNextObject()))))) {
3893 match
= dict
->isEqualTo( nextDict
, nextDict
);
3906 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
3909 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
3910 match
= (where
== entry
);
3917 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
3921 IOService
* service
= 0;
3922 UInt32 serviceCount
= 0;
3925 iter
= where
->getClientIterator();
3927 while( (service
= (IOService
*) iter
->getNextObject())) {
3928 if( kIOServiceInactiveState
& service
->__state
[0])
3930 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
3936 match
= (serviceCount
== num
->unsigned32BitValue());
3941 if( done
== table
->getCount()) {
3942 // don't call family if we've done all the entries in the table
3943 matchParent
= false;
3947 // pass in score from property table
3948 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
3950 // do family specific matching
3951 match
= where
->matchPropertyTable( table
, &score
);
3955 if( kIOLogMatch
& getDebugFlags( table
))
3956 LOG("%s: family specific matching fails\n", where
->getName());
3963 newPri
= OSNumber::withNumber( score
, 32 );
3965 table
->setObject( gIOProbeScoreKey
, newPri
);
3970 if( !(match
= where
->compareProperty( table
, kIOBSDNameKey
)))
3973 matchParent
= false;
3975 obj
= OSDynamicCast( OSDictionary
,
3976 table
->getObject( gIOParentMatchKey
));
3980 table
= (OSDictionary
*) obj
;
3984 table
= OSDynamicCast( OSDictionary
,
3985 table
->getObject( gIOLocationMatchKey
));
3988 where
= where
->getProvider();
3990 where
= where
->matchLocation( where
);
3993 } while( table
&& where
);
3995 } while( matchParent
&& (where
= where
->getProvider()) );
3997 if( kIOLogMatch
& gIOKitDebug
)
3999 LOG("match parent @ %s = %d\n",
4000 where
->getName(), match
);
4006 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4007 UInt32 type
, OSDictionary
* properties
,
4008 IOUserClient
** handler
)
4010 const OSSymbol
*userClientClass
= 0;
4011 IOUserClient
*client
;
4014 // First try my own properties for a user client class name
4015 temp
= getProperty(gIOUserClientClassKey
);
4017 if (OSDynamicCast(OSSymbol
, temp
))
4018 userClientClass
= (const OSSymbol
*) temp
;
4019 else if (OSDynamicCast(OSString
, temp
)) {
4020 userClientClass
= OSSymbol::withString((OSString
*) temp
);
4021 if (userClientClass
)
4022 setProperty(kIOUserClientClassKey
,
4023 (OSObject
*) userClientClass
);
4027 // Didn't find one so lets just bomb out now without further ado.
4028 if (!userClientClass
)
4029 return kIOReturnUnsupported
;
4031 temp
= OSMetaClass::allocClassWithName(userClientClass
);
4033 return kIOReturnNoMemory
;
4035 if (OSDynamicCast(IOUserClient
, temp
))
4036 client
= (IOUserClient
*) temp
;
4039 return kIOReturnUnsupported
;
4042 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
4044 return kIOReturnBadArgument
;
4047 if ( !client
->attach(this) ) {
4049 return kIOReturnUnsupported
;
4052 if ( !client
->start(this) ) {
4053 client
->detach(this);
4055 return kIOReturnUnsupported
;
4059 return kIOReturnSuccess
;
4062 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4063 UInt32 type
, IOUserClient
** handler
)
4065 return( newUserClient( owningTask
, securityID
, type
, 0, handler
));
4068 IOReturn
IOService::requestProbe( IOOptionBits options
)
4070 return( kIOReturnUnsupported
);
4074 * Convert an IOReturn to text. Subclasses which add additional
4075 * IOReturn's should override this method and call
4076 * super::stringFromReturn if the desired value is not found.
4079 const char * IOService::stringFromReturn( IOReturn rtn
)
4081 static const IONamedValue IOReturn_values
[] = {
4082 {kIOReturnSuccess
, "success" },
4083 {kIOReturnError
, "general error" },
4084 {kIOReturnNoMemory
, "memory allocation error" },
4085 {kIOReturnNoResources
, "resource shortage" },
4086 {kIOReturnIPCError
, "Mach IPC failure" },
4087 {kIOReturnNoDevice
, "no such device" },
4088 {kIOReturnNotPrivileged
, "privilege violation" },
4089 {kIOReturnBadArgument
, "invalid argument" },
4090 {kIOReturnLockedRead
, "device is read locked" },
4091 {kIOReturnLockedWrite
, "device is write locked" },
4092 {kIOReturnExclusiveAccess
, "device is exclusive access" },
4093 {kIOReturnBadMessageID
, "bad IPC message ID" },
4094 {kIOReturnUnsupported
, "unsupported function" },
4095 {kIOReturnVMError
, "virtual memory error" },
4096 {kIOReturnInternalError
, "internal driver error" },
4097 {kIOReturnIOError
, "I/O error" },
4098 {kIOReturnCannotLock
, "cannot acquire lock" },
4099 {kIOReturnNotOpen
, "device is not open" },
4100 {kIOReturnNotReadable
, "device is not readable" },
4101 {kIOReturnNotWritable
, "device is not writeable" },
4102 {kIOReturnNotAligned
, "alignment error" },
4103 {kIOReturnBadMedia
, "media error" },
4104 {kIOReturnStillOpen
, "device is still open" },
4105 {kIOReturnRLDError
, "rld failure" },
4106 {kIOReturnDMAError
, "DMA failure" },
4107 {kIOReturnBusy
, "device is busy" },
4108 {kIOReturnTimeout
, "I/O timeout" },
4109 {kIOReturnOffline
, "device is offline" },
4110 {kIOReturnNotReady
, "device is not ready" },
4111 {kIOReturnNotAttached
, "device/channel is not attached" },
4112 {kIOReturnNoChannels
, "no DMA channels available" },
4113 {kIOReturnNoSpace
, "no space for data" },
4114 {kIOReturnPortExists
, "device port already exists" },
4115 {kIOReturnCannotWire
, "cannot wire physical memory" },
4116 {kIOReturnNoInterrupt
, "no interrupt attached" },
4117 {kIOReturnNoFrames
, "no DMA frames enqueued" },
4118 {kIOReturnMessageTooLarge
, "message is too large" },
4119 {kIOReturnNotPermitted
, "operation is not permitted" },
4120 {kIOReturnNoPower
, "device is without power" },
4121 {kIOReturnNoMedia
, "media is not present" },
4122 {kIOReturnUnformattedMedia
, "media is not formatted" },
4123 {kIOReturnUnsupportedMode
, "unsupported mode" },
4124 {kIOReturnUnderrun
, "data underrun" },
4125 {kIOReturnOverrun
, "data overrun" },
4126 {kIOReturnDeviceError
, "device error" },
4127 {kIOReturnNoCompletion
, "no completion routine" },
4128 {kIOReturnAborted
, "operation was aborted" },
4129 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
4130 {kIOReturnNotResponding
, "device is not responding" },
4131 {kIOReturnInvalid
, "unanticipated driver error" },
4135 return IOFindNameForValue(rtn
, IOReturn_values
);
4139 * Convert an IOReturn to an errno.
4141 int IOService::errnoFromReturn( IOReturn rtn
)
4145 case kIOReturnSuccess
:
4147 case kIOReturnNoMemory
:
4149 case kIOReturnNoDevice
:
4151 case kIOReturnVMError
:
4153 case kIOReturnNotPermitted
:
4155 case kIOReturnNotPrivileged
:
4157 case kIOReturnIOError
:
4159 case kIOReturnNotWritable
:
4161 case kIOReturnBadArgument
:
4163 case kIOReturnUnsupported
:
4167 case kIOReturnNoPower
:
4169 case kIOReturnDeviceError
:
4171 case kIOReturnTimeout
:
4173 case kIOReturnMessageTooLarge
:
4175 case kIOReturnNoSpace
:
4177 case kIOReturnCannotLock
:
4181 case kIOReturnBadMessageID
:
4182 case kIOReturnNoCompletion
:
4183 case kIOReturnNotAligned
:
4185 case kIOReturnNotReady
:
4187 case kIOReturnRLDError
:
4189 case kIOReturnPortExists
:
4190 case kIOReturnStillOpen
:
4192 case kIOReturnExclusiveAccess
:
4193 case kIOReturnLockedRead
:
4194 case kIOReturnLockedWrite
:
4195 case kIOReturnNotAttached
:
4196 case kIOReturnNotOpen
:
4197 case kIOReturnNotReadable
:
4199 case kIOReturnCannotWire
:
4200 case kIOReturnNoResources
:
4202 case kIOReturnAborted
:
4203 case kIOReturnOffline
:
4204 case kIOReturnNotResponding
:
4206 case kIOReturnBadMedia
:
4207 case kIOReturnNoMedia
:
4208 case kIOReturnUnformattedMedia
:
4209 return(ENXIO
); // (media error)
4210 case kIOReturnDMAError
:
4211 case kIOReturnOverrun
:
4212 case kIOReturnUnderrun
:
4213 return(EIO
); // (transfer error)
4214 case kIOReturnNoBandwidth
:
4215 case kIOReturnNoChannels
:
4216 case kIOReturnNoFrames
:
4217 case kIOReturnNoInterrupt
:
4218 return(EIO
); // (hardware error)
4219 case kIOReturnError
:
4220 case kIOReturnInternalError
:
4221 case kIOReturnInvalid
:
4222 return(EIO
); // (generic error)
4223 case kIOReturnIPCError
:
4224 return(EIO
); // (ipc error)
4226 return(EIO
); // (all other errors)
4230 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
4234 * Generic entry point for calls from the provider. A return value of
4235 * kIOReturnSuccess indicates that the message was received, and where
4236 * applicable, that it was successful.
4239 return kIOReturnUnsupported
;
4246 IOItemCount
IOService::getDeviceMemoryCount( void )
4251 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4253 count
= array
->getCount();
4260 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
4263 IODeviceMemory
* range
;
4265 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4267 range
= (IODeviceMemory
*) array
->getObject( index
);
4274 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
4275 IOOptionBits options
)
4277 IODeviceMemory
* range
;
4280 range
= getDeviceMemoryWithIndex( index
);
4282 map
= range
->map( options
);
4289 OSArray
* IOService::getDeviceMemory( void )
4291 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
4295 void IOService::setDeviceMemory( OSArray
* array
)
4297 setProperty( gIODeviceMemoryKey
, array
);
4304 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
4306 IOInterruptController
*interruptController
;
4309 OSSymbol
*interruptControllerName
;
4311 IOInterruptSource
*interruptSources
;
4313 // Get the parents list from the nub.
4314 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
4315 if (array
== 0) return kIOReturnNoResources
;
4317 // Allocate space for the IOInterruptSources if needed... then return early.
4318 if (nub
->_interruptSources
== 0) {
4319 numSources
= array
->getCount();
4320 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
4321 if (interruptSources
== 0) return kIOReturnNoMemory
;
4323 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
4325 nub
->_numInterruptSources
= numSources
;
4326 nub
->_interruptSources
= interruptSources
;
4327 return kIOReturnSuccess
;
4330 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
4331 if (interruptControllerName
== 0) return kIOReturnNoResources
;
4333 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
4334 if (interruptController
== 0) return kIOReturnNoResources
;
4336 // Get the interrupt numbers from the nub.
4337 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
4338 if (array
== 0) return kIOReturnNoResources
;
4339 data
= OSDynamicCast(OSData
, array
->getObject(source
));
4340 if (data
== 0) return kIOReturnNoResources
;
4342 // Set the interruptController and interruptSource in the nub's table.
4343 interruptSources
= nub
->_interruptSources
;
4344 interruptSources
[source
].interruptController
= interruptController
;
4345 interruptSources
[source
].vectorData
= data
;
4347 return kIOReturnSuccess
;
4350 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
4354 /* Make sure the _interruptSources are set */
4355 if (_interruptSources
== 0) {
4356 ret
= resolveInterrupt(this, source
);
4357 if (ret
!= kIOReturnSuccess
) return ret
;
4360 /* Make sure the local source number is valid */
4361 if ((source
< 0) || (source
>= _numInterruptSources
))
4362 return kIOReturnNoInterrupt
;
4364 /* Look up the contoller for the local source */
4365 *interruptController
= _interruptSources
[source
].interruptController
;
4367 if (*interruptController
== NULL
) {
4368 if (!resolve
) return kIOReturnNoInterrupt
;
4370 /* Try to reslove the interrupt */
4371 ret
= resolveInterrupt(this, source
);
4372 if (ret
!= kIOReturnSuccess
) return ret
;
4374 *interruptController
= _interruptSources
[source
].interruptController
;
4377 return kIOReturnSuccess
;
4380 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
4381 IOInterruptAction handler
,
4384 IOInterruptController
*interruptController
;
4387 ret
= lookupInterrupt(source
, true, &interruptController
);
4388 if (ret
!= kIOReturnSuccess
) return ret
;
4390 /* Register the source */
4391 return interruptController
->registerInterrupt(this, source
, target
,
4392 (IOInterruptHandler
)handler
,
4396 IOReturn
IOService::unregisterInterrupt(int source
)
4398 IOInterruptController
*interruptController
;
4401 ret
= lookupInterrupt(source
, false, &interruptController
);
4402 if (ret
!= kIOReturnSuccess
) return ret
;
4404 /* Unregister the source */
4405 return interruptController
->unregisterInterrupt(this, source
);
4408 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
4410 IOInterruptController
*interruptController
;
4413 ret
= lookupInterrupt(source
, true, &interruptController
);
4414 if (ret
!= kIOReturnSuccess
) return ret
;
4416 /* Return the type */
4417 return interruptController
->getInterruptType(this, source
, interruptType
);
4420 IOReturn
IOService::enableInterrupt(int source
)
4422 IOInterruptController
*interruptController
;
4425 ret
= lookupInterrupt(source
, false, &interruptController
);
4426 if (ret
!= kIOReturnSuccess
) return ret
;
4428 /* Enable the source */
4429 return interruptController
->enableInterrupt(this, source
);
4432 IOReturn
IOService::disableInterrupt(int source
)
4434 IOInterruptController
*interruptController
;
4437 ret
= lookupInterrupt(source
, false, &interruptController
);
4438 if (ret
!= kIOReturnSuccess
) return ret
;
4440 /* Disable the source */
4441 return interruptController
->disableInterrupt(this, source
);
4444 IOReturn
IOService::causeInterrupt(int source
)
4446 IOInterruptController
*interruptController
;
4449 ret
= lookupInterrupt(source
, false, &interruptController
);
4450 if (ret
!= kIOReturnSuccess
) return ret
;
4452 /* Cause an interrupt for the source */
4453 return interruptController
->causeInterrupt(this, source
);
4456 OSMetaClassDefineReservedUsed(IOService
, 0);
4457 OSMetaClassDefineReservedUsed(IOService
, 1);
4458 OSMetaClassDefineReservedUsed(IOService
, 2);
4459 OSMetaClassDefineReservedUsed(IOService
, 3);
4461 OSMetaClassDefineReservedUnused(IOService
, 4);
4462 OSMetaClassDefineReservedUnused(IOService
, 5);
4463 OSMetaClassDefineReservedUnused(IOService
, 6);
4464 OSMetaClassDefineReservedUnused(IOService
, 7);
4465 OSMetaClassDefineReservedUnused(IOService
, 8);
4466 OSMetaClassDefineReservedUnused(IOService
, 9);
4467 OSMetaClassDefineReservedUnused(IOService
, 10);
4468 OSMetaClassDefineReservedUnused(IOService
, 11);
4469 OSMetaClassDefineReservedUnused(IOService
, 12);
4470 OSMetaClassDefineReservedUnused(IOService
, 13);
4471 OSMetaClassDefineReservedUnused(IOService
, 14);
4472 OSMetaClassDefineReservedUnused(IOService
, 15);
4473 OSMetaClassDefineReservedUnused(IOService
, 16);
4474 OSMetaClassDefineReservedUnused(IOService
, 17);
4475 OSMetaClassDefineReservedUnused(IOService
, 18);
4476 OSMetaClassDefineReservedUnused(IOService
, 19);
4477 OSMetaClassDefineReservedUnused(IOService
, 20);
4478 OSMetaClassDefineReservedUnused(IOService
, 21);
4479 OSMetaClassDefineReservedUnused(IOService
, 22);
4480 OSMetaClassDefineReservedUnused(IOService
, 23);
4481 OSMetaClassDefineReservedUnused(IOService
, 24);
4482 OSMetaClassDefineReservedUnused(IOService
, 25);
4483 OSMetaClassDefineReservedUnused(IOService
, 26);
4484 OSMetaClassDefineReservedUnused(IOService
, 27);
4485 OSMetaClassDefineReservedUnused(IOService
, 28);
4486 OSMetaClassDefineReservedUnused(IOService
, 29);
4487 OSMetaClassDefineReservedUnused(IOService
, 30);
4488 OSMetaClassDefineReservedUnused(IOService
, 31);
4489 OSMetaClassDefineReservedUnused(IOService
, 32);
4490 OSMetaClassDefineReservedUnused(IOService
, 33);
4491 OSMetaClassDefineReservedUnused(IOService
, 34);
4492 OSMetaClassDefineReservedUnused(IOService
, 35);
4493 OSMetaClassDefineReservedUnused(IOService
, 36);
4494 OSMetaClassDefineReservedUnused(IOService
, 37);
4495 OSMetaClassDefineReservedUnused(IOService
, 38);
4496 OSMetaClassDefineReservedUnused(IOService
, 39);
4497 OSMetaClassDefineReservedUnused(IOService
, 40);
4498 OSMetaClassDefineReservedUnused(IOService
, 41);
4499 OSMetaClassDefineReservedUnused(IOService
, 42);
4500 OSMetaClassDefineReservedUnused(IOService
, 43);
4501 OSMetaClassDefineReservedUnused(IOService
, 44);
4502 OSMetaClassDefineReservedUnused(IOService
, 45);
4503 OSMetaClassDefineReservedUnused(IOService
, 46);
4504 OSMetaClassDefineReservedUnused(IOService
, 47);
4505 OSMetaClassDefineReservedUnused(IOService
, 48);
4506 OSMetaClassDefineReservedUnused(IOService
, 49);
4507 OSMetaClassDefineReservedUnused(IOService
, 50);
4508 OSMetaClassDefineReservedUnused(IOService
, 51);
4509 OSMetaClassDefineReservedUnused(IOService
, 52);
4510 OSMetaClassDefineReservedUnused(IOService
, 53);
4511 OSMetaClassDefineReservedUnused(IOService
, 54);
4512 OSMetaClassDefineReservedUnused(IOService
, 55);
4513 OSMetaClassDefineReservedUnused(IOService
, 56);
4514 OSMetaClassDefineReservedUnused(IOService
, 57);
4515 OSMetaClassDefineReservedUnused(IOService
, 58);
4516 OSMetaClassDefineReservedUnused(IOService
, 59);
4517 OSMetaClassDefineReservedUnused(IOService
, 60);
4518 OSMetaClassDefineReservedUnused(IOService
, 61);
4519 OSMetaClassDefineReservedUnused(IOService
, 62);
4520 OSMetaClassDefineReservedUnused(IOService
, 63);