2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <IOKit/system.h>
31 #include <IOKit/IOService.h>
32 #include <libkern/c++/OSContainers.h>
33 #include <libkern/c++/OSUnserialize.h>
34 #include <IOKit/IOCatalogue.h>
35 #include <IOKit/IOCommand.h>
36 #include <IOKit/IODeviceMemory.h>
37 #include <IOKit/IOInterrupts.h>
38 #include <IOKit/IOInterruptController.h>
39 #include <IOKit/IOPlatformExpert.h>
40 #include <IOKit/IOMessage.h>
41 #include <IOKit/IOLib.h>
42 #include <IOKit/IOKitKeysPrivate.h>
43 #include <IOKit/IOBSD.h>
44 #include <IOKit/IOUserClient.h>
45 #include <IOKit/IOWorkLoop.h>
46 #include <mach/sync_policy.h>
47 #include <IOKit/assert.h>
48 #include <sys/errno.h>
53 #include "IOServicePrivate.h"
55 // take lockForArbitration before LOCKNOTIFY
57 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
59 #define super IORegistryEntry
61 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
63 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
65 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
67 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
69 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
71 OSDefineMetaClassAndStructors(IOResources
, IOService
)
73 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
75 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
77 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
79 static IOPlatformExpert
* gIOPlatform
;
80 static class IOPMrootDomain
* gIOPMRootDomain
;
81 const IORegistryPlane
* gIOServicePlane
;
82 const IORegistryPlane
* gIOPowerPlane
;
83 const OSSymbol
* gIODeviceMemoryKey
;
84 const OSSymbol
* gIOInterruptControllersKey
;
85 const OSSymbol
* gIOInterruptSpecifiersKey
;
87 const OSSymbol
* gIOResourcesKey
;
88 const OSSymbol
* gIOResourceMatchKey
;
89 const OSSymbol
* gIOProviderClassKey
;
90 const OSSymbol
* gIONameMatchKey
;
91 const OSSymbol
* gIONameMatchedKey
;
92 const OSSymbol
* gIOPropertyMatchKey
;
93 const OSSymbol
* gIOLocationMatchKey
;
94 const OSSymbol
* gIOParentMatchKey
;
95 const OSSymbol
* gIOPathMatchKey
;
96 const OSSymbol
* gIOMatchCategoryKey
;
97 const OSSymbol
* gIODefaultMatchCategoryKey
;
98 const OSSymbol
* gIOMatchedServiceCountKey
;
100 const OSSymbol
* gIOUserClientClassKey
;
101 const OSSymbol
* gIOKitDebugKey
;
103 const OSSymbol
* gIOCommandPoolSizeKey
;
105 const OSSymbol
* gIOConsoleUsersKey
;
106 const OSSymbol
* gIOConsoleSessionUIDKey
;
107 const OSSymbol
* gIOConsoleUsersSeedKey
;
108 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
109 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
111 static int gIOResourceGenerationCount
;
113 const OSSymbol
* gIOServiceKey
;
114 const OSSymbol
* gIOPublishNotification
;
115 const OSSymbol
* gIOFirstPublishNotification
;
116 const OSSymbol
* gIOMatchedNotification
;
117 const OSSymbol
* gIOFirstMatchNotification
;
118 const OSSymbol
* gIOTerminatedNotification
;
120 const OSSymbol
* gIOGeneralInterest
;
121 const OSSymbol
* gIOBusyInterest
;
122 const OSSymbol
* gIOAppPowerStateInterest
;
123 const OSSymbol
* gIOPriorityPowerStateInterest
;
125 static OSDictionary
* gNotifications
;
126 static IORecursiveLock
* gNotificationLock
;
128 static IOService
* gIOResources
;
129 static IOService
* gIOServiceRoot
;
131 static OSOrderedSet
* gJobs
;
132 static semaphore_port_t gJobsSemaphore
;
133 static IOLock
* gJobsLock
;
134 static int gOutstandingJobs
;
135 static int gNumConfigThreads
;
136 static int gNumWaitingThreads
;
137 static IOLock
* gIOServiceBusyLock
;
139 static thread_t gIOTerminateThread
;
140 static UInt32 gIOTerminateWork
;
141 static OSArray
* gIOTerminatePhase2List
;
142 static OSArray
* gIOStopList
;
143 static OSArray
* gIOStopProviderList
;
144 static OSArray
* gIOFinalizeList
;
146 static SInt32 gIOConsoleUsersSeed
;
147 static OSData
* gIOConsoleUsersSeedValue
;
149 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
151 #define LOCKREADNOTIFY() \
152 IORecursiveLockLock( gNotificationLock )
153 #define LOCKWRITENOTIFY() \
154 IORecursiveLockLock( gNotificationLock )
155 #define LOCKWRITE2READNOTIFY()
156 #define UNLOCKNOTIFY() \
157 IORecursiveLockUnlock( gNotificationLock )
158 #define SLEEPNOTIFY(event) \
159 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
160 #define WAKEUPNOTIFY(event) \
161 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
163 #define randomDelay() \
164 int del = read_processor_clock(); \
165 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
168 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
170 #define queue_element(entry, element, type, field) do { \
171 vm_address_t __ele = (vm_address_t) (entry); \
172 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
173 (element) = (type) __ele; \
176 #define iterqueue(que, elt) \
177 for (queue_entry_t elt = queue_first(que); \
178 !queue_end(que, elt); \
179 elt = queue_next(elt))
181 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
183 struct ArbitrationLockQueueElement
{
192 static queue_head_t gArbitrationLockQueueActive
;
193 static queue_head_t gArbitrationLockQueueWaiting
;
194 static queue_head_t gArbitrationLockQueueFree
;
195 static IOLock
* gArbitrationLockQueueLock
;
197 bool IOService::isInactive( void ) const
198 { return( 0 != (kIOServiceInactiveState
& getState())); }
200 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
202 void IOService::initialize( void )
206 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
207 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
209 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
210 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
211 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
212 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
213 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
214 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
215 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
217 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
218 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
219 kIODefaultMatchCategoryKey
);
220 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
221 kIOMatchedServiceCountKey
);
223 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
225 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
226 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
228 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
229 gIOInterruptControllersKey
230 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
231 gIOInterruptSpecifiersKey
232 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
234 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
236 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
238 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
239 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
240 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
241 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
243 gNotifications
= OSDictionary::withCapacity( 1 );
244 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
245 kIOPublishNotification
);
246 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
247 kIOFirstPublishNotification
);
248 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
249 kIOMatchedNotification
);
250 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
251 kIOFirstMatchNotification
);
252 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
253 kIOTerminatedNotification
);
254 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
256 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
257 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
258 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey
);
259 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionOnConsoleKey
);
260 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionSecureInputPIDKey
);
261 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
263 gNotificationLock
= IORecursiveLockAlloc();
265 assert( gIOServicePlane
&& gIODeviceMemoryKey
266 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
267 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
268 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
269 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
270 && gIOPublishNotification
&& gIOMatchedNotification
271 && gIOTerminatedNotification
&& gIOServiceKey
272 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
273 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
274 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
276 gJobsLock
= IOLockAlloc();
277 gJobs
= OSOrderedSet::withCapacity( 10 );
279 gIOServiceBusyLock
= IOLockAlloc();
281 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
283 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& (err
== KERN_SUCCESS
) );
285 gIOResources
= IOResources::resources();
286 assert( gIOResources
);
288 gArbitrationLockQueueLock
= IOLockAlloc();
289 queue_init(&gArbitrationLockQueueActive
);
290 queue_init(&gArbitrationLockQueueWaiting
);
291 queue_init(&gArbitrationLockQueueFree
);
293 assert( gArbitrationLockQueueLock
);
295 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
296 gIOStopList
= OSArray::withCapacity( 16 );
297 gIOStopProviderList
= OSArray::withCapacity( 16 );
298 gIOFinalizeList
= OSArray::withCapacity( 16 );
299 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
302 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
305 static UInt64
getDebugFlags( OSDictionary
* props
)
307 OSNumber
* debugProp
;
310 debugProp
= OSDynamicCast( OSNumber
,
311 props
->getObject( gIOKitDebugKey
));
313 debugFlags
= debugProp
->unsigned64BitValue();
315 debugFlags
= gIOKitDebug
;
317 return( debugFlags
);
321 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
323 // Probe a matched service and return an instance to be started.
324 // The default score is from the property table, & may be altered
325 // during probe to change the start order.
327 IOService
* IOService::probe( IOService
* provider
,
333 bool IOService::start( IOService
* provider
)
338 void IOService::stop( IOService
* provider
)
342 void IOService::free( void )
344 if( getPropertyTable())
345 unregisterAllInterest();
351 * Attach in service plane
353 bool IOService::attach( IOService
* provider
)
359 if( gIOKitDebug
& kIOLogAttach
)
360 LOG( "%s::attach(%s)\n", getName(),
361 provider
->getName());
363 provider
->lockForArbitration();
364 if( provider
->__state
[0] & kIOServiceInactiveState
)
367 ok
= attachToParent( provider
, gIOServicePlane
);
368 provider
->unlockForArbitration();
371 gIOServiceRoot
= this;
372 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
378 IOService
* IOService::getServiceRoot( void )
380 return( gIOServiceRoot
);
383 void IOService::detach( IOService
* provider
)
385 IOService
* newProvider
= 0;
389 if( gIOKitDebug
& kIOLogAttach
)
390 LOG("%s::detach(%s)\n", getName(), provider
->getName());
392 lockForArbitration();
394 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
395 && (provider
== getProvider()));
397 detachFromParent( provider
, gIOServicePlane
);
400 newProvider
= getProvider();
401 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
402 _adjustBusy( -busy
);
405 unlockForArbitration();
408 newProvider
->lockForArbitration();
409 newProvider
->_adjustBusy(1);
410 newProvider
->unlockForArbitration();
413 // check for last client detach from a terminated service
414 if( provider
->lockForArbitration( true )) {
416 provider
->_adjustBusy( -1 );
417 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
418 && (0 == provider
->getClient())) {
419 provider
->scheduleFinalize();
421 provider
->unlockForArbitration();
426 * Register instance - publish it for matching
429 void IOService::registerService( IOOptionBits options
)
435 enum { kMaxPathLen
= 256 };
436 enum { kMaxChars
= 63 };
438 IORegistryEntry
* parent
= this;
439 IORegistryEntry
* root
= getRegistryRoot();
440 while( parent
&& (parent
!= root
))
441 parent
= parent
->getParentEntry( gIOServicePlane
);
443 if( parent
!= root
) {
444 IOLog("%s: not registry member at registerService()\n", getName());
448 // Allow the Platform Expert to adjust this node.
449 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
452 if( (this != gIOResources
)
453 && (kIOLogRegister
& gIOKitDebug
)) {
455 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
457 IOLog( "Registering: " );
460 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
463 if( len
> kMaxChars
) {
467 if( (skip
= strchr( path
, '/')))
473 IOLog( "%s\n", path
);
476 IOFree( pathBuf
, kMaxPathLen
);
479 startMatching( options
);
482 void IOService::startMatching( IOOptionBits options
)
484 IOService
* provider
;
487 bool needWake
= false;
492 lockForArbitration();
494 sync
= (options
& kIOServiceSynchronous
)
495 || ((provider
= getProvider())
496 && (provider
->__state
[1] & kIOServiceSynchronousState
));
499 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
500 && (0 == (__state
[0] & kIOServiceInactiveState
));
502 __state
[1] |= kIOServiceNeedConfigState
;
504 // __state[0] &= ~kIOServiceInactiveState;
506 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
507 // OSKernelStackRemaining(), getName());
510 prevBusy
= _adjustBusy( 1 );
511 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
515 __state
[1] |= kIOServiceSynchronousState
;
517 __state
[1] &= ~kIOServiceSynchronousState
;
519 unlockForArbitration();
524 IOLockLock( gIOServiceBusyLock
);
525 thread_wakeup( (event_t
) this/*&__state[1]*/ );
526 IOLockUnlock( gIOServiceBusyLock
);
528 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
530 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
534 if( (__state
[1] & kIOServiceNeedConfigState
))
535 doServiceMatch( options
);
537 lockForArbitration();
538 IOLockLock( gIOServiceBusyLock
);
540 waitAgain
= (prevBusy
< (__state
[1] & kIOServiceBusyStateMask
));
542 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
544 __state
[1] &= ~kIOServiceSyncPubState
;
546 unlockForArbitration();
549 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
551 IOLockUnlock( gIOServiceBusyLock
);
553 thread_block(THREAD_CONTINUE_NULL
);
555 } while( waitAgain
);
559 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
561 OSDictionary
* table
;
571 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
574 set
= (OSSet
*) getExistingServices( table
,
575 kIOServiceRegisteredState
,
576 kIOServiceExistingSet
);
581 count
+= set
->getCount();
584 allSet
->merge((const OSSet
*) set
);
592 if( getDebugFlags( table
) & kIOLogMatch
)
593 LOG("Matching service count = %ld\n", count
);
595 newTables
->removeObject(table
);
599 while( (service
= (IOService
*) allSet
->getAnyObject())) {
600 service
->startMatching(kIOServiceAsynchronous
);
601 allSet
->removeObject(service
);
606 newTables
->release();
608 return( kIOReturnSuccess
);
611 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
612 IOOptionBits options
)
616 job
= new _IOServiceJob
;
617 if( job
&& !job
->init()) {
625 job
->options
= options
;
626 nub
->retain(); // thread will release()
634 * Called on a registered service to see if it matches
638 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
640 return( matchPropertyTable(table
) );
643 bool IOService::matchPropertyTable( OSDictionary
* table
)
649 * Called on a matched service to allocate resources
650 * before first driver is attached.
653 IOReturn
IOService::getResources( void )
655 return( kIOReturnSuccess
);
659 * Client/provider accessors
662 IOService
* IOService::getProvider( void ) const
664 IOService
* self
= (IOService
*) this;
669 generation
= getGenerationCount();
670 if( __providerGeneration
== generation
)
673 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
674 if( parent
== IORegistryEntry::getRegistryRoot())
675 /* root is not an IOService */
678 self
->__provider
= parent
;
679 // save the count before getParentEntry()
680 self
->__providerGeneration
= generation
;
685 IOWorkLoop
* IOService::getWorkLoop() const
687 IOService
*provider
= getProvider();
690 return provider
->getWorkLoop();
695 OSIterator
* IOService::getProviderIterator( void ) const
697 return( getParentIterator( gIOServicePlane
));
700 IOService
* IOService::getClient( void ) const
702 return( (IOService
*) getChildEntry( gIOServicePlane
));
705 OSIterator
* IOService::getClientIterator( void ) const
707 return( getChildIterator( gIOServicePlane
));
710 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
711 const IOService
* client
,
712 const IOService
* provider
)
714 _IOOpenServiceIterator
* inst
;
719 inst
= new _IOOpenServiceIterator
;
721 if( inst
&& !inst
->init()) {
727 inst
->client
= client
;
728 inst
->provider
= provider
;
734 void _IOOpenServiceIterator::free()
738 last
->unlockForArbitration();
742 OSObject
* _IOOpenServiceIterator::getNextObject()
747 last
->unlockForArbitration();
749 while( (next
= (IOService
*) iter
->getNextObject())) {
751 next
->lockForArbitration();
752 if( (client
&& (next
->isOpen( client
)))
753 || (provider
&& (provider
->isOpen( next
))) )
755 next
->unlockForArbitration();
763 bool _IOOpenServiceIterator::isValid()
765 return( iter
->isValid() );
768 void _IOOpenServiceIterator::reset()
771 last
->unlockForArbitration();
777 OSIterator
* IOService::getOpenProviderIterator( void ) const
779 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
782 OSIterator
* IOService::getOpenClientIterator( void ) const
784 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
788 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
789 bool waitForFunction
,
790 void *param1
, void *param2
,
791 void *param3
, void *param4
)
793 IOReturn result
= kIOReturnUnsupported
;
794 IOService
*provider
= getProvider();
797 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
798 param1
, param2
, param3
, param4
);
804 IOReturn
IOService::callPlatformFunction( const char * functionName
,
805 bool waitForFunction
,
806 void *param1
, void *param2
,
807 void *param3
, void *param4
)
809 IOReturn result
= kIOReturnNoMemory
;
810 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
812 if (functionSymbol
!= 0) {
813 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
814 param1
, param2
, param3
, param4
);
815 functionSymbol
->release();
823 * Accessors for global services
826 IOPlatformExpert
* IOService::getPlatform( void )
828 return( gIOPlatform
);
831 class IOPMrootDomain
* IOService::getPMRootDomain( void )
833 return( gIOPMRootDomain
);
836 IOService
* IOService::getResourceService( void )
838 return( gIOResources
);
841 void IOService::setPlatform( IOPlatformExpert
* platform
)
843 gIOPlatform
= platform
;
844 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
847 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
849 gIOPMRootDomain
= rootDomain
;
850 publishResource("IOKit");
857 bool IOService::lockForArbitration( bool isSuccessRequired
)
861 ArbitrationLockQueueElement
* element
;
862 ArbitrationLockQueueElement
* active
;
863 ArbitrationLockQueueElement
* waiting
;
865 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
867 // lock global access
868 IOTakeLock( gArbitrationLockQueueLock
);
870 // obtain an unused queue element
871 if( !queue_empty( &gArbitrationLockQueueFree
)) {
872 queue_remove_first( &gArbitrationLockQueueFree
,
874 ArbitrationLockQueueElement
*,
877 element
= IONew( ArbitrationLockQueueElement
, 1 );
881 // prepare the queue element
882 element
->thread
= IOThreadSelf();
883 element
->service
= this;
885 element
->required
= isSuccessRequired
;
886 element
->aborted
= false;
888 // determine whether this object is already locked (ie. on active queue)
890 queue_iterate( &gArbitrationLockQueueActive
,
892 ArbitrationLockQueueElement
*,
895 if( active
->service
== element
->service
) {
901 if( found
) { // this object is already locked
903 // determine whether it is the same or a different thread trying to lock
904 if( active
->thread
!= element
->thread
) { // it is a different thread
906 ArbitrationLockQueueElement
* victim
= 0;
908 // before placing this new thread on the waiting queue, we look for
909 // a deadlock cycle...
912 // determine whether the active thread holding the object we
913 // want is waiting for another object to be unlocked
915 queue_iterate( &gArbitrationLockQueueWaiting
,
917 ArbitrationLockQueueElement
*,
920 if( waiting
->thread
== active
->thread
) {
921 assert( false == waiting
->aborted
);
927 if( found
) { // yes, active thread waiting for another object
929 // this may be a candidate for rejection if the required
930 // flag is not set, should we detect a deadlock later on
931 if( false == waiting
->required
)
934 // find the thread that is holding this other object, that
935 // is blocking the active thread from proceeding (fun :-)
937 queue_iterate( &gArbitrationLockQueueActive
,
938 active
, // (reuse active queue element)
939 ArbitrationLockQueueElement
*,
942 if( active
->service
== waiting
->service
) {
948 // someone must be holding it or it wouldn't be waiting
951 if( active
->thread
== element
->thread
) {
953 // doh, it's waiting for the thread that originated
954 // this whole lock (ie. current thread) -> deadlock
955 if( false == element
->required
) { // willing to fail?
957 // the originating thread doesn't have the required
958 // flag, so it can fail
959 success
= false; // (fail originating lock request)
960 break; // (out of while)
962 } else { // originating thread is not willing to fail
964 // see if we came across a waiting thread that did
965 // not have the 'required' flag set: we'll fail it
968 // we do have a willing victim, fail it's lock
969 victim
->aborted
= true;
971 // take the victim off the waiting queue
972 queue_remove( &gArbitrationLockQueueWaiting
,
974 ArbitrationLockQueueElement
*,
978 IOLockWakeup( gArbitrationLockQueueLock
,
980 /* one thread */ true );
982 // allow this thread to proceed (ie. wait)
983 success
= true; // (put request on wait queue)
984 break; // (out of while)
987 // all the waiting threads we came across in
988 // finding this loop had the 'required' flag
989 // set, so we've got a deadlock we can't avoid
990 panic("I/O Kit: Unrecoverable deadlock.");
994 // repeat while loop, redefining active thread to be the
995 // thread holding "this other object" (see above), and
996 // looking for threads waiting on it; note the active
997 // variable points to "this other object" already... so
998 // there nothing to do in this else clause.
1000 } else { // no, active thread is not waiting for another object
1002 success
= true; // (put request on wait queue)
1003 break; // (out of while)
1007 if( success
) { // put the request on the waiting queue?
1008 kern_return_t wait_result
;
1010 // place this thread on the waiting queue and put it to sleep;
1011 // we place it at the tail of the queue...
1012 queue_enter( &gArbitrationLockQueueWaiting
,
1014 ArbitrationLockQueueElement
*,
1017 // declare that this thread will wait for a given event
1018 restart_sleep
: wait_result
= assert_wait( element
,
1019 element
->required
? THREAD_UNINT
1020 : THREAD_INTERRUPTIBLE
);
1022 // unlock global access
1023 IOUnlock( gArbitrationLockQueueLock
);
1025 // put thread to sleep, waiting for our event to fire...
1026 if (wait_result
== THREAD_WAITING
)
1027 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1030 // ...and we've been woken up; we might be in one of two states:
1031 // (a) we've been aborted and our queue element is not on
1032 // any of the three queues, but is floating around
1033 // (b) we're allowed to proceed with the lock and we have
1034 // already been moved from the waiting queue to the
1036 // ...plus a 3rd state, should the thread have been interrupted:
1037 // (c) we're still on the waiting queue
1039 // determine whether we were interrupted out of our sleep
1040 if( THREAD_INTERRUPTED
== wait_result
) {
1042 // re-lock global access
1043 IOTakeLock( gArbitrationLockQueueLock
);
1045 // determine whether we're still on the waiting queue
1047 queue_iterate( &gArbitrationLockQueueWaiting
,
1048 waiting
, // (reuse waiting queue element)
1049 ArbitrationLockQueueElement
*,
1052 if( waiting
== element
) {
1058 if( found
) { // yes, we're still on the waiting queue
1060 // determine whether we're willing to fail
1061 if( false == element
->required
) {
1063 // mark us as aborted
1064 element
->aborted
= true;
1066 // take us off the waiting queue
1067 queue_remove( &gArbitrationLockQueueWaiting
,
1069 ArbitrationLockQueueElement
*,
1071 } else { // we are not willing to fail
1073 // ignore interruption, go back to sleep
1078 // unlock global access
1079 IOUnlock( gArbitrationLockQueueLock
);
1081 // proceed as though this were a normal wake up
1082 wait_result
= THREAD_AWAKENED
;
1085 assert( THREAD_AWAKENED
== wait_result
);
1087 // determine whether we've been aborted while we were asleep
1088 if( element
->aborted
) {
1089 assert( false == element
->required
);
1091 // re-lock global access
1092 IOTakeLock( gArbitrationLockQueueLock
);
1094 action
= kPutOnFreeQueue
;
1096 } else { // we weren't aborted, so we must be ready to go :-)
1098 // we've already been moved from waiting to active queue
1102 } else { // the lock request is to be failed
1104 // return unused queue element to queue
1105 action
= kPutOnFreeQueue
;
1107 } else { // it is the same thread, recursive access is allowed
1109 // add one level of recursion
1112 // return unused queue element to queue
1113 action
= kPutOnFreeQueue
;
1116 } else { // this object is not already locked, so let this thread through
1117 action
= kPutOnActiveQueue
;
1121 // put the new element on a queue
1122 if( kPutOnActiveQueue
== action
) {
1123 queue_enter( &gArbitrationLockQueueActive
,
1125 ArbitrationLockQueueElement
*,
1127 } else if( kPutOnFreeQueue
== action
) {
1128 queue_enter( &gArbitrationLockQueueFree
,
1130 ArbitrationLockQueueElement
*,
1133 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1136 // unlock global access
1137 IOUnlock( gArbitrationLockQueueLock
);
1142 void IOService::unlockForArbitration( void )
1145 ArbitrationLockQueueElement
* element
;
1147 // lock global access
1148 IOTakeLock( gArbitrationLockQueueLock
);
1150 // find the lock element for this object (ie. on active queue)
1152 queue_iterate( &gArbitrationLockQueueActive
,
1154 ArbitrationLockQueueElement
*,
1157 if( element
->service
== this ) {
1165 // determine whether the lock has been taken recursively
1166 if( element
->count
> 1 ) {
1167 // undo one level of recursion
1172 // remove it from the active queue
1173 queue_remove( &gArbitrationLockQueueActive
,
1175 ArbitrationLockQueueElement
*,
1178 // put it on the free queue
1179 queue_enter( &gArbitrationLockQueueFree
,
1181 ArbitrationLockQueueElement
*,
1184 // determine whether a thread is waiting for object (head to tail scan)
1186 queue_iterate( &gArbitrationLockQueueWaiting
,
1188 ArbitrationLockQueueElement
*,
1191 if( element
->service
== this ) {
1197 if ( found
) { // we found an interested thread on waiting queue
1199 // remove it from the waiting queue
1200 queue_remove( &gArbitrationLockQueueWaiting
,
1202 ArbitrationLockQueueElement
*,
1205 // put it on the active queue
1206 queue_enter( &gArbitrationLockQueueActive
,
1208 ArbitrationLockQueueElement
*,
1211 // wake the waiting thread
1212 IOLockWakeup( gArbitrationLockQueueLock
,
1214 /* one thread */ true );
1218 // unlock global access
1219 IOUnlock( gArbitrationLockQueueLock
);
1222 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1225 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1226 context
, gIOServicePlane
);
1229 void IOService::applyToClients( IOServiceApplierFunction applier
,
1232 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1233 context
, gIOServicePlane
);
1242 // send a message to a client or interested party of this service
1243 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1244 void * argument
, vm_size_t argSize
)
1247 IOService
* service
;
1248 _IOServiceInterestNotifier
* notify
;
1250 if( (service
= OSDynamicCast( IOService
, client
)))
1251 ret
= service
->message( type
, this, argument
);
1253 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1255 _IOServiceNotifierInvocation invocation
;
1258 invocation
.thread
= current_thread();
1261 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1264 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1265 _IOServiceNotifierInvocation
*, link
);
1271 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1272 type
, this, argument
, argSize
);
1275 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1276 _IOServiceNotifierInvocation
*, link
);
1277 if( kIOServiceNotifyWaiter
& notify
->state
) {
1278 notify
->state
&= ~kIOServiceNotifyWaiter
;
1279 WAKEUPNOTIFY( notify
);
1284 ret
= kIOReturnSuccess
;
1287 ret
= kIOReturnBadArgument
;
1293 applyToInterestNotifiers(const IORegistryEntry
*target
,
1294 const OSSymbol
* typeOfInterest
,
1295 OSObjectApplierFunction applier
,
1298 OSArray
* copyArray
= 0;
1302 IOCommand
*notifyList
=
1303 OSDynamicCast( IOCommand
, target
->getProperty( typeOfInterest
));
1306 copyArray
= OSArray::withCapacity(1);
1308 // iterate over queue, entry is set to each element in the list
1309 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1310 _IOServiceInterestNotifier
* notify
;
1312 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1313 copyArray
->setObject(notify
);
1322 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1323 (*applier
)(next
, context
);
1324 copyArray
->release();
1328 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1329 OSObjectApplierFunction applier
,
1332 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1333 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1336 struct MessageClientsContext
{
1337 IOService
* service
;
1344 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1347 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1349 ret
= context
->service
->messageClient( context
->type
,
1350 object
, context
->argument
, context
->argSize
);
1351 if( kIOReturnSuccess
!= ret
)
1355 // send a message to all clients
1356 IOReturn
IOService::messageClients( UInt32 type
,
1357 void * argument
, vm_size_t argSize
)
1359 MessageClientsContext context
;
1361 context
.service
= this;
1362 context
.type
= type
;
1363 context
.argument
= argument
;
1364 context
.argSize
= argSize
;
1365 context
.ret
= kIOReturnSuccess
;
1367 applyToInterested( gIOGeneralInterest
,
1368 &messageClientsApplier
, &context
);
1370 return( context
.ret
);
1373 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1374 IOOptionBits response
)
1376 return( kIOReturnUnsupported
);
1379 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1380 IOServiceInterestHandler handler
, void * target
, void * ref
)
1382 _IOServiceInterestNotifier
* notify
= 0;
1384 if( (typeOfInterest
!= gIOGeneralInterest
)
1385 && (typeOfInterest
!= gIOBusyInterest
)
1386 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1387 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1390 lockForArbitration();
1391 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1393 notify
= new _IOServiceInterestNotifier
;
1394 if( notify
&& !notify
->init()) {
1400 notify
->handler
= handler
;
1401 notify
->target
= target
;
1403 notify
->state
= kIOServiceNotifyEnable
;
1404 queue_init( ¬ify
->handlerInvocations
);
1410 // Get the head of the notifier linked list
1411 IOCommand
*notifyList
= (IOCommand
*) getProperty( typeOfInterest
);
1412 if (!notifyList
|| !OSDynamicCast(IOCommand
, notifyList
)) {
1413 notifyList
= OSTypeAlloc(IOCommand
);
1416 setProperty( typeOfInterest
, notifyList
);
1417 notifyList
->release();
1422 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1423 notify
->retain(); // ref'ed while in list
1429 unlockForArbitration();
1434 static void cleanInterestList( OSObject
* head
)
1436 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1441 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1442 queue_next(entry
) = queue_prev(entry
) = 0;
1444 _IOServiceInterestNotifier
* notify
;
1446 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1452 void IOService::unregisterAllInterest( void )
1454 cleanInterestList( getProperty( gIOGeneralInterest
));
1455 cleanInterestList( getProperty( gIOBusyInterest
));
1456 cleanInterestList( getProperty( gIOAppPowerStateInterest
));
1457 cleanInterestList( getProperty( gIOPriorityPowerStateInterest
));
1461 * _IOServiceInterestNotifier
1464 // wait for all threads, other than the current one,
1465 // to exit the handler
1467 void _IOServiceInterestNotifier::wait()
1469 _IOServiceNotifierInvocation
* next
;
1474 queue_iterate( &handlerInvocations
, next
,
1475 _IOServiceNotifierInvocation
*, link
) {
1476 if( next
->thread
!= current_thread() ) {
1482 state
|= kIOServiceNotifyWaiter
;
1489 void _IOServiceInterestNotifier::free()
1491 assert( queue_empty( &handlerInvocations
));
1495 void _IOServiceInterestNotifier::remove()
1499 if( queue_next( &chain
)) {
1500 remqueue( 0, &chain
);
1501 queue_next( &chain
) = queue_prev( &chain
) = 0;
1505 state
&= ~kIOServiceNotifyEnable
;
1514 bool _IOServiceInterestNotifier::disable()
1520 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1521 state
&= ~kIOServiceNotifyEnable
;
1530 void _IOServiceInterestNotifier::enable( bool was
)
1534 state
|= kIOServiceNotifyEnable
;
1536 state
&= ~kIOServiceNotifyEnable
;
1540 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1546 #define tailQ(o) setObject(o)
1547 #define headQ(o) setObject(0, o)
1548 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); }
1550 inline void _workLoopAction( IOWorkLoop::Action action
,
1551 IOService
* service
,
1552 void * p0
= 0, void * p1
= 0,
1553 void * p2
= 0, void * p3
= 0 )
1557 if( (wl
= service
->getWorkLoop())) {
1559 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1562 (*action
)( service
, p0
, p1
, p2
, p3
);
1565 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1569 // if its our only provider
1570 ok
= isParent( provider
, gIOServicePlane
, true);
1574 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1575 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1582 bool IOService::terminatePhase1( IOOptionBits options
)
1587 OSArray
* makeInactive
;
1590 bool startPhase2
= false;
1592 TLOG("%s::terminatePhase1(%08lx)\n", getName(), options
);
1595 if( options
& kIOServiceRecursing
) {
1596 __state
[1] |= kIOServiceRecursing
;
1601 makeInactive
= OSArray::withCapacity( 16 );
1610 didInactive
= victim
->lockForArbitration( true );
1612 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1614 victim
->__state
[0] |= kIOServiceInactiveState
;
1615 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1616 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1617 victim
->_adjustBusy( 1 );
1619 victim
->unlockForArbitration();
1622 startPhase2
= didInactive
;
1625 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1626 IOUserClient::destroyUserReferences( victim
);
1628 iter
= victim
->getClientIterator();
1630 while( (client
= (IOService
*) iter
->getNextObject())) {
1631 TLOG("%s::requestTerminate(%s, %08lx)\n",
1632 client
->getName(), victim
->getName(), options
);
1633 ok
= client
->requestTerminate( victim
, options
);
1634 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1635 client
->getName(), victim
->getName(), ok
);
1637 makeInactive
->setObject( client
);
1643 victim
= (IOService
*) makeInactive
->getObject(0);
1646 makeInactive
->removeObject(0);
1650 makeInactive
->release();
1653 scheduleTerminatePhase2( options
);
1658 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
1660 AbsoluteTime deadline
;
1661 int waitResult
= THREAD_AWAKENED
;
1662 bool wait
, haveDeadline
= false;
1664 options
|= kIOServiceRequired
;
1668 IOLockLock( gJobsLock
);
1670 if( (options
& kIOServiceSynchronous
)
1671 && (current_thread() != gIOTerminateThread
)) {
1674 wait
= (gIOTerminateThread
!= 0);
1676 // wait to become the terminate thread
1677 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
1681 gIOTerminateThread
= current_thread();
1682 gIOTerminatePhase2List
->setObject( this );
1686 while( gIOTerminateWork
)
1687 terminateWorker( options
);
1688 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1690 // wait for the victim to go non-busy
1691 if( !haveDeadline
) {
1692 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1693 haveDeadline
= true;
1695 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
1696 deadline
, THREAD_UNINT
);
1697 if( waitResult
== THREAD_TIMED_OUT
) {
1698 TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName());
1701 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
1703 gIOTerminateThread
= 0;
1704 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1707 // ! kIOServiceSynchronous
1709 gIOTerminatePhase2List
->setObject( this );
1710 if( 0 == gIOTerminateWork
++) {
1711 if( !gIOTerminateThread
)
1712 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) options
);
1714 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1718 IOLockUnlock( gJobsLock
);
1723 void IOService::terminateThread( void * arg
)
1725 IOLockLock( gJobsLock
);
1727 while (gIOTerminateWork
)
1728 terminateWorker( (IOOptionBits
) arg
);
1730 gIOTerminateThread
= 0;
1731 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1733 IOLockUnlock( gJobsLock
);
1736 void IOService::scheduleStop( IOService
* provider
)
1738 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1740 IOLockLock( gJobsLock
);
1741 gIOStopList
->tailQ( this );
1742 gIOStopProviderList
->tailQ( provider
);
1744 if( 0 == gIOTerminateWork
++) {
1745 if( !gIOTerminateThread
)
1746 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1748 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1751 IOLockUnlock( gJobsLock
);
1754 void IOService::scheduleFinalize( void )
1756 TLOG("%s::scheduleFinalize\n", getName());
1758 IOLockLock( gJobsLock
);
1759 gIOFinalizeList
->tailQ( this );
1761 if( 0 == gIOTerminateWork
++) {
1762 if( !gIOTerminateThread
)
1763 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1765 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1768 IOLockUnlock( gJobsLock
);
1771 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1776 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1778 if( false == *defer
) {
1780 if( lockForArbitration( true )) {
1781 if( false == provider
->handleIsOpen( this ))
1782 scheduleStop( provider
);
1785 message( kIOMessageServiceIsRequestingClose
, provider
, (void *) options
);
1786 if( false == provider
->handleIsOpen( this ))
1787 scheduleStop( provider
);
1790 unlockForArbitration();
1797 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
1798 OSArray
* doPhase2List
)
1804 iter
= victim
->getClientIterator();
1806 while( (client
= (IOService
*) iter
->getNextObject())) {
1807 TLOG("%s::willTerminate(%s, %08lx)\n",
1808 client
->getName(), victim
->getName(), options
);
1809 ok
= client
->willTerminate( victim
, options
);
1810 doPhase2List
->tailQ( client
);
1816 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
)
1822 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *) options
);
1824 iter
= victim
->getClientIterator();
1826 while( (client
= (IOService
*) iter
->getNextObject())) {
1827 TLOG("%s::didTerminate(%s, %08lx)\n",
1828 client
->getName(), victim
->getName(), options
);
1829 client
->didTerminate( victim
, options
, &defer
);
1830 TLOG("%s::didTerminate(%s, defer %d)\n",
1831 client
->getName(), victim
->getName(), defer
);
1837 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
)
1839 TLOG("%s::finalize(%08lx)\n", victim
->getName(), options
);
1840 victim
->finalize( options
);
1843 void IOService::actionStop( IOService
* provider
, IOService
* client
)
1845 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
1846 client
->stop( provider
);
1847 if( provider
->isOpen( client
))
1848 provider
->close( client
);
1849 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
1850 client
->detach( provider
);
1853 void IOService::terminateWorker( IOOptionBits options
)
1855 OSArray
* doPhase2List
;
1856 OSArray
* didPhase2List
;
1861 IOService
* provider
;
1867 options
|= kIOServiceRequired
;
1869 doPhase2List
= OSArray::withCapacity( 16 );
1870 didPhase2List
= OSArray::withCapacity( 16 );
1871 freeList
= OSSet::withCapacity( 16 );
1872 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
1876 workDone
= gIOTerminateWork
;
1878 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
1881 gIOTerminatePhase2List
->removeObject(0);
1882 IOLockUnlock( gJobsLock
);
1886 doPhase2
= victim
->lockForArbitration( true );
1888 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
1890 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
1891 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
1893 victim
->__state
[1] |= kIOServiceTermPhase2State
;
1895 victim
->unlockForArbitration();
1898 if( 0 == victim
->getClient()) {
1899 // no clients - will go to finalize
1900 IOLockLock( gJobsLock
);
1901 gIOFinalizeList
->tailQ( victim
);
1902 IOLockUnlock( gJobsLock
);
1904 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
1905 victim
, (void *) options
, (void *) doPhase2List
);
1907 didPhase2List
->headQ( victim
);
1910 victim
= (IOService
*) doPhase2List
->getObject(0);
1913 doPhase2List
->removeObject(0);
1917 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
1919 if( victim
->lockForArbitration( true )) {
1920 victim
->__state
[1] |= kIOServiceTermPhase3State
;
1921 victim
->unlockForArbitration();
1923 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
1924 victim
, (void *) options
);
1925 didPhase2List
->removeObject(0);
1927 IOLockLock( gJobsLock
);
1934 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
1936 IOLockUnlock( gJobsLock
);
1937 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
1938 victim
, (void *) options
);
1939 IOLockLock( gJobsLock
);
1941 freeList
->setObject( victim
);
1942 // safe if finalize list is append only
1943 gIOFinalizeList
->removeObject(0);
1947 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
1949 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
1952 if( !provider
->isChild( client
, gIOServicePlane
)) {
1953 // may be multiply queued - nop it
1954 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
1956 // not ready for stop if it has clients, skip it
1957 if( (client
->__state
[1] & kIOServiceTermPhase3State
) && client
->getClient()) {
1958 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
1963 IOLockUnlock( gJobsLock
);
1964 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
1965 provider
, (void *) client
);
1966 IOLockLock( gJobsLock
);
1967 // check the finalize list now
1971 freeList
->setObject( client
);
1972 freeList
->setObject( provider
);
1974 // safe if stop list is append only
1975 gIOStopList
->removeObject( idx
);
1976 gIOStopProviderList
->removeObject( idx
);
1980 } while( doPhase3
);
1982 gIOTerminateWork
-= workDone
;
1983 moreToDo
= (gIOTerminateWork
!= 0);
1986 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
1989 } while( moreToDo
);
1991 IOLockUnlock( gJobsLock
);
1993 freeList
->release();
1994 doPhase2List
->release();
1995 didPhase2List
->release();
1997 IOLockLock( gJobsLock
);
2000 bool IOService::finalize( IOOptionBits options
)
2003 IOService
* provider
;
2005 iter
= getProviderIterator();
2009 while( (provider
= (IOService
*) iter
->getNextObject())) {
2012 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
2013 /* we come down here on programmatic terminate */
2015 if( provider
->isOpen( this ))
2016 provider
->close( this );
2020 if( provider
->lockForArbitration( true )) {
2021 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2022 scheduleStop( provider
);
2023 provider
->unlockForArbitration();
2040 void IOService::doServiceTerminate( IOOptionBits options
)
2044 // a method in case someone needs to override it
2045 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2049 if( client
->isParent( this, gIOServicePlane
, true))
2050 // we are the clients only provider
2051 ok
= client
->terminate( options
);
2058 bool IOService::terminate( IOOptionBits options
)
2060 options
|= kIOServiceTerminate
;
2062 return( terminatePhase1( options
));
2065 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2071 struct ServiceOpenMessageContext
2073 IOService
* service
;
2075 IOService
* excludeClient
;
2076 IOOptionBits options
;
2079 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2081 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2083 if( object
!= context
->excludeClient
)
2084 context
->service
->messageClient( context
->type
, object
, (void *) context
->options
);
2087 bool IOService::open( IOService
* forClient
,
2088 IOOptionBits options
,
2092 ServiceOpenMessageContext context
;
2094 context
.service
= this;
2095 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2096 context
.excludeClient
= forClient
;
2097 context
.options
= options
;
2099 applyToInterested( gIOGeneralInterest
,
2100 &serviceOpenMessageApplier
, &context
);
2102 if( false == lockForArbitration(false) )
2105 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2107 ok
= handleOpen( forClient
, options
, arg
);
2109 unlockForArbitration();
2114 void IOService::close( IOService
* forClient
,
2115 IOOptionBits options
)
2120 lockForArbitration();
2122 wasClosed
= handleIsOpen( forClient
);
2124 handleClose( forClient
, options
);
2125 last
= (__state
[1] & kIOServiceTermPhase3State
);
2128 unlockForArbitration();
2131 forClient
->scheduleStop( this );
2133 else if( wasClosed
) {
2135 ServiceOpenMessageContext context
;
2137 context
.service
= this;
2138 context
.type
= kIOMessageServiceWasClosed
;
2139 context
.excludeClient
= forClient
;
2140 context
.options
= options
;
2142 applyToInterested( gIOGeneralInterest
,
2143 &serviceOpenMessageApplier
, &context
);
2147 bool IOService::isOpen( const IOService
* forClient
) const
2149 IOService
* self
= (IOService
*) this;
2152 self
->lockForArbitration();
2154 ok
= handleIsOpen( forClient
);
2156 self
->unlockForArbitration();
2161 bool IOService::handleOpen( IOService
* forClient
,
2162 IOOptionBits options
,
2167 ok
= (0 == __owner
);
2169 __owner
= forClient
;
2171 else if( options
& kIOServiceSeize
) {
2172 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2173 __owner
, (void *) options
));
2174 if( ok
&& (0 == __owner
))
2175 __owner
= forClient
;
2182 void IOService::handleClose( IOService
* forClient
,
2183 IOOptionBits options
)
2185 if( __owner
== forClient
)
2189 bool IOService::handleIsOpen( const IOService
* forClient
) const
2192 return( __owner
== forClient
);
2194 return( __owner
!= forClient
);
2198 * Probing & starting
2200 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2202 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2203 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2211 val1
= obj1
->priority
;
2214 val2
= obj2
->priority
;
2216 return ( val1
- val2
);
2219 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2221 OSDictionary
* dict
;
2222 IOService
* service
;
2223 _IOServiceNotifier
* notify
;
2224 OSSymbol
* key
= (OSSymbol
*) ref
;
2227 if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2228 return( notify
->priority
);
2230 else if( (service
= OSDynamicCast( IOService
, entry
)))
2231 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2232 else if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2233 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2240 return( (SInt32
) offset
->unsigned32BitValue());
2242 return( kIODefaultProbeScore
);
2245 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2247 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2248 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2256 val1
= IOServiceObjectOrder( obj1
, ref
);
2259 val2
= IOServiceObjectOrder( obj2
, ref
);
2261 return ( val1
- val2
);
2264 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2266 IOService
* service
= 0;
2268 const OSSymbol
* nextCat
;
2270 iter
= getClientIterator();
2272 while( (service
= (IOService
*) iter
->getNextObject())) {
2273 if( kIOServiceInactiveState
& service
->__state
[0])
2275 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2276 service
->getProperty( gIOMatchCategoryKey
));
2277 if( category
== nextCat
)
2285 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2287 _IOServiceNotifierInvocation invocation
;
2291 invocation
.thread
= current_thread();
2294 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2297 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2298 _IOServiceNotifierInvocation
*, link
);
2304 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
, this );
2307 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2308 _IOServiceNotifierInvocation
*, link
);
2309 if( kIOServiceNotifyWaiter
& notify
->state
) {
2310 notify
->state
&= ~kIOServiceNotifyWaiter
;
2311 WAKEUPNOTIFY( notify
);
2320 * Alloc and probe matching classes,
2321 * called on the provider instance
2324 void IOService::probeCandidates( OSOrderedSet
* matches
)
2326 OSDictionary
* match
= 0;
2329 IOService
* newInst
;
2330 OSDictionary
* props
;
2333 OSOrderedSet
* familyMatches
= 0;
2334 OSOrderedSet
* startList
;
2335 OSDictionary
* startDict
= 0;
2336 const OSSymbol
* category
;
2338 _IOServiceNotifier
* notify
;
2339 OSObject
* nextMatch
= 0;
2341 bool needReloc
= false;
2347 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2349 nextMatch
->retain();
2350 matches
->removeObject(nextMatch
);
2352 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2354 lockForArbitration();
2355 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2356 invokeNotifer( notify
);
2357 unlockForArbitration();
2358 nextMatch
->release();
2362 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2363 nextMatch
->release();
2370 debugFlags
= getDebugFlags( match
);
2374 category
= OSDynamicCast( OSSymbol
,
2375 match
->getObject( gIOMatchCategoryKey
));
2377 category
= gIODefaultMatchCategoryKey
;
2379 if( getClientWithCategory( category
)) {
2381 if( debugFlags
& kIOLogMatch
)
2382 LOG("%s: match category %s exists\n", getName(),
2383 category
->getCStringNoCopy());
2385 nextMatch
->release();
2390 // create a copy now in case its modified during matching
2391 props
= OSDictionary::withDictionary( match
, match
->getCount());
2394 props
->setCapacityIncrement(1);
2396 // check the nub matches
2397 if( false == passiveMatch( props
, true ))
2400 // Check to see if driver reloc has been loaded.
2401 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2404 if( debugFlags
& kIOLogCatalogue
)
2405 LOG("%s: stalling for module\n", getName());
2407 // If reloc hasn't been loaded, exit;
2408 // reprobing will occur after reloc has been loaded.
2412 // reorder on family matchPropertyTable score.
2413 if( 0 == familyMatches
)
2414 familyMatches
= OSOrderedSet::withCapacity( 1,
2415 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2417 familyMatches
->setObject( props
);
2422 nextMatch
->release();
2431 if( familyMatches
) {
2434 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2437 familyMatches
->removeObject( props
);
2442 debugFlags
= getDebugFlags( props
);
2445 symbol
= OSDynamicCast( OSSymbol
,
2446 props
->getObject( gIOClassKey
));
2450 // alloc the driver instance
2451 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2454 IOLog("Couldn't alloc class \"%s\"\n",
2455 symbol
->getCStringNoCopy());
2459 // init driver instance
2460 if( !(inst
->init( props
))) {
2462 if( debugFlags
& kIOLogStart
)
2463 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2467 if( __state
[1] & kIOServiceSynchronousState
)
2468 inst
->__state
[1] |= kIOServiceSynchronousState
;
2470 // give the driver the default match category if not specified
2471 category
= OSDynamicCast( OSSymbol
,
2472 props
->getObject( gIOMatchCategoryKey
));
2474 category
= gIODefaultMatchCategoryKey
;
2475 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2477 // attach driver instance
2478 if( !(inst
->attach( this )))
2481 // pass in score from property table
2482 score
= familyMatches
->orderObject( props
);
2484 // & probe the new driver instance
2486 if( debugFlags
& kIOLogProbe
)
2487 LOG("%s::probe(%s)\n",
2488 inst
->getMetaClass()->getClassName(), getName());
2491 newInst
= inst
->probe( this, &score
);
2492 inst
->detach( this );
2495 if( debugFlags
& kIOLogProbe
)
2496 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2502 newPri
= OSNumber::withNumber( score
, 32 );
2504 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2508 // add to start list for the match category
2510 startDict
= OSDictionary::withCapacity( 1 );
2511 assert( startDict
);
2512 startList
= (OSOrderedSet
*)
2513 startDict
->getObject( category
);
2514 if( 0 == startList
) {
2515 startList
= OSOrderedSet::withCapacity( 1,
2516 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2517 if( startDict
&& startList
) {
2518 startDict
->setObject( category
, startList
);
2519 startList
->release();
2522 assert( startList
);
2524 startList
->setObject( newInst
);
2532 familyMatches
->release();
2536 // start the best (until success) of each category
2538 iter
= OSCollectionIterator::withCollection( startDict
);
2540 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2542 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2543 assert( startList
);
2548 while( true // (!started)
2549 && (inst
= (IOService
*)startList
->getFirstObject())) {
2552 startList
->removeObject(inst
);
2555 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2557 if( debugFlags
& kIOLogStart
) {
2559 LOG( "match category exists, skipping " );
2560 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2561 getName(), inst
->getRetainCount());
2564 if( false == started
)
2565 started
= startCandidate( inst
);
2567 if( (debugFlags
& kIOLogStart
) && (false == started
))
2568 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2569 inst
->getRetainCount());
2578 // adjust the busy count by -1 if matching is stalled for a module,
2579 // or +1 if a previously stalled matching is complete.
2580 lockForArbitration();
2583 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2585 __state
[1] |= kIOServiceModuleStallState
;
2587 } else if( __state
[1] & kIOServiceModuleStallState
) {
2588 __state
[1] &= ~kIOServiceModuleStallState
;
2592 _adjustBusy( adjBusy
);
2593 unlockForArbitration();
2596 startDict
->release();
2600 * Start a previously attached & probed instance,
2601 * called on exporting object instance
2604 bool IOService::startCandidate( IOService
* service
)
2608 ok
= service
->attach( this );
2612 if (this != gIOResources
)
2614 // stall for any nub resources
2616 // stall for any driver resources
2617 service
->checkResources();
2620 AbsoluteTime startTime
;
2621 AbsoluteTime endTime
;
2624 if (kIOLogStart
& gIOKitDebug
)
2625 clock_get_uptime(&startTime
);
2627 ok
= service
->start(this);
2629 if (kIOLogStart
& gIOKitDebug
)
2631 clock_get_uptime(&endTime
);
2633 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2635 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2636 absolutetime_to_nanoseconds(endTime
, &nano
);
2637 if (nano
> 500000000ULL)
2638 IOLog("%s::start took %ld ms\n", service
->getName(), (UInt32
)(nano
/ 1000000ULL));
2642 service
->detach( this );
2647 IOService
* IOService::resources( void )
2649 return( gIOResources
);
2652 void IOService::publishResource( const char * key
, OSObject
* value
)
2654 const OSSymbol
* sym
;
2656 if( (sym
= OSSymbol::withCString( key
))) {
2657 publishResource( sym
, value
);
2662 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
2665 value
= (OSObject
*) gIOServiceKey
;
2667 gIOResources
->setProperty( key
, value
);
2669 if( IORecursiveLockHaveLock( gNotificationLock
))
2672 gIOResourceGenerationCount
++;
2673 gIOResources
->registerService();
2676 bool IOService::addNeededResource( const char * key
)
2678 OSObject
* resourcesProp
;
2683 resourcesProp
= getProperty( gIOResourceMatchKey
);
2685 newKey
= OSString::withCString( key
);
2686 if( (0 == resourcesProp
) || (0 == newKey
))
2689 set
= OSDynamicCast( OSSet
, resourcesProp
);
2691 set
= OSSet::withCapacity( 1 );
2693 set
->setObject( resourcesProp
);
2698 set
->setObject( newKey
);
2700 ret
= setProperty( gIOResourceMatchKey
, set
);
2706 bool IOService::checkResource( OSObject
* matching
)
2709 OSDictionary
* table
;
2711 if( (str
= OSDynamicCast( OSString
, matching
))) {
2712 if( gIOResources
->getProperty( str
))
2717 table
= resourceMatching( str
);
2718 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
2721 IOLog("%s: Can't match using: %s\n", getName(),
2722 matching
->getMetaClass()->getClassName());
2723 /* false would stall forever */
2727 if( gIOKitDebug
& kIOLogConfig
)
2728 LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName());
2730 waitForService( table
);
2732 if( gIOKitDebug
& kIOLogConfig
)
2733 LOG("config(%x): waking\n", (int) IOThreadSelf() );
2738 bool IOService::checkResources( void )
2740 OSObject
* resourcesProp
;
2745 resourcesProp
= getProperty( gIOResourceMatchKey
);
2746 if( 0 == resourcesProp
)
2749 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
2751 iter
= OSCollectionIterator::withCollection( set
);
2753 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
2754 ok
= checkResource( resourcesProp
);
2759 ok
= checkResource( resourcesProp
);
2765 void _IOConfigThread::configThread( void )
2767 _IOConfigThread
* inst
;
2770 if( !(inst
= new _IOConfigThread
))
2774 if( !(IOCreateThread((IOThreadFunc
) &_IOConfigThread::main
, inst
)))
2787 void _IOConfigThread::free( void )
2792 void IOService::doServiceMatch( IOOptionBits options
)
2794 _IOServiceNotifier
* notify
;
2796 OSOrderedSet
* matches
;
2797 SInt32 catalogGeneration
;
2798 bool keepGuessing
= true;
2799 bool reRegistered
= true;
2801 // job->nub->deliverNotification( gIOPublishNotification,
2802 // kIOServiceRegisteredState, 0xffffffff );
2804 while( keepGuessing
) {
2806 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
2807 // the matches list should always be created by findDrivers()
2810 lockForArbitration();
2811 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
2812 deliverNotification( gIOFirstPublishNotification
,
2813 kIOServiceFirstPublishState
, 0xffffffff );
2815 __state
[1] &= ~kIOServiceNeedConfigState
;
2816 __state
[1] |= kIOServiceConfigState
;
2817 __state
[0] |= kIOServiceRegisteredState
;
2819 if( reRegistered
&& (0 == (__state
[0] & kIOServiceInactiveState
))) {
2821 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
2822 gNotifications
->getObject( gIOPublishNotification
) );
2824 while((notify
= (_IOServiceNotifier
*)
2825 iter
->getNextObject())) {
2827 if( passiveMatch( notify
->matching
)
2828 && (kIOServiceNotifyEnable
& notify
->state
))
2829 matches
->setObject( notify
);
2836 unlockForArbitration();
2838 if( matches
->getCount() && (kIOReturnSuccess
== getResources()))
2839 probeCandidates( matches
);
2844 lockForArbitration();
2845 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
2847 (reRegistered
|| (catalogGeneration
!=
2848 gIOCatalogue
->getGenerationCount()))
2849 && (0 == (__state
[0] & kIOServiceInactiveState
));
2852 unlockForArbitration();
2855 if( (0 == (__state
[0] & kIOServiceInactiveState
))
2856 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
2857 deliverNotification( gIOMatchedNotification
,
2858 kIOServiceMatchedState
, 0xffffffff );
2859 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
2860 deliverNotification( gIOFirstMatchNotification
,
2861 kIOServiceFirstMatchState
, 0xffffffff );
2864 __state
[1] &= ~kIOServiceConfigState
;
2865 if( __state
[0] & kIOServiceInactiveState
)
2866 scheduleTerminatePhase2();
2869 unlockForArbitration();
2872 UInt32
IOService::_adjustBusy( SInt32 delta
)
2877 bool wasQuiet
, nowQuiet
, needWake
;
2880 result
= __state
[1] & kIOServiceBusyStateMask
;
2884 next
->lockForArbitration();
2885 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
2886 assert( count
< kIOServiceBusyMax
);
2887 wasQuiet
= (0 == count
);
2888 assert( (!wasQuiet
) || (delta
> 0));
2889 next
->__state
[1] += delta
;
2890 nowQuiet
= (0 == (next
->__state
[1] & kIOServiceBusyStateMask
));
2891 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
2894 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
2895 IOLockLock( gIOServiceBusyLock
);
2896 thread_wakeup( (event_t
) next
);
2897 IOLockUnlock( gIOServiceBusyLock
);
2900 next
->unlockForArbitration();
2902 if( (wasQuiet
|| nowQuiet
) ) {
2903 MessageClientsContext context
;
2905 context
.service
= next
;
2906 context
.type
= kIOMessageServiceBusyStateChange
;
2907 context
.argument
= (void *) wasQuiet
; // busy now
2908 context
.argSize
= 0;
2910 applyToInterestNotifiers( next
, gIOBusyInterest
,
2911 &messageClientsApplier
, &context
);
2913 if( nowQuiet
&& (next
== gIOServiceRoot
))
2914 OSMetaClass::considerUnloads();
2917 delta
= nowQuiet
? -1 : +1;
2919 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
2924 void IOService::adjustBusy( SInt32 delta
)
2926 lockForArbitration();
2927 _adjustBusy( delta
);
2928 unlockForArbitration();
2931 UInt32
IOService::getBusyState( void )
2933 return( __state
[1] & kIOServiceBusyStateMask
);
2936 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
2937 mach_timespec_t
* timeout
)
2940 int waitResult
= THREAD_AWAKENED
;
2941 bool computeDeadline
= true;
2942 AbsoluteTime abstime
;
2945 lockForArbitration();
2946 IOLockLock( gIOServiceBusyLock
);
2947 wait
= (value
!= (__state
[1] & mask
));
2949 __state
[1] |= kIOServiceBusyWaiterState
;
2950 unlockForArbitration();
2952 if( computeDeadline
) {
2953 AbsoluteTime nsinterval
;
2954 clock_interval_to_absolutetime_interval(
2955 timeout
->tv_sec
, kSecondScale
, &abstime
);
2956 clock_interval_to_absolutetime_interval(
2957 timeout
->tv_nsec
, kNanosecondScale
, &nsinterval
);
2958 ADD_ABSOLUTETIME( &abstime
, &nsinterval
);
2959 clock_absolutetime_interval_to_deadline(
2960 abstime
, &abstime
);
2961 computeDeadline
= false;
2964 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
2967 assert_wait((event_t
)this, THREAD_UNINT
);
2969 unlockForArbitration();
2970 IOLockUnlock( gIOServiceBusyLock
);
2972 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2974 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2976 if( waitResult
== THREAD_TIMED_OUT
)
2977 return( kIOReturnTimeout
);
2979 return( kIOReturnSuccess
);
2982 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
2984 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
2987 bool IOService::serializeProperties( OSSerialize
* s
) const
2990 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
2991 sizeof( __state
), "__state");
2993 return( super::serializeProperties(s
) );
2997 void _IOConfigThread::main( _IOConfigThread
* self
)
2999 _IOServiceJob
* job
;
3007 semaphore_wait( gJobsSemaphore
);
3009 IOTakeLock( gJobsLock
);
3010 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
3012 gJobs
->removeObject(job
);
3015 // gNumConfigThreads--; // we're out of service
3016 gNumWaitingThreads
--; // we're out of service
3018 IOUnlock( gJobsLock
);
3024 if( gIOKitDebug
& kIOLogConfig
)
3025 LOG("config(%x): starting on %s, %d\n",
3026 (int) IOThreadSelf(), job
->nub
->getName(), job
->type
);
3028 switch( job
->type
) {
3031 nub
->doServiceMatch( job
->options
);
3035 LOG("config(%x): strange type (%d)\n",
3036 (int) IOThreadSelf(), job
->type
);
3043 IOTakeLock( gJobsLock
);
3044 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
3046 gNumWaitingThreads
++; // back in service
3047 // gNumConfigThreads++;
3049 if( 0 == --gNumConfigThreads
) {
3050 // IOLog("MATCH IDLE\n");
3051 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3054 IOUnlock( gJobsLock
);
3059 if( gIOKitDebug
& kIOLogConfig
)
3060 LOG("config(%x): terminating\n", (int) IOThreadSelf() );
3065 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3068 int waitResult
= THREAD_AWAKENED
;
3069 bool computeDeadline
= true;
3070 AbsoluteTime abstime
;
3072 IOLockLock( gJobsLock
);
3074 wait
= (0 != gNumConfigThreads
);
3077 if( computeDeadline
) {
3078 clock_interval_to_absolutetime_interval(
3079 msToWait
, kMillisecondScale
, &abstime
);
3080 clock_absolutetime_interval_to_deadline(
3081 abstime
, &abstime
);
3082 computeDeadline
= false;
3084 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
3085 abstime
, THREAD_UNINT
);
3087 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3091 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3092 IOLockUnlock( gJobsLock
);
3094 if( waitResult
== THREAD_TIMED_OUT
)
3095 return( kIOReturnTimeout
);
3097 return( kIOReturnSuccess
);
3100 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3107 IOTakeLock( gJobsLock
);
3110 gJobs
->setLastObject( job
);
3112 count
= gNumWaitingThreads
;
3113 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3115 create
= ( (gOutstandingJobs
> count
)
3116 && (gNumConfigThreads
< kMaxConfigThreads
) );
3118 gNumConfigThreads
++;
3119 gNumWaitingThreads
++;
3122 IOUnlock( gJobsLock
);
3127 if( gIOKitDebug
& kIOLogConfig
)
3128 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3129 _IOConfigThread::configThread();
3132 semaphore_signal( gJobsSemaphore
);
3135 // internal - call with gNotificationLock
3136 OSObject
* IOService::getExistingServices( OSDictionary
* matching
,
3137 IOOptionBits inState
, IOOptionBits options
)
3139 OSObject
* current
= 0;
3141 IOService
* service
;
3148 && (obj
= matching
->getObject(gIOProviderClassKey
))
3150 && gIOResourcesKey
->isEqualTo(obj
)
3151 && (service
= gIOResources
))
3153 if( (inState
== (service
->__state
[0] & inState
))
3154 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3155 && service
->passiveMatch( matching
))
3157 if( options
& kIONotifyOnce
)
3160 current
= OSSet::withObjects(
3161 (const OSObject
**) &service
, 1, 1 );
3166 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3167 kIORegistryIterateRecursively
);
3171 while( (service
= (IOService
*) iter
->getNextObject())) {
3172 if( (inState
== (service
->__state
[0] & inState
))
3173 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3174 && service
->passiveMatch( matching
)) {
3176 if( options
& kIONotifyOnce
) {
3181 ((OSSet
*)current
)->setObject( service
);
3183 current
= OSSet::withObjects(
3184 (const OSObject
**) &service
, 1, 1 );
3187 } while( !service
&& !iter
->isValid());
3192 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
3193 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3202 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3206 // is a lock even needed?
3209 iter
= (OSIterator
*) getExistingServices( matching
,
3210 kIOServiceMatchedState
);
3218 // internal - call with gNotificationLock
3219 IONotifier
* IOService::setNotification(
3220 const OSSymbol
* type
, OSDictionary
* matching
,
3221 IOServiceNotificationHandler handler
, void * target
, void * ref
,
3224 _IOServiceNotifier
* notify
= 0;
3230 notify
= new _IOServiceNotifier
;
3231 if( notify
&& !notify
->init()) {
3237 notify
->matching
= matching
;
3238 notify
->handler
= handler
;
3239 notify
->target
= target
;
3241 notify
->priority
= priority
;
3242 notify
->state
= kIOServiceNotifyEnable
;
3243 queue_init( ¬ify
->handlerInvocations
);
3247 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3248 set
= OSOrderedSet::withCapacity( 1,
3249 IONotifyOrdering
, 0 );
3251 gNotifications
->setObject( type
, set
);
3255 notify
->whence
= set
;
3257 set
->setObject( notify
);
3263 // internal - call with gNotificationLock
3264 IONotifier
* IOService::doInstallNotification(
3265 const OSSymbol
* type
, OSDictionary
* matching
,
3266 IOServiceNotificationHandler handler
,
3267 void * target
, void * ref
,
3268 SInt32 priority
, OSIterator
** existing
)
3271 IONotifier
* notify
;
3272 IOOptionBits inState
;
3277 if( type
== gIOPublishNotification
)
3278 inState
= kIOServiceRegisteredState
;
3280 else if( type
== gIOFirstPublishNotification
)
3281 inState
= kIOServiceFirstPublishState
;
3283 else if( (type
== gIOMatchedNotification
)
3284 || (type
== gIOFirstMatchNotification
))
3285 inState
= kIOServiceMatchedState
;
3286 else if( type
== gIOTerminatedNotification
)
3291 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3294 // get the current set
3295 exist
= (OSIterator
*) getExistingServices( matching
, inState
);
3305 IONotifier
* IOService::installNotification(
3306 const OSSymbol
* type
, OSDictionary
* matching
,
3307 IOServiceNotificationHandler handler
,
3308 void * target
, void * ref
,
3309 SInt32 priority
, OSIterator
** existing
)
3311 IONotifier
* notify
;
3315 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3316 priority
, existing
);
3323 IONotifier
* IOService::addNotification(
3324 const OSSymbol
* type
, OSDictionary
* matching
,
3325 IOServiceNotificationHandler handler
,
3326 void * target
, void * ref
,
3329 OSIterator
* existing
;
3330 _IOServiceNotifier
* notify
;
3333 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3334 handler
, target
, ref
, priority
, &existing
);
3336 // send notifications for existing set
3339 notify
->retain(); // in case handler remove()s
3340 while( (next
= (IOService
*) existing
->getNextObject())) {
3342 next
->lockForArbitration();
3343 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3344 next
->invokeNotifer( notify
);
3345 next
->unlockForArbitration();
3348 existing
->release();
3354 struct SyncNotifyVars
{
3355 semaphore_port_t waitHere
;
3359 bool IOService::syncNotificationHandler(
3360 void * /* target */, void * ref
,
3361 IOService
* newService
)
3364 // result may get written more than once before the
3365 // notification is removed!
3366 ((SyncNotifyVars
*) ref
)->result
= newService
;
3367 semaphore_signal( ((SyncNotifyVars
*) ref
)->waitHere
);
3372 IOService
* IOService::waitForService( OSDictionary
* matching
,
3373 mach_timespec_t
* timeout
)
3375 IONotifier
* notify
= 0;
3376 // priority doesn't help us much since we need a thread wakeup
3377 SInt32 priority
= 0;
3378 SyncNotifyVars state
;
3379 kern_return_t err
= kIOReturnBadArgument
;
3391 state
.result
= (IOService
*) getExistingServices( matching
,
3392 kIOServiceMatchedState
, kIONotifyOnce
);
3396 err
= semaphore_create( kernel_task
, &state
.waitHere
,
3397 SYNC_POLICY_FIFO
, 0 );
3398 if( KERN_SUCCESS
!= err
)
3401 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
3402 &IOService::syncNotificationHandler
, (void *) 0,
3403 (void *) &state
, priority
);
3411 err
= semaphore_timedwait( state
.waitHere
, *timeout
);
3413 err
= semaphore_wait( state
.waitHere
);
3417 notify
->remove(); // dequeues
3419 matching
->release();
3421 semaphore_destroy( kernel_task
, state
.waitHere
);
3423 return( state
.result
);
3426 void IOService::deliverNotification( const OSSymbol
* type
,
3427 IOOptionBits orNewState
, IOOptionBits andNewState
)
3429 _IOServiceNotifier
* notify
;
3431 OSArray
* willSend
= 0;
3433 lockForArbitration();
3435 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3436 || (type
== gIOTerminatedNotification
)) {
3440 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3441 gNotifications
->getObject( type
) );
3444 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
3446 if( passiveMatch( notify
->matching
)
3447 && (kIOServiceNotifyEnable
& notify
->state
)) {
3449 willSend
= OSArray::withCapacity(8);
3451 willSend
->setObject( notify
);
3457 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
3463 for( unsigned int idx
= 0;
3464 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
3466 invokeNotifer( notify
);
3468 willSend
->release();
3470 unlockForArbitration();
3473 IOOptionBits
IOService::getState( void ) const
3475 return( __state
[0] );
3479 * Helpers to make matching objects for simple cases
3482 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
3483 OSDictionary
* table
)
3486 table
= OSDictionary::withCapacity( 2 );
3488 table
->setObject(gIOProviderClassKey
, (OSObject
*)name
);
3493 OSDictionary
* IOService::serviceMatching( const char * name
,
3494 OSDictionary
* table
)
3496 const OSString
* str
;
3498 str
= OSSymbol::withCString( name
);
3502 table
= serviceMatching( str
, table
);
3507 OSDictionary
* IOService::nameMatching( const OSString
* name
,
3508 OSDictionary
* table
)
3511 table
= OSDictionary::withCapacity( 2 );
3513 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
3518 OSDictionary
* IOService::nameMatching( const char * name
,
3519 OSDictionary
* table
)
3521 const OSString
* str
;
3523 str
= OSSymbol::withCString( name
);
3527 table
= nameMatching( str
, table
);
3532 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
3533 OSDictionary
* table
)
3535 table
= serviceMatching( gIOResourcesKey
, table
);
3537 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
3542 OSDictionary
* IOService::resourceMatching( const char * name
,
3543 OSDictionary
* table
)
3545 const OSSymbol
* str
;
3547 str
= OSSymbol::withCString( name
);
3551 table
= resourceMatching( str
, table
);
3558 * _IOServiceNotifier
3561 // wait for all threads, other than the current one,
3562 // to exit the handler
3564 void _IOServiceNotifier::wait()
3566 _IOServiceNotifierInvocation
* next
;
3571 queue_iterate( &handlerInvocations
, next
,
3572 _IOServiceNotifierInvocation
*, link
) {
3573 if( next
->thread
!= current_thread() ) {
3579 state
|= kIOServiceNotifyWaiter
;
3586 void _IOServiceNotifier::free()
3588 assert( queue_empty( &handlerInvocations
));
3592 void _IOServiceNotifier::remove()
3597 whence
->removeObject( (OSObject
*) this );
3601 matching
->release();
3605 state
&= ~kIOServiceNotifyEnable
;
3614 bool _IOServiceNotifier::disable()
3620 ret
= (0 != (kIOServiceNotifyEnable
& state
));
3621 state
&= ~kIOServiceNotifyEnable
;
3630 void _IOServiceNotifier::enable( bool was
)
3634 state
|= kIOServiceNotifyEnable
;
3636 state
&= ~kIOServiceNotifyEnable
;
3644 IOService
* IOResources::resources( void )
3648 inst
= new IOResources
;
3649 if( inst
&& !inst
->init()) {
3657 IOWorkLoop
* IOResources::getWorkLoop() const
3659 // If we are the resource root then bringe over to the
3660 // platform to get its workloop
3661 if (this == (IOResources
*) gIOResources
)
3662 return getPlatform()->getWorkLoop();
3664 return IOService::getWorkLoop();
3667 bool IOResources::matchPropertyTable( OSDictionary
* table
)
3675 prop
= table
->getObject( gIOResourceMatchKey
);
3676 str
= OSDynamicCast( OSString
, prop
);
3678 ok
= (0 != getProperty( str
));
3680 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
3682 iter
= OSCollectionIterator::withCollection( set
);
3684 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
3685 ok
= (0 != getProperty( str
));
3694 IOReturn
IOResources::setProperties( OSObject
* properties
)
3697 const OSSymbol
* key
;
3698 OSDictionary
* dict
;
3699 OSCollectionIterator
* iter
;
3701 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
3702 if ( kIOReturnSuccess
!= err
)
3705 dict
= OSDynamicCast(OSDictionary
, properties
);
3707 return( kIOReturnBadArgument
);
3709 iter
= OSCollectionIterator::withCollection( dict
);
3711 return( kIOReturnBadArgument
);
3713 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
3715 if (gIOConsoleUsersKey
== key
)
3717 IORegistryEntry::getRegistryRoot()->setProperty(key
, dict
->getObject(key
));
3718 OSIncrementAtomic( &gIOConsoleUsersSeed
);
3719 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
3723 publishResource( key
, dict
->getObject(key
) );
3728 return( kIOReturnSuccess
);
3732 * Helpers for matching dictionaries.
3733 * Keys existing in matching are checked in properties.
3734 * Keys may be a string or OSCollection of IOStrings
3737 bool IOService::compareProperty( OSDictionary
* matching
,
3743 value
= matching
->getObject( key
);
3745 ok
= value
->isEqualTo( getProperty( key
));
3753 bool IOService::compareProperty( OSDictionary
* matching
,
3754 const OSString
* key
)
3759 value
= matching
->getObject( key
);
3761 ok
= value
->isEqualTo( getProperty( key
));
3768 bool IOService::compareProperties( OSDictionary
* matching
,
3769 OSCollection
* keys
)
3771 OSCollectionIterator
* iter
;
3772 const OSString
* key
;
3775 if( !matching
|| !keys
)
3778 iter
= OSCollectionIterator::withCollection( keys
);
3781 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
3782 ok
= compareProperty( matching
, key
);
3786 keys
->release(); // !! consume a ref !!
3791 /* Helper to add a location matching dict to the table */
3793 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
3795 OSDictionary
* dict
;
3800 dict
= OSDictionary::withCapacity( 1 );
3802 table
->setObject( gIOLocationMatchKey
, dict
);
3810 * Go looking for a provider to match a location dict.
3813 IOService
* IOService::matchLocation( IOService
* /* client */ )
3817 parent
= getProvider();
3820 parent
= parent
->matchLocation( this );
3825 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
3831 IORegistryEntry
* entry
;
3836 bool matchParent
= false;
3847 str
= OSDynamicCast( OSString
, table
->getObject( gIOProviderClassKey
));
3850 match
= (0 != where
->metaCast( str
));
3855 obj
= table
->getObject( gIONameMatchKey
);
3858 match
= where
->compareNames( obj
, changesOK
? &matched
: 0 );
3861 if( changesOK
&& matched
) {
3862 // leave a hint as to which name matched
3863 table
->setObject( gIONameMatchedKey
, matched
);
3868 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
3871 const OSSymbol
* sym
;
3875 sym
= where
->copyLocation();
3877 match
= sym
->isEqualTo( str
);
3884 obj
= table
->getObject( gIOPropertyMatchKey
);
3887 OSDictionary
* dict
;
3888 OSDictionary
* nextDict
;
3893 dict
= where
->dictionaryWithProperties();
3895 nextDict
= OSDynamicCast( OSDictionary
, obj
);
3899 iter
= OSCollectionIterator::withCollection(
3900 OSDynamicCast(OSCollection
, obj
));
3903 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
3904 iter
->getNextObject()))))) {
3905 match
= dict
->isEqualTo( nextDict
, nextDict
);
3918 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
3921 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
3922 match
= (where
== entry
);
3929 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
3933 IOService
* service
= 0;
3934 UInt32 serviceCount
= 0;
3937 iter
= where
->getClientIterator();
3939 while( (service
= (IOService
*) iter
->getNextObject())) {
3940 if( kIOServiceInactiveState
& service
->__state
[0])
3942 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
3948 match
= (serviceCount
== num
->unsigned32BitValue());
3953 if( done
== table
->getCount()) {
3954 // don't call family if we've done all the entries in the table
3955 matchParent
= false;
3959 // pass in score from property table
3960 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
3962 // do family specific matching
3963 match
= where
->matchPropertyTable( table
, &score
);
3967 if( kIOLogMatch
& getDebugFlags( table
))
3968 LOG("%s: family specific matching fails\n", where
->getName());
3975 newPri
= OSNumber::withNumber( score
, 32 );
3977 table
->setObject( gIOProbeScoreKey
, newPri
);
3982 if( !(match
= where
->compareProperty( table
, kIOBSDNameKey
)))
3985 matchParent
= false;
3987 obj
= OSDynamicCast( OSDictionary
,
3988 table
->getObject( gIOParentMatchKey
));
3992 table
= (OSDictionary
*) obj
;
3996 table
= OSDynamicCast( OSDictionary
,
3997 table
->getObject( gIOLocationMatchKey
));
4000 where
= where
->getProvider();
4002 where
= where
->matchLocation( where
);
4005 } while( table
&& where
);
4007 } while( matchParent
&& (where
= where
->getProvider()) );
4009 if( kIOLogMatch
& gIOKitDebug
)
4011 LOG("match parent @ %s = %d\n",
4012 where
->getName(), match
);
4018 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4019 UInt32 type
, OSDictionary
* properties
,
4020 IOUserClient
** handler
)
4022 const OSSymbol
*userClientClass
= 0;
4023 IOUserClient
*client
;
4026 // First try my own properties for a user client class name
4027 temp
= getProperty(gIOUserClientClassKey
);
4029 if (OSDynamicCast(OSSymbol
, temp
))
4030 userClientClass
= (const OSSymbol
*) temp
;
4031 else if (OSDynamicCast(OSString
, temp
)) {
4032 userClientClass
= OSSymbol::withString((OSString
*) temp
);
4033 if (userClientClass
)
4034 setProperty(kIOUserClientClassKey
,
4035 (OSObject
*) userClientClass
);
4039 // Didn't find one so lets just bomb out now without further ado.
4040 if (!userClientClass
)
4041 return kIOReturnUnsupported
;
4043 temp
= OSMetaClass::allocClassWithName(userClientClass
);
4045 return kIOReturnNoMemory
;
4047 if (OSDynamicCast(IOUserClient
, temp
))
4048 client
= (IOUserClient
*) temp
;
4051 return kIOReturnUnsupported
;
4054 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
4056 return kIOReturnBadArgument
;
4059 if ( !client
->attach(this) ) {
4061 return kIOReturnUnsupported
;
4064 if ( !client
->start(this) ) {
4065 client
->detach(this);
4067 return kIOReturnUnsupported
;
4071 return kIOReturnSuccess
;
4074 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4075 UInt32 type
, IOUserClient
** handler
)
4077 return( newUserClient( owningTask
, securityID
, type
, 0, handler
));
4080 IOReturn
IOService::requestProbe( IOOptionBits options
)
4082 return( kIOReturnUnsupported
);
4086 * Convert an IOReturn to text. Subclasses which add additional
4087 * IOReturn's should override this method and call
4088 * super::stringFromReturn if the desired value is not found.
4091 const char * IOService::stringFromReturn( IOReturn rtn
)
4093 static const IONamedValue IOReturn_values
[] = {
4094 {kIOReturnSuccess
, "success" },
4095 {kIOReturnError
, "general error" },
4096 {kIOReturnNoMemory
, "memory allocation error" },
4097 {kIOReturnNoResources
, "resource shortage" },
4098 {kIOReturnIPCError
, "Mach IPC failure" },
4099 {kIOReturnNoDevice
, "no such device" },
4100 {kIOReturnNotPrivileged
, "privilege violation" },
4101 {kIOReturnBadArgument
, "invalid argument" },
4102 {kIOReturnLockedRead
, "device is read locked" },
4103 {kIOReturnLockedWrite
, "device is write locked" },
4104 {kIOReturnExclusiveAccess
, "device is exclusive access" },
4105 {kIOReturnBadMessageID
, "bad IPC message ID" },
4106 {kIOReturnUnsupported
, "unsupported function" },
4107 {kIOReturnVMError
, "virtual memory error" },
4108 {kIOReturnInternalError
, "internal driver error" },
4109 {kIOReturnIOError
, "I/O error" },
4110 {kIOReturnCannotLock
, "cannot acquire lock" },
4111 {kIOReturnNotOpen
, "device is not open" },
4112 {kIOReturnNotReadable
, "device is not readable" },
4113 {kIOReturnNotWritable
, "device is not writeable" },
4114 {kIOReturnNotAligned
, "alignment error" },
4115 {kIOReturnBadMedia
, "media error" },
4116 {kIOReturnStillOpen
, "device is still open" },
4117 {kIOReturnRLDError
, "rld failure" },
4118 {kIOReturnDMAError
, "DMA failure" },
4119 {kIOReturnBusy
, "device is busy" },
4120 {kIOReturnTimeout
, "I/O timeout" },
4121 {kIOReturnOffline
, "device is offline" },
4122 {kIOReturnNotReady
, "device is not ready" },
4123 {kIOReturnNotAttached
, "device/channel is not attached" },
4124 {kIOReturnNoChannels
, "no DMA channels available" },
4125 {kIOReturnNoSpace
, "no space for data" },
4126 {kIOReturnPortExists
, "device port already exists" },
4127 {kIOReturnCannotWire
, "cannot wire physical memory" },
4128 {kIOReturnNoInterrupt
, "no interrupt attached" },
4129 {kIOReturnNoFrames
, "no DMA frames enqueued" },
4130 {kIOReturnMessageTooLarge
, "message is too large" },
4131 {kIOReturnNotPermitted
, "operation is not permitted" },
4132 {kIOReturnNoPower
, "device is without power" },
4133 {kIOReturnNoMedia
, "media is not present" },
4134 {kIOReturnUnformattedMedia
, "media is not formatted" },
4135 {kIOReturnUnsupportedMode
, "unsupported mode" },
4136 {kIOReturnUnderrun
, "data underrun" },
4137 {kIOReturnOverrun
, "data overrun" },
4138 {kIOReturnDeviceError
, "device error" },
4139 {kIOReturnNoCompletion
, "no completion routine" },
4140 {kIOReturnAborted
, "operation was aborted" },
4141 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
4142 {kIOReturnNotResponding
, "device is not responding" },
4143 {kIOReturnInvalid
, "unanticipated driver error" },
4147 return IOFindNameForValue(rtn
, IOReturn_values
);
4151 * Convert an IOReturn to an errno.
4153 int IOService::errnoFromReturn( IOReturn rtn
)
4157 case kIOReturnSuccess
:
4159 case kIOReturnNoMemory
:
4161 case kIOReturnNoDevice
:
4163 case kIOReturnVMError
:
4165 case kIOReturnNotPermitted
:
4167 case kIOReturnNotPrivileged
:
4169 case kIOReturnIOError
:
4171 case kIOReturnNotWritable
:
4173 case kIOReturnBadArgument
:
4175 case kIOReturnUnsupported
:
4179 case kIOReturnNoPower
:
4181 case kIOReturnDeviceError
:
4183 case kIOReturnTimeout
:
4185 case kIOReturnMessageTooLarge
:
4187 case kIOReturnNoSpace
:
4189 case kIOReturnCannotLock
:
4193 case kIOReturnBadMessageID
:
4194 case kIOReturnNoCompletion
:
4195 case kIOReturnNotAligned
:
4197 case kIOReturnNotReady
:
4199 case kIOReturnRLDError
:
4201 case kIOReturnPortExists
:
4202 case kIOReturnStillOpen
:
4204 case kIOReturnExclusiveAccess
:
4205 case kIOReturnLockedRead
:
4206 case kIOReturnLockedWrite
:
4207 case kIOReturnNotAttached
:
4208 case kIOReturnNotOpen
:
4209 case kIOReturnNotReadable
:
4211 case kIOReturnCannotWire
:
4212 case kIOReturnNoResources
:
4214 case kIOReturnAborted
:
4215 case kIOReturnOffline
:
4216 case kIOReturnNotResponding
:
4218 case kIOReturnBadMedia
:
4219 case kIOReturnNoMedia
:
4220 case kIOReturnUnformattedMedia
:
4221 return(ENXIO
); // (media error)
4222 case kIOReturnDMAError
:
4223 case kIOReturnOverrun
:
4224 case kIOReturnUnderrun
:
4225 return(EIO
); // (transfer error)
4226 case kIOReturnNoBandwidth
:
4227 case kIOReturnNoChannels
:
4228 case kIOReturnNoFrames
:
4229 case kIOReturnNoInterrupt
:
4230 return(EIO
); // (hardware error)
4231 case kIOReturnError
:
4232 case kIOReturnInternalError
:
4233 case kIOReturnInvalid
:
4234 return(EIO
); // (generic error)
4235 case kIOReturnIPCError
:
4236 return(EIO
); // (ipc error)
4238 return(EIO
); // (all other errors)
4242 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
4246 * Generic entry point for calls from the provider. A return value of
4247 * kIOReturnSuccess indicates that the message was received, and where
4248 * applicable, that it was successful.
4251 return kIOReturnUnsupported
;
4258 IOItemCount
IOService::getDeviceMemoryCount( void )
4263 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4265 count
= array
->getCount();
4272 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
4275 IODeviceMemory
* range
;
4277 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4279 range
= (IODeviceMemory
*) array
->getObject( index
);
4286 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
4287 IOOptionBits options
)
4289 IODeviceMemory
* range
;
4292 range
= getDeviceMemoryWithIndex( index
);
4294 map
= range
->map( options
);
4301 OSArray
* IOService::getDeviceMemory( void )
4303 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
4307 void IOService::setDeviceMemory( OSArray
* array
)
4309 setProperty( gIODeviceMemoryKey
, array
);
4316 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
4318 IOInterruptController
*interruptController
;
4321 OSSymbol
*interruptControllerName
;
4323 IOInterruptSource
*interruptSources
;
4325 // Get the parents list from the nub.
4326 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
4327 if (array
== 0) return kIOReturnNoResources
;
4329 // Allocate space for the IOInterruptSources if needed... then return early.
4330 if (nub
->_interruptSources
== 0) {
4331 numSources
= array
->getCount();
4332 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
4333 if (interruptSources
== 0) return kIOReturnNoMemory
;
4335 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
4337 nub
->_numInterruptSources
= numSources
;
4338 nub
->_interruptSources
= interruptSources
;
4339 return kIOReturnSuccess
;
4342 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
4343 if (interruptControllerName
== 0) return kIOReturnNoResources
;
4345 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
4346 if (interruptController
== 0) return kIOReturnNoResources
;
4348 // Get the interrupt numbers from the nub.
4349 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
4350 if (array
== 0) return kIOReturnNoResources
;
4351 data
= OSDynamicCast(OSData
, array
->getObject(source
));
4352 if (data
== 0) return kIOReturnNoResources
;
4354 // Set the interruptController and interruptSource in the nub's table.
4355 interruptSources
= nub
->_interruptSources
;
4356 interruptSources
[source
].interruptController
= interruptController
;
4357 interruptSources
[source
].vectorData
= data
;
4359 return kIOReturnSuccess
;
4362 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
4366 /* Make sure the _interruptSources are set */
4367 if (_interruptSources
== 0) {
4368 ret
= resolveInterrupt(this, source
);
4369 if (ret
!= kIOReturnSuccess
) return ret
;
4372 /* Make sure the local source number is valid */
4373 if ((source
< 0) || (source
>= _numInterruptSources
))
4374 return kIOReturnNoInterrupt
;
4376 /* Look up the contoller for the local source */
4377 *interruptController
= _interruptSources
[source
].interruptController
;
4379 if (*interruptController
== NULL
) {
4380 if (!resolve
) return kIOReturnNoInterrupt
;
4382 /* Try to reslove the interrupt */
4383 ret
= resolveInterrupt(this, source
);
4384 if (ret
!= kIOReturnSuccess
) return ret
;
4386 *interruptController
= _interruptSources
[source
].interruptController
;
4389 return kIOReturnSuccess
;
4392 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
4393 IOInterruptAction handler
,
4396 IOInterruptController
*interruptController
;
4399 ret
= lookupInterrupt(source
, true, &interruptController
);
4400 if (ret
!= kIOReturnSuccess
) return ret
;
4402 /* Register the source */
4403 return interruptController
->registerInterrupt(this, source
, target
,
4404 (IOInterruptHandler
)handler
,
4408 IOReturn
IOService::unregisterInterrupt(int source
)
4410 IOInterruptController
*interruptController
;
4413 ret
= lookupInterrupt(source
, false, &interruptController
);
4414 if (ret
!= kIOReturnSuccess
) return ret
;
4416 /* Unregister the source */
4417 return interruptController
->unregisterInterrupt(this, source
);
4420 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
4422 IOInterruptController
*interruptController
;
4425 ret
= lookupInterrupt(source
, true, &interruptController
);
4426 if (ret
!= kIOReturnSuccess
) return ret
;
4428 /* Return the type */
4429 return interruptController
->getInterruptType(this, source
, interruptType
);
4432 IOReturn
IOService::enableInterrupt(int source
)
4434 IOInterruptController
*interruptController
;
4437 ret
= lookupInterrupt(source
, false, &interruptController
);
4438 if (ret
!= kIOReturnSuccess
) return ret
;
4440 /* Enable the source */
4441 return interruptController
->enableInterrupt(this, source
);
4444 IOReturn
IOService::disableInterrupt(int source
)
4446 IOInterruptController
*interruptController
;
4449 ret
= lookupInterrupt(source
, false, &interruptController
);
4450 if (ret
!= kIOReturnSuccess
) return ret
;
4452 /* Disable the source */
4453 return interruptController
->disableInterrupt(this, source
);
4456 IOReturn
IOService::causeInterrupt(int source
)
4458 IOInterruptController
*interruptController
;
4461 ret
= lookupInterrupt(source
, false, &interruptController
);
4462 if (ret
!= kIOReturnSuccess
) return ret
;
4464 /* Cause an interrupt for the source */
4465 return interruptController
->causeInterrupt(this, source
);
4468 OSMetaClassDefineReservedUsed(IOService
, 0);
4469 OSMetaClassDefineReservedUsed(IOService
, 1);
4470 OSMetaClassDefineReservedUsed(IOService
, 2);
4471 OSMetaClassDefineReservedUsed(IOService
, 3);
4473 OSMetaClassDefineReservedUnused(IOService
, 4);
4474 OSMetaClassDefineReservedUnused(IOService
, 5);
4475 OSMetaClassDefineReservedUnused(IOService
, 6);
4476 OSMetaClassDefineReservedUnused(IOService
, 7);
4477 OSMetaClassDefineReservedUnused(IOService
, 8);
4478 OSMetaClassDefineReservedUnused(IOService
, 9);
4479 OSMetaClassDefineReservedUnused(IOService
, 10);
4480 OSMetaClassDefineReservedUnused(IOService
, 11);
4481 OSMetaClassDefineReservedUnused(IOService
, 12);
4482 OSMetaClassDefineReservedUnused(IOService
, 13);
4483 OSMetaClassDefineReservedUnused(IOService
, 14);
4484 OSMetaClassDefineReservedUnused(IOService
, 15);
4485 OSMetaClassDefineReservedUnused(IOService
, 16);
4486 OSMetaClassDefineReservedUnused(IOService
, 17);
4487 OSMetaClassDefineReservedUnused(IOService
, 18);
4488 OSMetaClassDefineReservedUnused(IOService
, 19);
4489 OSMetaClassDefineReservedUnused(IOService
, 20);
4490 OSMetaClassDefineReservedUnused(IOService
, 21);
4491 OSMetaClassDefineReservedUnused(IOService
, 22);
4492 OSMetaClassDefineReservedUnused(IOService
, 23);
4493 OSMetaClassDefineReservedUnused(IOService
, 24);
4494 OSMetaClassDefineReservedUnused(IOService
, 25);
4495 OSMetaClassDefineReservedUnused(IOService
, 26);
4496 OSMetaClassDefineReservedUnused(IOService
, 27);
4497 OSMetaClassDefineReservedUnused(IOService
, 28);
4498 OSMetaClassDefineReservedUnused(IOService
, 29);
4499 OSMetaClassDefineReservedUnused(IOService
, 30);
4500 OSMetaClassDefineReservedUnused(IOService
, 31);
4501 OSMetaClassDefineReservedUnused(IOService
, 32);
4502 OSMetaClassDefineReservedUnused(IOService
, 33);
4503 OSMetaClassDefineReservedUnused(IOService
, 34);
4504 OSMetaClassDefineReservedUnused(IOService
, 35);
4505 OSMetaClassDefineReservedUnused(IOService
, 36);
4506 OSMetaClassDefineReservedUnused(IOService
, 37);
4507 OSMetaClassDefineReservedUnused(IOService
, 38);
4508 OSMetaClassDefineReservedUnused(IOService
, 39);
4509 OSMetaClassDefineReservedUnused(IOService
, 40);
4510 OSMetaClassDefineReservedUnused(IOService
, 41);
4511 OSMetaClassDefineReservedUnused(IOService
, 42);
4512 OSMetaClassDefineReservedUnused(IOService
, 43);
4513 OSMetaClassDefineReservedUnused(IOService
, 44);
4514 OSMetaClassDefineReservedUnused(IOService
, 45);
4515 OSMetaClassDefineReservedUnused(IOService
, 46);
4516 OSMetaClassDefineReservedUnused(IOService
, 47);
4517 OSMetaClassDefineReservedUnused(IOService
, 48);
4518 OSMetaClassDefineReservedUnused(IOService
, 49);
4519 OSMetaClassDefineReservedUnused(IOService
, 50);
4520 OSMetaClassDefineReservedUnused(IOService
, 51);
4521 OSMetaClassDefineReservedUnused(IOService
, 52);
4522 OSMetaClassDefineReservedUnused(IOService
, 53);
4523 OSMetaClassDefineReservedUnused(IOService
, 54);
4524 OSMetaClassDefineReservedUnused(IOService
, 55);
4525 OSMetaClassDefineReservedUnused(IOService
, 56);
4526 OSMetaClassDefineReservedUnused(IOService
, 57);
4527 OSMetaClassDefineReservedUnused(IOService
, 58);
4528 OSMetaClassDefineReservedUnused(IOService
, 59);
4529 OSMetaClassDefineReservedUnused(IOService
, 60);
4530 OSMetaClassDefineReservedUnused(IOService
, 61);
4531 OSMetaClassDefineReservedUnused(IOService
, 62);
4532 OSMetaClassDefineReservedUnused(IOService
, 63);