2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 #include <IOKit/system.h>
33 #include <IOKit/IOService.h>
34 #include <libkern/c++/OSContainers.h>
35 #include <libkern/c++/OSUnserialize.h>
36 #include <IOKit/IOCatalogue.h>
37 #include <IOKit/IOCommand.h>
38 #include <IOKit/IODeviceMemory.h>
39 #include <IOKit/IOInterrupts.h>
40 #include <IOKit/IOInterruptController.h>
41 #include <IOKit/IOPlatformExpert.h>
42 #include <IOKit/IOMessage.h>
43 #include <IOKit/IOLib.h>
44 #include <IOKit/IOKitKeysPrivate.h>
45 #include <IOKit/IOBSD.h>
46 #include <IOKit/IOUserClient.h>
47 #include <IOKit/IOWorkLoop.h>
48 #include <mach/sync_policy.h>
49 #include <IOKit/assert.h>
50 #include <sys/errno.h>
55 #include "IOServicePrivate.h"
57 // take lockForArbitration before LOCKNOTIFY
59 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
61 #define super IORegistryEntry
63 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
65 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
67 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
69 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
71 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
73 OSDefineMetaClassAndStructors(IOResources
, IOService
)
75 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
77 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
79 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
81 static IOPlatformExpert
* gIOPlatform
;
82 static class IOPMrootDomain
* gIOPMRootDomain
;
83 const IORegistryPlane
* gIOServicePlane
;
84 const IORegistryPlane
* gIOPowerPlane
;
85 const OSSymbol
* gIODeviceMemoryKey
;
86 const OSSymbol
* gIOInterruptControllersKey
;
87 const OSSymbol
* gIOInterruptSpecifiersKey
;
89 const OSSymbol
* gIOResourcesKey
;
90 const OSSymbol
* gIOResourceMatchKey
;
91 const OSSymbol
* gIOProviderClassKey
;
92 const OSSymbol
* gIONameMatchKey
;
93 const OSSymbol
* gIONameMatchedKey
;
94 const OSSymbol
* gIOPropertyMatchKey
;
95 const OSSymbol
* gIOLocationMatchKey
;
96 const OSSymbol
* gIOParentMatchKey
;
97 const OSSymbol
* gIOPathMatchKey
;
98 const OSSymbol
* gIOMatchCategoryKey
;
99 const OSSymbol
* gIODefaultMatchCategoryKey
;
100 const OSSymbol
* gIOMatchedServiceCountKey
;
102 const OSSymbol
* gIOUserClientClassKey
;
103 const OSSymbol
* gIOKitDebugKey
;
105 const OSSymbol
* gIOCommandPoolSizeKey
;
107 const OSSymbol
* gIOConsoleUsersKey
;
108 const OSSymbol
* gIOConsoleSessionUIDKey
;
109 const OSSymbol
* gIOConsoleUsersSeedKey
;
111 static int gIOResourceGenerationCount
;
113 const OSSymbol
* gIOServiceKey
;
114 const OSSymbol
* gIOPublishNotification
;
115 const OSSymbol
* gIOFirstPublishNotification
;
116 const OSSymbol
* gIOMatchedNotification
;
117 const OSSymbol
* gIOFirstMatchNotification
;
118 const OSSymbol
* gIOTerminatedNotification
;
120 const OSSymbol
* gIOGeneralInterest
;
121 const OSSymbol
* gIOBusyInterest
;
122 const OSSymbol
* gIOAppPowerStateInterest
;
123 const OSSymbol
* gIOPriorityPowerStateInterest
;
125 static OSDictionary
* gNotifications
;
126 static IORecursiveLock
* gNotificationLock
;
128 static IOService
* gIOResources
;
129 static IOService
* gIOServiceRoot
;
131 static OSOrderedSet
* gJobs
;
132 static semaphore_port_t gJobsSemaphore
;
133 static IOLock
* gJobsLock
;
134 static int gOutstandingJobs
;
135 static int gNumConfigThreads
;
136 static int gNumWaitingThreads
;
137 static IOLock
* gIOServiceBusyLock
;
139 static thread_t gIOTerminateThread
;
140 static UInt32 gIOTerminateWork
;
141 static OSArray
* gIOTerminatePhase2List
;
142 static OSArray
* gIOStopList
;
143 static OSArray
* gIOStopProviderList
;
144 static OSArray
* gIOFinalizeList
;
146 static SInt32 gIOConsoleUsersSeed
;
147 static OSData
* gIOConsoleUsersSeedValue
;
149 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
151 #define LOCKREADNOTIFY() \
152 IORecursiveLockLock( gNotificationLock )
153 #define LOCKWRITENOTIFY() \
154 IORecursiveLockLock( gNotificationLock )
155 #define LOCKWRITE2READNOTIFY()
156 #define UNLOCKNOTIFY() \
157 IORecursiveLockUnlock( gNotificationLock )
158 #define SLEEPNOTIFY(event) \
159 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
160 #define WAKEUPNOTIFY(event) \
161 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
163 #define randomDelay() \
164 int del = read_processor_clock(); \
165 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
168 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
170 #define queue_element(entry, element, type, field) do { \
171 vm_address_t __ele = (vm_address_t) (entry); \
172 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
173 (element) = (type) __ele; \
176 #define iterqueue(que, elt) \
177 for (queue_entry_t elt = queue_first(que); \
178 !queue_end(que, elt); \
179 elt = queue_next(elt))
181 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
183 struct ArbitrationLockQueueElement
{
192 static queue_head_t gArbitrationLockQueueActive
;
193 static queue_head_t gArbitrationLockQueueWaiting
;
194 static queue_head_t gArbitrationLockQueueFree
;
195 static IOLock
* gArbitrationLockQueueLock
;
197 bool IOService::isInactive( void ) const
198 { return( 0 != (kIOServiceInactiveState
& getState())); }
200 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
202 void IOService::initialize( void )
206 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
207 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
209 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
210 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
211 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
212 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
213 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
214 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
215 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
217 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
218 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
219 kIODefaultMatchCategoryKey
);
220 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
221 kIOMatchedServiceCountKey
);
223 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
225 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
226 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
228 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
229 gIOInterruptControllersKey
230 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
231 gIOInterruptSpecifiersKey
232 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
234 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
236 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
238 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
239 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
240 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
241 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
243 gNotifications
= OSDictionary::withCapacity( 1 );
244 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
245 kIOPublishNotification
);
246 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
247 kIOFirstPublishNotification
);
248 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
249 kIOMatchedNotification
);
250 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
251 kIOFirstMatchNotification
);
252 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
253 kIOTerminatedNotification
);
254 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
256 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
257 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
258 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey
);
259 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
261 gNotificationLock
= IORecursiveLockAlloc();
263 assert( gIOServicePlane
&& gIODeviceMemoryKey
264 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
265 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
266 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
267 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
268 && gIOPublishNotification
&& gIOMatchedNotification
269 && gIOTerminatedNotification
&& gIOServiceKey
270 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
271 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
273 gJobsLock
= IOLockAlloc();
274 gJobs
= OSOrderedSet::withCapacity( 10 );
276 gIOServiceBusyLock
= IOLockAlloc();
278 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
280 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& (err
== KERN_SUCCESS
) );
282 gIOResources
= IOResources::resources();
283 assert( gIOResources
);
285 gArbitrationLockQueueLock
= IOLockAlloc();
286 queue_init(&gArbitrationLockQueueActive
);
287 queue_init(&gArbitrationLockQueueWaiting
);
288 queue_init(&gArbitrationLockQueueFree
);
290 assert( gArbitrationLockQueueLock
);
292 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
293 gIOStopList
= OSArray::withCapacity( 16 );
294 gIOStopProviderList
= OSArray::withCapacity( 16 );
295 gIOFinalizeList
= OSArray::withCapacity( 16 );
296 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
299 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
302 static UInt64
getDebugFlags( OSDictionary
* props
)
304 OSNumber
* debugProp
;
307 debugProp
= OSDynamicCast( OSNumber
,
308 props
->getObject( gIOKitDebugKey
));
310 debugFlags
= debugProp
->unsigned64BitValue();
312 debugFlags
= gIOKitDebug
;
314 return( debugFlags
);
318 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
320 // Probe a matched service and return an instance to be started.
321 // The default score is from the property table, & may be altered
322 // during probe to change the start order.
324 IOService
* IOService::probe( IOService
* provider
,
330 bool IOService::start( IOService
* provider
)
335 void IOService::stop( IOService
* provider
)
339 void IOService::free( void )
341 if( getPropertyTable())
342 unregisterAllInterest();
348 * Attach in service plane
350 bool IOService::attach( IOService
* provider
)
356 if( gIOKitDebug
& kIOLogAttach
)
357 LOG( "%s::attach(%s)\n", getName(),
358 provider
->getName());
360 provider
->lockForArbitration();
361 if( provider
->__state
[0] & kIOServiceInactiveState
)
364 ok
= attachToParent( provider
, gIOServicePlane
);
365 provider
->unlockForArbitration();
368 gIOServiceRoot
= this;
369 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
375 IOService
* IOService::getServiceRoot( void )
377 return( gIOServiceRoot
);
380 void IOService::detach( IOService
* provider
)
382 IOService
* newProvider
= 0;
386 if( gIOKitDebug
& kIOLogAttach
)
387 LOG("%s::detach(%s)\n", getName(), provider
->getName());
389 lockForArbitration();
391 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
392 && (provider
== getProvider()));
394 detachFromParent( provider
, gIOServicePlane
);
397 newProvider
= getProvider();
398 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
399 _adjustBusy( -busy
);
402 unlockForArbitration();
405 newProvider
->lockForArbitration();
406 newProvider
->_adjustBusy(1);
407 newProvider
->unlockForArbitration();
410 // check for last client detach from a terminated service
411 if( provider
->lockForArbitration( true )) {
413 provider
->_adjustBusy( -1 );
414 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
415 && (0 == provider
->getClient())) {
416 provider
->scheduleFinalize();
418 provider
->unlockForArbitration();
423 * Register instance - publish it for matching
426 void IOService::registerService( IOOptionBits options
)
432 enum { kMaxPathLen
= 256 };
433 enum { kMaxChars
= 63 };
435 IORegistryEntry
* parent
= this;
436 IORegistryEntry
* root
= getRegistryRoot();
437 while( parent
&& (parent
!= root
))
438 parent
= parent
->getParentEntry( gIOServicePlane
);
440 if( parent
!= root
) {
441 IOLog("%s: not registry member at registerService()\n", getName());
445 // Allow the Platform Expert to adjust this node.
446 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
449 if( (this != gIOResources
)
450 && (kIOLogRegister
& gIOKitDebug
)) {
452 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
454 IOLog( "Registering: " );
457 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
460 if( len
> kMaxChars
) {
464 if( (skip
= strchr( path
, '/')))
470 IOLog( "%s\n", path
);
473 IOFree( pathBuf
, kMaxPathLen
);
476 startMatching( options
);
479 void IOService::startMatching( IOOptionBits options
)
481 IOService
* provider
;
484 bool needWake
= false;
489 lockForArbitration();
491 sync
= (options
& kIOServiceSynchronous
)
492 || ((provider
= getProvider())
493 && (provider
->__state
[1] & kIOServiceSynchronousState
));
496 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
497 && (0 == (__state
[0] & kIOServiceInactiveState
));
499 __state
[1] |= kIOServiceNeedConfigState
;
501 // __state[0] &= ~kIOServiceInactiveState;
503 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
504 // OSKernelStackRemaining(), getName());
507 prevBusy
= _adjustBusy( 1 );
508 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
512 __state
[1] |= kIOServiceSynchronousState
;
514 __state
[1] &= ~kIOServiceSynchronousState
;
516 unlockForArbitration();
521 IOLockLock( gIOServiceBusyLock
);
522 thread_wakeup( (event_t
) this/*&__state[1]*/ );
523 IOLockUnlock( gIOServiceBusyLock
);
525 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
527 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
531 if( (__state
[1] & kIOServiceNeedConfigState
))
532 doServiceMatch( options
);
534 lockForArbitration();
535 IOLockLock( gIOServiceBusyLock
);
537 waitAgain
= (prevBusy
< (__state
[1] & kIOServiceBusyStateMask
));
539 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
541 __state
[1] &= ~kIOServiceSyncPubState
;
543 unlockForArbitration();
546 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
548 IOLockUnlock( gIOServiceBusyLock
);
550 thread_block(THREAD_CONTINUE_NULL
);
552 } while( waitAgain
);
556 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
558 OSDictionary
* table
;
568 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
571 set
= (OSSet
*) getExistingServices( table
,
572 kIOServiceRegisteredState
,
573 kIOServiceExistingSet
);
578 count
+= set
->getCount();
581 allSet
->merge((const OSSet
*) set
);
589 if( getDebugFlags( table
) & kIOLogMatch
)
590 LOG("Matching service count = %ld\n", count
);
592 newTables
->removeObject(table
);
596 while( (service
= (IOService
*) allSet
->getAnyObject())) {
597 service
->startMatching(kIOServiceAsynchronous
);
598 allSet
->removeObject(service
);
603 newTables
->release();
605 return( kIOReturnSuccess
);
608 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
609 IOOptionBits options
)
613 job
= new _IOServiceJob
;
614 if( job
&& !job
->init()) {
622 job
->options
= options
;
623 nub
->retain(); // thread will release()
631 * Called on a registered service to see if it matches
635 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
637 return( matchPropertyTable(table
) );
640 bool IOService::matchPropertyTable( OSDictionary
* table
)
646 * Called on a matched service to allocate resources
647 * before first driver is attached.
650 IOReturn
IOService::getResources( void )
652 return( kIOReturnSuccess
);
656 * Client/provider accessors
659 IOService
* IOService::getProvider( void ) const
661 IOService
* self
= (IOService
*) this;
666 generation
= getGenerationCount();
667 if( __providerGeneration
== generation
)
670 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
671 if( parent
== IORegistryEntry::getRegistryRoot())
672 /* root is not an IOService */
675 self
->__provider
= parent
;
676 // save the count before getParentEntry()
677 self
->__providerGeneration
= generation
;
682 IOWorkLoop
* IOService::getWorkLoop() const
684 IOService
*provider
= getProvider();
687 return provider
->getWorkLoop();
692 OSIterator
* IOService::getProviderIterator( void ) const
694 return( getParentIterator( gIOServicePlane
));
697 IOService
* IOService::getClient( void ) const
699 return( (IOService
*) getChildEntry( gIOServicePlane
));
702 OSIterator
* IOService::getClientIterator( void ) const
704 return( getChildIterator( gIOServicePlane
));
707 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
708 const IOService
* client
,
709 const IOService
* provider
)
711 _IOOpenServiceIterator
* inst
;
716 inst
= new _IOOpenServiceIterator
;
718 if( inst
&& !inst
->init()) {
724 inst
->client
= client
;
725 inst
->provider
= provider
;
731 void _IOOpenServiceIterator::free()
735 last
->unlockForArbitration();
739 OSObject
* _IOOpenServiceIterator::getNextObject()
744 last
->unlockForArbitration();
746 while( (next
= (IOService
*) iter
->getNextObject())) {
748 next
->lockForArbitration();
749 if( (client
&& (next
->isOpen( client
)))
750 || (provider
&& (provider
->isOpen( next
))) )
752 next
->unlockForArbitration();
760 bool _IOOpenServiceIterator::isValid()
762 return( iter
->isValid() );
765 void _IOOpenServiceIterator::reset()
768 last
->unlockForArbitration();
774 OSIterator
* IOService::getOpenProviderIterator( void ) const
776 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
779 OSIterator
* IOService::getOpenClientIterator( void ) const
781 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
785 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
786 bool waitForFunction
,
787 void *param1
, void *param2
,
788 void *param3
, void *param4
)
790 IOReturn result
= kIOReturnUnsupported
;
791 IOService
*provider
= getProvider();
794 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
795 param1
, param2
, param3
, param4
);
801 IOReturn
IOService::callPlatformFunction( const char * functionName
,
802 bool waitForFunction
,
803 void *param1
, void *param2
,
804 void *param3
, void *param4
)
806 IOReturn result
= kIOReturnNoMemory
;
807 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
809 if (functionSymbol
!= 0) {
810 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
811 param1
, param2
, param3
, param4
);
812 functionSymbol
->release();
820 * Accessors for global services
823 IOPlatformExpert
* IOService::getPlatform( void )
825 return( gIOPlatform
);
828 class IOPMrootDomain
* IOService::getPMRootDomain( void )
830 return( gIOPMRootDomain
);
833 IOService
* IOService::getResourceService( void )
835 return( gIOResources
);
838 void IOService::setPlatform( IOPlatformExpert
* platform
)
840 gIOPlatform
= platform
;
841 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
844 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
846 gIOPMRootDomain
= rootDomain
;
847 publishResource("IOKit");
854 bool IOService::lockForArbitration( bool isSuccessRequired
)
858 ArbitrationLockQueueElement
* element
;
859 ArbitrationLockQueueElement
* active
;
860 ArbitrationLockQueueElement
* waiting
;
862 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
864 // lock global access
865 IOTakeLock( gArbitrationLockQueueLock
);
867 // obtain an unused queue element
868 if( !queue_empty( &gArbitrationLockQueueFree
)) {
869 queue_remove_first( &gArbitrationLockQueueFree
,
871 ArbitrationLockQueueElement
*,
874 element
= IONew( ArbitrationLockQueueElement
, 1 );
878 // prepare the queue element
879 element
->thread
= IOThreadSelf();
880 element
->service
= this;
882 element
->required
= isSuccessRequired
;
883 element
->aborted
= false;
885 // determine whether this object is already locked (ie. on active queue)
887 queue_iterate( &gArbitrationLockQueueActive
,
889 ArbitrationLockQueueElement
*,
892 if( active
->service
== element
->service
) {
898 if( found
) { // this object is already locked
900 // determine whether it is the same or a different thread trying to lock
901 if( active
->thread
!= element
->thread
) { // it is a different thread
903 ArbitrationLockQueueElement
* victim
= 0;
905 // before placing this new thread on the waiting queue, we look for
906 // a deadlock cycle...
909 // determine whether the active thread holding the object we
910 // want is waiting for another object to be unlocked
912 queue_iterate( &gArbitrationLockQueueWaiting
,
914 ArbitrationLockQueueElement
*,
917 if( waiting
->thread
== active
->thread
) {
918 assert( false == waiting
->aborted
);
924 if( found
) { // yes, active thread waiting for another object
926 // this may be a candidate for rejection if the required
927 // flag is not set, should we detect a deadlock later on
928 if( false == waiting
->required
)
931 // find the thread that is holding this other object, that
932 // is blocking the active thread from proceeding (fun :-)
934 queue_iterate( &gArbitrationLockQueueActive
,
935 active
, // (reuse active queue element)
936 ArbitrationLockQueueElement
*,
939 if( active
->service
== waiting
->service
) {
945 // someone must be holding it or it wouldn't be waiting
948 if( active
->thread
== element
->thread
) {
950 // doh, it's waiting for the thread that originated
951 // this whole lock (ie. current thread) -> deadlock
952 if( false == element
->required
) { // willing to fail?
954 // the originating thread doesn't have the required
955 // flag, so it can fail
956 success
= false; // (fail originating lock request)
957 break; // (out of while)
959 } else { // originating thread is not willing to fail
961 // see if we came across a waiting thread that did
962 // not have the 'required' flag set: we'll fail it
965 // we do have a willing victim, fail it's lock
966 victim
->aborted
= true;
968 // take the victim off the waiting queue
969 queue_remove( &gArbitrationLockQueueWaiting
,
971 ArbitrationLockQueueElement
*,
975 IOLockWakeup( gArbitrationLockQueueLock
,
977 /* one thread */ true );
979 // allow this thread to proceed (ie. wait)
980 success
= true; // (put request on wait queue)
981 break; // (out of while)
984 // all the waiting threads we came across in
985 // finding this loop had the 'required' flag
986 // set, so we've got a deadlock we can't avoid
987 panic("I/O Kit: Unrecoverable deadlock.");
991 // repeat while loop, redefining active thread to be the
992 // thread holding "this other object" (see above), and
993 // looking for threads waiting on it; note the active
994 // variable points to "this other object" already... so
995 // there nothing to do in this else clause.
997 } else { // no, active thread is not waiting for another object
999 success
= true; // (put request on wait queue)
1000 break; // (out of while)
1004 if( success
) { // put the request on the waiting queue?
1005 kern_return_t wait_result
;
1007 // place this thread on the waiting queue and put it to sleep;
1008 // we place it at the tail of the queue...
1009 queue_enter( &gArbitrationLockQueueWaiting
,
1011 ArbitrationLockQueueElement
*,
1014 // declare that this thread will wait for a given event
1015 restart_sleep
: wait_result
= assert_wait( element
,
1016 element
->required
? THREAD_UNINT
1017 : THREAD_INTERRUPTIBLE
);
1019 // unlock global access
1020 IOUnlock( gArbitrationLockQueueLock
);
1022 // put thread to sleep, waiting for our event to fire...
1023 if (wait_result
== THREAD_WAITING
)
1024 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1027 // ...and we've been woken up; we might be in one of two states:
1028 // (a) we've been aborted and our queue element is not on
1029 // any of the three queues, but is floating around
1030 // (b) we're allowed to proceed with the lock and we have
1031 // already been moved from the waiting queue to the
1033 // ...plus a 3rd state, should the thread have been interrupted:
1034 // (c) we're still on the waiting queue
1036 // determine whether we were interrupted out of our sleep
1037 if( THREAD_INTERRUPTED
== wait_result
) {
1039 // re-lock global access
1040 IOTakeLock( gArbitrationLockQueueLock
);
1042 // determine whether we're still on the waiting queue
1044 queue_iterate( &gArbitrationLockQueueWaiting
,
1045 waiting
, // (reuse waiting queue element)
1046 ArbitrationLockQueueElement
*,
1049 if( waiting
== element
) {
1055 if( found
) { // yes, we're still on the waiting queue
1057 // determine whether we're willing to fail
1058 if( false == element
->required
) {
1060 // mark us as aborted
1061 element
->aborted
= true;
1063 // take us off the waiting queue
1064 queue_remove( &gArbitrationLockQueueWaiting
,
1066 ArbitrationLockQueueElement
*,
1068 } else { // we are not willing to fail
1070 // ignore interruption, go back to sleep
1075 // unlock global access
1076 IOUnlock( gArbitrationLockQueueLock
);
1078 // proceed as though this were a normal wake up
1079 wait_result
= THREAD_AWAKENED
;
1082 assert( THREAD_AWAKENED
== wait_result
);
1084 // determine whether we've been aborted while we were asleep
1085 if( element
->aborted
) {
1086 assert( false == element
->required
);
1088 // re-lock global access
1089 IOTakeLock( gArbitrationLockQueueLock
);
1091 action
= kPutOnFreeQueue
;
1093 } else { // we weren't aborted, so we must be ready to go :-)
1095 // we've already been moved from waiting to active queue
1099 } else { // the lock request is to be failed
1101 // return unused queue element to queue
1102 action
= kPutOnFreeQueue
;
1104 } else { // it is the same thread, recursive access is allowed
1106 // add one level of recursion
1109 // return unused queue element to queue
1110 action
= kPutOnFreeQueue
;
1113 } else { // this object is not already locked, so let this thread through
1114 action
= kPutOnActiveQueue
;
1118 // put the new element on a queue
1119 if( kPutOnActiveQueue
== action
) {
1120 queue_enter( &gArbitrationLockQueueActive
,
1122 ArbitrationLockQueueElement
*,
1124 } else if( kPutOnFreeQueue
== action
) {
1125 queue_enter( &gArbitrationLockQueueFree
,
1127 ArbitrationLockQueueElement
*,
1130 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1133 // unlock global access
1134 IOUnlock( gArbitrationLockQueueLock
);
1139 void IOService::unlockForArbitration( void )
1142 ArbitrationLockQueueElement
* element
;
1144 // lock global access
1145 IOTakeLock( gArbitrationLockQueueLock
);
1147 // find the lock element for this object (ie. on active queue)
1149 queue_iterate( &gArbitrationLockQueueActive
,
1151 ArbitrationLockQueueElement
*,
1154 if( element
->service
== this ) {
1162 // determine whether the lock has been taken recursively
1163 if( element
->count
> 1 ) {
1164 // undo one level of recursion
1169 // remove it from the active queue
1170 queue_remove( &gArbitrationLockQueueActive
,
1172 ArbitrationLockQueueElement
*,
1175 // put it on the free queue
1176 queue_enter( &gArbitrationLockQueueFree
,
1178 ArbitrationLockQueueElement
*,
1181 // determine whether a thread is waiting for object (head to tail scan)
1183 queue_iterate( &gArbitrationLockQueueWaiting
,
1185 ArbitrationLockQueueElement
*,
1188 if( element
->service
== this ) {
1194 if ( found
) { // we found an interested thread on waiting queue
1196 // remove it from the waiting queue
1197 queue_remove( &gArbitrationLockQueueWaiting
,
1199 ArbitrationLockQueueElement
*,
1202 // put it on the active queue
1203 queue_enter( &gArbitrationLockQueueActive
,
1205 ArbitrationLockQueueElement
*,
1208 // wake the waiting thread
1209 IOLockWakeup( gArbitrationLockQueueLock
,
1211 /* one thread */ true );
1215 // unlock global access
1216 IOUnlock( gArbitrationLockQueueLock
);
1219 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1222 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1223 context
, gIOServicePlane
);
1226 void IOService::applyToClients( IOServiceApplierFunction applier
,
1229 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1230 context
, gIOServicePlane
);
1239 // send a message to a client or interested party of this service
1240 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1241 void * argument
, vm_size_t argSize
)
1244 IOService
* service
;
1245 _IOServiceInterestNotifier
* notify
;
1247 if( (service
= OSDynamicCast( IOService
, client
)))
1248 ret
= service
->message( type
, this, argument
);
1250 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1252 _IOServiceNotifierInvocation invocation
;
1255 invocation
.thread
= current_thread();
1258 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1261 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1262 _IOServiceNotifierInvocation
*, link
);
1268 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1269 type
, this, argument
, argSize
);
1272 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1273 _IOServiceNotifierInvocation
*, link
);
1274 if( kIOServiceNotifyWaiter
& notify
->state
) {
1275 notify
->state
&= ~kIOServiceNotifyWaiter
;
1276 WAKEUPNOTIFY( notify
);
1281 ret
= kIOReturnSuccess
;
1284 ret
= kIOReturnBadArgument
;
1290 applyToInterestNotifiers(const IORegistryEntry
*target
,
1291 const OSSymbol
* typeOfInterest
,
1292 OSObjectApplierFunction applier
,
1295 OSArray
* copyArray
= 0;
1299 IOCommand
*notifyList
=
1300 OSDynamicCast( IOCommand
, target
->getProperty( typeOfInterest
));
1303 copyArray
= OSArray::withCapacity(1);
1305 // iterate over queue, entry is set to each element in the list
1306 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1307 _IOServiceInterestNotifier
* notify
;
1309 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1310 copyArray
->setObject(notify
);
1319 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1320 (*applier
)(next
, context
);
1321 copyArray
->release();
1325 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1326 OSObjectApplierFunction applier
,
1329 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1330 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1333 struct MessageClientsContext
{
1334 IOService
* service
;
1341 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1344 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1346 ret
= context
->service
->messageClient( context
->type
,
1347 object
, context
->argument
, context
->argSize
);
1348 if( kIOReturnSuccess
!= ret
)
1352 // send a message to all clients
1353 IOReturn
IOService::messageClients( UInt32 type
,
1354 void * argument
, vm_size_t argSize
)
1356 MessageClientsContext context
;
1358 context
.service
= this;
1359 context
.type
= type
;
1360 context
.argument
= argument
;
1361 context
.argSize
= argSize
;
1362 context
.ret
= kIOReturnSuccess
;
1364 applyToInterested( gIOGeneralInterest
,
1365 &messageClientsApplier
, &context
);
1367 return( context
.ret
);
1370 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1371 IOOptionBits response
)
1373 return( kIOReturnUnsupported
);
1376 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1377 IOServiceInterestHandler handler
, void * target
, void * ref
)
1379 _IOServiceInterestNotifier
* notify
= 0;
1381 if( (typeOfInterest
!= gIOGeneralInterest
)
1382 && (typeOfInterest
!= gIOBusyInterest
)
1383 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1384 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1387 lockForArbitration();
1388 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1390 notify
= new _IOServiceInterestNotifier
;
1391 if( notify
&& !notify
->init()) {
1397 notify
->handler
= handler
;
1398 notify
->target
= target
;
1400 notify
->state
= kIOServiceNotifyEnable
;
1401 queue_init( ¬ify
->handlerInvocations
);
1407 // Get the head of the notifier linked list
1408 IOCommand
*notifyList
= (IOCommand
*) getProperty( typeOfInterest
);
1409 if (!notifyList
|| !OSDynamicCast(IOCommand
, notifyList
)) {
1410 notifyList
= OSTypeAlloc(IOCommand
);
1413 setProperty( typeOfInterest
, notifyList
);
1414 notifyList
->release();
1419 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1420 notify
->retain(); // ref'ed while in list
1426 unlockForArbitration();
1431 static void cleanInterestList( OSObject
* head
)
1433 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1438 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1439 queue_next(entry
) = queue_prev(entry
) = 0;
1441 _IOServiceInterestNotifier
* notify
;
1443 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1449 void IOService::unregisterAllInterest( void )
1451 cleanInterestList( getProperty( gIOGeneralInterest
));
1452 cleanInterestList( getProperty( gIOBusyInterest
));
1453 cleanInterestList( getProperty( gIOAppPowerStateInterest
));
1454 cleanInterestList( getProperty( gIOPriorityPowerStateInterest
));
1458 * _IOServiceInterestNotifier
1461 // wait for all threads, other than the current one,
1462 // to exit the handler
1464 void _IOServiceInterestNotifier::wait()
1466 _IOServiceNotifierInvocation
* next
;
1471 queue_iterate( &handlerInvocations
, next
,
1472 _IOServiceNotifierInvocation
*, link
) {
1473 if( next
->thread
!= current_thread() ) {
1479 state
|= kIOServiceNotifyWaiter
;
1486 void _IOServiceInterestNotifier::free()
1488 assert( queue_empty( &handlerInvocations
));
1492 void _IOServiceInterestNotifier::remove()
1496 if( queue_next( &chain
)) {
1497 remqueue( 0, &chain
);
1498 queue_next( &chain
) = queue_prev( &chain
) = 0;
1502 state
&= ~kIOServiceNotifyEnable
;
1511 bool _IOServiceInterestNotifier::disable()
1517 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1518 state
&= ~kIOServiceNotifyEnable
;
1527 void _IOServiceInterestNotifier::enable( bool was
)
1531 state
|= kIOServiceNotifyEnable
;
1533 state
&= ~kIOServiceNotifyEnable
;
1537 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1543 #define tailQ(o) setObject(o)
1544 #define headQ(o) setObject(0, o)
1545 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); }
1547 inline void _workLoopAction( IOWorkLoop::Action action
,
1548 IOService
* service
,
1549 void * p0
= 0, void * p1
= 0,
1550 void * p2
= 0, void * p3
= 0 )
1554 if( (wl
= service
->getWorkLoop())) {
1556 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1559 (*action
)( service
, p0
, p1
, p2
, p3
);
1562 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1566 // if its our only provider
1567 ok
= isParent( provider
, gIOServicePlane
, true);
1571 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1572 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1579 bool IOService::terminatePhase1( IOOptionBits options
)
1584 OSArray
* makeInactive
;
1587 bool startPhase2
= false;
1589 TLOG("%s::terminatePhase1(%08lx)\n", getName(), options
);
1592 if( options
& kIOServiceRecursing
) {
1593 __state
[1] |= kIOServiceRecursing
;
1598 makeInactive
= OSArray::withCapacity( 16 );
1607 didInactive
= victim
->lockForArbitration( true );
1609 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1611 victim
->__state
[0] |= kIOServiceInactiveState
;
1612 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1613 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1614 victim
->_adjustBusy( 1 );
1616 victim
->unlockForArbitration();
1619 startPhase2
= didInactive
;
1622 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1623 IOUserClient::destroyUserReferences( victim
);
1625 iter
= victim
->getClientIterator();
1627 while( (client
= (IOService
*) iter
->getNextObject())) {
1628 TLOG("%s::requestTerminate(%s, %08lx)\n",
1629 client
->getName(), victim
->getName(), options
);
1630 ok
= client
->requestTerminate( victim
, options
);
1631 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1632 client
->getName(), victim
->getName(), ok
);
1634 makeInactive
->setObject( client
);
1640 victim
= (IOService
*) makeInactive
->getObject(0);
1643 makeInactive
->removeObject(0);
1647 makeInactive
->release();
1650 scheduleTerminatePhase2( options
);
1655 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
1657 AbsoluteTime deadline
;
1658 int waitResult
= THREAD_AWAKENED
;
1659 bool wait
, haveDeadline
= false;
1661 options
|= kIOServiceRequired
;
1665 IOLockLock( gJobsLock
);
1667 if( (options
& kIOServiceSynchronous
)
1668 && (current_thread() != gIOTerminateThread
)) {
1671 wait
= (gIOTerminateThread
!= 0);
1673 // wait to become the terminate thread
1674 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
1678 gIOTerminateThread
= current_thread();
1679 gIOTerminatePhase2List
->setObject( this );
1683 while( gIOTerminateWork
)
1684 terminateWorker( options
);
1685 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1687 // wait for the victim to go non-busy
1688 if( !haveDeadline
) {
1689 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1690 haveDeadline
= true;
1692 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
1693 deadline
, THREAD_UNINT
);
1694 if( waitResult
== THREAD_TIMED_OUT
) {
1695 TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName());
1698 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
1700 gIOTerminateThread
= 0;
1701 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1704 // ! kIOServiceSynchronous
1706 gIOTerminatePhase2List
->setObject( this );
1707 if( 0 == gIOTerminateWork
++) {
1708 if( !gIOTerminateThread
)
1709 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) options
);
1711 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1715 IOLockUnlock( gJobsLock
);
1720 void IOService::terminateThread( void * arg
)
1722 IOLockLock( gJobsLock
);
1724 while (gIOTerminateWork
)
1725 terminateWorker( (IOOptionBits
) arg
);
1727 gIOTerminateThread
= 0;
1728 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1730 IOLockUnlock( gJobsLock
);
1733 void IOService::scheduleStop( IOService
* provider
)
1735 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1737 IOLockLock( gJobsLock
);
1738 gIOStopList
->tailQ( this );
1739 gIOStopProviderList
->tailQ( provider
);
1741 if( 0 == gIOTerminateWork
++) {
1742 if( !gIOTerminateThread
)
1743 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1745 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1748 IOLockUnlock( gJobsLock
);
1751 void IOService::scheduleFinalize( void )
1753 TLOG("%s::scheduleFinalize\n", getName());
1755 IOLockLock( gJobsLock
);
1756 gIOFinalizeList
->tailQ( this );
1758 if( 0 == gIOTerminateWork
++) {
1759 if( !gIOTerminateThread
)
1760 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1762 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1765 IOLockUnlock( gJobsLock
);
1768 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1773 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1775 if( false == *defer
) {
1777 if( lockForArbitration( true )) {
1778 if( false == provider
->handleIsOpen( this ))
1779 scheduleStop( provider
);
1782 message( kIOMessageServiceIsRequestingClose
, provider
, (void *) options
);
1783 if( false == provider
->handleIsOpen( this ))
1784 scheduleStop( provider
);
1787 unlockForArbitration();
1794 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
1795 OSArray
* doPhase2List
)
1801 iter
= victim
->getClientIterator();
1803 while( (client
= (IOService
*) iter
->getNextObject())) {
1804 TLOG("%s::willTerminate(%s, %08lx)\n",
1805 client
->getName(), victim
->getName(), options
);
1806 ok
= client
->willTerminate( victim
, options
);
1807 doPhase2List
->tailQ( client
);
1813 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
)
1819 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *) options
);
1821 iter
= victim
->getClientIterator();
1823 while( (client
= (IOService
*) iter
->getNextObject())) {
1824 TLOG("%s::didTerminate(%s, %08lx)\n",
1825 client
->getName(), victim
->getName(), options
);
1826 client
->didTerminate( victim
, options
, &defer
);
1827 TLOG("%s::didTerminate(%s, defer %d)\n",
1828 client
->getName(), victim
->getName(), defer
);
1834 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
)
1836 TLOG("%s::finalize(%08lx)\n", victim
->getName(), options
);
1837 victim
->finalize( options
);
1840 void IOService::actionStop( IOService
* provider
, IOService
* client
)
1842 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
1843 client
->stop( provider
);
1844 if( provider
->isOpen( client
))
1845 provider
->close( client
);
1846 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
1847 client
->detach( provider
);
1850 void IOService::terminateWorker( IOOptionBits options
)
1852 OSArray
* doPhase2List
;
1853 OSArray
* didPhase2List
;
1858 IOService
* provider
;
1864 options
|= kIOServiceRequired
;
1866 doPhase2List
= OSArray::withCapacity( 16 );
1867 didPhase2List
= OSArray::withCapacity( 16 );
1868 freeList
= OSSet::withCapacity( 16 );
1869 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
1873 workDone
= gIOTerminateWork
;
1875 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
1878 gIOTerminatePhase2List
->removeObject(0);
1879 IOLockUnlock( gJobsLock
);
1883 doPhase2
= victim
->lockForArbitration( true );
1885 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
1887 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
1888 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
1890 victim
->__state
[1] |= kIOServiceTermPhase2State
;
1892 victim
->unlockForArbitration();
1895 if( 0 == victim
->getClient()) {
1896 // no clients - will go to finalize
1897 IOLockLock( gJobsLock
);
1898 gIOFinalizeList
->tailQ( victim
);
1899 IOLockUnlock( gJobsLock
);
1901 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
1902 victim
, (void *) options
, (void *) doPhase2List
);
1904 didPhase2List
->headQ( victim
);
1907 victim
= (IOService
*) doPhase2List
->getObject(0);
1910 doPhase2List
->removeObject(0);
1914 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
1916 if( victim
->lockForArbitration( true )) {
1917 victim
->__state
[1] |= kIOServiceTermPhase3State
;
1918 victim
->unlockForArbitration();
1920 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
1921 victim
, (void *) options
);
1922 didPhase2List
->removeObject(0);
1924 IOLockLock( gJobsLock
);
1931 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
1933 IOLockUnlock( gJobsLock
);
1934 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
1935 victim
, (void *) options
);
1936 IOLockLock( gJobsLock
);
1938 freeList
->setObject( victim
);
1939 // safe if finalize list is append only
1940 gIOFinalizeList
->removeObject(0);
1944 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
1946 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
1949 if( !provider
->isChild( client
, gIOServicePlane
)) {
1950 // may be multiply queued - nop it
1951 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
1953 // not ready for stop if it has clients, skip it
1954 if( (client
->__state
[1] & kIOServiceTermPhase3State
) && client
->getClient()) {
1955 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
1960 IOLockUnlock( gJobsLock
);
1961 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
1962 provider
, (void *) client
);
1963 IOLockLock( gJobsLock
);
1964 // check the finalize list now
1968 freeList
->setObject( client
);
1969 freeList
->setObject( provider
);
1971 // safe if stop list is append only
1972 gIOStopList
->removeObject( idx
);
1973 gIOStopProviderList
->removeObject( idx
);
1977 } while( doPhase3
);
1979 gIOTerminateWork
-= workDone
;
1980 moreToDo
= (gIOTerminateWork
!= 0);
1983 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
1986 } while( moreToDo
);
1988 IOLockUnlock( gJobsLock
);
1990 freeList
->release();
1991 doPhase2List
->release();
1992 didPhase2List
->release();
1994 IOLockLock( gJobsLock
);
1997 bool IOService::finalize( IOOptionBits options
)
2000 IOService
* provider
;
2002 iter
= getProviderIterator();
2006 while( (provider
= (IOService
*) iter
->getNextObject())) {
2009 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
2010 /* we come down here on programmatic terminate */
2012 if( provider
->isOpen( this ))
2013 provider
->close( this );
2017 if( provider
->lockForArbitration( true )) {
2018 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2019 scheduleStop( provider
);
2020 provider
->unlockForArbitration();
2037 void IOService::doServiceTerminate( IOOptionBits options
)
2041 // a method in case someone needs to override it
2042 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2046 if( client
->isParent( this, gIOServicePlane
, true))
2047 // we are the clients only provider
2048 ok
= client
->terminate( options
);
2055 bool IOService::terminate( IOOptionBits options
)
2057 options
|= kIOServiceTerminate
;
2059 return( terminatePhase1( options
));
2062 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2068 struct ServiceOpenMessageContext
2070 IOService
* service
;
2072 IOService
* excludeClient
;
2073 IOOptionBits options
;
2076 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2078 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2080 if( object
!= context
->excludeClient
)
2081 context
->service
->messageClient( context
->type
, object
, (void *) context
->options
);
2084 bool IOService::open( IOService
* forClient
,
2085 IOOptionBits options
,
2089 ServiceOpenMessageContext context
;
2091 context
.service
= this;
2092 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2093 context
.excludeClient
= forClient
;
2094 context
.options
= options
;
2096 applyToInterested( gIOGeneralInterest
,
2097 &serviceOpenMessageApplier
, &context
);
2099 if( false == lockForArbitration(false) )
2102 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2104 ok
= handleOpen( forClient
, options
, arg
);
2106 unlockForArbitration();
2111 void IOService::close( IOService
* forClient
,
2112 IOOptionBits options
)
2117 lockForArbitration();
2119 wasClosed
= handleIsOpen( forClient
);
2121 handleClose( forClient
, options
);
2122 last
= (__state
[1] & kIOServiceTermPhase3State
);
2125 unlockForArbitration();
2128 forClient
->scheduleStop( this );
2130 else if( wasClosed
) {
2132 ServiceOpenMessageContext context
;
2134 context
.service
= this;
2135 context
.type
= kIOMessageServiceWasClosed
;
2136 context
.excludeClient
= forClient
;
2137 context
.options
= options
;
2139 applyToInterested( gIOGeneralInterest
,
2140 &serviceOpenMessageApplier
, &context
);
2144 bool IOService::isOpen( const IOService
* forClient
) const
2146 IOService
* self
= (IOService
*) this;
2149 self
->lockForArbitration();
2151 ok
= handleIsOpen( forClient
);
2153 self
->unlockForArbitration();
2158 bool IOService::handleOpen( IOService
* forClient
,
2159 IOOptionBits options
,
2164 ok
= (0 == __owner
);
2166 __owner
= forClient
;
2168 else if( options
& kIOServiceSeize
) {
2169 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2170 __owner
, (void *) options
));
2171 if( ok
&& (0 == __owner
))
2172 __owner
= forClient
;
2179 void IOService::handleClose( IOService
* forClient
,
2180 IOOptionBits options
)
2182 if( __owner
== forClient
)
2186 bool IOService::handleIsOpen( const IOService
* forClient
) const
2189 return( __owner
== forClient
);
2191 return( __owner
!= forClient
);
2195 * Probing & starting
2197 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2199 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2200 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2208 val1
= obj1
->priority
;
2211 val2
= obj2
->priority
;
2213 return ( val1
- val2
);
2216 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2218 OSDictionary
* dict
;
2219 IOService
* service
;
2220 _IOServiceNotifier
* notify
;
2221 OSSymbol
* key
= (OSSymbol
*) ref
;
2224 if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2225 return( notify
->priority
);
2227 else if( (service
= OSDynamicCast( IOService
, entry
)))
2228 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2229 else if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2230 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2237 return( (SInt32
) offset
->unsigned32BitValue());
2239 return( kIODefaultProbeScore
);
2242 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2244 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2245 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2253 val1
= IOServiceObjectOrder( obj1
, ref
);
2256 val2
= IOServiceObjectOrder( obj2
, ref
);
2258 return ( val1
- val2
);
2261 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2263 IOService
* service
= 0;
2265 const OSSymbol
* nextCat
;
2267 iter
= getClientIterator();
2269 while( (service
= (IOService
*) iter
->getNextObject())) {
2270 if( kIOServiceInactiveState
& service
->__state
[0])
2272 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2273 service
->getProperty( gIOMatchCategoryKey
));
2274 if( category
== nextCat
)
2282 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2284 _IOServiceNotifierInvocation invocation
;
2288 invocation
.thread
= current_thread();
2291 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2294 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2295 _IOServiceNotifierInvocation
*, link
);
2301 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
, this );
2304 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2305 _IOServiceNotifierInvocation
*, link
);
2306 if( kIOServiceNotifyWaiter
& notify
->state
) {
2307 notify
->state
&= ~kIOServiceNotifyWaiter
;
2308 WAKEUPNOTIFY( notify
);
2317 * Alloc and probe matching classes,
2318 * called on the provider instance
2321 void IOService::probeCandidates( OSOrderedSet
* matches
)
2323 OSDictionary
* match
= 0;
2326 IOService
* newInst
;
2327 OSDictionary
* props
;
2330 OSOrderedSet
* familyMatches
= 0;
2331 OSOrderedSet
* startList
;
2332 OSDictionary
* startDict
= 0;
2333 const OSSymbol
* category
;
2335 _IOServiceNotifier
* notify
;
2336 OSObject
* nextMatch
= 0;
2338 bool needReloc
= false;
2344 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2346 nextMatch
->retain();
2347 matches
->removeObject(nextMatch
);
2349 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2351 lockForArbitration();
2352 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2353 invokeNotifer( notify
);
2354 unlockForArbitration();
2355 nextMatch
->release();
2359 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2360 nextMatch
->release();
2367 debugFlags
= getDebugFlags( match
);
2371 category
= OSDynamicCast( OSSymbol
,
2372 match
->getObject( gIOMatchCategoryKey
));
2374 category
= gIODefaultMatchCategoryKey
;
2376 if( getClientWithCategory( category
)) {
2378 if( debugFlags
& kIOLogMatch
)
2379 LOG("%s: match category %s exists\n", getName(),
2380 category
->getCStringNoCopy());
2382 nextMatch
->release();
2387 // create a copy now in case its modified during matching
2388 props
= OSDictionary::withDictionary( match
, match
->getCount());
2391 props
->setCapacityIncrement(1);
2393 // check the nub matches
2394 if( false == passiveMatch( props
, true ))
2397 // Check to see if driver reloc has been loaded.
2398 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2401 if( debugFlags
& kIOLogCatalogue
)
2402 LOG("%s: stalling for module\n", getName());
2404 // If reloc hasn't been loaded, exit;
2405 // reprobing will occur after reloc has been loaded.
2409 // reorder on family matchPropertyTable score.
2410 if( 0 == familyMatches
)
2411 familyMatches
= OSOrderedSet::withCapacity( 1,
2412 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2414 familyMatches
->setObject( props
);
2419 nextMatch
->release();
2428 if( familyMatches
) {
2431 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2434 familyMatches
->removeObject( props
);
2439 debugFlags
= getDebugFlags( props
);
2442 symbol
= OSDynamicCast( OSSymbol
,
2443 props
->getObject( gIOClassKey
));
2447 // alloc the driver instance
2448 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2451 IOLog("Couldn't alloc class \"%s\"\n",
2452 symbol
->getCStringNoCopy());
2456 // init driver instance
2457 if( !(inst
->init( props
))) {
2459 if( debugFlags
& kIOLogStart
)
2460 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2464 if( __state
[1] & kIOServiceSynchronousState
)
2465 inst
->__state
[1] |= kIOServiceSynchronousState
;
2467 // give the driver the default match category if not specified
2468 category
= OSDynamicCast( OSSymbol
,
2469 props
->getObject( gIOMatchCategoryKey
));
2471 category
= gIODefaultMatchCategoryKey
;
2472 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2474 // attach driver instance
2475 if( !(inst
->attach( this )))
2478 // pass in score from property table
2479 score
= familyMatches
->orderObject( props
);
2481 // & probe the new driver instance
2483 if( debugFlags
& kIOLogProbe
)
2484 LOG("%s::probe(%s)\n",
2485 inst
->getMetaClass()->getClassName(), getName());
2488 newInst
= inst
->probe( this, &score
);
2489 inst
->detach( this );
2492 if( debugFlags
& kIOLogProbe
)
2493 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2499 newPri
= OSNumber::withNumber( score
, 32 );
2501 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2505 // add to start list for the match category
2507 startDict
= OSDictionary::withCapacity( 1 );
2508 assert( startDict
);
2509 startList
= (OSOrderedSet
*)
2510 startDict
->getObject( category
);
2511 if( 0 == startList
) {
2512 startList
= OSOrderedSet::withCapacity( 1,
2513 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2514 if( startDict
&& startList
) {
2515 startDict
->setObject( category
, startList
);
2516 startList
->release();
2519 assert( startList
);
2521 startList
->setObject( newInst
);
2529 familyMatches
->release();
2533 // start the best (until success) of each category
2535 iter
= OSCollectionIterator::withCollection( startDict
);
2537 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2539 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2540 assert( startList
);
2545 while( true // (!started)
2546 && (inst
= (IOService
*)startList
->getFirstObject())) {
2549 startList
->removeObject(inst
);
2552 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2554 if( debugFlags
& kIOLogStart
) {
2556 LOG( "match category exists, skipping " );
2557 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2558 getName(), inst
->getRetainCount());
2561 if( false == started
)
2562 started
= startCandidate( inst
);
2564 if( (debugFlags
& kIOLogStart
) && (false == started
))
2565 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2566 inst
->getRetainCount());
2575 // adjust the busy count by -1 if matching is stalled for a module,
2576 // or +1 if a previously stalled matching is complete.
2577 lockForArbitration();
2580 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2582 __state
[1] |= kIOServiceModuleStallState
;
2584 } else if( __state
[1] & kIOServiceModuleStallState
) {
2585 __state
[1] &= ~kIOServiceModuleStallState
;
2589 _adjustBusy( adjBusy
);
2590 unlockForArbitration();
2593 startDict
->release();
2597 * Start a previously attached & probed instance,
2598 * called on exporting object instance
2601 bool IOService::startCandidate( IOService
* service
)
2605 ok
= service
->attach( this );
2609 if (this != gIOResources
)
2611 // stall for any nub resources
2613 // stall for any driver resources
2614 service
->checkResources();
2617 AbsoluteTime startTime
;
2618 AbsoluteTime endTime
;
2621 if (kIOLogStart
& gIOKitDebug
)
2622 clock_get_uptime(&startTime
);
2624 ok
= service
->start(this);
2626 if (kIOLogStart
& gIOKitDebug
)
2628 clock_get_uptime(&endTime
);
2630 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2632 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2633 absolutetime_to_nanoseconds(endTime
, &nano
);
2634 if (nano
> 500000000ULL)
2635 IOLog("%s::start took %ld ms\n", service
->getName(), (UInt32
)(nano
/ 1000000ULL));
2639 service
->detach( this );
2644 IOService
* IOService::resources( void )
2646 return( gIOResources
);
2649 void IOService::publishResource( const char * key
, OSObject
* value
)
2651 const OSSymbol
* sym
;
2653 if( (sym
= OSSymbol::withCString( key
))) {
2654 publishResource( sym
, value
);
2659 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
2662 value
= (OSObject
*) gIOServiceKey
;
2664 gIOResources
->setProperty( key
, value
);
2666 if( IORecursiveLockHaveLock( gNotificationLock
))
2669 gIOResourceGenerationCount
++;
2670 gIOResources
->registerService();
2673 bool IOService::addNeededResource( const char * key
)
2675 OSObject
* resourcesProp
;
2680 resourcesProp
= getProperty( gIOResourceMatchKey
);
2682 newKey
= OSString::withCString( key
);
2683 if( (0 == resourcesProp
) || (0 == newKey
))
2686 set
= OSDynamicCast( OSSet
, resourcesProp
);
2688 set
= OSSet::withCapacity( 1 );
2690 set
->setObject( resourcesProp
);
2695 set
->setObject( newKey
);
2697 ret
= setProperty( gIOResourceMatchKey
, set
);
2703 bool IOService::checkResource( OSObject
* matching
)
2706 OSDictionary
* table
;
2708 if( (str
= OSDynamicCast( OSString
, matching
))) {
2709 if( gIOResources
->getProperty( str
))
2714 table
= resourceMatching( str
);
2715 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
2718 IOLog("%s: Can't match using: %s\n", getName(),
2719 matching
->getMetaClass()->getClassName());
2720 /* false would stall forever */
2724 if( gIOKitDebug
& kIOLogConfig
)
2725 LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName());
2727 waitForService( table
);
2729 if( gIOKitDebug
& kIOLogConfig
)
2730 LOG("config(%x): waking\n", (int) IOThreadSelf() );
2735 bool IOService::checkResources( void )
2737 OSObject
* resourcesProp
;
2742 resourcesProp
= getProperty( gIOResourceMatchKey
);
2743 if( 0 == resourcesProp
)
2746 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
2748 iter
= OSCollectionIterator::withCollection( set
);
2750 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
2751 ok
= checkResource( resourcesProp
);
2756 ok
= checkResource( resourcesProp
);
2762 void _IOConfigThread::configThread( void )
2764 _IOConfigThread
* inst
;
2767 if( !(inst
= new _IOConfigThread
))
2771 if( !(IOCreateThread((IOThreadFunc
) &_IOConfigThread::main
, inst
)))
2784 void _IOConfigThread::free( void )
2789 void IOService::doServiceMatch( IOOptionBits options
)
2791 _IOServiceNotifier
* notify
;
2793 OSOrderedSet
* matches
;
2794 SInt32 catalogGeneration
;
2795 bool keepGuessing
= true;
2796 bool reRegistered
= true;
2798 // job->nub->deliverNotification( gIOPublishNotification,
2799 // kIOServiceRegisteredState, 0xffffffff );
2801 while( keepGuessing
) {
2803 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
2804 // the matches list should always be created by findDrivers()
2807 lockForArbitration();
2808 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
2809 deliverNotification( gIOFirstPublishNotification
,
2810 kIOServiceFirstPublishState
, 0xffffffff );
2812 __state
[1] &= ~kIOServiceNeedConfigState
;
2813 __state
[1] |= kIOServiceConfigState
;
2814 __state
[0] |= kIOServiceRegisteredState
;
2816 if( reRegistered
&& (0 == (__state
[0] & kIOServiceInactiveState
))) {
2818 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
2819 gNotifications
->getObject( gIOPublishNotification
) );
2821 while((notify
= (_IOServiceNotifier
*)
2822 iter
->getNextObject())) {
2824 if( passiveMatch( notify
->matching
)
2825 && (kIOServiceNotifyEnable
& notify
->state
))
2826 matches
->setObject( notify
);
2833 unlockForArbitration();
2835 if( matches
->getCount() && (kIOReturnSuccess
== getResources()))
2836 probeCandidates( matches
);
2841 lockForArbitration();
2842 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
2844 (reRegistered
|| (catalogGeneration
!=
2845 gIOCatalogue
->getGenerationCount()))
2846 && (0 == (__state
[0] & kIOServiceInactiveState
));
2849 unlockForArbitration();
2852 if( (0 == (__state
[0] & kIOServiceInactiveState
))
2853 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
2854 deliverNotification( gIOMatchedNotification
,
2855 kIOServiceMatchedState
, 0xffffffff );
2856 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
2857 deliverNotification( gIOFirstMatchNotification
,
2858 kIOServiceFirstMatchState
, 0xffffffff );
2861 __state
[1] &= ~kIOServiceConfigState
;
2862 if( __state
[0] & kIOServiceInactiveState
)
2863 scheduleTerminatePhase2();
2866 unlockForArbitration();
2869 UInt32
IOService::_adjustBusy( SInt32 delta
)
2874 bool wasQuiet
, nowQuiet
, needWake
;
2877 result
= __state
[1] & kIOServiceBusyStateMask
;
2881 next
->lockForArbitration();
2882 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
2883 assert( count
< kIOServiceBusyMax
);
2884 wasQuiet
= (0 == count
);
2885 assert( (!wasQuiet
) || (delta
> 0));
2886 next
->__state
[1] += delta
;
2887 nowQuiet
= (0 == (next
->__state
[1] & kIOServiceBusyStateMask
));
2888 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
2891 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
2892 IOLockLock( gIOServiceBusyLock
);
2893 thread_wakeup( (event_t
) next
);
2894 IOLockUnlock( gIOServiceBusyLock
);
2897 next
->unlockForArbitration();
2899 if( (wasQuiet
|| nowQuiet
) ) {
2900 MessageClientsContext context
;
2902 context
.service
= next
;
2903 context
.type
= kIOMessageServiceBusyStateChange
;
2904 context
.argument
= (void *) wasQuiet
; // busy now
2905 context
.argSize
= 0;
2907 applyToInterestNotifiers( next
, gIOBusyInterest
,
2908 &messageClientsApplier
, &context
);
2910 if( nowQuiet
&& (next
== gIOServiceRoot
))
2911 OSMetaClass::considerUnloads();
2914 delta
= nowQuiet
? -1 : +1;
2916 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
2921 void IOService::adjustBusy( SInt32 delta
)
2923 lockForArbitration();
2924 _adjustBusy( delta
);
2925 unlockForArbitration();
2928 UInt32
IOService::getBusyState( void )
2930 return( __state
[1] & kIOServiceBusyStateMask
);
2933 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
2934 mach_timespec_t
* timeout
)
2937 int waitResult
= THREAD_AWAKENED
;
2938 bool computeDeadline
= true;
2939 AbsoluteTime abstime
;
2942 lockForArbitration();
2943 IOLockLock( gIOServiceBusyLock
);
2944 wait
= (value
!= (__state
[1] & mask
));
2946 __state
[1] |= kIOServiceBusyWaiterState
;
2947 unlockForArbitration();
2949 if( computeDeadline
) {
2950 AbsoluteTime nsinterval
;
2951 clock_interval_to_absolutetime_interval(
2952 timeout
->tv_sec
, kSecondScale
, &abstime
);
2953 clock_interval_to_absolutetime_interval(
2954 timeout
->tv_nsec
, kNanosecondScale
, &nsinterval
);
2955 ADD_ABSOLUTETIME( &abstime
, &nsinterval
);
2956 clock_absolutetime_interval_to_deadline(
2957 abstime
, &abstime
);
2958 computeDeadline
= false;
2961 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
2964 assert_wait((event_t
)this, THREAD_UNINT
);
2966 unlockForArbitration();
2967 IOLockUnlock( gIOServiceBusyLock
);
2969 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2971 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2973 if( waitResult
== THREAD_TIMED_OUT
)
2974 return( kIOReturnTimeout
);
2976 return( kIOReturnSuccess
);
2979 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
2981 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
2984 bool IOService::serializeProperties( OSSerialize
* s
) const
2987 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
2988 sizeof( __state
), "__state");
2990 return( super::serializeProperties(s
) );
2994 void _IOConfigThread::main( _IOConfigThread
* self
)
2996 _IOServiceJob
* job
;
3004 semaphore_wait( gJobsSemaphore
);
3006 IOTakeLock( gJobsLock
);
3007 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
3009 gJobs
->removeObject(job
);
3012 // gNumConfigThreads--; // we're out of service
3013 gNumWaitingThreads
--; // we're out of service
3015 IOUnlock( gJobsLock
);
3021 if( gIOKitDebug
& kIOLogConfig
)
3022 LOG("config(%x): starting on %s, %d\n",
3023 (int) IOThreadSelf(), job
->nub
->getName(), job
->type
);
3025 switch( job
->type
) {
3028 nub
->doServiceMatch( job
->options
);
3032 LOG("config(%x): strange type (%d)\n",
3033 (int) IOThreadSelf(), job
->type
);
3040 IOTakeLock( gJobsLock
);
3041 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
3043 gNumWaitingThreads
++; // back in service
3044 // gNumConfigThreads++;
3046 if( 0 == --gNumConfigThreads
) {
3047 // IOLog("MATCH IDLE\n");
3048 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3051 IOUnlock( gJobsLock
);
3056 if( gIOKitDebug
& kIOLogConfig
)
3057 LOG("config(%x): terminating\n", (int) IOThreadSelf() );
3062 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3065 int waitResult
= THREAD_AWAKENED
;
3066 bool computeDeadline
= true;
3067 AbsoluteTime abstime
;
3069 IOLockLock( gJobsLock
);
3071 wait
= (0 != gNumConfigThreads
);
3074 if( computeDeadline
) {
3075 clock_interval_to_absolutetime_interval(
3076 msToWait
, kMillisecondScale
, &abstime
);
3077 clock_absolutetime_interval_to_deadline(
3078 abstime
, &abstime
);
3079 computeDeadline
= false;
3081 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
3082 abstime
, THREAD_UNINT
);
3084 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3088 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3089 IOLockUnlock( gJobsLock
);
3091 if( waitResult
== THREAD_TIMED_OUT
)
3092 return( kIOReturnTimeout
);
3094 return( kIOReturnSuccess
);
3097 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3104 IOTakeLock( gJobsLock
);
3107 gJobs
->setLastObject( job
);
3109 count
= gNumWaitingThreads
;
3110 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3112 create
= ( (gOutstandingJobs
> count
)
3113 && (gNumConfigThreads
< kMaxConfigThreads
) );
3115 gNumConfigThreads
++;
3116 gNumWaitingThreads
++;
3119 IOUnlock( gJobsLock
);
3124 if( gIOKitDebug
& kIOLogConfig
)
3125 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3126 _IOConfigThread::configThread();
3129 semaphore_signal( gJobsSemaphore
);
3132 // internal - call with gNotificationLock
3133 OSObject
* IOService::getExistingServices( OSDictionary
* matching
,
3134 IOOptionBits inState
, IOOptionBits options
)
3136 OSObject
* current
= 0;
3138 IOService
* service
;
3145 && (obj
= matching
->getObject(gIOProviderClassKey
))
3147 && gIOResourcesKey
->isEqualTo(obj
)
3148 && (service
= gIOResources
))
3150 if( (inState
== (service
->__state
[0] & inState
))
3151 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3152 && service
->passiveMatch( matching
))
3154 if( options
& kIONotifyOnce
)
3157 current
= OSSet::withObjects(
3158 (const OSObject
**) &service
, 1, 1 );
3163 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3164 kIORegistryIterateRecursively
);
3168 while( (service
= (IOService
*) iter
->getNextObject())) {
3169 if( (inState
== (service
->__state
[0] & inState
))
3170 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3171 && service
->passiveMatch( matching
)) {
3173 if( options
& kIONotifyOnce
) {
3178 ((OSSet
*)current
)->setObject( service
);
3180 current
= OSSet::withObjects(
3181 (const OSObject
**) &service
, 1, 1 );
3184 } while( !service
&& !iter
->isValid());
3189 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
3190 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3199 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3203 // is a lock even needed?
3206 iter
= (OSIterator
*) getExistingServices( matching
,
3207 kIOServiceMatchedState
);
3215 // internal - call with gNotificationLock
3216 IONotifier
* IOService::setNotification(
3217 const OSSymbol
* type
, OSDictionary
* matching
,
3218 IOServiceNotificationHandler handler
, void * target
, void * ref
,
3221 _IOServiceNotifier
* notify
= 0;
3227 notify
= new _IOServiceNotifier
;
3228 if( notify
&& !notify
->init()) {
3234 notify
->matching
= matching
;
3235 notify
->handler
= handler
;
3236 notify
->target
= target
;
3238 notify
->priority
= priority
;
3239 notify
->state
= kIOServiceNotifyEnable
;
3240 queue_init( ¬ify
->handlerInvocations
);
3244 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3245 set
= OSOrderedSet::withCapacity( 1,
3246 IONotifyOrdering
, 0 );
3248 gNotifications
->setObject( type
, set
);
3252 notify
->whence
= set
;
3254 set
->setObject( notify
);
3260 // internal - call with gNotificationLock
3261 IONotifier
* IOService::doInstallNotification(
3262 const OSSymbol
* type
, OSDictionary
* matching
,
3263 IOServiceNotificationHandler handler
,
3264 void * target
, void * ref
,
3265 SInt32 priority
, OSIterator
** existing
)
3268 IONotifier
* notify
;
3269 IOOptionBits inState
;
3274 if( type
== gIOPublishNotification
)
3275 inState
= kIOServiceRegisteredState
;
3277 else if( type
== gIOFirstPublishNotification
)
3278 inState
= kIOServiceFirstPublishState
;
3280 else if( (type
== gIOMatchedNotification
)
3281 || (type
== gIOFirstMatchNotification
))
3282 inState
= kIOServiceMatchedState
;
3283 else if( type
== gIOTerminatedNotification
)
3288 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3291 // get the current set
3292 exist
= (OSIterator
*) getExistingServices( matching
, inState
);
3302 IONotifier
* IOService::installNotification(
3303 const OSSymbol
* type
, OSDictionary
* matching
,
3304 IOServiceNotificationHandler handler
,
3305 void * target
, void * ref
,
3306 SInt32 priority
, OSIterator
** existing
)
3308 IONotifier
* notify
;
3312 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3313 priority
, existing
);
3320 IONotifier
* IOService::addNotification(
3321 const OSSymbol
* type
, OSDictionary
* matching
,
3322 IOServiceNotificationHandler handler
,
3323 void * target
, void * ref
,
3326 OSIterator
* existing
;
3327 _IOServiceNotifier
* notify
;
3330 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3331 handler
, target
, ref
, priority
, &existing
);
3333 // send notifications for existing set
3336 notify
->retain(); // in case handler remove()s
3337 while( (next
= (IOService
*) existing
->getNextObject())) {
3339 next
->lockForArbitration();
3340 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3341 next
->invokeNotifer( notify
);
3342 next
->unlockForArbitration();
3345 existing
->release();
3351 struct SyncNotifyVars
{
3352 semaphore_port_t waitHere
;
3356 bool IOService::syncNotificationHandler(
3357 void * /* target */, void * ref
,
3358 IOService
* newService
)
3361 // result may get written more than once before the
3362 // notification is removed!
3363 ((SyncNotifyVars
*) ref
)->result
= newService
;
3364 semaphore_signal( ((SyncNotifyVars
*) ref
)->waitHere
);
3369 IOService
* IOService::waitForService( OSDictionary
* matching
,
3370 mach_timespec_t
* timeout
)
3372 IONotifier
* notify
= 0;
3373 // priority doesn't help us much since we need a thread wakeup
3374 SInt32 priority
= 0;
3375 SyncNotifyVars state
;
3376 kern_return_t err
= kIOReturnBadArgument
;
3388 state
.result
= (IOService
*) getExistingServices( matching
,
3389 kIOServiceMatchedState
, kIONotifyOnce
);
3393 err
= semaphore_create( kernel_task
, &state
.waitHere
,
3394 SYNC_POLICY_FIFO
, 0 );
3395 if( KERN_SUCCESS
!= err
)
3398 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
3399 &IOService::syncNotificationHandler
, (void *) 0,
3400 (void *) &state
, priority
);
3408 err
= semaphore_timedwait( state
.waitHere
, *timeout
);
3410 err
= semaphore_wait( state
.waitHere
);
3414 notify
->remove(); // dequeues
3416 matching
->release();
3418 semaphore_destroy( kernel_task
, state
.waitHere
);
3420 return( state
.result
);
3423 void IOService::deliverNotification( const OSSymbol
* type
,
3424 IOOptionBits orNewState
, IOOptionBits andNewState
)
3426 _IOServiceNotifier
* notify
;
3428 OSArray
* willSend
= 0;
3430 lockForArbitration();
3432 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3433 || (type
== gIOTerminatedNotification
)) {
3437 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3438 gNotifications
->getObject( type
) );
3441 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
3443 if( passiveMatch( notify
->matching
)
3444 && (kIOServiceNotifyEnable
& notify
->state
)) {
3446 willSend
= OSArray::withCapacity(8);
3448 willSend
->setObject( notify
);
3454 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
3460 for( unsigned int idx
= 0;
3461 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
3463 invokeNotifer( notify
);
3465 willSend
->release();
3467 unlockForArbitration();
3470 IOOptionBits
IOService::getState( void ) const
3472 return( __state
[0] );
3476 * Helpers to make matching objects for simple cases
3479 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
3480 OSDictionary
* table
)
3483 table
= OSDictionary::withCapacity( 2 );
3485 table
->setObject(gIOProviderClassKey
, (OSObject
*)name
);
3490 OSDictionary
* IOService::serviceMatching( const char * name
,
3491 OSDictionary
* table
)
3493 const OSString
* str
;
3495 str
= OSSymbol::withCString( name
);
3499 table
= serviceMatching( str
, table
);
3504 OSDictionary
* IOService::nameMatching( const OSString
* name
,
3505 OSDictionary
* table
)
3508 table
= OSDictionary::withCapacity( 2 );
3510 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
3515 OSDictionary
* IOService::nameMatching( const char * name
,
3516 OSDictionary
* table
)
3518 const OSString
* str
;
3520 str
= OSSymbol::withCString( name
);
3524 table
= nameMatching( str
, table
);
3529 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
3530 OSDictionary
* table
)
3532 table
= serviceMatching( gIOResourcesKey
, table
);
3534 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
3539 OSDictionary
* IOService::resourceMatching( const char * name
,
3540 OSDictionary
* table
)
3542 const OSSymbol
* str
;
3544 str
= OSSymbol::withCString( name
);
3548 table
= resourceMatching( str
, table
);
3555 * _IOServiceNotifier
3558 // wait for all threads, other than the current one,
3559 // to exit the handler
3561 void _IOServiceNotifier::wait()
3563 _IOServiceNotifierInvocation
* next
;
3568 queue_iterate( &handlerInvocations
, next
,
3569 _IOServiceNotifierInvocation
*, link
) {
3570 if( next
->thread
!= current_thread() ) {
3576 state
|= kIOServiceNotifyWaiter
;
3583 void _IOServiceNotifier::free()
3585 assert( queue_empty( &handlerInvocations
));
3589 void _IOServiceNotifier::remove()
3594 whence
->removeObject( (OSObject
*) this );
3598 matching
->release();
3602 state
&= ~kIOServiceNotifyEnable
;
3611 bool _IOServiceNotifier::disable()
3617 ret
= (0 != (kIOServiceNotifyEnable
& state
));
3618 state
&= ~kIOServiceNotifyEnable
;
3627 void _IOServiceNotifier::enable( bool was
)
3631 state
|= kIOServiceNotifyEnable
;
3633 state
&= ~kIOServiceNotifyEnable
;
3641 IOService
* IOResources::resources( void )
3645 inst
= new IOResources
;
3646 if( inst
&& !inst
->init()) {
3654 IOWorkLoop
* IOResources::getWorkLoop() const
3656 // If we are the resource root then bringe over to the
3657 // platform to get its workloop
3658 if (this == (IOResources
*) gIOResources
)
3659 return getPlatform()->getWorkLoop();
3661 return IOService::getWorkLoop();
3664 bool IOResources::matchPropertyTable( OSDictionary
* table
)
3672 prop
= table
->getObject( gIOResourceMatchKey
);
3673 str
= OSDynamicCast( OSString
, prop
);
3675 ok
= (0 != getProperty( str
));
3677 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
3679 iter
= OSCollectionIterator::withCollection( set
);
3681 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
3682 ok
= (0 != getProperty( str
));
3691 IOReturn
IOResources::setProperties( OSObject
* properties
)
3694 const OSSymbol
* key
;
3695 OSDictionary
* dict
;
3696 OSCollectionIterator
* iter
;
3698 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
3699 if ( kIOReturnSuccess
!= err
)
3702 dict
= OSDynamicCast(OSDictionary
, properties
);
3704 return( kIOReturnBadArgument
);
3706 iter
= OSCollectionIterator::withCollection( dict
);
3708 return( kIOReturnBadArgument
);
3710 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
3712 if (gIOConsoleUsersKey
== key
)
3714 IORegistryEntry::getRegistryRoot()->setProperty(key
, dict
->getObject(key
));
3715 OSIncrementAtomic( &gIOConsoleUsersSeed
);
3716 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
3720 publishResource( key
, dict
->getObject(key
) );
3725 return( kIOReturnSuccess
);
3729 * Helpers for matching dictionaries.
3730 * Keys existing in matching are checked in properties.
3731 * Keys may be a string or OSCollection of IOStrings
3734 bool IOService::compareProperty( OSDictionary
* matching
,
3740 value
= matching
->getObject( key
);
3742 ok
= value
->isEqualTo( getProperty( key
));
3750 bool IOService::compareProperty( OSDictionary
* matching
,
3751 const OSString
* key
)
3756 value
= matching
->getObject( key
);
3758 ok
= value
->isEqualTo( getProperty( key
));
3765 bool IOService::compareProperties( OSDictionary
* matching
,
3766 OSCollection
* keys
)
3768 OSCollectionIterator
* iter
;
3769 const OSString
* key
;
3772 if( !matching
|| !keys
)
3775 iter
= OSCollectionIterator::withCollection( keys
);
3778 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
3779 ok
= compareProperty( matching
, key
);
3783 keys
->release(); // !! consume a ref !!
3788 /* Helper to add a location matching dict to the table */
3790 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
3792 OSDictionary
* dict
;
3797 dict
= OSDictionary::withCapacity( 1 );
3799 table
->setObject( gIOLocationMatchKey
, dict
);
3807 * Go looking for a provider to match a location dict.
3810 IOService
* IOService::matchLocation( IOService
* /* client */ )
3814 parent
= getProvider();
3817 parent
= parent
->matchLocation( this );
3822 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
3828 IORegistryEntry
* entry
;
3833 bool matchParent
= false;
3844 str
= OSDynamicCast( OSString
, table
->getObject( gIOProviderClassKey
));
3847 match
= (0 != where
->metaCast( str
));
3852 obj
= table
->getObject( gIONameMatchKey
);
3855 match
= where
->compareNames( obj
, changesOK
? &matched
: 0 );
3858 if( changesOK
&& matched
) {
3859 // leave a hint as to which name matched
3860 table
->setObject( gIONameMatchedKey
, matched
);
3865 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
3868 const OSSymbol
* sym
;
3872 sym
= where
->copyLocation();
3874 match
= sym
->isEqualTo( str
);
3881 obj
= table
->getObject( gIOPropertyMatchKey
);
3884 OSDictionary
* dict
;
3885 OSDictionary
* nextDict
;
3890 dict
= where
->dictionaryWithProperties();
3892 nextDict
= OSDynamicCast( OSDictionary
, obj
);
3896 iter
= OSCollectionIterator::withCollection(
3897 OSDynamicCast(OSCollection
, obj
));
3900 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
3901 iter
->getNextObject()))))) {
3902 match
= dict
->isEqualTo( nextDict
, nextDict
);
3915 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
3918 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
3919 match
= (where
== entry
);
3926 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
3930 IOService
* service
= 0;
3931 UInt32 serviceCount
= 0;
3934 iter
= where
->getClientIterator();
3936 while( (service
= (IOService
*) iter
->getNextObject())) {
3937 if( kIOServiceInactiveState
& service
->__state
[0])
3939 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
3945 match
= (serviceCount
== num
->unsigned32BitValue());
3950 if( done
== table
->getCount()) {
3951 // don't call family if we've done all the entries in the table
3952 matchParent
= false;
3956 // pass in score from property table
3957 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
3959 // do family specific matching
3960 match
= where
->matchPropertyTable( table
, &score
);
3964 if( kIOLogMatch
& getDebugFlags( table
))
3965 LOG("%s: family specific matching fails\n", where
->getName());
3972 newPri
= OSNumber::withNumber( score
, 32 );
3974 table
->setObject( gIOProbeScoreKey
, newPri
);
3979 if( !(match
= where
->compareProperty( table
, kIOBSDNameKey
)))
3982 matchParent
= false;
3984 obj
= OSDynamicCast( OSDictionary
,
3985 table
->getObject( gIOParentMatchKey
));
3989 table
= (OSDictionary
*) obj
;
3993 table
= OSDynamicCast( OSDictionary
,
3994 table
->getObject( gIOLocationMatchKey
));
3997 where
= where
->getProvider();
3999 where
= where
->matchLocation( where
);
4002 } while( table
&& where
);
4004 } while( matchParent
&& (where
= where
->getProvider()) );
4006 if( kIOLogMatch
& gIOKitDebug
)
4008 LOG("match parent @ %s = %d\n",
4009 where
->getName(), match
);
4015 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4016 UInt32 type
, OSDictionary
* properties
,
4017 IOUserClient
** handler
)
4019 const OSSymbol
*userClientClass
= 0;
4020 IOUserClient
*client
;
4023 // First try my own properties for a user client class name
4024 temp
= getProperty(gIOUserClientClassKey
);
4026 if (OSDynamicCast(OSSymbol
, temp
))
4027 userClientClass
= (const OSSymbol
*) temp
;
4028 else if (OSDynamicCast(OSString
, temp
)) {
4029 userClientClass
= OSSymbol::withString((OSString
*) temp
);
4030 if (userClientClass
)
4031 setProperty(kIOUserClientClassKey
,
4032 (OSObject
*) userClientClass
);
4036 // Didn't find one so lets just bomb out now without further ado.
4037 if (!userClientClass
)
4038 return kIOReturnUnsupported
;
4040 temp
= OSMetaClass::allocClassWithName(userClientClass
);
4042 return kIOReturnNoMemory
;
4044 if (OSDynamicCast(IOUserClient
, temp
))
4045 client
= (IOUserClient
*) temp
;
4048 return kIOReturnUnsupported
;
4051 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
4053 return kIOReturnBadArgument
;
4056 if ( !client
->attach(this) ) {
4058 return kIOReturnUnsupported
;
4061 if ( !client
->start(this) ) {
4062 client
->detach(this);
4064 return kIOReturnUnsupported
;
4068 return kIOReturnSuccess
;
4071 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4072 UInt32 type
, IOUserClient
** handler
)
4074 return( newUserClient( owningTask
, securityID
, type
, 0, handler
));
4077 IOReturn
IOService::requestProbe( IOOptionBits options
)
4079 return( kIOReturnUnsupported
);
4083 * Convert an IOReturn to text. Subclasses which add additional
4084 * IOReturn's should override this method and call
4085 * super::stringFromReturn if the desired value is not found.
4088 const char * IOService::stringFromReturn( IOReturn rtn
)
4090 static const IONamedValue IOReturn_values
[] = {
4091 {kIOReturnSuccess
, "success" },
4092 {kIOReturnError
, "general error" },
4093 {kIOReturnNoMemory
, "memory allocation error" },
4094 {kIOReturnNoResources
, "resource shortage" },
4095 {kIOReturnIPCError
, "Mach IPC failure" },
4096 {kIOReturnNoDevice
, "no such device" },
4097 {kIOReturnNotPrivileged
, "privilege violation" },
4098 {kIOReturnBadArgument
, "invalid argument" },
4099 {kIOReturnLockedRead
, "device is read locked" },
4100 {kIOReturnLockedWrite
, "device is write locked" },
4101 {kIOReturnExclusiveAccess
, "device is exclusive access" },
4102 {kIOReturnBadMessageID
, "bad IPC message ID" },
4103 {kIOReturnUnsupported
, "unsupported function" },
4104 {kIOReturnVMError
, "virtual memory error" },
4105 {kIOReturnInternalError
, "internal driver error" },
4106 {kIOReturnIOError
, "I/O error" },
4107 {kIOReturnCannotLock
, "cannot acquire lock" },
4108 {kIOReturnNotOpen
, "device is not open" },
4109 {kIOReturnNotReadable
, "device is not readable" },
4110 {kIOReturnNotWritable
, "device is not writeable" },
4111 {kIOReturnNotAligned
, "alignment error" },
4112 {kIOReturnBadMedia
, "media error" },
4113 {kIOReturnStillOpen
, "device is still open" },
4114 {kIOReturnRLDError
, "rld failure" },
4115 {kIOReturnDMAError
, "DMA failure" },
4116 {kIOReturnBusy
, "device is busy" },
4117 {kIOReturnTimeout
, "I/O timeout" },
4118 {kIOReturnOffline
, "device is offline" },
4119 {kIOReturnNotReady
, "device is not ready" },
4120 {kIOReturnNotAttached
, "device/channel is not attached" },
4121 {kIOReturnNoChannels
, "no DMA channels available" },
4122 {kIOReturnNoSpace
, "no space for data" },
4123 {kIOReturnPortExists
, "device port already exists" },
4124 {kIOReturnCannotWire
, "cannot wire physical memory" },
4125 {kIOReturnNoInterrupt
, "no interrupt attached" },
4126 {kIOReturnNoFrames
, "no DMA frames enqueued" },
4127 {kIOReturnMessageTooLarge
, "message is too large" },
4128 {kIOReturnNotPermitted
, "operation is not permitted" },
4129 {kIOReturnNoPower
, "device is without power" },
4130 {kIOReturnNoMedia
, "media is not present" },
4131 {kIOReturnUnformattedMedia
, "media is not formatted" },
4132 {kIOReturnUnsupportedMode
, "unsupported mode" },
4133 {kIOReturnUnderrun
, "data underrun" },
4134 {kIOReturnOverrun
, "data overrun" },
4135 {kIOReturnDeviceError
, "device error" },
4136 {kIOReturnNoCompletion
, "no completion routine" },
4137 {kIOReturnAborted
, "operation was aborted" },
4138 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
4139 {kIOReturnNotResponding
, "device is not responding" },
4140 {kIOReturnInvalid
, "unanticipated driver error" },
4144 return IOFindNameForValue(rtn
, IOReturn_values
);
4148 * Convert an IOReturn to an errno.
4150 int IOService::errnoFromReturn( IOReturn rtn
)
4154 case kIOReturnSuccess
:
4156 case kIOReturnNoMemory
:
4158 case kIOReturnNoDevice
:
4160 case kIOReturnVMError
:
4162 case kIOReturnNotPermitted
:
4164 case kIOReturnNotPrivileged
:
4166 case kIOReturnIOError
:
4168 case kIOReturnNotWritable
:
4170 case kIOReturnBadArgument
:
4172 case kIOReturnUnsupported
:
4176 case kIOReturnNoPower
:
4178 case kIOReturnDeviceError
:
4180 case kIOReturnTimeout
:
4182 case kIOReturnMessageTooLarge
:
4184 case kIOReturnNoSpace
:
4186 case kIOReturnCannotLock
:
4190 case kIOReturnBadMessageID
:
4191 case kIOReturnNoCompletion
:
4192 case kIOReturnNotAligned
:
4194 case kIOReturnNotReady
:
4196 case kIOReturnRLDError
:
4198 case kIOReturnPortExists
:
4199 case kIOReturnStillOpen
:
4201 case kIOReturnExclusiveAccess
:
4202 case kIOReturnLockedRead
:
4203 case kIOReturnLockedWrite
:
4204 case kIOReturnNotAttached
:
4205 case kIOReturnNotOpen
:
4206 case kIOReturnNotReadable
:
4208 case kIOReturnCannotWire
:
4209 case kIOReturnNoResources
:
4211 case kIOReturnAborted
:
4212 case kIOReturnOffline
:
4213 case kIOReturnNotResponding
:
4215 case kIOReturnBadMedia
:
4216 case kIOReturnNoMedia
:
4217 case kIOReturnUnformattedMedia
:
4218 return(ENXIO
); // (media error)
4219 case kIOReturnDMAError
:
4220 case kIOReturnOverrun
:
4221 case kIOReturnUnderrun
:
4222 return(EIO
); // (transfer error)
4223 case kIOReturnNoBandwidth
:
4224 case kIOReturnNoChannels
:
4225 case kIOReturnNoFrames
:
4226 case kIOReturnNoInterrupt
:
4227 return(EIO
); // (hardware error)
4228 case kIOReturnError
:
4229 case kIOReturnInternalError
:
4230 case kIOReturnInvalid
:
4231 return(EIO
); // (generic error)
4232 case kIOReturnIPCError
:
4233 return(EIO
); // (ipc error)
4235 return(EIO
); // (all other errors)
4239 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
4243 * Generic entry point for calls from the provider. A return value of
4244 * kIOReturnSuccess indicates that the message was received, and where
4245 * applicable, that it was successful.
4248 return kIOReturnUnsupported
;
4255 IOItemCount
IOService::getDeviceMemoryCount( void )
4260 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4262 count
= array
->getCount();
4269 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
4272 IODeviceMemory
* range
;
4274 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4276 range
= (IODeviceMemory
*) array
->getObject( index
);
4283 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
4284 IOOptionBits options
)
4286 IODeviceMemory
* range
;
4289 range
= getDeviceMemoryWithIndex( index
);
4291 map
= range
->map( options
);
4298 OSArray
* IOService::getDeviceMemory( void )
4300 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
4304 void IOService::setDeviceMemory( OSArray
* array
)
4306 setProperty( gIODeviceMemoryKey
, array
);
4313 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
4315 IOInterruptController
*interruptController
;
4318 OSSymbol
*interruptControllerName
;
4320 IOInterruptSource
*interruptSources
;
4322 // Get the parents list from the nub.
4323 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
4324 if (array
== 0) return kIOReturnNoResources
;
4326 // Allocate space for the IOInterruptSources if needed... then return early.
4327 if (nub
->_interruptSources
== 0) {
4328 numSources
= array
->getCount();
4329 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
4330 if (interruptSources
== 0) return kIOReturnNoMemory
;
4332 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
4334 nub
->_numInterruptSources
= numSources
;
4335 nub
->_interruptSources
= interruptSources
;
4336 return kIOReturnSuccess
;
4339 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
4340 if (interruptControllerName
== 0) return kIOReturnNoResources
;
4342 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
4343 if (interruptController
== 0) return kIOReturnNoResources
;
4345 // Get the interrupt numbers from the nub.
4346 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
4347 if (array
== 0) return kIOReturnNoResources
;
4348 data
= OSDynamicCast(OSData
, array
->getObject(source
));
4349 if (data
== 0) return kIOReturnNoResources
;
4351 // Set the interruptController and interruptSource in the nub's table.
4352 interruptSources
= nub
->_interruptSources
;
4353 interruptSources
[source
].interruptController
= interruptController
;
4354 interruptSources
[source
].vectorData
= data
;
4356 return kIOReturnSuccess
;
4359 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
4363 /* Make sure the _interruptSources are set */
4364 if (_interruptSources
== 0) {
4365 ret
= resolveInterrupt(this, source
);
4366 if (ret
!= kIOReturnSuccess
) return ret
;
4369 /* Make sure the local source number is valid */
4370 if ((source
< 0) || (source
>= _numInterruptSources
))
4371 return kIOReturnNoInterrupt
;
4373 /* Look up the contoller for the local source */
4374 *interruptController
= _interruptSources
[source
].interruptController
;
4376 if (*interruptController
== NULL
) {
4377 if (!resolve
) return kIOReturnNoInterrupt
;
4379 /* Try to reslove the interrupt */
4380 ret
= resolveInterrupt(this, source
);
4381 if (ret
!= kIOReturnSuccess
) return ret
;
4383 *interruptController
= _interruptSources
[source
].interruptController
;
4386 return kIOReturnSuccess
;
4389 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
4390 IOInterruptAction handler
,
4393 IOInterruptController
*interruptController
;
4396 ret
= lookupInterrupt(source
, true, &interruptController
);
4397 if (ret
!= kIOReturnSuccess
) return ret
;
4399 /* Register the source */
4400 return interruptController
->registerInterrupt(this, source
, target
,
4401 (IOInterruptHandler
)handler
,
4405 IOReturn
IOService::unregisterInterrupt(int source
)
4407 IOInterruptController
*interruptController
;
4410 ret
= lookupInterrupt(source
, false, &interruptController
);
4411 if (ret
!= kIOReturnSuccess
) return ret
;
4413 /* Unregister the source */
4414 return interruptController
->unregisterInterrupt(this, source
);
4417 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
4419 IOInterruptController
*interruptController
;
4422 ret
= lookupInterrupt(source
, true, &interruptController
);
4423 if (ret
!= kIOReturnSuccess
) return ret
;
4425 /* Return the type */
4426 return interruptController
->getInterruptType(this, source
, interruptType
);
4429 IOReturn
IOService::enableInterrupt(int source
)
4431 IOInterruptController
*interruptController
;
4434 ret
= lookupInterrupt(source
, false, &interruptController
);
4435 if (ret
!= kIOReturnSuccess
) return ret
;
4437 /* Enable the source */
4438 return interruptController
->enableInterrupt(this, source
);
4441 IOReturn
IOService::disableInterrupt(int source
)
4443 IOInterruptController
*interruptController
;
4446 ret
= lookupInterrupt(source
, false, &interruptController
);
4447 if (ret
!= kIOReturnSuccess
) return ret
;
4449 /* Disable the source */
4450 return interruptController
->disableInterrupt(this, source
);
4453 IOReturn
IOService::causeInterrupt(int source
)
4455 IOInterruptController
*interruptController
;
4458 ret
= lookupInterrupt(source
, false, &interruptController
);
4459 if (ret
!= kIOReturnSuccess
) return ret
;
4461 /* Cause an interrupt for the source */
4462 return interruptController
->causeInterrupt(this, source
);
4465 OSMetaClassDefineReservedUsed(IOService
, 0);
4466 OSMetaClassDefineReservedUsed(IOService
, 1);
4467 OSMetaClassDefineReservedUsed(IOService
, 2);
4468 OSMetaClassDefineReservedUsed(IOService
, 3);
4470 OSMetaClassDefineReservedUnused(IOService
, 4);
4471 OSMetaClassDefineReservedUnused(IOService
, 5);
4472 OSMetaClassDefineReservedUnused(IOService
, 6);
4473 OSMetaClassDefineReservedUnused(IOService
, 7);
4474 OSMetaClassDefineReservedUnused(IOService
, 8);
4475 OSMetaClassDefineReservedUnused(IOService
, 9);
4476 OSMetaClassDefineReservedUnused(IOService
, 10);
4477 OSMetaClassDefineReservedUnused(IOService
, 11);
4478 OSMetaClassDefineReservedUnused(IOService
, 12);
4479 OSMetaClassDefineReservedUnused(IOService
, 13);
4480 OSMetaClassDefineReservedUnused(IOService
, 14);
4481 OSMetaClassDefineReservedUnused(IOService
, 15);
4482 OSMetaClassDefineReservedUnused(IOService
, 16);
4483 OSMetaClassDefineReservedUnused(IOService
, 17);
4484 OSMetaClassDefineReservedUnused(IOService
, 18);
4485 OSMetaClassDefineReservedUnused(IOService
, 19);
4486 OSMetaClassDefineReservedUnused(IOService
, 20);
4487 OSMetaClassDefineReservedUnused(IOService
, 21);
4488 OSMetaClassDefineReservedUnused(IOService
, 22);
4489 OSMetaClassDefineReservedUnused(IOService
, 23);
4490 OSMetaClassDefineReservedUnused(IOService
, 24);
4491 OSMetaClassDefineReservedUnused(IOService
, 25);
4492 OSMetaClassDefineReservedUnused(IOService
, 26);
4493 OSMetaClassDefineReservedUnused(IOService
, 27);
4494 OSMetaClassDefineReservedUnused(IOService
, 28);
4495 OSMetaClassDefineReservedUnused(IOService
, 29);
4496 OSMetaClassDefineReservedUnused(IOService
, 30);
4497 OSMetaClassDefineReservedUnused(IOService
, 31);
4498 OSMetaClassDefineReservedUnused(IOService
, 32);
4499 OSMetaClassDefineReservedUnused(IOService
, 33);
4500 OSMetaClassDefineReservedUnused(IOService
, 34);
4501 OSMetaClassDefineReservedUnused(IOService
, 35);
4502 OSMetaClassDefineReservedUnused(IOService
, 36);
4503 OSMetaClassDefineReservedUnused(IOService
, 37);
4504 OSMetaClassDefineReservedUnused(IOService
, 38);
4505 OSMetaClassDefineReservedUnused(IOService
, 39);
4506 OSMetaClassDefineReservedUnused(IOService
, 40);
4507 OSMetaClassDefineReservedUnused(IOService
, 41);
4508 OSMetaClassDefineReservedUnused(IOService
, 42);
4509 OSMetaClassDefineReservedUnused(IOService
, 43);
4510 OSMetaClassDefineReservedUnused(IOService
, 44);
4511 OSMetaClassDefineReservedUnused(IOService
, 45);
4512 OSMetaClassDefineReservedUnused(IOService
, 46);
4513 OSMetaClassDefineReservedUnused(IOService
, 47);
4514 OSMetaClassDefineReservedUnused(IOService
, 48);
4515 OSMetaClassDefineReservedUnused(IOService
, 49);
4516 OSMetaClassDefineReservedUnused(IOService
, 50);
4517 OSMetaClassDefineReservedUnused(IOService
, 51);
4518 OSMetaClassDefineReservedUnused(IOService
, 52);
4519 OSMetaClassDefineReservedUnused(IOService
, 53);
4520 OSMetaClassDefineReservedUnused(IOService
, 54);
4521 OSMetaClassDefineReservedUnused(IOService
, 55);
4522 OSMetaClassDefineReservedUnused(IOService
, 56);
4523 OSMetaClassDefineReservedUnused(IOService
, 57);
4524 OSMetaClassDefineReservedUnused(IOService
, 58);
4525 OSMetaClassDefineReservedUnused(IOService
, 59);
4526 OSMetaClassDefineReservedUnused(IOService
, 60);
4527 OSMetaClassDefineReservedUnused(IOService
, 61);
4528 OSMetaClassDefineReservedUnused(IOService
, 62);
4529 OSMetaClassDefineReservedUnused(IOService
, 63);