2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include <IOKit/system.h>
25 #include <IOKit/IOService.h>
26 #include <libkern/c++/OSContainers.h>
27 #include <libkern/c++/OSUnserialize.h>
28 #include <IOKit/IOCatalogue.h>
29 #include <IOKit/IOCommand.h>
30 #include <IOKit/IODeviceMemory.h>
31 #include <IOKit/IOInterrupts.h>
32 #include <IOKit/IOInterruptController.h>
33 #include <IOKit/IOPlatformExpert.h>
34 #include <IOKit/IOMessage.h>
35 #include <IOKit/IOLib.h>
36 #include <IOKit/IOKitKeysPrivate.h>
37 #include <IOKit/IOBSD.h>
38 #include <IOKit/IOUserClient.h>
39 #include <IOKit/IOWorkLoop.h>
40 #include <mach/sync_policy.h>
41 #include <IOKit/assert.h>
42 #include <sys/errno.h>
47 #include "IOServicePrivate.h"
49 // take lockForArbitration before LOCKNOTIFY
51 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
53 #define super IORegistryEntry
55 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
57 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
59 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
61 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
63 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
65 OSDefineMetaClassAndStructors(IOResources
, IOService
)
67 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
69 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
71 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
73 static IOPlatformExpert
* gIOPlatform
;
74 static class IOPMrootDomain
* gIOPMRootDomain
;
75 const IORegistryPlane
* gIOServicePlane
;
76 const IORegistryPlane
* gIOPowerPlane
;
77 const OSSymbol
* gIODeviceMemoryKey
;
78 const OSSymbol
* gIOInterruptControllersKey
;
79 const OSSymbol
* gIOInterruptSpecifiersKey
;
81 const OSSymbol
* gIOResourcesKey
;
82 const OSSymbol
* gIOResourceMatchKey
;
83 const OSSymbol
* gIOProviderClassKey
;
84 const OSSymbol
* gIONameMatchKey
;
85 const OSSymbol
* gIONameMatchedKey
;
86 const OSSymbol
* gIOPropertyMatchKey
;
87 const OSSymbol
* gIOLocationMatchKey
;
88 const OSSymbol
* gIOParentMatchKey
;
89 const OSSymbol
* gIOPathMatchKey
;
90 const OSSymbol
* gIOMatchCategoryKey
;
91 const OSSymbol
* gIODefaultMatchCategoryKey
;
92 const OSSymbol
* gIOMatchedServiceCountKey
;
94 const OSSymbol
* gIOUserClientClassKey
;
95 const OSSymbol
* gIOKitDebugKey
;
97 const OSSymbol
* gIOCommandPoolSizeKey
;
99 const OSSymbol
* gIOConsoleUsersKey
;
100 const OSSymbol
* gIOConsoleSessionUIDKey
;
101 const OSSymbol
* gIOConsoleUsersSeedKey
;
103 static int gIOResourceGenerationCount
;
105 const OSSymbol
* gIOServiceKey
;
106 const OSSymbol
* gIOPublishNotification
;
107 const OSSymbol
* gIOFirstPublishNotification
;
108 const OSSymbol
* gIOMatchedNotification
;
109 const OSSymbol
* gIOFirstMatchNotification
;
110 const OSSymbol
* gIOTerminatedNotification
;
112 const OSSymbol
* gIOGeneralInterest
;
113 const OSSymbol
* gIOBusyInterest
;
114 const OSSymbol
* gIOAppPowerStateInterest
;
115 const OSSymbol
* gIOPriorityPowerStateInterest
;
117 static OSDictionary
* gNotifications
;
118 static IORecursiveLock
* gNotificationLock
;
120 static IOService
* gIOResources
;
121 static IOService
* gIOServiceRoot
;
123 static OSOrderedSet
* gJobs
;
124 static semaphore_port_t gJobsSemaphore
;
125 static IOLock
* gJobsLock
;
126 static int gOutstandingJobs
;
127 static int gNumConfigThreads
;
128 static int gNumWaitingThreads
;
129 static IOLock
* gIOServiceBusyLock
;
131 static thread_t gIOTerminateThread
;
132 static UInt32 gIOTerminateWork
;
133 static OSArray
* gIOTerminatePhase2List
;
134 static OSArray
* gIOStopList
;
135 static OSArray
* gIOStopProviderList
;
136 static OSArray
* gIOFinalizeList
;
138 static SInt32 gIOConsoleUsersSeed
;
139 static OSData
* gIOConsoleUsersSeedValue
;
141 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
143 #define LOCKREADNOTIFY() \
144 IORecursiveLockLock( gNotificationLock )
145 #define LOCKWRITENOTIFY() \
146 IORecursiveLockLock( gNotificationLock )
147 #define LOCKWRITE2READNOTIFY()
148 #define UNLOCKNOTIFY() \
149 IORecursiveLockUnlock( gNotificationLock )
150 #define SLEEPNOTIFY(event) \
151 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
152 #define WAKEUPNOTIFY(event) \
153 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
155 #define randomDelay() \
156 int del = read_processor_clock(); \
157 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
160 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
162 #define queue_element(entry, element, type, field) do { \
163 vm_address_t __ele = (vm_address_t) (entry); \
164 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
165 (element) = (type) __ele; \
168 #define iterqueue(que, elt) \
169 for (queue_entry_t elt = queue_first(que); \
170 !queue_end(que, elt); \
171 elt = queue_next(elt))
173 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
175 struct ArbitrationLockQueueElement
{
184 static queue_head_t gArbitrationLockQueueActive
;
185 static queue_head_t gArbitrationLockQueueWaiting
;
186 static queue_head_t gArbitrationLockQueueFree
;
187 static IOLock
* gArbitrationLockQueueLock
;
189 bool IOService::isInactive( void ) const
190 { return( 0 != (kIOServiceInactiveState
& getState())); }
192 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
196 // Only used by the intel implementation of
197 // IOService::requireMaxBusStall(UInt32 __unused ns)
200 const IOService
*fService
;
204 static OSData
*sBusStall
= OSData::withCapacity(8 * sizeof(BusStallEntry
));
205 static IOLock
*sBusStallLock
= IOLockAlloc();
206 #endif /* __i386__ */
208 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
210 void IOService::initialize( void )
214 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
215 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
217 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
218 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
219 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
220 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
221 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
222 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
223 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
225 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
226 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
227 kIODefaultMatchCategoryKey
);
228 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
229 kIOMatchedServiceCountKey
);
231 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
233 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
234 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
236 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
237 gIOInterruptControllersKey
238 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
239 gIOInterruptSpecifiersKey
240 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
242 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
244 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
246 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
247 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
248 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
249 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
251 gNotifications
= OSDictionary::withCapacity( 1 );
252 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
253 kIOPublishNotification
);
254 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
255 kIOFirstPublishNotification
);
256 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
257 kIOMatchedNotification
);
258 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
259 kIOFirstMatchNotification
);
260 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
261 kIOTerminatedNotification
);
262 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
264 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
265 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
266 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey
);
267 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
269 gNotificationLock
= IORecursiveLockAlloc();
271 assert( gIOServicePlane
&& gIODeviceMemoryKey
272 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
273 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
274 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
275 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
276 && gIOPublishNotification
&& gIOMatchedNotification
277 && gIOTerminatedNotification
&& gIOServiceKey
278 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
279 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
281 gJobsLock
= IOLockAlloc();
282 gJobs
= OSOrderedSet::withCapacity( 10 );
284 gIOServiceBusyLock
= IOLockAlloc();
286 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
288 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& (err
== KERN_SUCCESS
) );
290 gIOResources
= IOResources::resources();
291 assert( gIOResources
);
293 gArbitrationLockQueueLock
= IOLockAlloc();
294 queue_init(&gArbitrationLockQueueActive
);
295 queue_init(&gArbitrationLockQueueWaiting
);
296 queue_init(&gArbitrationLockQueueFree
);
298 assert( gArbitrationLockQueueLock
);
300 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
301 gIOStopList
= OSArray::withCapacity( 16 );
302 gIOStopProviderList
= OSArray::withCapacity( 16 );
303 gIOFinalizeList
= OSArray::withCapacity( 16 );
304 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
307 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
310 static UInt64
getDebugFlags( OSDictionary
* props
)
312 OSNumber
* debugProp
;
315 debugProp
= OSDynamicCast( OSNumber
,
316 props
->getObject( gIOKitDebugKey
));
318 debugFlags
= debugProp
->unsigned64BitValue();
320 debugFlags
= gIOKitDebug
;
322 return( debugFlags
);
326 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
328 // Probe a matched service and return an instance to be started.
329 // The default score is from the property table, & may be altered
330 // during probe to change the start order.
332 IOService
* IOService::probe( IOService
* provider
,
338 bool IOService::start( IOService
* provider
)
343 void IOService::stop( IOService
* provider
)
347 void IOService::free( void )
349 requireMaxBusStall(0);
350 if( getPropertyTable())
351 unregisterAllInterest();
357 * Attach in service plane
359 bool IOService::attach( IOService
* provider
)
365 if( gIOKitDebug
& kIOLogAttach
)
366 LOG( "%s::attach(%s)\n", getName(),
367 provider
->getName());
369 provider
->lockForArbitration();
370 if( provider
->__state
[0] & kIOServiceInactiveState
)
373 ok
= attachToParent( provider
, gIOServicePlane
);
374 provider
->unlockForArbitration();
377 gIOServiceRoot
= this;
378 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
384 IOService
* IOService::getServiceRoot( void )
386 return( gIOServiceRoot
);
389 void IOService::detach( IOService
* provider
)
391 IOService
* newProvider
= 0;
395 if( gIOKitDebug
& kIOLogAttach
)
396 LOG("%s::detach(%s)\n", getName(), provider
->getName());
398 lockForArbitration();
400 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
401 && (provider
== getProvider()));
403 detachFromParent( provider
, gIOServicePlane
);
406 newProvider
= getProvider();
407 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
408 _adjustBusy( -busy
);
411 unlockForArbitration();
414 newProvider
->lockForArbitration();
415 newProvider
->_adjustBusy(1);
416 newProvider
->unlockForArbitration();
419 // check for last client detach from a terminated service
420 if( provider
->lockForArbitration( true )) {
422 provider
->_adjustBusy( -1 );
423 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
424 && (0 == provider
->getClient())) {
425 provider
->scheduleFinalize();
427 provider
->unlockForArbitration();
432 * Register instance - publish it for matching
435 void IOService::registerService( IOOptionBits options
)
441 enum { kMaxPathLen
= 256 };
442 enum { kMaxChars
= 63 };
444 IORegistryEntry
* parent
= this;
445 IORegistryEntry
* root
= getRegistryRoot();
446 while( parent
&& (parent
!= root
))
447 parent
= parent
->getParentEntry( gIOServicePlane
);
449 if( parent
!= root
) {
450 IOLog("%s: not registry member at registerService()\n", getName());
454 // Allow the Platform Expert to adjust this node.
455 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
458 if( (this != gIOResources
)
459 && (kIOLogRegister
& gIOKitDebug
)) {
461 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
463 IOLog( "Registering: " );
466 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
469 if( len
> kMaxChars
) {
473 if( (skip
= strchr( path
, '/')))
479 IOLog( "%s\n", path
);
482 IOFree( pathBuf
, kMaxPathLen
);
485 startMatching( options
);
488 void IOService::startMatching( IOOptionBits options
)
490 IOService
* provider
;
493 bool needWake
= false;
498 lockForArbitration();
500 sync
= (options
& kIOServiceSynchronous
)
501 || ((provider
= getProvider())
502 && (provider
->__state
[1] & kIOServiceSynchronousState
));
504 if ( options
& kIOServiceAsynchronous
)
507 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
508 && (0 == (__state
[0] & kIOServiceInactiveState
));
510 __state
[1] |= kIOServiceNeedConfigState
;
512 // __state[0] &= ~kIOServiceInactiveState;
514 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
515 // OSKernelStackRemaining(), getName());
518 prevBusy
= _adjustBusy( 1 );
519 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
523 __state
[1] |= kIOServiceSynchronousState
;
525 __state
[1] &= ~kIOServiceSynchronousState
;
527 unlockForArbitration();
532 IOLockLock( gIOServiceBusyLock
);
533 thread_wakeup( (event_t
) this/*&__state[1]*/ );
534 IOLockUnlock( gIOServiceBusyLock
);
536 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
538 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
542 if( (__state
[1] & kIOServiceNeedConfigState
))
543 doServiceMatch( options
);
545 lockForArbitration();
546 IOLockLock( gIOServiceBusyLock
);
548 waitAgain
= (prevBusy
< (__state
[1] & kIOServiceBusyStateMask
));
550 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
552 __state
[1] &= ~kIOServiceSyncPubState
;
554 unlockForArbitration();
557 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
559 IOLockUnlock( gIOServiceBusyLock
);
561 thread_block(THREAD_CONTINUE_NULL
);
563 } while( waitAgain
);
567 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
569 OSDictionary
* table
;
579 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
582 set
= (OSSet
*) getExistingServices( table
,
583 kIOServiceRegisteredState
,
584 kIOServiceExistingSet
);
589 count
+= set
->getCount();
592 allSet
->merge((const OSSet
*) set
);
600 if( getDebugFlags( table
) & kIOLogMatch
)
601 LOG("Matching service count = %ld\n", count
);
603 newTables
->removeObject(table
);
607 while( (service
= (IOService
*) allSet
->getAnyObject())) {
608 service
->startMatching(kIOServiceAsynchronous
);
609 allSet
->removeObject(service
);
614 newTables
->release();
616 return( kIOReturnSuccess
);
619 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
620 IOOptionBits options
)
624 job
= new _IOServiceJob
;
625 if( job
&& !job
->init()) {
633 job
->options
= options
;
634 nub
->retain(); // thread will release()
642 * Called on a registered service to see if it matches
646 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
648 return( matchPropertyTable(table
) );
651 bool IOService::matchPropertyTable( OSDictionary
* table
)
657 * Called on a matched service to allocate resources
658 * before first driver is attached.
661 IOReturn
IOService::getResources( void )
663 return( kIOReturnSuccess
);
667 * Client/provider accessors
670 IOService
* IOService::getProvider( void ) const
672 IOService
* self
= (IOService
*) this;
677 generation
= getGenerationCount();
678 if( __providerGeneration
== generation
)
681 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
682 if( parent
== IORegistryEntry::getRegistryRoot())
683 /* root is not an IOService */
686 self
->__provider
= parent
;
687 // save the count before getParentEntry()
688 self
->__providerGeneration
= generation
;
693 IOWorkLoop
* IOService::getWorkLoop() const
695 IOService
*provider
= getProvider();
698 return provider
->getWorkLoop();
703 OSIterator
* IOService::getProviderIterator( void ) const
705 return( getParentIterator( gIOServicePlane
));
708 IOService
* IOService::getClient( void ) const
710 return( (IOService
*) getChildEntry( gIOServicePlane
));
713 OSIterator
* IOService::getClientIterator( void ) const
715 return( getChildIterator( gIOServicePlane
));
718 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
719 const IOService
* client
,
720 const IOService
* provider
)
722 _IOOpenServiceIterator
* inst
;
727 inst
= new _IOOpenServiceIterator
;
729 if( inst
&& !inst
->init()) {
735 inst
->client
= client
;
736 inst
->provider
= provider
;
742 void _IOOpenServiceIterator::free()
746 last
->unlockForArbitration();
750 OSObject
* _IOOpenServiceIterator::getNextObject()
755 last
->unlockForArbitration();
757 while( (next
= (IOService
*) iter
->getNextObject())) {
759 next
->lockForArbitration();
760 if( (client
&& (next
->isOpen( client
)))
761 || (provider
&& (provider
->isOpen( next
))) )
763 next
->unlockForArbitration();
771 bool _IOOpenServiceIterator::isValid()
773 return( iter
->isValid() );
776 void _IOOpenServiceIterator::reset()
779 last
->unlockForArbitration();
785 OSIterator
* IOService::getOpenProviderIterator( void ) const
787 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
790 OSIterator
* IOService::getOpenClientIterator( void ) const
792 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
796 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
797 bool waitForFunction
,
798 void *param1
, void *param2
,
799 void *param3
, void *param4
)
801 IOReturn result
= kIOReturnUnsupported
;
802 IOService
*provider
= getProvider();
805 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
806 param1
, param2
, param3
, param4
);
812 IOReturn
IOService::callPlatformFunction( const char * functionName
,
813 bool waitForFunction
,
814 void *param1
, void *param2
,
815 void *param3
, void *param4
)
817 IOReturn result
= kIOReturnNoMemory
;
818 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
820 if (functionSymbol
!= 0) {
821 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
822 param1
, param2
, param3
, param4
);
823 functionSymbol
->release();
831 * Accessors for global services
834 IOPlatformExpert
* IOService::getPlatform( void )
836 return( gIOPlatform
);
839 class IOPMrootDomain
* IOService::getPMRootDomain( void )
841 return( gIOPMRootDomain
);
844 IOService
* IOService::getResourceService( void )
846 return( gIOResources
);
849 void IOService::setPlatform( IOPlatformExpert
* platform
)
851 gIOPlatform
= platform
;
852 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
855 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
857 gIOPMRootDomain
= rootDomain
;
858 publishResource("IOKit");
865 bool IOService::lockForArbitration( bool isSuccessRequired
)
869 ArbitrationLockQueueElement
* element
;
870 ArbitrationLockQueueElement
* active
;
871 ArbitrationLockQueueElement
* waiting
;
873 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
875 // lock global access
876 IOTakeLock( gArbitrationLockQueueLock
);
878 // obtain an unused queue element
879 if( !queue_empty( &gArbitrationLockQueueFree
)) {
880 queue_remove_first( &gArbitrationLockQueueFree
,
882 ArbitrationLockQueueElement
*,
885 element
= IONew( ArbitrationLockQueueElement
, 1 );
889 // prepare the queue element
890 element
->thread
= IOThreadSelf();
891 element
->service
= this;
893 element
->required
= isSuccessRequired
;
894 element
->aborted
= false;
896 // determine whether this object is already locked (ie. on active queue)
898 queue_iterate( &gArbitrationLockQueueActive
,
900 ArbitrationLockQueueElement
*,
903 if( active
->service
== element
->service
) {
909 if( found
) { // this object is already locked
911 // determine whether it is the same or a different thread trying to lock
912 if( active
->thread
!= element
->thread
) { // it is a different thread
914 ArbitrationLockQueueElement
* victim
= 0;
916 // before placing this new thread on the waiting queue, we look for
917 // a deadlock cycle...
920 // determine whether the active thread holding the object we
921 // want is waiting for another object to be unlocked
923 queue_iterate( &gArbitrationLockQueueWaiting
,
925 ArbitrationLockQueueElement
*,
928 if( waiting
->thread
== active
->thread
) {
929 assert( false == waiting
->aborted
);
935 if( found
) { // yes, active thread waiting for another object
937 // this may be a candidate for rejection if the required
938 // flag is not set, should we detect a deadlock later on
939 if( false == waiting
->required
)
942 // find the thread that is holding this other object, that
943 // is blocking the active thread from proceeding (fun :-)
945 queue_iterate( &gArbitrationLockQueueActive
,
946 active
, // (reuse active queue element)
947 ArbitrationLockQueueElement
*,
950 if( active
->service
== waiting
->service
) {
956 // someone must be holding it or it wouldn't be waiting
959 if( active
->thread
== element
->thread
) {
961 // doh, it's waiting for the thread that originated
962 // this whole lock (ie. current thread) -> deadlock
963 if( false == element
->required
) { // willing to fail?
965 // the originating thread doesn't have the required
966 // flag, so it can fail
967 success
= false; // (fail originating lock request)
968 break; // (out of while)
970 } else { // originating thread is not willing to fail
972 // see if we came across a waiting thread that did
973 // not have the 'required' flag set: we'll fail it
976 // we do have a willing victim, fail it's lock
977 victim
->aborted
= true;
979 // take the victim off the waiting queue
980 queue_remove( &gArbitrationLockQueueWaiting
,
982 ArbitrationLockQueueElement
*,
986 IOLockWakeup( gArbitrationLockQueueLock
,
988 /* one thread */ true );
990 // allow this thread to proceed (ie. wait)
991 success
= true; // (put request on wait queue)
992 break; // (out of while)
995 // all the waiting threads we came across in
996 // finding this loop had the 'required' flag
997 // set, so we've got a deadlock we can't avoid
998 panic("I/O Kit: Unrecoverable deadlock.");
1002 // repeat while loop, redefining active thread to be the
1003 // thread holding "this other object" (see above), and
1004 // looking for threads waiting on it; note the active
1005 // variable points to "this other object" already... so
1006 // there nothing to do in this else clause.
1008 } else { // no, active thread is not waiting for another object
1010 success
= true; // (put request on wait queue)
1011 break; // (out of while)
1015 if( success
) { // put the request on the waiting queue?
1016 kern_return_t wait_result
;
1018 // place this thread on the waiting queue and put it to sleep;
1019 // we place it at the tail of the queue...
1020 queue_enter( &gArbitrationLockQueueWaiting
,
1022 ArbitrationLockQueueElement
*,
1025 // declare that this thread will wait for a given event
1026 restart_sleep
: wait_result
= assert_wait( element
,
1027 element
->required
? THREAD_UNINT
1028 : THREAD_INTERRUPTIBLE
);
1030 // unlock global access
1031 IOUnlock( gArbitrationLockQueueLock
);
1033 // put thread to sleep, waiting for our event to fire...
1034 if (wait_result
== THREAD_WAITING
)
1035 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1038 // ...and we've been woken up; we might be in one of two states:
1039 // (a) we've been aborted and our queue element is not on
1040 // any of the three queues, but is floating around
1041 // (b) we're allowed to proceed with the lock and we have
1042 // already been moved from the waiting queue to the
1044 // ...plus a 3rd state, should the thread have been interrupted:
1045 // (c) we're still on the waiting queue
1047 // determine whether we were interrupted out of our sleep
1048 if( THREAD_INTERRUPTED
== wait_result
) {
1050 // re-lock global access
1051 IOTakeLock( gArbitrationLockQueueLock
);
1053 // determine whether we're still on the waiting queue
1055 queue_iterate( &gArbitrationLockQueueWaiting
,
1056 waiting
, // (reuse waiting queue element)
1057 ArbitrationLockQueueElement
*,
1060 if( waiting
== element
) {
1066 if( found
) { // yes, we're still on the waiting queue
1068 // determine whether we're willing to fail
1069 if( false == element
->required
) {
1071 // mark us as aborted
1072 element
->aborted
= true;
1074 // take us off the waiting queue
1075 queue_remove( &gArbitrationLockQueueWaiting
,
1077 ArbitrationLockQueueElement
*,
1079 } else { // we are not willing to fail
1081 // ignore interruption, go back to sleep
1086 // unlock global access
1087 IOUnlock( gArbitrationLockQueueLock
);
1089 // proceed as though this were a normal wake up
1090 wait_result
= THREAD_AWAKENED
;
1093 assert( THREAD_AWAKENED
== wait_result
);
1095 // determine whether we've been aborted while we were asleep
1096 if( element
->aborted
) {
1097 assert( false == element
->required
);
1099 // re-lock global access
1100 IOTakeLock( gArbitrationLockQueueLock
);
1102 action
= kPutOnFreeQueue
;
1104 } else { // we weren't aborted, so we must be ready to go :-)
1106 // we've already been moved from waiting to active queue
1110 } else { // the lock request is to be failed
1112 // return unused queue element to queue
1113 action
= kPutOnFreeQueue
;
1115 } else { // it is the same thread, recursive access is allowed
1117 // add one level of recursion
1120 // return unused queue element to queue
1121 action
= kPutOnFreeQueue
;
1124 } else { // this object is not already locked, so let this thread through
1125 action
= kPutOnActiveQueue
;
1129 // put the new element on a queue
1130 if( kPutOnActiveQueue
== action
) {
1131 queue_enter( &gArbitrationLockQueueActive
,
1133 ArbitrationLockQueueElement
*,
1135 } else if( kPutOnFreeQueue
== action
) {
1136 queue_enter( &gArbitrationLockQueueFree
,
1138 ArbitrationLockQueueElement
*,
1141 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1144 // unlock global access
1145 IOUnlock( gArbitrationLockQueueLock
);
1150 void IOService::unlockForArbitration( void )
1153 ArbitrationLockQueueElement
* element
;
1155 // lock global access
1156 IOTakeLock( gArbitrationLockQueueLock
);
1158 // find the lock element for this object (ie. on active queue)
1160 queue_iterate( &gArbitrationLockQueueActive
,
1162 ArbitrationLockQueueElement
*,
1165 if( element
->service
== this ) {
1173 // determine whether the lock has been taken recursively
1174 if( element
->count
> 1 ) {
1175 // undo one level of recursion
1180 // remove it from the active queue
1181 queue_remove( &gArbitrationLockQueueActive
,
1183 ArbitrationLockQueueElement
*,
1186 // put it on the free queue
1187 queue_enter( &gArbitrationLockQueueFree
,
1189 ArbitrationLockQueueElement
*,
1192 // determine whether a thread is waiting for object (head to tail scan)
1194 queue_iterate( &gArbitrationLockQueueWaiting
,
1196 ArbitrationLockQueueElement
*,
1199 if( element
->service
== this ) {
1205 if ( found
) { // we found an interested thread on waiting queue
1207 // remove it from the waiting queue
1208 queue_remove( &gArbitrationLockQueueWaiting
,
1210 ArbitrationLockQueueElement
*,
1213 // put it on the active queue
1214 queue_enter( &gArbitrationLockQueueActive
,
1216 ArbitrationLockQueueElement
*,
1219 // wake the waiting thread
1220 IOLockWakeup( gArbitrationLockQueueLock
,
1222 /* one thread */ true );
1226 // unlock global access
1227 IOUnlock( gArbitrationLockQueueLock
);
1230 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1233 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1234 context
, gIOServicePlane
);
1237 void IOService::applyToClients( IOServiceApplierFunction applier
,
1240 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1241 context
, gIOServicePlane
);
1250 // send a message to a client or interested party of this service
1251 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1252 void * argument
, vm_size_t argSize
)
1255 IOService
* service
;
1256 _IOServiceInterestNotifier
* notify
;
1258 if( (service
= OSDynamicCast( IOService
, client
)))
1259 ret
= service
->message( type
, this, argument
);
1261 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1263 _IOServiceNotifierInvocation invocation
;
1266 invocation
.thread
= current_thread();
1269 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1272 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1273 _IOServiceNotifierInvocation
*, link
);
1279 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1280 type
, this, argument
, argSize
);
1283 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1284 _IOServiceNotifierInvocation
*, link
);
1285 if( kIOServiceNotifyWaiter
& notify
->state
) {
1286 notify
->state
&= ~kIOServiceNotifyWaiter
;
1287 WAKEUPNOTIFY( notify
);
1292 ret
= kIOReturnSuccess
;
1295 ret
= kIOReturnBadArgument
;
1301 applyToInterestNotifiers(const IORegistryEntry
*target
,
1302 const OSSymbol
* typeOfInterest
,
1303 OSObjectApplierFunction applier
,
1306 OSArray
* copyArray
= 0;
1310 IOCommand
*notifyList
=
1311 OSDynamicCast( IOCommand
, target
->getProperty( typeOfInterest
));
1314 copyArray
= OSArray::withCapacity(1);
1316 // iterate over queue, entry is set to each element in the list
1317 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1318 _IOServiceInterestNotifier
* notify
;
1320 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1321 copyArray
->setObject(notify
);
1330 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1331 (*applier
)(next
, context
);
1332 copyArray
->release();
1336 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1337 OSObjectApplierFunction applier
,
1340 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1341 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1344 struct MessageClientsContext
{
1345 IOService
* service
;
1352 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1355 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1357 ret
= context
->service
->messageClient( context
->type
,
1358 object
, context
->argument
, context
->argSize
);
1359 if( kIOReturnSuccess
!= ret
)
1363 // send a message to all clients
1364 IOReturn
IOService::messageClients( UInt32 type
,
1365 void * argument
, vm_size_t argSize
)
1367 MessageClientsContext context
;
1369 context
.service
= this;
1370 context
.type
= type
;
1371 context
.argument
= argument
;
1372 context
.argSize
= argSize
;
1373 context
.ret
= kIOReturnSuccess
;
1375 applyToInterested( gIOGeneralInterest
,
1376 &messageClientsApplier
, &context
);
1378 return( context
.ret
);
1381 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1382 IOOptionBits response
)
1384 return( kIOReturnUnsupported
);
1387 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1388 IOServiceInterestHandler handler
, void * target
, void * ref
)
1390 _IOServiceInterestNotifier
* notify
= 0;
1392 if( (typeOfInterest
!= gIOGeneralInterest
)
1393 && (typeOfInterest
!= gIOBusyInterest
)
1394 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1395 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1398 lockForArbitration();
1399 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1401 notify
= new _IOServiceInterestNotifier
;
1402 if( notify
&& !notify
->init()) {
1408 notify
->handler
= handler
;
1409 notify
->target
= target
;
1411 notify
->state
= kIOServiceNotifyEnable
;
1412 queue_init( ¬ify
->handlerInvocations
);
1418 // Get the head of the notifier linked list
1419 IOCommand
*notifyList
= (IOCommand
*) getProperty( typeOfInterest
);
1420 if (!notifyList
|| !OSDynamicCast(IOCommand
, notifyList
)) {
1421 notifyList
= OSTypeAlloc(IOCommand
);
1424 setProperty( typeOfInterest
, notifyList
);
1425 notifyList
->release();
1430 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1431 notify
->retain(); // ref'ed while in list
1437 unlockForArbitration();
1442 static void cleanInterestList( OSObject
* head
)
1444 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1449 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1450 queue_next(entry
) = queue_prev(entry
) = 0;
1452 _IOServiceInterestNotifier
* notify
;
1454 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1460 void IOService::unregisterAllInterest( void )
1462 cleanInterestList( getProperty( gIOGeneralInterest
));
1463 cleanInterestList( getProperty( gIOBusyInterest
));
1464 cleanInterestList( getProperty( gIOAppPowerStateInterest
));
1465 cleanInterestList( getProperty( gIOPriorityPowerStateInterest
));
1469 * _IOServiceInterestNotifier
1472 // wait for all threads, other than the current one,
1473 // to exit the handler
1475 void _IOServiceInterestNotifier::wait()
1477 _IOServiceNotifierInvocation
* next
;
1482 queue_iterate( &handlerInvocations
, next
,
1483 _IOServiceNotifierInvocation
*, link
) {
1484 if( next
->thread
!= current_thread() ) {
1490 state
|= kIOServiceNotifyWaiter
;
1497 void _IOServiceInterestNotifier::free()
1499 assert( queue_empty( &handlerInvocations
));
1503 void _IOServiceInterestNotifier::remove()
1507 if( queue_next( &chain
)) {
1508 remqueue( 0, &chain
);
1509 queue_next( &chain
) = queue_prev( &chain
) = 0;
1513 state
&= ~kIOServiceNotifyEnable
;
1522 bool _IOServiceInterestNotifier::disable()
1528 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1529 state
&= ~kIOServiceNotifyEnable
;
1538 void _IOServiceInterestNotifier::enable( bool was
)
1542 state
|= kIOServiceNotifyEnable
;
1544 state
&= ~kIOServiceNotifyEnable
;
1548 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1554 #define tailQ(o) setObject(o)
1555 #define headQ(o) setObject(0, o)
1556 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); }
1558 inline void _workLoopAction( IOWorkLoop::Action action
,
1559 IOService
* service
,
1560 void * p0
= 0, void * p1
= 0,
1561 void * p2
= 0, void * p3
= 0 )
1565 if( (wl
= service
->getWorkLoop())) {
1567 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1570 (*action
)( service
, p0
, p1
, p2
, p3
);
1573 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1577 // if its our only provider
1578 ok
= isParent( provider
, gIOServicePlane
, true);
1582 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1583 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1590 bool IOService::terminatePhase1( IOOptionBits options
)
1595 OSArray
* makeInactive
;
1598 bool startPhase2
= false;
1600 TLOG("%s::terminatePhase1(%08lx)\n", getName(), options
);
1603 if( options
& kIOServiceRecursing
) {
1604 __state
[1] |= kIOServiceRecursing
;
1609 makeInactive
= OSArray::withCapacity( 16 );
1618 didInactive
= victim
->lockForArbitration( true );
1620 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1622 victim
->__state
[0] |= kIOServiceInactiveState
;
1623 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1624 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1625 victim
->_adjustBusy( 1 );
1627 victim
->unlockForArbitration();
1630 startPhase2
= didInactive
;
1633 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1634 IOUserClient::destroyUserReferences( victim
);
1636 iter
= victim
->getClientIterator();
1638 while( (client
= (IOService
*) iter
->getNextObject())) {
1639 TLOG("%s::requestTerminate(%s, %08lx)\n",
1640 client
->getName(), victim
->getName(), options
);
1641 ok
= client
->requestTerminate( victim
, options
);
1642 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1643 client
->getName(), victim
->getName(), ok
);
1645 makeInactive
->setObject( client
);
1651 victim
= (IOService
*) makeInactive
->getObject(0);
1654 makeInactive
->removeObject(0);
1658 makeInactive
->release();
1661 scheduleTerminatePhase2( options
);
1666 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
1668 AbsoluteTime deadline
;
1669 int waitResult
= THREAD_AWAKENED
;
1670 bool wait
, haveDeadline
= false;
1672 options
|= kIOServiceRequired
;
1676 IOLockLock( gJobsLock
);
1678 if( (options
& kIOServiceSynchronous
)
1679 && (current_thread() != gIOTerminateThread
)) {
1682 wait
= (gIOTerminateThread
!= 0);
1684 // wait to become the terminate thread
1685 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
1689 gIOTerminateThread
= current_thread();
1690 gIOTerminatePhase2List
->setObject( this );
1694 while( gIOTerminateWork
)
1695 terminateWorker( options
);
1696 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1698 // wait for the victim to go non-busy
1699 if( !haveDeadline
) {
1700 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1701 haveDeadline
= true;
1703 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
1704 deadline
, THREAD_UNINT
);
1705 if( waitResult
== THREAD_TIMED_OUT
) {
1706 TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName());
1709 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
1711 gIOTerminateThread
= 0;
1712 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1715 // ! kIOServiceSynchronous
1717 gIOTerminatePhase2List
->setObject( this );
1718 if( 0 == gIOTerminateWork
++) {
1719 if( !gIOTerminateThread
)
1720 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) options
);
1722 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1726 IOLockUnlock( gJobsLock
);
1731 void IOService::terminateThread( void * arg
)
1733 IOLockLock( gJobsLock
);
1735 while (gIOTerminateWork
)
1736 terminateWorker( (IOOptionBits
) arg
);
1738 gIOTerminateThread
= 0;
1739 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1741 IOLockUnlock( gJobsLock
);
1744 void IOService::scheduleStop( IOService
* provider
)
1746 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1748 IOLockLock( gJobsLock
);
1749 gIOStopList
->tailQ( this );
1750 gIOStopProviderList
->tailQ( provider
);
1752 if( 0 == gIOTerminateWork
++) {
1753 if( !gIOTerminateThread
)
1754 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1756 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1759 IOLockUnlock( gJobsLock
);
1762 void IOService::scheduleFinalize( void )
1764 TLOG("%s::scheduleFinalize\n", getName());
1766 IOLockLock( gJobsLock
);
1767 gIOFinalizeList
->tailQ( this );
1769 if( 0 == gIOTerminateWork
++) {
1770 if( !gIOTerminateThread
)
1771 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1773 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1776 IOLockUnlock( gJobsLock
);
1779 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1784 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1786 if( false == *defer
) {
1788 if( lockForArbitration( true )) {
1789 if( false == provider
->handleIsOpen( this ))
1790 scheduleStop( provider
);
1793 message( kIOMessageServiceIsRequestingClose
, provider
, (void *) options
);
1794 if( false == provider
->handleIsOpen( this ))
1795 scheduleStop( provider
);
1798 unlockForArbitration();
1805 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
1806 OSArray
* doPhase2List
)
1812 iter
= victim
->getClientIterator();
1814 while( (client
= (IOService
*) iter
->getNextObject())) {
1815 TLOG("%s::willTerminate(%s, %08lx)\n",
1816 client
->getName(), victim
->getName(), options
);
1817 ok
= client
->willTerminate( victim
, options
);
1818 doPhase2List
->tailQ( client
);
1824 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
)
1830 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *) options
);
1832 iter
= victim
->getClientIterator();
1834 while( (client
= (IOService
*) iter
->getNextObject())) {
1835 TLOG("%s::didTerminate(%s, %08lx)\n",
1836 client
->getName(), victim
->getName(), options
);
1837 client
->didTerminate( victim
, options
, &defer
);
1838 TLOG("%s::didTerminate(%s, defer %d)\n",
1839 client
->getName(), victim
->getName(), defer
);
1845 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
)
1847 TLOG("%s::finalize(%08lx)\n", victim
->getName(), options
);
1848 victim
->finalize( options
);
1851 void IOService::actionStop( IOService
* provider
, IOService
* client
)
1853 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
1854 client
->stop( provider
);
1855 if( provider
->isOpen( client
))
1856 provider
->close( client
);
1857 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
1858 client
->detach( provider
);
1861 void IOService::terminateWorker( IOOptionBits options
)
1863 OSArray
* doPhase2List
;
1864 OSArray
* didPhase2List
;
1869 IOService
* provider
;
1875 options
|= kIOServiceRequired
;
1877 doPhase2List
= OSArray::withCapacity( 16 );
1878 didPhase2List
= OSArray::withCapacity( 16 );
1879 freeList
= OSSet::withCapacity( 16 );
1880 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
1884 workDone
= gIOTerminateWork
;
1886 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
1889 gIOTerminatePhase2List
->removeObject(0);
1890 IOLockUnlock( gJobsLock
);
1894 doPhase2
= victim
->lockForArbitration( true );
1896 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
1898 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
1899 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
1901 victim
->__state
[1] |= kIOServiceTermPhase2State
;
1903 victim
->unlockForArbitration();
1906 if( 0 == victim
->getClient()) {
1907 // no clients - will go to finalize
1908 IOLockLock( gJobsLock
);
1909 gIOFinalizeList
->tailQ( victim
);
1910 IOLockUnlock( gJobsLock
);
1912 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
1913 victim
, (void *) options
, (void *) doPhase2List
);
1915 didPhase2List
->headQ( victim
);
1918 victim
= (IOService
*) doPhase2List
->getObject(0);
1921 doPhase2List
->removeObject(0);
1925 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
1927 if( victim
->lockForArbitration( true )) {
1928 victim
->__state
[1] |= kIOServiceTermPhase3State
;
1929 victim
->unlockForArbitration();
1931 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
1932 victim
, (void *) options
);
1933 didPhase2List
->removeObject(0);
1935 IOLockLock( gJobsLock
);
1942 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
1944 IOLockUnlock( gJobsLock
);
1945 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
1946 victim
, (void *) options
);
1947 IOLockLock( gJobsLock
);
1949 freeList
->setObject( victim
);
1950 // safe if finalize list is append only
1951 gIOFinalizeList
->removeObject(0);
1955 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
1957 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
1960 if( !provider
->isChild( client
, gIOServicePlane
)) {
1961 // may be multiply queued - nop it
1962 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
1964 // not ready for stop if it has clients, skip it
1965 if( (client
->__state
[1] & kIOServiceTermPhase3State
) && client
->getClient()) {
1966 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
1971 IOLockUnlock( gJobsLock
);
1972 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
1973 provider
, (void *) client
);
1974 IOLockLock( gJobsLock
);
1975 // check the finalize list now
1979 freeList
->setObject( client
);
1980 freeList
->setObject( provider
);
1982 // safe if stop list is append only
1983 gIOStopList
->removeObject( idx
);
1984 gIOStopProviderList
->removeObject( idx
);
1988 } while( doPhase3
);
1990 gIOTerminateWork
-= workDone
;
1991 moreToDo
= (gIOTerminateWork
!= 0);
1994 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
1997 } while( moreToDo
);
1999 IOLockUnlock( gJobsLock
);
2001 freeList
->release();
2002 doPhase2List
->release();
2003 didPhase2List
->release();
2005 IOLockLock( gJobsLock
);
2008 bool IOService::finalize( IOOptionBits options
)
2011 IOService
* provider
;
2013 iter
= getProviderIterator();
2017 while( (provider
= (IOService
*) iter
->getNextObject())) {
2020 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
2021 /* we come down here on programmatic terminate */
2023 if( provider
->isOpen( this ))
2024 provider
->close( this );
2028 if( provider
->lockForArbitration( true )) {
2029 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2030 scheduleStop( provider
);
2031 provider
->unlockForArbitration();
2048 void IOService::doServiceTerminate( IOOptionBits options
)
2052 // a method in case someone needs to override it
2053 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2057 if( client
->isParent( this, gIOServicePlane
, true))
2058 // we are the clients only provider
2059 ok
= client
->terminate( options
);
2066 bool IOService::terminate( IOOptionBits options
)
2068 options
|= kIOServiceTerminate
;
2070 return( terminatePhase1( options
));
2073 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2079 struct ServiceOpenMessageContext
2081 IOService
* service
;
2083 IOService
* excludeClient
;
2084 IOOptionBits options
;
2087 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2089 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2091 if( object
!= context
->excludeClient
)
2092 context
->service
->messageClient( context
->type
, object
, (void *) context
->options
);
2095 bool IOService::open( IOService
* forClient
,
2096 IOOptionBits options
,
2100 ServiceOpenMessageContext context
;
2102 context
.service
= this;
2103 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2104 context
.excludeClient
= forClient
;
2105 context
.options
= options
;
2107 applyToInterested( gIOGeneralInterest
,
2108 &serviceOpenMessageApplier
, &context
);
2110 if( false == lockForArbitration(false) )
2113 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2115 ok
= handleOpen( forClient
, options
, arg
);
2117 unlockForArbitration();
2122 void IOService::close( IOService
* forClient
,
2123 IOOptionBits options
)
2128 lockForArbitration();
2130 wasClosed
= handleIsOpen( forClient
);
2132 handleClose( forClient
, options
);
2133 last
= (__state
[1] & kIOServiceTermPhase3State
);
2136 unlockForArbitration();
2139 forClient
->scheduleStop( this );
2141 else if( wasClosed
) {
2143 ServiceOpenMessageContext context
;
2145 context
.service
= this;
2146 context
.type
= kIOMessageServiceWasClosed
;
2147 context
.excludeClient
= forClient
;
2148 context
.options
= options
;
2150 applyToInterested( gIOGeneralInterest
,
2151 &serviceOpenMessageApplier
, &context
);
2155 bool IOService::isOpen( const IOService
* forClient
) const
2157 IOService
* self
= (IOService
*) this;
2160 self
->lockForArbitration();
2162 ok
= handleIsOpen( forClient
);
2164 self
->unlockForArbitration();
2169 bool IOService::handleOpen( IOService
* forClient
,
2170 IOOptionBits options
,
2175 ok
= (0 == __owner
);
2177 __owner
= forClient
;
2179 else if( options
& kIOServiceSeize
) {
2180 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2181 __owner
, (void *) options
));
2182 if( ok
&& (0 == __owner
))
2183 __owner
= forClient
;
2190 void IOService::handleClose( IOService
* forClient
,
2191 IOOptionBits options
)
2193 if( __owner
== forClient
)
2197 bool IOService::handleIsOpen( const IOService
* forClient
) const
2200 return( __owner
== forClient
);
2202 return( __owner
!= forClient
);
2206 * Probing & starting
2208 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2210 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2211 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2219 val1
= obj1
->priority
;
2222 val2
= obj2
->priority
;
2224 return ( val1
- val2
);
2227 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2229 OSDictionary
* dict
;
2230 IOService
* service
;
2231 _IOServiceNotifier
* notify
;
2232 OSSymbol
* key
= (OSSymbol
*) ref
;
2235 if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2236 return( notify
->priority
);
2238 else if( (service
= OSDynamicCast( IOService
, entry
)))
2239 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2240 else if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2241 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2248 return( (SInt32
) offset
->unsigned32BitValue());
2250 return( kIODefaultProbeScore
);
2253 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2255 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2256 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2264 val1
= IOServiceObjectOrder( obj1
, ref
);
2267 val2
= IOServiceObjectOrder( obj2
, ref
);
2269 return ( val1
- val2
);
2272 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2274 IOService
* service
= 0;
2276 const OSSymbol
* nextCat
;
2278 iter
= getClientIterator();
2280 while( (service
= (IOService
*) iter
->getNextObject())) {
2281 if( kIOServiceInactiveState
& service
->__state
[0])
2283 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2284 service
->getProperty( gIOMatchCategoryKey
));
2285 if( category
== nextCat
)
2293 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2295 _IOServiceNotifierInvocation invocation
;
2299 invocation
.thread
= current_thread();
2302 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2305 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2306 _IOServiceNotifierInvocation
*, link
);
2312 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
, this );
2315 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2316 _IOServiceNotifierInvocation
*, link
);
2317 if( kIOServiceNotifyWaiter
& notify
->state
) {
2318 notify
->state
&= ~kIOServiceNotifyWaiter
;
2319 WAKEUPNOTIFY( notify
);
2328 * Alloc and probe matching classes,
2329 * called on the provider instance
2332 void IOService::probeCandidates( OSOrderedSet
* matches
)
2334 OSDictionary
* match
= 0;
2337 IOService
* newInst
;
2338 OSDictionary
* props
;
2341 OSOrderedSet
* familyMatches
= 0;
2342 OSOrderedSet
* startList
;
2343 OSDictionary
* startDict
= 0;
2344 const OSSymbol
* category
;
2346 _IOServiceNotifier
* notify
;
2347 OSObject
* nextMatch
= 0;
2349 bool needReloc
= false;
2355 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2357 nextMatch
->retain();
2358 matches
->removeObject(nextMatch
);
2360 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2362 lockForArbitration();
2363 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2364 invokeNotifer( notify
);
2365 unlockForArbitration();
2366 nextMatch
->release();
2370 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2371 nextMatch
->release();
2378 debugFlags
= getDebugFlags( match
);
2382 category
= OSDynamicCast( OSSymbol
,
2383 match
->getObject( gIOMatchCategoryKey
));
2385 category
= gIODefaultMatchCategoryKey
;
2387 if( getClientWithCategory( category
)) {
2389 if( debugFlags
& kIOLogMatch
)
2390 LOG("%s: match category %s exists\n", getName(),
2391 category
->getCStringNoCopy());
2393 nextMatch
->release();
2398 // create a copy now in case its modified during matching
2399 props
= OSDictionary::withDictionary( match
, match
->getCount());
2402 props
->setCapacityIncrement(1);
2404 // check the nub matches
2405 if( false == passiveMatch( props
, true ))
2408 // Check to see if driver reloc has been loaded.
2409 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2412 if( debugFlags
& kIOLogCatalogue
)
2413 LOG("%s: stalling for module\n", getName());
2415 // If reloc hasn't been loaded, exit;
2416 // reprobing will occur after reloc has been loaded.
2420 // reorder on family matchPropertyTable score.
2421 if( 0 == familyMatches
)
2422 familyMatches
= OSOrderedSet::withCapacity( 1,
2423 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2425 familyMatches
->setObject( props
);
2430 nextMatch
->release();
2439 if( familyMatches
) {
2442 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2445 familyMatches
->removeObject( props
);
2450 debugFlags
= getDebugFlags( props
);
2453 symbol
= OSDynamicCast( OSSymbol
,
2454 props
->getObject( gIOClassKey
));
2458 // alloc the driver instance
2459 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2462 IOLog("Couldn't alloc class \"%s\"\n",
2463 symbol
->getCStringNoCopy());
2467 // init driver instance
2468 if( !(inst
->init( props
))) {
2470 if( debugFlags
& kIOLogStart
)
2471 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2475 if( __state
[1] & kIOServiceSynchronousState
)
2476 inst
->__state
[1] |= kIOServiceSynchronousState
;
2478 // give the driver the default match category if not specified
2479 category
= OSDynamicCast( OSSymbol
,
2480 props
->getObject( gIOMatchCategoryKey
));
2482 category
= gIODefaultMatchCategoryKey
;
2483 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2485 // attach driver instance
2486 if( !(inst
->attach( this )))
2489 // pass in score from property table
2490 score
= familyMatches
->orderObject( props
);
2492 // & probe the new driver instance
2494 if( debugFlags
& kIOLogProbe
)
2495 LOG("%s::probe(%s)\n",
2496 inst
->getMetaClass()->getClassName(), getName());
2499 newInst
= inst
->probe( this, &score
);
2500 inst
->detach( this );
2503 if( debugFlags
& kIOLogProbe
)
2504 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2510 newPri
= OSNumber::withNumber( score
, 32 );
2512 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2516 // add to start list for the match category
2518 startDict
= OSDictionary::withCapacity( 1 );
2519 assert( startDict
);
2520 startList
= (OSOrderedSet
*)
2521 startDict
->getObject( category
);
2522 if( 0 == startList
) {
2523 startList
= OSOrderedSet::withCapacity( 1,
2524 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2525 if( startDict
&& startList
) {
2526 startDict
->setObject( category
, startList
);
2527 startList
->release();
2530 assert( startList
);
2532 startList
->setObject( newInst
);
2540 familyMatches
->release();
2544 // start the best (until success) of each category
2546 iter
= OSCollectionIterator::withCollection( startDict
);
2548 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2550 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2551 assert( startList
);
2556 while( true // (!started)
2557 && (inst
= (IOService
*)startList
->getFirstObject())) {
2560 startList
->removeObject(inst
);
2563 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2565 if( debugFlags
& kIOLogStart
) {
2567 LOG( "match category exists, skipping " );
2568 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2569 getName(), inst
->getRetainCount());
2572 if( false == started
)
2573 started
= startCandidate( inst
);
2575 if( (debugFlags
& kIOLogStart
) && (false == started
))
2576 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2577 inst
->getRetainCount());
2586 // adjust the busy count by -1 if matching is stalled for a module,
2587 // or +1 if a previously stalled matching is complete.
2588 lockForArbitration();
2591 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2593 __state
[1] |= kIOServiceModuleStallState
;
2595 } else if( __state
[1] & kIOServiceModuleStallState
) {
2596 __state
[1] &= ~kIOServiceModuleStallState
;
2600 _adjustBusy( adjBusy
);
2601 unlockForArbitration();
2604 startDict
->release();
2608 * Start a previously attached & probed instance,
2609 * called on exporting object instance
2612 bool IOService::startCandidate( IOService
* service
)
2616 ok
= service
->attach( this );
2620 if (this != gIOResources
)
2622 // stall for any nub resources
2624 // stall for any driver resources
2625 service
->checkResources();
2628 AbsoluteTime startTime
;
2629 AbsoluteTime endTime
;
2632 if (kIOLogStart
& gIOKitDebug
)
2633 clock_get_uptime(&startTime
);
2635 ok
= service
->start(this);
2637 if (kIOLogStart
& gIOKitDebug
)
2639 clock_get_uptime(&endTime
);
2641 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2643 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2644 absolutetime_to_nanoseconds(endTime
, &nano
);
2645 if (nano
> 500000000ULL)
2646 IOLog("%s::start took %ld ms\n", service
->getName(), (UInt32
)(nano
/ 1000000ULL));
2650 service
->detach( this );
2655 IOService
* IOService::resources( void )
2657 return( gIOResources
);
2660 void IOService::publishResource( const char * key
, OSObject
* value
)
2662 const OSSymbol
* sym
;
2664 if( (sym
= OSSymbol::withCString( key
))) {
2665 publishResource( sym
, value
);
2670 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
2673 value
= (OSObject
*) gIOServiceKey
;
2675 gIOResources
->setProperty( key
, value
);
2677 if( IORecursiveLockHaveLock( gNotificationLock
))
2680 gIOResourceGenerationCount
++;
2681 gIOResources
->registerService();
2684 bool IOService::addNeededResource( const char * key
)
2686 OSObject
* resourcesProp
;
2691 resourcesProp
= getProperty( gIOResourceMatchKey
);
2693 newKey
= OSString::withCString( key
);
2694 if( (0 == resourcesProp
) || (0 == newKey
))
2697 set
= OSDynamicCast( OSSet
, resourcesProp
);
2699 set
= OSSet::withCapacity( 1 );
2701 set
->setObject( resourcesProp
);
2706 set
->setObject( newKey
);
2708 ret
= setProperty( gIOResourceMatchKey
, set
);
2714 bool IOService::checkResource( OSObject
* matching
)
2717 OSDictionary
* table
;
2719 if( (str
= OSDynamicCast( OSString
, matching
))) {
2720 if( gIOResources
->getProperty( str
))
2725 table
= resourceMatching( str
);
2726 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
2729 IOLog("%s: Can't match using: %s\n", getName(),
2730 matching
->getMetaClass()->getClassName());
2731 /* false would stall forever */
2735 if( gIOKitDebug
& kIOLogConfig
)
2736 LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName());
2738 waitForService( table
);
2740 if( gIOKitDebug
& kIOLogConfig
)
2741 LOG("config(%x): waking\n", (int) IOThreadSelf() );
2746 bool IOService::checkResources( void )
2748 OSObject
* resourcesProp
;
2753 resourcesProp
= getProperty( gIOResourceMatchKey
);
2754 if( 0 == resourcesProp
)
2757 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
2759 iter
= OSCollectionIterator::withCollection( set
);
2761 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
2762 ok
= checkResource( resourcesProp
);
2767 ok
= checkResource( resourcesProp
);
2773 void _IOConfigThread::configThread( void )
2775 _IOConfigThread
* inst
;
2778 if( !(inst
= new _IOConfigThread
))
2782 if( !(IOCreateThread((IOThreadFunc
) &_IOConfigThread::main
, inst
)))
2795 void _IOConfigThread::free( void )
2800 void IOService::doServiceMatch( IOOptionBits options
)
2802 _IOServiceNotifier
* notify
;
2804 OSOrderedSet
* matches
;
2805 SInt32 catalogGeneration
;
2806 bool keepGuessing
= true;
2807 bool reRegistered
= true;
2809 // job->nub->deliverNotification( gIOPublishNotification,
2810 // kIOServiceRegisteredState, 0xffffffff );
2812 while( keepGuessing
) {
2814 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
2815 // the matches list should always be created by findDrivers()
2818 lockForArbitration();
2819 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
2820 deliverNotification( gIOFirstPublishNotification
,
2821 kIOServiceFirstPublishState
, 0xffffffff );
2823 __state
[1] &= ~kIOServiceNeedConfigState
;
2824 __state
[1] |= kIOServiceConfigState
;
2825 __state
[0] |= kIOServiceRegisteredState
;
2827 if( reRegistered
&& (0 == (__state
[0] & kIOServiceInactiveState
))) {
2829 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
2830 gNotifications
->getObject( gIOPublishNotification
) );
2832 while((notify
= (_IOServiceNotifier
*)
2833 iter
->getNextObject())) {
2835 if( passiveMatch( notify
->matching
)
2836 && (kIOServiceNotifyEnable
& notify
->state
))
2837 matches
->setObject( notify
);
2844 unlockForArbitration();
2846 if( matches
->getCount() && (kIOReturnSuccess
== getResources()))
2847 probeCandidates( matches
);
2852 lockForArbitration();
2853 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
2855 (reRegistered
|| (catalogGeneration
!=
2856 gIOCatalogue
->getGenerationCount()))
2857 && (0 == (__state
[0] & kIOServiceInactiveState
));
2860 unlockForArbitration();
2863 if( (0 == (__state
[0] & kIOServiceInactiveState
))
2864 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
2865 deliverNotification( gIOMatchedNotification
,
2866 kIOServiceMatchedState
, 0xffffffff );
2867 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
2868 deliverNotification( gIOFirstMatchNotification
,
2869 kIOServiceFirstMatchState
, 0xffffffff );
2872 __state
[1] &= ~kIOServiceConfigState
;
2873 if( __state
[0] & kIOServiceInactiveState
)
2874 scheduleTerminatePhase2();
2877 unlockForArbitration();
2880 UInt32
IOService::_adjustBusy( SInt32 delta
)
2885 bool wasQuiet
, nowQuiet
, needWake
;
2888 result
= __state
[1] & kIOServiceBusyStateMask
;
2892 next
->lockForArbitration();
2893 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
2894 assert( count
< kIOServiceBusyMax
);
2895 wasQuiet
= (0 == count
);
2896 assert( (!wasQuiet
) || (delta
> 0));
2897 next
->__state
[1] += delta
;
2898 nowQuiet
= (0 == (next
->__state
[1] & kIOServiceBusyStateMask
));
2899 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
2902 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
2903 IOLockLock( gIOServiceBusyLock
);
2904 thread_wakeup( (event_t
) next
);
2905 IOLockUnlock( gIOServiceBusyLock
);
2908 next
->unlockForArbitration();
2910 if( (wasQuiet
|| nowQuiet
) ) {
2911 MessageClientsContext context
;
2913 context
.service
= next
;
2914 context
.type
= kIOMessageServiceBusyStateChange
;
2915 context
.argument
= (void *) wasQuiet
; // busy now
2916 context
.argSize
= 0;
2918 applyToInterestNotifiers( next
, gIOBusyInterest
,
2919 &messageClientsApplier
, &context
);
2921 if( nowQuiet
&& (next
== gIOServiceRoot
))
2922 OSMetaClass::considerUnloads();
2925 delta
= nowQuiet
? -1 : +1;
2927 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
2932 void IOService::adjustBusy( SInt32 delta
)
2934 lockForArbitration();
2935 _adjustBusy( delta
);
2936 unlockForArbitration();
2939 UInt32
IOService::getBusyState( void )
2941 return( __state
[1] & kIOServiceBusyStateMask
);
2944 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
2945 mach_timespec_t
* timeout
)
2948 int waitResult
= THREAD_AWAKENED
;
2949 bool computeDeadline
= true;
2950 AbsoluteTime abstime
;
2953 lockForArbitration();
2954 IOLockLock( gIOServiceBusyLock
);
2955 wait
= (value
!= (__state
[1] & mask
));
2957 __state
[1] |= kIOServiceBusyWaiterState
;
2958 unlockForArbitration();
2960 if( computeDeadline
) {
2961 AbsoluteTime nsinterval
;
2962 clock_interval_to_absolutetime_interval(
2963 timeout
->tv_sec
, kSecondScale
, &abstime
);
2964 clock_interval_to_absolutetime_interval(
2965 timeout
->tv_nsec
, kNanosecondScale
, &nsinterval
);
2966 ADD_ABSOLUTETIME( &abstime
, &nsinterval
);
2967 clock_absolutetime_interval_to_deadline(
2968 abstime
, &abstime
);
2969 computeDeadline
= false;
2972 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
2975 assert_wait((event_t
)this, THREAD_UNINT
);
2977 unlockForArbitration();
2978 IOLockUnlock( gIOServiceBusyLock
);
2980 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2982 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2984 if( waitResult
== THREAD_TIMED_OUT
)
2985 return( kIOReturnTimeout
);
2987 return( kIOReturnSuccess
);
2990 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
2992 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
2995 bool IOService::serializeProperties( OSSerialize
* s
) const
2998 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
2999 sizeof( __state
), "__state");
3001 return( super::serializeProperties(s
) );
3005 void _IOConfigThread::main( _IOConfigThread
* self
)
3007 _IOServiceJob
* job
;
3015 semaphore_wait( gJobsSemaphore
);
3017 IOTakeLock( gJobsLock
);
3018 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
3020 gJobs
->removeObject(job
);
3023 // gNumConfigThreads--; // we're out of service
3024 gNumWaitingThreads
--; // we're out of service
3026 IOUnlock( gJobsLock
);
3032 if( gIOKitDebug
& kIOLogConfig
)
3033 LOG("config(%x): starting on %s, %d\n",
3034 (int) IOThreadSelf(), job
->nub
->getName(), job
->type
);
3036 switch( job
->type
) {
3039 nub
->doServiceMatch( job
->options
);
3043 LOG("config(%x): strange type (%d)\n",
3044 (int) IOThreadSelf(), job
->type
);
3051 IOTakeLock( gJobsLock
);
3052 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
3054 gNumWaitingThreads
++; // back in service
3055 // gNumConfigThreads++;
3057 if( 0 == --gNumConfigThreads
) {
3058 // IOLog("MATCH IDLE\n");
3059 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3062 IOUnlock( gJobsLock
);
3067 if( gIOKitDebug
& kIOLogConfig
)
3068 LOG("config(%x): terminating\n", (int) IOThreadSelf() );
3073 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3076 int waitResult
= THREAD_AWAKENED
;
3077 bool computeDeadline
= true;
3078 AbsoluteTime abstime
;
3080 IOLockLock( gJobsLock
);
3082 wait
= (0 != gNumConfigThreads
);
3085 if( computeDeadline
) {
3086 clock_interval_to_absolutetime_interval(
3087 msToWait
, kMillisecondScale
, &abstime
);
3088 clock_absolutetime_interval_to_deadline(
3089 abstime
, &abstime
);
3090 computeDeadline
= false;
3092 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
3093 abstime
, THREAD_UNINT
);
3095 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3099 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3100 IOLockUnlock( gJobsLock
);
3102 if( waitResult
== THREAD_TIMED_OUT
)
3103 return( kIOReturnTimeout
);
3105 return( kIOReturnSuccess
);
3108 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3115 IOTakeLock( gJobsLock
);
3118 gJobs
->setLastObject( job
);
3120 count
= gNumWaitingThreads
;
3121 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3123 create
= ( (gOutstandingJobs
> count
)
3124 && (gNumConfigThreads
< kMaxConfigThreads
) );
3126 gNumConfigThreads
++;
3127 gNumWaitingThreads
++;
3130 IOUnlock( gJobsLock
);
3135 if( gIOKitDebug
& kIOLogConfig
)
3136 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3137 _IOConfigThread::configThread();
3140 semaphore_signal( gJobsSemaphore
);
3143 // internal - call with gNotificationLock
3144 OSObject
* IOService::getExistingServices( OSDictionary
* matching
,
3145 IOOptionBits inState
, IOOptionBits options
)
3147 OSObject
* current
= 0;
3149 IOService
* service
;
3156 && (obj
= matching
->getObject(gIOProviderClassKey
))
3158 && gIOResourcesKey
->isEqualTo(obj
)
3159 && (service
= gIOResources
))
3161 if( (inState
== (service
->__state
[0] & inState
))
3162 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3163 && service
->passiveMatch( matching
))
3165 if( options
& kIONotifyOnce
)
3168 current
= OSSet::withObjects(
3169 (const OSObject
**) &service
, 1, 1 );
3174 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3175 kIORegistryIterateRecursively
);
3179 while( (service
= (IOService
*) iter
->getNextObject())) {
3180 if( (inState
== (service
->__state
[0] & inState
))
3181 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3182 && service
->passiveMatch( matching
)) {
3184 if( options
& kIONotifyOnce
) {
3189 ((OSSet
*)current
)->setObject( service
);
3191 current
= OSSet::withObjects(
3192 (const OSObject
**) &service
, 1, 1 );
3195 } while( !service
&& !iter
->isValid());
3200 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
3201 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3210 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3214 // is a lock even needed?
3217 iter
= (OSIterator
*) getExistingServices( matching
,
3218 kIOServiceMatchedState
);
3226 // internal - call with gNotificationLock
3227 IONotifier
* IOService::setNotification(
3228 const OSSymbol
* type
, OSDictionary
* matching
,
3229 IOServiceNotificationHandler handler
, void * target
, void * ref
,
3232 _IOServiceNotifier
* notify
= 0;
3238 notify
= new _IOServiceNotifier
;
3239 if( notify
&& !notify
->init()) {
3245 notify
->matching
= matching
;
3246 notify
->handler
= handler
;
3247 notify
->target
= target
;
3249 notify
->priority
= priority
;
3250 notify
->state
= kIOServiceNotifyEnable
;
3251 queue_init( ¬ify
->handlerInvocations
);
3255 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3256 set
= OSOrderedSet::withCapacity( 1,
3257 IONotifyOrdering
, 0 );
3259 gNotifications
->setObject( type
, set
);
3263 notify
->whence
= set
;
3265 set
->setObject( notify
);
3271 // internal - call with gNotificationLock
3272 IONotifier
* IOService::doInstallNotification(
3273 const OSSymbol
* type
, OSDictionary
* matching
,
3274 IOServiceNotificationHandler handler
,
3275 void * target
, void * ref
,
3276 SInt32 priority
, OSIterator
** existing
)
3279 IONotifier
* notify
;
3280 IOOptionBits inState
;
3285 if( type
== gIOPublishNotification
)
3286 inState
= kIOServiceRegisteredState
;
3288 else if( type
== gIOFirstPublishNotification
)
3289 inState
= kIOServiceFirstPublishState
;
3291 else if( (type
== gIOMatchedNotification
)
3292 || (type
== gIOFirstMatchNotification
))
3293 inState
= kIOServiceMatchedState
;
3294 else if( type
== gIOTerminatedNotification
)
3299 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3302 // get the current set
3303 exist
= (OSIterator
*) getExistingServices( matching
, inState
);
3313 IONotifier
* IOService::installNotification(
3314 const OSSymbol
* type
, OSDictionary
* matching
,
3315 IOServiceNotificationHandler handler
,
3316 void * target
, void * ref
,
3317 SInt32 priority
, OSIterator
** existing
)
3319 IONotifier
* notify
;
3323 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3324 priority
, existing
);
3331 IONotifier
* IOService::addNotification(
3332 const OSSymbol
* type
, OSDictionary
* matching
,
3333 IOServiceNotificationHandler handler
,
3334 void * target
, void * ref
,
3337 OSIterator
* existing
;
3338 _IOServiceNotifier
* notify
;
3341 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3342 handler
, target
, ref
, priority
, &existing
);
3344 // send notifications for existing set
3347 notify
->retain(); // in case handler remove()s
3348 while( (next
= (IOService
*) existing
->getNextObject())) {
3350 next
->lockForArbitration();
3351 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3352 next
->invokeNotifer( notify
);
3353 next
->unlockForArbitration();
3356 existing
->release();
3362 struct SyncNotifyVars
{
3363 semaphore_port_t waitHere
;
3367 bool IOService::syncNotificationHandler(
3368 void * /* target */, void * ref
,
3369 IOService
* newService
)
3372 // result may get written more than once before the
3373 // notification is removed!
3374 ((SyncNotifyVars
*) ref
)->result
= newService
;
3375 semaphore_signal( ((SyncNotifyVars
*) ref
)->waitHere
);
3380 IOService
* IOService::waitForService( OSDictionary
* matching
,
3381 mach_timespec_t
* timeout
)
3383 IONotifier
* notify
= 0;
3384 // priority doesn't help us much since we need a thread wakeup
3385 SInt32 priority
= 0;
3386 SyncNotifyVars state
;
3387 kern_return_t err
= kIOReturnBadArgument
;
3399 state
.result
= (IOService
*) getExistingServices( matching
,
3400 kIOServiceMatchedState
, kIONotifyOnce
);
3404 err
= semaphore_create( kernel_task
, &state
.waitHere
,
3405 SYNC_POLICY_FIFO
, 0 );
3406 if( KERN_SUCCESS
!= err
)
3409 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
3410 &IOService::syncNotificationHandler
, (void *) 0,
3411 (void *) &state
, priority
);
3419 err
= semaphore_timedwait( state
.waitHere
, *timeout
);
3421 err
= semaphore_wait( state
.waitHere
);
3425 notify
->remove(); // dequeues
3427 matching
->release();
3429 semaphore_destroy( kernel_task
, state
.waitHere
);
3431 return( state
.result
);
3434 void IOService::deliverNotification( const OSSymbol
* type
,
3435 IOOptionBits orNewState
, IOOptionBits andNewState
)
3437 _IOServiceNotifier
* notify
;
3439 OSArray
* willSend
= 0;
3441 lockForArbitration();
3443 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3444 || (type
== gIOTerminatedNotification
)) {
3448 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3449 gNotifications
->getObject( type
) );
3452 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
3454 if( passiveMatch( notify
->matching
)
3455 && (kIOServiceNotifyEnable
& notify
->state
)) {
3457 willSend
= OSArray::withCapacity(8);
3459 willSend
->setObject( notify
);
3465 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
3471 for( unsigned int idx
= 0;
3472 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
3474 invokeNotifer( notify
);
3476 willSend
->release();
3478 unlockForArbitration();
3481 IOOptionBits
IOService::getState( void ) const
3483 return( __state
[0] );
3487 * Helpers to make matching objects for simple cases
3490 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
3491 OSDictionary
* table
)
3494 table
= OSDictionary::withCapacity( 2 );
3496 table
->setObject(gIOProviderClassKey
, (OSObject
*)name
);
3501 OSDictionary
* IOService::serviceMatching( const char * name
,
3502 OSDictionary
* table
)
3504 const OSString
* str
;
3506 str
= OSSymbol::withCString( name
);
3510 table
= serviceMatching( str
, table
);
3515 OSDictionary
* IOService::nameMatching( const OSString
* name
,
3516 OSDictionary
* table
)
3519 table
= OSDictionary::withCapacity( 2 );
3521 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
3526 OSDictionary
* IOService::nameMatching( const char * name
,
3527 OSDictionary
* table
)
3529 const OSString
* str
;
3531 str
= OSSymbol::withCString( name
);
3535 table
= nameMatching( str
, table
);
3540 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
3541 OSDictionary
* table
)
3543 table
= serviceMatching( gIOResourcesKey
, table
);
3545 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
3550 OSDictionary
* IOService::resourceMatching( const char * name
,
3551 OSDictionary
* table
)
3553 const OSSymbol
* str
;
3555 str
= OSSymbol::withCString( name
);
3559 table
= resourceMatching( str
, table
);
3566 * _IOServiceNotifier
3569 // wait for all threads, other than the current one,
3570 // to exit the handler
3572 void _IOServiceNotifier::wait()
3574 _IOServiceNotifierInvocation
* next
;
3579 queue_iterate( &handlerInvocations
, next
,
3580 _IOServiceNotifierInvocation
*, link
) {
3581 if( next
->thread
!= current_thread() ) {
3587 state
|= kIOServiceNotifyWaiter
;
3594 void _IOServiceNotifier::free()
3596 assert( queue_empty( &handlerInvocations
));
3600 void _IOServiceNotifier::remove()
3605 whence
->removeObject( (OSObject
*) this );
3609 matching
->release();
3613 state
&= ~kIOServiceNotifyEnable
;
3622 bool _IOServiceNotifier::disable()
3628 ret
= (0 != (kIOServiceNotifyEnable
& state
));
3629 state
&= ~kIOServiceNotifyEnable
;
3638 void _IOServiceNotifier::enable( bool was
)
3642 state
|= kIOServiceNotifyEnable
;
3644 state
&= ~kIOServiceNotifyEnable
;
3652 IOService
* IOResources::resources( void )
3656 inst
= new IOResources
;
3657 if( inst
&& !inst
->init()) {
3665 IOWorkLoop
* IOResources::getWorkLoop() const
3667 // If we are the resource root then bringe over to the
3668 // platform to get its workloop
3669 if (this == (IOResources
*) gIOResources
)
3670 return getPlatform()->getWorkLoop();
3672 return IOService::getWorkLoop();
3675 bool IOResources::matchPropertyTable( OSDictionary
* table
)
3683 prop
= table
->getObject( gIOResourceMatchKey
);
3684 str
= OSDynamicCast( OSString
, prop
);
3686 ok
= (0 != getProperty( str
));
3688 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
3690 iter
= OSCollectionIterator::withCollection( set
);
3692 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
3693 ok
= (0 != getProperty( str
));
3702 IOReturn
IOResources::setProperties( OSObject
* properties
)
3705 const OSSymbol
* key
;
3706 OSDictionary
* dict
;
3707 OSCollectionIterator
* iter
;
3709 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
3710 if ( kIOReturnSuccess
!= err
)
3713 dict
= OSDynamicCast(OSDictionary
, properties
);
3715 return( kIOReturnBadArgument
);
3717 iter
= OSCollectionIterator::withCollection( dict
);
3719 return( kIOReturnBadArgument
);
3721 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
3723 if (gIOConsoleUsersKey
== key
)
3725 IORegistryEntry::getRegistryRoot()->setProperty(key
, dict
->getObject(key
));
3726 OSIncrementAtomic( &gIOConsoleUsersSeed
);
3727 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
3731 publishResource( key
, dict
->getObject(key
) );
3736 return( kIOReturnSuccess
);
3740 * Helpers for matching dictionaries.
3741 * Keys existing in matching are checked in properties.
3742 * Keys may be a string or OSCollection of IOStrings
3745 bool IOService::compareProperty( OSDictionary
* matching
,
3751 value
= matching
->getObject( key
);
3753 ok
= value
->isEqualTo( getProperty( key
));
3761 bool IOService::compareProperty( OSDictionary
* matching
,
3762 const OSString
* key
)
3767 value
= matching
->getObject( key
);
3769 ok
= value
->isEqualTo( getProperty( key
));
3776 bool IOService::compareProperties( OSDictionary
* matching
,
3777 OSCollection
* keys
)
3779 OSCollectionIterator
* iter
;
3780 const OSString
* key
;
3783 if( !matching
|| !keys
)
3786 iter
= OSCollectionIterator::withCollection( keys
);
3789 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
3790 ok
= compareProperty( matching
, key
);
3794 keys
->release(); // !! consume a ref !!
3799 /* Helper to add a location matching dict to the table */
3801 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
3803 OSDictionary
* dict
;
3808 dict
= OSDictionary::withCapacity( 1 );
3810 table
->setObject( gIOLocationMatchKey
, dict
);
3818 * Go looking for a provider to match a location dict.
3821 IOService
* IOService::matchLocation( IOService
* /* client */ )
3825 parent
= getProvider();
3828 parent
= parent
->matchLocation( this );
3833 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
3839 IORegistryEntry
* entry
;
3844 bool matchParent
= false;
3855 str
= OSDynamicCast( OSString
, table
->getObject( gIOProviderClassKey
));
3858 match
= (0 != where
->metaCast( str
));
3863 obj
= table
->getObject( gIONameMatchKey
);
3866 match
= where
->compareNames( obj
, changesOK
? &matched
: 0 );
3869 if( changesOK
&& matched
) {
3870 // leave a hint as to which name matched
3871 table
->setObject( gIONameMatchedKey
, matched
);
3876 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
3879 const OSSymbol
* sym
;
3883 sym
= where
->copyLocation();
3885 match
= sym
->isEqualTo( str
);
3892 obj
= table
->getObject( gIOPropertyMatchKey
);
3895 OSDictionary
* dict
;
3896 OSDictionary
* nextDict
;
3901 dict
= where
->dictionaryWithProperties();
3903 nextDict
= OSDynamicCast( OSDictionary
, obj
);
3907 iter
= OSCollectionIterator::withCollection(
3908 OSDynamicCast(OSCollection
, obj
));
3911 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
3912 iter
->getNextObject()))))) {
3913 match
= dict
->isEqualTo( nextDict
, nextDict
);
3926 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
3929 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
3930 match
= (where
== entry
);
3937 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
3941 IOService
* service
= 0;
3942 UInt32 serviceCount
= 0;
3945 iter
= where
->getClientIterator();
3947 while( (service
= (IOService
*) iter
->getNextObject())) {
3948 if( kIOServiceInactiveState
& service
->__state
[0])
3950 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
3956 match
= (serviceCount
== num
->unsigned32BitValue());
3961 if( done
== table
->getCount()) {
3962 // don't call family if we've done all the entries in the table
3963 matchParent
= false;
3967 // pass in score from property table
3968 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
3970 // do family specific matching
3971 match
= where
->matchPropertyTable( table
, &score
);
3975 if( kIOLogMatch
& getDebugFlags( table
))
3976 LOG("%s: family specific matching fails\n", where
->getName());
3983 newPri
= OSNumber::withNumber( score
, 32 );
3985 table
->setObject( gIOProbeScoreKey
, newPri
);
3990 if( !(match
= where
->compareProperty( table
, kIOBSDNameKey
)))
3993 matchParent
= false;
3995 obj
= OSDynamicCast( OSDictionary
,
3996 table
->getObject( gIOParentMatchKey
));
4000 table
= (OSDictionary
*) obj
;
4004 table
= OSDynamicCast( OSDictionary
,
4005 table
->getObject( gIOLocationMatchKey
));
4008 where
= where
->getProvider();
4010 where
= where
->matchLocation( where
);
4013 } while( table
&& where
);
4015 } while( matchParent
&& (where
= where
->getProvider()) );
4017 if( kIOLogMatch
& gIOKitDebug
)
4019 LOG("match parent @ %s = %d\n",
4020 where
->getName(), match
);
4026 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4027 UInt32 type
, OSDictionary
* properties
,
4028 IOUserClient
** handler
)
4030 const OSSymbol
*userClientClass
= 0;
4031 IOUserClient
*client
;
4034 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
))
4035 return kIOReturnSuccess
;
4037 // First try my own properties for a user client class name
4038 temp
= getProperty(gIOUserClientClassKey
);
4040 if (OSDynamicCast(OSSymbol
, temp
))
4041 userClientClass
= (const OSSymbol
*) temp
;
4042 else if (OSDynamicCast(OSString
, temp
)) {
4043 userClientClass
= OSSymbol::withString((OSString
*) temp
);
4044 if (userClientClass
)
4045 setProperty(kIOUserClientClassKey
,
4046 (OSObject
*) userClientClass
);
4050 // Didn't find one so lets just bomb out now without further ado.
4051 if (!userClientClass
)
4052 return kIOReturnUnsupported
;
4054 // This reference is consumed by the IOServiceOpen call
4055 temp
= OSMetaClass::allocClassWithName(userClientClass
);
4057 return kIOReturnNoMemory
;
4059 if (OSDynamicCast(IOUserClient
, temp
))
4060 client
= (IOUserClient
*) temp
;
4063 return kIOReturnUnsupported
;
4066 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
4068 return kIOReturnBadArgument
;
4071 if ( !client
->attach(this) ) {
4073 return kIOReturnUnsupported
;
4076 if ( !client
->start(this) ) {
4077 client
->detach(this);
4079 return kIOReturnUnsupported
;
4083 return kIOReturnSuccess
;
4086 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4087 UInt32 type
, IOUserClient
** handler
)
4089 return( kIOReturnUnsupported
);
4092 IOReturn
IOService::requestProbe( IOOptionBits options
)
4094 return( kIOReturnUnsupported
);
4098 * Convert an IOReturn to text. Subclasses which add additional
4099 * IOReturn's should override this method and call
4100 * super::stringFromReturn if the desired value is not found.
4103 const char * IOService::stringFromReturn( IOReturn rtn
)
4105 static const IONamedValue IOReturn_values
[] = {
4106 {kIOReturnSuccess
, "success" },
4107 {kIOReturnError
, "general error" },
4108 {kIOReturnNoMemory
, "memory allocation error" },
4109 {kIOReturnNoResources
, "resource shortage" },
4110 {kIOReturnIPCError
, "Mach IPC failure" },
4111 {kIOReturnNoDevice
, "no such device" },
4112 {kIOReturnNotPrivileged
, "privilege violation" },
4113 {kIOReturnBadArgument
, "invalid argument" },
4114 {kIOReturnLockedRead
, "device is read locked" },
4115 {kIOReturnLockedWrite
, "device is write locked" },
4116 {kIOReturnExclusiveAccess
, "device is exclusive access" },
4117 {kIOReturnBadMessageID
, "bad IPC message ID" },
4118 {kIOReturnUnsupported
, "unsupported function" },
4119 {kIOReturnVMError
, "virtual memory error" },
4120 {kIOReturnInternalError
, "internal driver error" },
4121 {kIOReturnIOError
, "I/O error" },
4122 {kIOReturnCannotLock
, "cannot acquire lock" },
4123 {kIOReturnNotOpen
, "device is not open" },
4124 {kIOReturnNotReadable
, "device is not readable" },
4125 {kIOReturnNotWritable
, "device is not writeable" },
4126 {kIOReturnNotAligned
, "alignment error" },
4127 {kIOReturnBadMedia
, "media error" },
4128 {kIOReturnStillOpen
, "device is still open" },
4129 {kIOReturnRLDError
, "rld failure" },
4130 {kIOReturnDMAError
, "DMA failure" },
4131 {kIOReturnBusy
, "device is busy" },
4132 {kIOReturnTimeout
, "I/O timeout" },
4133 {kIOReturnOffline
, "device is offline" },
4134 {kIOReturnNotReady
, "device is not ready" },
4135 {kIOReturnNotAttached
, "device/channel is not attached" },
4136 {kIOReturnNoChannels
, "no DMA channels available" },
4137 {kIOReturnNoSpace
, "no space for data" },
4138 {kIOReturnPortExists
, "device port already exists" },
4139 {kIOReturnCannotWire
, "cannot wire physical memory" },
4140 {kIOReturnNoInterrupt
, "no interrupt attached" },
4141 {kIOReturnNoFrames
, "no DMA frames enqueued" },
4142 {kIOReturnMessageTooLarge
, "message is too large" },
4143 {kIOReturnNotPermitted
, "operation is not permitted" },
4144 {kIOReturnNoPower
, "device is without power" },
4145 {kIOReturnNoMedia
, "media is not present" },
4146 {kIOReturnUnformattedMedia
, "media is not formatted" },
4147 {kIOReturnUnsupportedMode
, "unsupported mode" },
4148 {kIOReturnUnderrun
, "data underrun" },
4149 {kIOReturnOverrun
, "data overrun" },
4150 {kIOReturnDeviceError
, "device error" },
4151 {kIOReturnNoCompletion
, "no completion routine" },
4152 {kIOReturnAborted
, "operation was aborted" },
4153 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
4154 {kIOReturnNotResponding
, "device is not responding" },
4155 {kIOReturnInvalid
, "unanticipated driver error" },
4159 return IOFindNameForValue(rtn
, IOReturn_values
);
4163 * Convert an IOReturn to an errno.
4165 int IOService::errnoFromReturn( IOReturn rtn
)
4169 case kIOReturnSuccess
:
4171 case kIOReturnNoMemory
:
4173 case kIOReturnNoDevice
:
4175 case kIOReturnVMError
:
4177 case kIOReturnNotPermitted
:
4179 case kIOReturnNotPrivileged
:
4181 case kIOReturnIOError
:
4183 case kIOReturnNotWritable
:
4185 case kIOReturnBadArgument
:
4187 case kIOReturnUnsupported
:
4191 case kIOReturnNoPower
:
4193 case kIOReturnDeviceError
:
4195 case kIOReturnTimeout
:
4197 case kIOReturnMessageTooLarge
:
4199 case kIOReturnNoSpace
:
4201 case kIOReturnCannotLock
:
4205 case kIOReturnBadMessageID
:
4206 case kIOReturnNoCompletion
:
4207 case kIOReturnNotAligned
:
4209 case kIOReturnNotReady
:
4211 case kIOReturnRLDError
:
4213 case kIOReturnPortExists
:
4214 case kIOReturnStillOpen
:
4216 case kIOReturnExclusiveAccess
:
4217 case kIOReturnLockedRead
:
4218 case kIOReturnLockedWrite
:
4219 case kIOReturnNotAttached
:
4220 case kIOReturnNotOpen
:
4221 case kIOReturnNotReadable
:
4223 case kIOReturnCannotWire
:
4224 case kIOReturnNoResources
:
4226 case kIOReturnAborted
:
4227 case kIOReturnOffline
:
4228 case kIOReturnNotResponding
:
4230 case kIOReturnBadMedia
:
4231 case kIOReturnNoMedia
:
4232 case kIOReturnUnformattedMedia
:
4233 return(ENXIO
); // (media error)
4234 case kIOReturnDMAError
:
4235 case kIOReturnOverrun
:
4236 case kIOReturnUnderrun
:
4237 return(EIO
); // (transfer error)
4238 case kIOReturnNoBandwidth
:
4239 case kIOReturnNoChannels
:
4240 case kIOReturnNoFrames
:
4241 case kIOReturnNoInterrupt
:
4242 return(EIO
); // (hardware error)
4243 case kIOReturnError
:
4244 case kIOReturnInternalError
:
4245 case kIOReturnInvalid
:
4246 return(EIO
); // (generic error)
4247 case kIOReturnIPCError
:
4248 return(EIO
); // (ipc error)
4250 return(EIO
); // (all other errors)
4254 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
4258 * Generic entry point for calls from the provider. A return value of
4259 * kIOReturnSuccess indicates that the message was received, and where
4260 * applicable, that it was successful.
4263 return kIOReturnUnsupported
;
4270 IOItemCount
IOService::getDeviceMemoryCount( void )
4275 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4277 count
= array
->getCount();
4284 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
4287 IODeviceMemory
* range
;
4289 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4291 range
= (IODeviceMemory
*) array
->getObject( index
);
4298 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
4299 IOOptionBits options
)
4301 IODeviceMemory
* range
;
4304 range
= getDeviceMemoryWithIndex( index
);
4306 map
= range
->map( options
);
4313 OSArray
* IOService::getDeviceMemory( void )
4315 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
4319 void IOService::setDeviceMemory( OSArray
* array
)
4321 setProperty( gIODeviceMemoryKey
, array
);
4325 * For machines where the transfers on an I/O bus can stall because
4326 * the CPU is in an idle mode, These APIs allow a driver to specify
4327 * the maximum bus stall that they can handle. 0 indicates no limit.
4330 setCPUSnoopDelay(UInt32 __unused ns
)
4333 ml_set_maxsnoop(ns
);
4334 #endif /* __i386__ */
4341 return ml_get_maxsnoop();
4344 #endif /* __i386__ */
4348 requireMaxBusStall(UInt32 __unused ns
)
4351 static const UInt kNoReplace
= -1U; // Must be an illegal index
4352 UInt replace
= kNoReplace
;
4354 IOLockLock(sBusStallLock
);
4356 UInt count
= sBusStall
->getLength() / sizeof(BusStallEntry
);
4357 BusStallEntry
*entries
= (BusStallEntry
*) sBusStall
->getBytesNoCopy();
4360 const BusStallEntry ne
= {this, ns
};
4362 // Set Maximum bus delay.
4363 for (UInt i
= 0; i
< count
; i
++) {
4364 const IOService
*thisService
= entries
[i
].fService
;
4365 if (this == thisService
)
4367 else if (!thisService
) {
4368 if (kNoReplace
== replace
)
4372 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
4378 // Must be safe to call from locked context
4379 ml_set_maxbusdelay(ns
);
4381 if (kNoReplace
== replace
)
4382 sBusStall
->appendBytes(&ne
, sizeof(ne
));
4384 entries
[replace
] = ne
;
4387 ns
= -1U; // Set to max unsigned, i.e. no restriction
4389 for (UInt i
= 0; i
< count
; i
++) {
4390 // Clear a maximum bus delay.
4391 const IOService
*thisService
= entries
[i
].fService
;
4392 UInt32 thisMax
= entries
[i
].fMaxDelay
;
4393 if (this == thisService
)
4395 else if (thisService
&& thisMax
< ns
)
4399 // Check if entry found
4400 if (kNoReplace
!= replace
) {
4401 entries
[replace
].fService
= 0; // Null the entry
4402 ml_set_maxbusdelay(ns
);
4406 IOLockUnlock(sBusStallLock
);
4407 #endif /* __i386__ */
4414 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
4416 IOInterruptController
*interruptController
;
4419 OSSymbol
*interruptControllerName
;
4421 IOInterruptSource
*interruptSources
;
4423 // Get the parents list from the nub.
4424 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
4425 if (array
== 0) return kIOReturnNoResources
;
4427 // Allocate space for the IOInterruptSources if needed... then return early.
4428 if (nub
->_interruptSources
== 0) {
4429 numSources
= array
->getCount();
4430 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
4431 if (interruptSources
== 0) return kIOReturnNoMemory
;
4433 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
4435 nub
->_numInterruptSources
= numSources
;
4436 nub
->_interruptSources
= interruptSources
;
4437 return kIOReturnSuccess
;
4440 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
4441 if (interruptControllerName
== 0) return kIOReturnNoResources
;
4443 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
4444 if (interruptController
== 0) return kIOReturnNoResources
;
4446 // Get the interrupt numbers from the nub.
4447 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
4448 if (array
== 0) return kIOReturnNoResources
;
4449 data
= OSDynamicCast(OSData
, array
->getObject(source
));
4450 if (data
== 0) return kIOReturnNoResources
;
4452 // Set the interruptController and interruptSource in the nub's table.
4453 interruptSources
= nub
->_interruptSources
;
4454 interruptSources
[source
].interruptController
= interruptController
;
4455 interruptSources
[source
].vectorData
= data
;
4457 return kIOReturnSuccess
;
4460 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
4464 /* Make sure the _interruptSources are set */
4465 if (_interruptSources
== 0) {
4466 ret
= resolveInterrupt(this, source
);
4467 if (ret
!= kIOReturnSuccess
) return ret
;
4470 /* Make sure the local source number is valid */
4471 if ((source
< 0) || (source
>= _numInterruptSources
))
4472 return kIOReturnNoInterrupt
;
4474 /* Look up the contoller for the local source */
4475 *interruptController
= _interruptSources
[source
].interruptController
;
4477 if (*interruptController
== NULL
) {
4478 if (!resolve
) return kIOReturnNoInterrupt
;
4480 /* Try to reslove the interrupt */
4481 ret
= resolveInterrupt(this, source
);
4482 if (ret
!= kIOReturnSuccess
) return ret
;
4484 *interruptController
= _interruptSources
[source
].interruptController
;
4487 return kIOReturnSuccess
;
4490 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
4491 IOInterruptAction handler
,
4494 IOInterruptController
*interruptController
;
4497 ret
= lookupInterrupt(source
, true, &interruptController
);
4498 if (ret
!= kIOReturnSuccess
) return ret
;
4500 /* Register the source */
4501 return interruptController
->registerInterrupt(this, source
, target
,
4502 (IOInterruptHandler
)handler
,
4506 IOReturn
IOService::unregisterInterrupt(int source
)
4508 IOInterruptController
*interruptController
;
4511 ret
= lookupInterrupt(source
, false, &interruptController
);
4512 if (ret
!= kIOReturnSuccess
) return ret
;
4514 /* Unregister the source */
4515 return interruptController
->unregisterInterrupt(this, source
);
4518 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
4520 IOInterruptController
*interruptController
;
4523 ret
= lookupInterrupt(source
, true, &interruptController
);
4524 if (ret
!= kIOReturnSuccess
) return ret
;
4526 /* Return the type */
4527 return interruptController
->getInterruptType(this, source
, interruptType
);
4530 IOReturn
IOService::enableInterrupt(int source
)
4532 IOInterruptController
*interruptController
;
4535 ret
= lookupInterrupt(source
, false, &interruptController
);
4536 if (ret
!= kIOReturnSuccess
) return ret
;
4538 /* Enable the source */
4539 return interruptController
->enableInterrupt(this, source
);
4542 IOReturn
IOService::disableInterrupt(int source
)
4544 IOInterruptController
*interruptController
;
4547 ret
= lookupInterrupt(source
, false, &interruptController
);
4548 if (ret
!= kIOReturnSuccess
) return ret
;
4550 /* Disable the source */
4551 return interruptController
->disableInterrupt(this, source
);
4554 IOReturn
IOService::causeInterrupt(int source
)
4556 IOInterruptController
*interruptController
;
4559 ret
= lookupInterrupt(source
, false, &interruptController
);
4560 if (ret
!= kIOReturnSuccess
) return ret
;
4562 /* Cause an interrupt for the source */
4563 return interruptController
->causeInterrupt(this, source
);
4566 OSMetaClassDefineReservedUsed(IOService
, 0);
4567 OSMetaClassDefineReservedUsed(IOService
, 1);
4568 OSMetaClassDefineReservedUsed(IOService
, 2);
4569 OSMetaClassDefineReservedUsed(IOService
, 3);
4571 OSMetaClassDefineReservedUnused(IOService
, 4);
4572 OSMetaClassDefineReservedUnused(IOService
, 5);
4573 OSMetaClassDefineReservedUnused(IOService
, 6);
4574 OSMetaClassDefineReservedUnused(IOService
, 7);
4575 OSMetaClassDefineReservedUnused(IOService
, 8);
4576 OSMetaClassDefineReservedUnused(IOService
, 9);
4577 OSMetaClassDefineReservedUnused(IOService
, 10);
4578 OSMetaClassDefineReservedUnused(IOService
, 11);
4579 OSMetaClassDefineReservedUnused(IOService
, 12);
4580 OSMetaClassDefineReservedUnused(IOService
, 13);
4581 OSMetaClassDefineReservedUnused(IOService
, 14);
4582 OSMetaClassDefineReservedUnused(IOService
, 15);
4583 OSMetaClassDefineReservedUnused(IOService
, 16);
4584 OSMetaClassDefineReservedUnused(IOService
, 17);
4585 OSMetaClassDefineReservedUnused(IOService
, 18);
4586 OSMetaClassDefineReservedUnused(IOService
, 19);
4587 OSMetaClassDefineReservedUnused(IOService
, 20);
4588 OSMetaClassDefineReservedUnused(IOService
, 21);
4589 OSMetaClassDefineReservedUnused(IOService
, 22);
4590 OSMetaClassDefineReservedUnused(IOService
, 23);
4591 OSMetaClassDefineReservedUnused(IOService
, 24);
4592 OSMetaClassDefineReservedUnused(IOService
, 25);
4593 OSMetaClassDefineReservedUnused(IOService
, 26);
4594 OSMetaClassDefineReservedUnused(IOService
, 27);
4595 OSMetaClassDefineReservedUnused(IOService
, 28);
4596 OSMetaClassDefineReservedUnused(IOService
, 29);
4597 OSMetaClassDefineReservedUnused(IOService
, 30);
4598 OSMetaClassDefineReservedUnused(IOService
, 31);
4599 OSMetaClassDefineReservedUnused(IOService
, 32);
4600 OSMetaClassDefineReservedUnused(IOService
, 33);
4601 OSMetaClassDefineReservedUnused(IOService
, 34);
4602 OSMetaClassDefineReservedUnused(IOService
, 35);
4603 OSMetaClassDefineReservedUnused(IOService
, 36);
4604 OSMetaClassDefineReservedUnused(IOService
, 37);
4605 OSMetaClassDefineReservedUnused(IOService
, 38);
4606 OSMetaClassDefineReservedUnused(IOService
, 39);
4607 OSMetaClassDefineReservedUnused(IOService
, 40);
4608 OSMetaClassDefineReservedUnused(IOService
, 41);
4609 OSMetaClassDefineReservedUnused(IOService
, 42);
4610 OSMetaClassDefineReservedUnused(IOService
, 43);
4611 OSMetaClassDefineReservedUnused(IOService
, 44);
4612 OSMetaClassDefineReservedUnused(IOService
, 45);
4613 OSMetaClassDefineReservedUnused(IOService
, 46);
4614 OSMetaClassDefineReservedUnused(IOService
, 47);
4617 OSMetaClassDefineReservedUnused(IOService
, 48);
4618 OSMetaClassDefineReservedUnused(IOService
, 49);
4619 OSMetaClassDefineReservedUnused(IOService
, 50);
4620 OSMetaClassDefineReservedUnused(IOService
, 51);
4621 OSMetaClassDefineReservedUnused(IOService
, 52);
4622 OSMetaClassDefineReservedUnused(IOService
, 53);
4623 OSMetaClassDefineReservedUnused(IOService
, 54);
4624 OSMetaClassDefineReservedUnused(IOService
, 55);
4625 OSMetaClassDefineReservedUnused(IOService
, 56);
4626 OSMetaClassDefineReservedUnused(IOService
, 57);
4627 OSMetaClassDefineReservedUnused(IOService
, 58);
4628 OSMetaClassDefineReservedUnused(IOService
, 59);
4629 OSMetaClassDefineReservedUnused(IOService
, 60);
4630 OSMetaClassDefineReservedUnused(IOService
, 61);
4631 OSMetaClassDefineReservedUnused(IOService
, 62);
4632 OSMetaClassDefineReservedUnused(IOService
, 63);