2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include <IOKit/system.h>
25 #include <IOKit/IOService.h>
26 #include <libkern/c++/OSContainers.h>
27 #include <libkern/c++/OSUnserialize.h>
28 #include <IOKit/IOCatalogue.h>
29 #include <IOKit/IOCommand.h>
30 #include <IOKit/IODeviceMemory.h>
31 #include <IOKit/IOInterrupts.h>
32 #include <IOKit/IOInterruptController.h>
33 #include <IOKit/IOPlatformExpert.h>
34 #include <IOKit/IOMessage.h>
35 #include <IOKit/IOLib.h>
36 #include <IOKit/IOKitKeysPrivate.h>
37 #include <IOKit/IOBSD.h>
38 #include <IOKit/IOUserClient.h>
39 #include <IOKit/IOWorkLoop.h>
40 #include <mach/sync_policy.h>
41 #include <IOKit/assert.h>
42 #include <sys/errno.h>
47 #include "IOServicePrivate.h"
49 // take lockForArbitration before LOCKNOTIFY
51 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
53 #define super IORegistryEntry
55 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
57 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
59 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
61 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
63 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
65 OSDefineMetaClassAndStructors(IOResources
, IOService
)
67 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
69 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
71 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
73 static IOPlatformExpert
* gIOPlatform
;
74 static class IOPMrootDomain
* gIOPMRootDomain
;
75 const IORegistryPlane
* gIOServicePlane
;
76 const IORegistryPlane
* gIOPowerPlane
;
77 const OSSymbol
* gIODeviceMemoryKey
;
78 const OSSymbol
* gIOInterruptControllersKey
;
79 const OSSymbol
* gIOInterruptSpecifiersKey
;
81 const OSSymbol
* gIOResourcesKey
;
82 const OSSymbol
* gIOResourceMatchKey
;
83 const OSSymbol
* gIOProviderClassKey
;
84 const OSSymbol
* gIONameMatchKey
;
85 const OSSymbol
* gIONameMatchedKey
;
86 const OSSymbol
* gIOPropertyMatchKey
;
87 const OSSymbol
* gIOLocationMatchKey
;
88 const OSSymbol
* gIOParentMatchKey
;
89 const OSSymbol
* gIOPathMatchKey
;
90 const OSSymbol
* gIOMatchCategoryKey
;
91 const OSSymbol
* gIODefaultMatchCategoryKey
;
92 const OSSymbol
* gIOMatchedServiceCountKey
;
94 const OSSymbol
* gIOUserClientClassKey
;
95 const OSSymbol
* gIOKitDebugKey
;
97 const OSSymbol
* gIOCommandPoolSizeKey
;
99 const OSSymbol
* gIOConsoleUsersKey
;
100 const OSSymbol
* gIOConsoleSessionUIDKey
;
101 const OSSymbol
* gIOConsoleUsersSeedKey
;
102 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
103 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
105 static int gIOResourceGenerationCount
;
107 const OSSymbol
* gIOServiceKey
;
108 const OSSymbol
* gIOPublishNotification
;
109 const OSSymbol
* gIOFirstPublishNotification
;
110 const OSSymbol
* gIOMatchedNotification
;
111 const OSSymbol
* gIOFirstMatchNotification
;
112 const OSSymbol
* gIOTerminatedNotification
;
114 const OSSymbol
* gIOGeneralInterest
;
115 const OSSymbol
* gIOBusyInterest
;
116 const OSSymbol
* gIOAppPowerStateInterest
;
117 const OSSymbol
* gIOPriorityPowerStateInterest
;
119 static OSDictionary
* gNotifications
;
120 static IORecursiveLock
* gNotificationLock
;
122 static IOService
* gIOResources
;
123 static IOService
* gIOServiceRoot
;
125 static OSOrderedSet
* gJobs
;
126 static semaphore_port_t gJobsSemaphore
;
127 static IOLock
* gJobsLock
;
128 static int gOutstandingJobs
;
129 static int gNumConfigThreads
;
130 static int gNumWaitingThreads
;
131 static IOLock
* gIOServiceBusyLock
;
133 static thread_t gIOTerminateThread
;
134 static UInt32 gIOTerminateWork
;
135 static OSArray
* gIOTerminatePhase2List
;
136 static OSArray
* gIOStopList
;
137 static OSArray
* gIOStopProviderList
;
138 static OSArray
* gIOFinalizeList
;
140 static SInt32 gIOConsoleUsersSeed
;
141 static OSData
* gIOConsoleUsersSeedValue
;
143 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
145 #define LOCKREADNOTIFY() \
146 IORecursiveLockLock( gNotificationLock )
147 #define LOCKWRITENOTIFY() \
148 IORecursiveLockLock( gNotificationLock )
149 #define LOCKWRITE2READNOTIFY()
150 #define UNLOCKNOTIFY() \
151 IORecursiveLockUnlock( gNotificationLock )
152 #define SLEEPNOTIFY(event) \
153 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
154 #define WAKEUPNOTIFY(event) \
155 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
157 #define randomDelay() \
158 int del = read_processor_clock(); \
159 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
162 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
164 #define queue_element(entry, element, type, field) do { \
165 vm_address_t __ele = (vm_address_t) (entry); \
166 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
167 (element) = (type) __ele; \
170 #define iterqueue(que, elt) \
171 for (queue_entry_t elt = queue_first(que); \
172 !queue_end(que, elt); \
173 elt = queue_next(elt))
175 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
177 struct ArbitrationLockQueueElement
{
186 static queue_head_t gArbitrationLockQueueActive
;
187 static queue_head_t gArbitrationLockQueueWaiting
;
188 static queue_head_t gArbitrationLockQueueFree
;
189 static IOLock
* gArbitrationLockQueueLock
;
191 bool IOService::isInactive( void ) const
192 { return( 0 != (kIOServiceInactiveState
& getState())); }
194 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
196 void IOService::initialize( void )
200 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
201 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
203 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
204 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
205 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
206 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
207 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
208 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
209 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
211 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
212 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
213 kIODefaultMatchCategoryKey
);
214 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
215 kIOMatchedServiceCountKey
);
217 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
219 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
220 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
222 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
223 gIOInterruptControllersKey
224 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
225 gIOInterruptSpecifiersKey
226 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
228 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
230 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
232 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
233 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
234 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
235 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
237 gNotifications
= OSDictionary::withCapacity( 1 );
238 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
239 kIOPublishNotification
);
240 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
241 kIOFirstPublishNotification
);
242 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
243 kIOMatchedNotification
);
244 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
245 kIOFirstMatchNotification
);
246 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
247 kIOTerminatedNotification
);
248 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
250 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
251 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
252 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey
);
253 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionOnConsoleKey
);
254 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionSecureInputPIDKey
);
255 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
257 gNotificationLock
= IORecursiveLockAlloc();
259 assert( gIOServicePlane
&& gIODeviceMemoryKey
260 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
261 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
262 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
263 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
264 && gIOPublishNotification
&& gIOMatchedNotification
265 && gIOTerminatedNotification
&& gIOServiceKey
266 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
267 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
268 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
270 gJobsLock
= IOLockAlloc();
271 gJobs
= OSOrderedSet::withCapacity( 10 );
273 gIOServiceBusyLock
= IOLockAlloc();
275 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
277 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& (err
== KERN_SUCCESS
) );
279 gIOResources
= IOResources::resources();
280 assert( gIOResources
);
282 gArbitrationLockQueueLock
= IOLockAlloc();
283 queue_init(&gArbitrationLockQueueActive
);
284 queue_init(&gArbitrationLockQueueWaiting
);
285 queue_init(&gArbitrationLockQueueFree
);
287 assert( gArbitrationLockQueueLock
);
289 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
290 gIOStopList
= OSArray::withCapacity( 16 );
291 gIOStopProviderList
= OSArray::withCapacity( 16 );
292 gIOFinalizeList
= OSArray::withCapacity( 16 );
293 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
296 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
299 static UInt64
getDebugFlags( OSDictionary
* props
)
301 OSNumber
* debugProp
;
304 debugProp
= OSDynamicCast( OSNumber
,
305 props
->getObject( gIOKitDebugKey
));
307 debugFlags
= debugProp
->unsigned64BitValue();
309 debugFlags
= gIOKitDebug
;
311 return( debugFlags
);
315 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
317 // Probe a matched service and return an instance to be started.
318 // The default score is from the property table, & may be altered
319 // during probe to change the start order.
321 IOService
* IOService::probe( IOService
* provider
,
327 bool IOService::start( IOService
* provider
)
332 void IOService::stop( IOService
* provider
)
336 void IOService::free( void )
338 if( getPropertyTable())
339 unregisterAllInterest();
345 * Attach in service plane
347 bool IOService::attach( IOService
* provider
)
353 if( gIOKitDebug
& kIOLogAttach
)
354 LOG( "%s::attach(%s)\n", getName(),
355 provider
->getName());
357 provider
->lockForArbitration();
358 if( provider
->__state
[0] & kIOServiceInactiveState
)
361 ok
= attachToParent( provider
, gIOServicePlane
);
362 provider
->unlockForArbitration();
365 gIOServiceRoot
= this;
366 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
372 IOService
* IOService::getServiceRoot( void )
374 return( gIOServiceRoot
);
377 void IOService::detach( IOService
* provider
)
379 IOService
* newProvider
= 0;
383 if( gIOKitDebug
& kIOLogAttach
)
384 LOG("%s::detach(%s)\n", getName(), provider
->getName());
386 lockForArbitration();
388 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
389 && (provider
== getProvider()));
391 detachFromParent( provider
, gIOServicePlane
);
394 newProvider
= getProvider();
395 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
396 _adjustBusy( -busy
);
399 unlockForArbitration();
402 newProvider
->lockForArbitration();
403 newProvider
->_adjustBusy(1);
404 newProvider
->unlockForArbitration();
407 // check for last client detach from a terminated service
408 if( provider
->lockForArbitration( true )) {
410 provider
->_adjustBusy( -1 );
411 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
412 && (0 == provider
->getClient())) {
413 provider
->scheduleFinalize();
415 provider
->unlockForArbitration();
420 * Register instance - publish it for matching
423 void IOService::registerService( IOOptionBits options
)
429 enum { kMaxPathLen
= 256 };
430 enum { kMaxChars
= 63 };
432 IORegistryEntry
* parent
= this;
433 IORegistryEntry
* root
= getRegistryRoot();
434 while( parent
&& (parent
!= root
))
435 parent
= parent
->getParentEntry( gIOServicePlane
);
437 if( parent
!= root
) {
438 IOLog("%s: not registry member at registerService()\n", getName());
442 // Allow the Platform Expert to adjust this node.
443 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
446 if( (this != gIOResources
)
447 && (kIOLogRegister
& gIOKitDebug
)) {
449 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
451 IOLog( "Registering: " );
454 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
457 if( len
> kMaxChars
) {
461 if( (skip
= strchr( path
, '/')))
467 IOLog( "%s\n", path
);
470 IOFree( pathBuf
, kMaxPathLen
);
473 startMatching( options
);
476 void IOService::startMatching( IOOptionBits options
)
478 IOService
* provider
;
481 bool needWake
= false;
486 lockForArbitration();
488 sync
= (options
& kIOServiceSynchronous
)
489 || ((provider
= getProvider())
490 && (provider
->__state
[1] & kIOServiceSynchronousState
));
493 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
494 && (0 == (__state
[0] & kIOServiceInactiveState
));
496 __state
[1] |= kIOServiceNeedConfigState
;
498 // __state[0] &= ~kIOServiceInactiveState;
500 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
501 // OSKernelStackRemaining(), getName());
504 prevBusy
= _adjustBusy( 1 );
505 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
509 __state
[1] |= kIOServiceSynchronousState
;
511 __state
[1] &= ~kIOServiceSynchronousState
;
513 unlockForArbitration();
518 IOLockLock( gIOServiceBusyLock
);
519 thread_wakeup( (event_t
) this/*&__state[1]*/ );
520 IOLockUnlock( gIOServiceBusyLock
);
522 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
524 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
528 if( (__state
[1] & kIOServiceNeedConfigState
))
529 doServiceMatch( options
);
531 lockForArbitration();
532 IOLockLock( gIOServiceBusyLock
);
534 waitAgain
= (prevBusy
< (__state
[1] & kIOServiceBusyStateMask
));
536 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
538 __state
[1] &= ~kIOServiceSyncPubState
;
540 unlockForArbitration();
543 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
545 IOLockUnlock( gIOServiceBusyLock
);
547 thread_block(THREAD_CONTINUE_NULL
);
549 } while( waitAgain
);
553 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
555 OSDictionary
* table
;
565 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
568 set
= (OSSet
*) getExistingServices( table
,
569 kIOServiceRegisteredState
,
570 kIOServiceExistingSet
);
575 count
+= set
->getCount();
578 allSet
->merge((const OSSet
*) set
);
586 if( getDebugFlags( table
) & kIOLogMatch
)
587 LOG("Matching service count = %ld\n", count
);
589 newTables
->removeObject(table
);
593 while( (service
= (IOService
*) allSet
->getAnyObject())) {
594 service
->startMatching(kIOServiceAsynchronous
);
595 allSet
->removeObject(service
);
600 newTables
->release();
602 return( kIOReturnSuccess
);
605 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
606 IOOptionBits options
)
610 job
= new _IOServiceJob
;
611 if( job
&& !job
->init()) {
619 job
->options
= options
;
620 nub
->retain(); // thread will release()
628 * Called on a registered service to see if it matches
632 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
634 return( matchPropertyTable(table
) );
637 bool IOService::matchPropertyTable( OSDictionary
* table
)
643 * Called on a matched service to allocate resources
644 * before first driver is attached.
647 IOReturn
IOService::getResources( void )
649 return( kIOReturnSuccess
);
653 * Client/provider accessors
656 IOService
* IOService::getProvider( void ) const
658 IOService
* self
= (IOService
*) this;
663 generation
= getGenerationCount();
664 if( __providerGeneration
== generation
)
667 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
668 if( parent
== IORegistryEntry::getRegistryRoot())
669 /* root is not an IOService */
672 self
->__provider
= parent
;
673 // save the count before getParentEntry()
674 self
->__providerGeneration
= generation
;
679 IOWorkLoop
* IOService::getWorkLoop() const
681 IOService
*provider
= getProvider();
684 return provider
->getWorkLoop();
689 OSIterator
* IOService::getProviderIterator( void ) const
691 return( getParentIterator( gIOServicePlane
));
694 IOService
* IOService::getClient( void ) const
696 return( (IOService
*) getChildEntry( gIOServicePlane
));
699 OSIterator
* IOService::getClientIterator( void ) const
701 return( getChildIterator( gIOServicePlane
));
704 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
705 const IOService
* client
,
706 const IOService
* provider
)
708 _IOOpenServiceIterator
* inst
;
713 inst
= new _IOOpenServiceIterator
;
715 if( inst
&& !inst
->init()) {
721 inst
->client
= client
;
722 inst
->provider
= provider
;
728 void _IOOpenServiceIterator::free()
732 last
->unlockForArbitration();
736 OSObject
* _IOOpenServiceIterator::getNextObject()
741 last
->unlockForArbitration();
743 while( (next
= (IOService
*) iter
->getNextObject())) {
745 next
->lockForArbitration();
746 if( (client
&& (next
->isOpen( client
)))
747 || (provider
&& (provider
->isOpen( next
))) )
749 next
->unlockForArbitration();
757 bool _IOOpenServiceIterator::isValid()
759 return( iter
->isValid() );
762 void _IOOpenServiceIterator::reset()
765 last
->unlockForArbitration();
771 OSIterator
* IOService::getOpenProviderIterator( void ) const
773 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
776 OSIterator
* IOService::getOpenClientIterator( void ) const
778 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
782 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
783 bool waitForFunction
,
784 void *param1
, void *param2
,
785 void *param3
, void *param4
)
787 IOReturn result
= kIOReturnUnsupported
;
788 IOService
*provider
= getProvider();
791 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
792 param1
, param2
, param3
, param4
);
798 IOReturn
IOService::callPlatformFunction( const char * functionName
,
799 bool waitForFunction
,
800 void *param1
, void *param2
,
801 void *param3
, void *param4
)
803 IOReturn result
= kIOReturnNoMemory
;
804 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
806 if (functionSymbol
!= 0) {
807 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
808 param1
, param2
, param3
, param4
);
809 functionSymbol
->release();
817 * Accessors for global services
820 IOPlatformExpert
* IOService::getPlatform( void )
822 return( gIOPlatform
);
825 class IOPMrootDomain
* IOService::getPMRootDomain( void )
827 return( gIOPMRootDomain
);
830 IOService
* IOService::getResourceService( void )
832 return( gIOResources
);
835 void IOService::setPlatform( IOPlatformExpert
* platform
)
837 gIOPlatform
= platform
;
838 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
841 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
843 gIOPMRootDomain
= rootDomain
;
844 publishResource("IOKit");
851 bool IOService::lockForArbitration( bool isSuccessRequired
)
855 ArbitrationLockQueueElement
* element
;
856 ArbitrationLockQueueElement
* active
;
857 ArbitrationLockQueueElement
* waiting
;
859 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
861 // lock global access
862 IOTakeLock( gArbitrationLockQueueLock
);
864 // obtain an unused queue element
865 if( !queue_empty( &gArbitrationLockQueueFree
)) {
866 queue_remove_first( &gArbitrationLockQueueFree
,
868 ArbitrationLockQueueElement
*,
871 element
= IONew( ArbitrationLockQueueElement
, 1 );
875 // prepare the queue element
876 element
->thread
= IOThreadSelf();
877 element
->service
= this;
879 element
->required
= isSuccessRequired
;
880 element
->aborted
= false;
882 // determine whether this object is already locked (ie. on active queue)
884 queue_iterate( &gArbitrationLockQueueActive
,
886 ArbitrationLockQueueElement
*,
889 if( active
->service
== element
->service
) {
895 if( found
) { // this object is already locked
897 // determine whether it is the same or a different thread trying to lock
898 if( active
->thread
!= element
->thread
) { // it is a different thread
900 ArbitrationLockQueueElement
* victim
= 0;
902 // before placing this new thread on the waiting queue, we look for
903 // a deadlock cycle...
906 // determine whether the active thread holding the object we
907 // want is waiting for another object to be unlocked
909 queue_iterate( &gArbitrationLockQueueWaiting
,
911 ArbitrationLockQueueElement
*,
914 if( waiting
->thread
== active
->thread
) {
915 assert( false == waiting
->aborted
);
921 if( found
) { // yes, active thread waiting for another object
923 // this may be a candidate for rejection if the required
924 // flag is not set, should we detect a deadlock later on
925 if( false == waiting
->required
)
928 // find the thread that is holding this other object, that
929 // is blocking the active thread from proceeding (fun :-)
931 queue_iterate( &gArbitrationLockQueueActive
,
932 active
, // (reuse active queue element)
933 ArbitrationLockQueueElement
*,
936 if( active
->service
== waiting
->service
) {
942 // someone must be holding it or it wouldn't be waiting
945 if( active
->thread
== element
->thread
) {
947 // doh, it's waiting for the thread that originated
948 // this whole lock (ie. current thread) -> deadlock
949 if( false == element
->required
) { // willing to fail?
951 // the originating thread doesn't have the required
952 // flag, so it can fail
953 success
= false; // (fail originating lock request)
954 break; // (out of while)
956 } else { // originating thread is not willing to fail
958 // see if we came across a waiting thread that did
959 // not have the 'required' flag set: we'll fail it
962 // we do have a willing victim, fail it's lock
963 victim
->aborted
= true;
965 // take the victim off the waiting queue
966 queue_remove( &gArbitrationLockQueueWaiting
,
968 ArbitrationLockQueueElement
*,
972 IOLockWakeup( gArbitrationLockQueueLock
,
974 /* one thread */ true );
976 // allow this thread to proceed (ie. wait)
977 success
= true; // (put request on wait queue)
978 break; // (out of while)
981 // all the waiting threads we came across in
982 // finding this loop had the 'required' flag
983 // set, so we've got a deadlock we can't avoid
984 panic("I/O Kit: Unrecoverable deadlock.");
988 // repeat while loop, redefining active thread to be the
989 // thread holding "this other object" (see above), and
990 // looking for threads waiting on it; note the active
991 // variable points to "this other object" already... so
992 // there nothing to do in this else clause.
994 } else { // no, active thread is not waiting for another object
996 success
= true; // (put request on wait queue)
997 break; // (out of while)
1001 if( success
) { // put the request on the waiting queue?
1002 kern_return_t wait_result
;
1004 // place this thread on the waiting queue and put it to sleep;
1005 // we place it at the tail of the queue...
1006 queue_enter( &gArbitrationLockQueueWaiting
,
1008 ArbitrationLockQueueElement
*,
1011 // declare that this thread will wait for a given event
1012 restart_sleep
: wait_result
= assert_wait( element
,
1013 element
->required
? THREAD_UNINT
1014 : THREAD_INTERRUPTIBLE
);
1016 // unlock global access
1017 IOUnlock( gArbitrationLockQueueLock
);
1019 // put thread to sleep, waiting for our event to fire...
1020 if (wait_result
== THREAD_WAITING
)
1021 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1024 // ...and we've been woken up; we might be in one of two states:
1025 // (a) we've been aborted and our queue element is not on
1026 // any of the three queues, but is floating around
1027 // (b) we're allowed to proceed with the lock and we have
1028 // already been moved from the waiting queue to the
1030 // ...plus a 3rd state, should the thread have been interrupted:
1031 // (c) we're still on the waiting queue
1033 // determine whether we were interrupted out of our sleep
1034 if( THREAD_INTERRUPTED
== wait_result
) {
1036 // re-lock global access
1037 IOTakeLock( gArbitrationLockQueueLock
);
1039 // determine whether we're still on the waiting queue
1041 queue_iterate( &gArbitrationLockQueueWaiting
,
1042 waiting
, // (reuse waiting queue element)
1043 ArbitrationLockQueueElement
*,
1046 if( waiting
== element
) {
1052 if( found
) { // yes, we're still on the waiting queue
1054 // determine whether we're willing to fail
1055 if( false == element
->required
) {
1057 // mark us as aborted
1058 element
->aborted
= true;
1060 // take us off the waiting queue
1061 queue_remove( &gArbitrationLockQueueWaiting
,
1063 ArbitrationLockQueueElement
*,
1065 } else { // we are not willing to fail
1067 // ignore interruption, go back to sleep
1072 // unlock global access
1073 IOUnlock( gArbitrationLockQueueLock
);
1075 // proceed as though this were a normal wake up
1076 wait_result
= THREAD_AWAKENED
;
1079 assert( THREAD_AWAKENED
== wait_result
);
1081 // determine whether we've been aborted while we were asleep
1082 if( element
->aborted
) {
1083 assert( false == element
->required
);
1085 // re-lock global access
1086 IOTakeLock( gArbitrationLockQueueLock
);
1088 action
= kPutOnFreeQueue
;
1090 } else { // we weren't aborted, so we must be ready to go :-)
1092 // we've already been moved from waiting to active queue
1096 } else { // the lock request is to be failed
1098 // return unused queue element to queue
1099 action
= kPutOnFreeQueue
;
1101 } else { // it is the same thread, recursive access is allowed
1103 // add one level of recursion
1106 // return unused queue element to queue
1107 action
= kPutOnFreeQueue
;
1110 } else { // this object is not already locked, so let this thread through
1111 action
= kPutOnActiveQueue
;
1115 // put the new element on a queue
1116 if( kPutOnActiveQueue
== action
) {
1117 queue_enter( &gArbitrationLockQueueActive
,
1119 ArbitrationLockQueueElement
*,
1121 } else if( kPutOnFreeQueue
== action
) {
1122 queue_enter( &gArbitrationLockQueueFree
,
1124 ArbitrationLockQueueElement
*,
1127 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1130 // unlock global access
1131 IOUnlock( gArbitrationLockQueueLock
);
1136 void IOService::unlockForArbitration( void )
1139 ArbitrationLockQueueElement
* element
;
1141 // lock global access
1142 IOTakeLock( gArbitrationLockQueueLock
);
1144 // find the lock element for this object (ie. on active queue)
1146 queue_iterate( &gArbitrationLockQueueActive
,
1148 ArbitrationLockQueueElement
*,
1151 if( element
->service
== this ) {
1159 // determine whether the lock has been taken recursively
1160 if( element
->count
> 1 ) {
1161 // undo one level of recursion
1166 // remove it from the active queue
1167 queue_remove( &gArbitrationLockQueueActive
,
1169 ArbitrationLockQueueElement
*,
1172 // put it on the free queue
1173 queue_enter( &gArbitrationLockQueueFree
,
1175 ArbitrationLockQueueElement
*,
1178 // determine whether a thread is waiting for object (head to tail scan)
1180 queue_iterate( &gArbitrationLockQueueWaiting
,
1182 ArbitrationLockQueueElement
*,
1185 if( element
->service
== this ) {
1191 if ( found
) { // we found an interested thread on waiting queue
1193 // remove it from the waiting queue
1194 queue_remove( &gArbitrationLockQueueWaiting
,
1196 ArbitrationLockQueueElement
*,
1199 // put it on the active queue
1200 queue_enter( &gArbitrationLockQueueActive
,
1202 ArbitrationLockQueueElement
*,
1205 // wake the waiting thread
1206 IOLockWakeup( gArbitrationLockQueueLock
,
1208 /* one thread */ true );
1212 // unlock global access
1213 IOUnlock( gArbitrationLockQueueLock
);
1216 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1219 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1220 context
, gIOServicePlane
);
1223 void IOService::applyToClients( IOServiceApplierFunction applier
,
1226 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1227 context
, gIOServicePlane
);
1236 // send a message to a client or interested party of this service
1237 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1238 void * argument
, vm_size_t argSize
)
1241 IOService
* service
;
1242 _IOServiceInterestNotifier
* notify
;
1244 if( (service
= OSDynamicCast( IOService
, client
)))
1245 ret
= service
->message( type
, this, argument
);
1247 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1249 _IOServiceNotifierInvocation invocation
;
1252 invocation
.thread
= current_thread();
1255 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1258 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1259 _IOServiceNotifierInvocation
*, link
);
1265 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1266 type
, this, argument
, argSize
);
1269 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1270 _IOServiceNotifierInvocation
*, link
);
1271 if( kIOServiceNotifyWaiter
& notify
->state
) {
1272 notify
->state
&= ~kIOServiceNotifyWaiter
;
1273 WAKEUPNOTIFY( notify
);
1278 ret
= kIOReturnSuccess
;
1281 ret
= kIOReturnBadArgument
;
1287 applyToInterestNotifiers(const IORegistryEntry
*target
,
1288 const OSSymbol
* typeOfInterest
,
1289 OSObjectApplierFunction applier
,
1292 OSArray
* copyArray
= 0;
1296 IOCommand
*notifyList
=
1297 OSDynamicCast( IOCommand
, target
->getProperty( typeOfInterest
));
1300 copyArray
= OSArray::withCapacity(1);
1302 // iterate over queue, entry is set to each element in the list
1303 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1304 _IOServiceInterestNotifier
* notify
;
1306 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1307 copyArray
->setObject(notify
);
1316 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1317 (*applier
)(next
, context
);
1318 copyArray
->release();
1322 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1323 OSObjectApplierFunction applier
,
1326 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1327 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1330 struct MessageClientsContext
{
1331 IOService
* service
;
1338 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1341 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1343 ret
= context
->service
->messageClient( context
->type
,
1344 object
, context
->argument
, context
->argSize
);
1345 if( kIOReturnSuccess
!= ret
)
1349 // send a message to all clients
1350 IOReturn
IOService::messageClients( UInt32 type
,
1351 void * argument
, vm_size_t argSize
)
1353 MessageClientsContext context
;
1355 context
.service
= this;
1356 context
.type
= type
;
1357 context
.argument
= argument
;
1358 context
.argSize
= argSize
;
1359 context
.ret
= kIOReturnSuccess
;
1361 applyToInterested( gIOGeneralInterest
,
1362 &messageClientsApplier
, &context
);
1364 return( context
.ret
);
1367 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1368 IOOptionBits response
)
1370 return( kIOReturnUnsupported
);
1373 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1374 IOServiceInterestHandler handler
, void * target
, void * ref
)
1376 _IOServiceInterestNotifier
* notify
= 0;
1378 if( (typeOfInterest
!= gIOGeneralInterest
)
1379 && (typeOfInterest
!= gIOBusyInterest
)
1380 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1381 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1384 lockForArbitration();
1385 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1387 notify
= new _IOServiceInterestNotifier
;
1388 if( notify
&& !notify
->init()) {
1394 notify
->handler
= handler
;
1395 notify
->target
= target
;
1397 notify
->state
= kIOServiceNotifyEnable
;
1398 queue_init( ¬ify
->handlerInvocations
);
1404 // Get the head of the notifier linked list
1405 IOCommand
*notifyList
= (IOCommand
*) getProperty( typeOfInterest
);
1406 if (!notifyList
|| !OSDynamicCast(IOCommand
, notifyList
)) {
1407 notifyList
= OSTypeAlloc(IOCommand
);
1410 setProperty( typeOfInterest
, notifyList
);
1411 notifyList
->release();
1416 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1417 notify
->retain(); // ref'ed while in list
1423 unlockForArbitration();
1428 static void cleanInterestList( OSObject
* head
)
1430 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1435 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1436 queue_next(entry
) = queue_prev(entry
) = 0;
1438 _IOServiceInterestNotifier
* notify
;
1440 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1446 void IOService::unregisterAllInterest( void )
1448 cleanInterestList( getProperty( gIOGeneralInterest
));
1449 cleanInterestList( getProperty( gIOBusyInterest
));
1450 cleanInterestList( getProperty( gIOAppPowerStateInterest
));
1451 cleanInterestList( getProperty( gIOPriorityPowerStateInterest
));
1455 * _IOServiceInterestNotifier
1458 // wait for all threads, other than the current one,
1459 // to exit the handler
1461 void _IOServiceInterestNotifier::wait()
1463 _IOServiceNotifierInvocation
* next
;
1468 queue_iterate( &handlerInvocations
, next
,
1469 _IOServiceNotifierInvocation
*, link
) {
1470 if( next
->thread
!= current_thread() ) {
1476 state
|= kIOServiceNotifyWaiter
;
1483 void _IOServiceInterestNotifier::free()
1485 assert( queue_empty( &handlerInvocations
));
1489 void _IOServiceInterestNotifier::remove()
1493 if( queue_next( &chain
)) {
1494 remqueue( 0, &chain
);
1495 queue_next( &chain
) = queue_prev( &chain
) = 0;
1499 state
&= ~kIOServiceNotifyEnable
;
1508 bool _IOServiceInterestNotifier::disable()
1514 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1515 state
&= ~kIOServiceNotifyEnable
;
1524 void _IOServiceInterestNotifier::enable( bool was
)
1528 state
|= kIOServiceNotifyEnable
;
1530 state
&= ~kIOServiceNotifyEnable
;
1534 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1540 #define tailQ(o) setObject(o)
1541 #define headQ(o) setObject(0, o)
1542 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); }
1544 inline void _workLoopAction( IOWorkLoop::Action action
,
1545 IOService
* service
,
1546 void * p0
= 0, void * p1
= 0,
1547 void * p2
= 0, void * p3
= 0 )
1551 if( (wl
= service
->getWorkLoop())) {
1553 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1556 (*action
)( service
, p0
, p1
, p2
, p3
);
1559 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1563 // if its our only provider
1564 ok
= isParent( provider
, gIOServicePlane
, true);
1568 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1569 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1576 bool IOService::terminatePhase1( IOOptionBits options
)
1581 OSArray
* makeInactive
;
1584 bool startPhase2
= false;
1586 TLOG("%s::terminatePhase1(%08lx)\n", getName(), options
);
1589 if( options
& kIOServiceRecursing
) {
1590 __state
[1] |= kIOServiceRecursing
;
1595 makeInactive
= OSArray::withCapacity( 16 );
1604 didInactive
= victim
->lockForArbitration( true );
1606 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1608 victim
->__state
[0] |= kIOServiceInactiveState
;
1609 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1610 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1611 victim
->_adjustBusy( 1 );
1613 victim
->unlockForArbitration();
1616 startPhase2
= didInactive
;
1619 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1620 IOUserClient::destroyUserReferences( victim
);
1622 iter
= victim
->getClientIterator();
1624 while( (client
= (IOService
*) iter
->getNextObject())) {
1625 TLOG("%s::requestTerminate(%s, %08lx)\n",
1626 client
->getName(), victim
->getName(), options
);
1627 ok
= client
->requestTerminate( victim
, options
);
1628 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1629 client
->getName(), victim
->getName(), ok
);
1631 makeInactive
->setObject( client
);
1637 victim
= (IOService
*) makeInactive
->getObject(0);
1640 makeInactive
->removeObject(0);
1644 makeInactive
->release();
1647 scheduleTerminatePhase2( options
);
1652 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
1654 AbsoluteTime deadline
;
1655 int waitResult
= THREAD_AWAKENED
;
1656 bool wait
, haveDeadline
= false;
1658 options
|= kIOServiceRequired
;
1662 IOLockLock( gJobsLock
);
1664 if( (options
& kIOServiceSynchronous
)
1665 && (current_thread() != gIOTerminateThread
)) {
1668 wait
= (gIOTerminateThread
!= 0);
1670 // wait to become the terminate thread
1671 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
1675 gIOTerminateThread
= current_thread();
1676 gIOTerminatePhase2List
->setObject( this );
1680 while( gIOTerminateWork
)
1681 terminateWorker( options
);
1682 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1684 // wait for the victim to go non-busy
1685 if( !haveDeadline
) {
1686 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1687 haveDeadline
= true;
1689 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
1690 deadline
, THREAD_UNINT
);
1691 if( waitResult
== THREAD_TIMED_OUT
) {
1692 TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName());
1695 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
1697 gIOTerminateThread
= 0;
1698 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1701 // ! kIOServiceSynchronous
1703 gIOTerminatePhase2List
->setObject( this );
1704 if( 0 == gIOTerminateWork
++) {
1705 if( !gIOTerminateThread
)
1706 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) options
);
1708 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1712 IOLockUnlock( gJobsLock
);
1717 void IOService::terminateThread( void * arg
)
1719 IOLockLock( gJobsLock
);
1721 while (gIOTerminateWork
)
1722 terminateWorker( (IOOptionBits
) arg
);
1724 gIOTerminateThread
= 0;
1725 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1727 IOLockUnlock( gJobsLock
);
1730 void IOService::scheduleStop( IOService
* provider
)
1732 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1734 IOLockLock( gJobsLock
);
1735 gIOStopList
->tailQ( this );
1736 gIOStopProviderList
->tailQ( provider
);
1738 if( 0 == gIOTerminateWork
++) {
1739 if( !gIOTerminateThread
)
1740 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1742 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1745 IOLockUnlock( gJobsLock
);
1748 void IOService::scheduleFinalize( void )
1750 TLOG("%s::scheduleFinalize\n", getName());
1752 IOLockLock( gJobsLock
);
1753 gIOFinalizeList
->tailQ( this );
1755 if( 0 == gIOTerminateWork
++) {
1756 if( !gIOTerminateThread
)
1757 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1759 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1762 IOLockUnlock( gJobsLock
);
1765 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1770 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1772 if( false == *defer
) {
1774 if( lockForArbitration( true )) {
1775 if( false == provider
->handleIsOpen( this ))
1776 scheduleStop( provider
);
1779 message( kIOMessageServiceIsRequestingClose
, provider
, (void *) options
);
1780 if( false == provider
->handleIsOpen( this ))
1781 scheduleStop( provider
);
1784 unlockForArbitration();
1791 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
1792 OSArray
* doPhase2List
)
1798 iter
= victim
->getClientIterator();
1800 while( (client
= (IOService
*) iter
->getNextObject())) {
1801 TLOG("%s::willTerminate(%s, %08lx)\n",
1802 client
->getName(), victim
->getName(), options
);
1803 ok
= client
->willTerminate( victim
, options
);
1804 doPhase2List
->tailQ( client
);
1810 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
)
1816 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *) options
);
1818 iter
= victim
->getClientIterator();
1820 while( (client
= (IOService
*) iter
->getNextObject())) {
1821 TLOG("%s::didTerminate(%s, %08lx)\n",
1822 client
->getName(), victim
->getName(), options
);
1823 client
->didTerminate( victim
, options
, &defer
);
1824 TLOG("%s::didTerminate(%s, defer %d)\n",
1825 client
->getName(), victim
->getName(), defer
);
1831 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
)
1833 TLOG("%s::finalize(%08lx)\n", victim
->getName(), options
);
1834 victim
->finalize( options
);
1837 void IOService::actionStop( IOService
* provider
, IOService
* client
)
1839 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
1840 client
->stop( provider
);
1841 if( provider
->isOpen( client
))
1842 provider
->close( client
);
1843 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
1844 client
->detach( provider
);
1847 void IOService::terminateWorker( IOOptionBits options
)
1849 OSArray
* doPhase2List
;
1850 OSArray
* didPhase2List
;
1855 IOService
* provider
;
1861 options
|= kIOServiceRequired
;
1863 doPhase2List
= OSArray::withCapacity( 16 );
1864 didPhase2List
= OSArray::withCapacity( 16 );
1865 freeList
= OSSet::withCapacity( 16 );
1866 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
1870 workDone
= gIOTerminateWork
;
1872 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
1875 gIOTerminatePhase2List
->removeObject(0);
1876 IOLockUnlock( gJobsLock
);
1880 doPhase2
= victim
->lockForArbitration( true );
1882 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
1884 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
1885 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
1887 victim
->__state
[1] |= kIOServiceTermPhase2State
;
1889 victim
->unlockForArbitration();
1892 if( 0 == victim
->getClient()) {
1893 // no clients - will go to finalize
1894 IOLockLock( gJobsLock
);
1895 gIOFinalizeList
->tailQ( victim
);
1896 IOLockUnlock( gJobsLock
);
1898 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
1899 victim
, (void *) options
, (void *) doPhase2List
);
1901 didPhase2List
->headQ( victim
);
1904 victim
= (IOService
*) doPhase2List
->getObject(0);
1907 doPhase2List
->removeObject(0);
1911 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
1913 if( victim
->lockForArbitration( true )) {
1914 victim
->__state
[1] |= kIOServiceTermPhase3State
;
1915 victim
->unlockForArbitration();
1917 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
1918 victim
, (void *) options
);
1919 didPhase2List
->removeObject(0);
1921 IOLockLock( gJobsLock
);
1928 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
1930 IOLockUnlock( gJobsLock
);
1931 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
1932 victim
, (void *) options
);
1933 IOLockLock( gJobsLock
);
1935 freeList
->setObject( victim
);
1936 // safe if finalize list is append only
1937 gIOFinalizeList
->removeObject(0);
1941 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
1943 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
1946 if( !provider
->isChild( client
, gIOServicePlane
)) {
1947 // may be multiply queued - nop it
1948 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
1950 // not ready for stop if it has clients, skip it
1951 if( (client
->__state
[1] & kIOServiceTermPhase3State
) && client
->getClient()) {
1952 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
1957 IOLockUnlock( gJobsLock
);
1958 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
1959 provider
, (void *) client
);
1960 IOLockLock( gJobsLock
);
1961 // check the finalize list now
1965 freeList
->setObject( client
);
1966 freeList
->setObject( provider
);
1968 // safe if stop list is append only
1969 gIOStopList
->removeObject( idx
);
1970 gIOStopProviderList
->removeObject( idx
);
1974 } while( doPhase3
);
1976 gIOTerminateWork
-= workDone
;
1977 moreToDo
= (gIOTerminateWork
!= 0);
1980 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
1983 } while( moreToDo
);
1985 IOLockUnlock( gJobsLock
);
1987 freeList
->release();
1988 doPhase2List
->release();
1989 didPhase2List
->release();
1991 IOLockLock( gJobsLock
);
1994 bool IOService::finalize( IOOptionBits options
)
1997 IOService
* provider
;
1999 iter
= getProviderIterator();
2003 while( (provider
= (IOService
*) iter
->getNextObject())) {
2006 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
2007 /* we come down here on programmatic terminate */
2009 if( provider
->isOpen( this ))
2010 provider
->close( this );
2014 if( provider
->lockForArbitration( true )) {
2015 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2016 scheduleStop( provider
);
2017 provider
->unlockForArbitration();
2034 void IOService::doServiceTerminate( IOOptionBits options
)
2038 // a method in case someone needs to override it
2039 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2043 if( client
->isParent( this, gIOServicePlane
, true))
2044 // we are the clients only provider
2045 ok
= client
->terminate( options
);
2052 bool IOService::terminate( IOOptionBits options
)
2054 options
|= kIOServiceTerminate
;
2056 return( terminatePhase1( options
));
2059 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2065 struct ServiceOpenMessageContext
2067 IOService
* service
;
2069 IOService
* excludeClient
;
2070 IOOptionBits options
;
2073 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2075 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2077 if( object
!= context
->excludeClient
)
2078 context
->service
->messageClient( context
->type
, object
, (void *) context
->options
);
2081 bool IOService::open( IOService
* forClient
,
2082 IOOptionBits options
,
2086 ServiceOpenMessageContext context
;
2088 context
.service
= this;
2089 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2090 context
.excludeClient
= forClient
;
2091 context
.options
= options
;
2093 applyToInterested( gIOGeneralInterest
,
2094 &serviceOpenMessageApplier
, &context
);
2096 if( false == lockForArbitration(false) )
2099 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2101 ok
= handleOpen( forClient
, options
, arg
);
2103 unlockForArbitration();
2108 void IOService::close( IOService
* forClient
,
2109 IOOptionBits options
)
2114 lockForArbitration();
2116 wasClosed
= handleIsOpen( forClient
);
2118 handleClose( forClient
, options
);
2119 last
= (__state
[1] & kIOServiceTermPhase3State
);
2122 unlockForArbitration();
2125 forClient
->scheduleStop( this );
2127 else if( wasClosed
) {
2129 ServiceOpenMessageContext context
;
2131 context
.service
= this;
2132 context
.type
= kIOMessageServiceWasClosed
;
2133 context
.excludeClient
= forClient
;
2134 context
.options
= options
;
2136 applyToInterested( gIOGeneralInterest
,
2137 &serviceOpenMessageApplier
, &context
);
2141 bool IOService::isOpen( const IOService
* forClient
) const
2143 IOService
* self
= (IOService
*) this;
2146 self
->lockForArbitration();
2148 ok
= handleIsOpen( forClient
);
2150 self
->unlockForArbitration();
2155 bool IOService::handleOpen( IOService
* forClient
,
2156 IOOptionBits options
,
2161 ok
= (0 == __owner
);
2163 __owner
= forClient
;
2165 else if( options
& kIOServiceSeize
) {
2166 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2167 __owner
, (void *) options
));
2168 if( ok
&& (0 == __owner
))
2169 __owner
= forClient
;
2176 void IOService::handleClose( IOService
* forClient
,
2177 IOOptionBits options
)
2179 if( __owner
== forClient
)
2183 bool IOService::handleIsOpen( const IOService
* forClient
) const
2186 return( __owner
== forClient
);
2188 return( __owner
!= forClient
);
2192 * Probing & starting
2194 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2196 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2197 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2205 val1
= obj1
->priority
;
2208 val2
= obj2
->priority
;
2210 return ( val1
- val2
);
2213 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2215 OSDictionary
* dict
;
2216 IOService
* service
;
2217 _IOServiceNotifier
* notify
;
2218 OSSymbol
* key
= (OSSymbol
*) ref
;
2221 if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2222 return( notify
->priority
);
2224 else if( (service
= OSDynamicCast( IOService
, entry
)))
2225 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2226 else if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2227 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2234 return( (SInt32
) offset
->unsigned32BitValue());
2236 return( kIODefaultProbeScore
);
2239 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2241 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2242 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2250 val1
= IOServiceObjectOrder( obj1
, ref
);
2253 val2
= IOServiceObjectOrder( obj2
, ref
);
2255 return ( val1
- val2
);
2258 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2260 IOService
* service
= 0;
2262 const OSSymbol
* nextCat
;
2264 iter
= getClientIterator();
2266 while( (service
= (IOService
*) iter
->getNextObject())) {
2267 if( kIOServiceInactiveState
& service
->__state
[0])
2269 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2270 service
->getProperty( gIOMatchCategoryKey
));
2271 if( category
== nextCat
)
2279 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2281 _IOServiceNotifierInvocation invocation
;
2285 invocation
.thread
= current_thread();
2288 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2291 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2292 _IOServiceNotifierInvocation
*, link
);
2298 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
, this );
2301 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2302 _IOServiceNotifierInvocation
*, link
);
2303 if( kIOServiceNotifyWaiter
& notify
->state
) {
2304 notify
->state
&= ~kIOServiceNotifyWaiter
;
2305 WAKEUPNOTIFY( notify
);
2314 * Alloc and probe matching classes,
2315 * called on the provider instance
2318 void IOService::probeCandidates( OSOrderedSet
* matches
)
2320 OSDictionary
* match
= 0;
2323 IOService
* newInst
;
2324 OSDictionary
* props
;
2327 OSOrderedSet
* familyMatches
= 0;
2328 OSOrderedSet
* startList
;
2329 OSDictionary
* startDict
= 0;
2330 const OSSymbol
* category
;
2332 _IOServiceNotifier
* notify
;
2333 OSObject
* nextMatch
= 0;
2335 bool needReloc
= false;
2341 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2343 nextMatch
->retain();
2344 matches
->removeObject(nextMatch
);
2346 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2348 lockForArbitration();
2349 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2350 invokeNotifer( notify
);
2351 unlockForArbitration();
2352 nextMatch
->release();
2356 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2357 nextMatch
->release();
2364 debugFlags
= getDebugFlags( match
);
2368 category
= OSDynamicCast( OSSymbol
,
2369 match
->getObject( gIOMatchCategoryKey
));
2371 category
= gIODefaultMatchCategoryKey
;
2373 if( getClientWithCategory( category
)) {
2375 if( debugFlags
& kIOLogMatch
)
2376 LOG("%s: match category %s exists\n", getName(),
2377 category
->getCStringNoCopy());
2379 nextMatch
->release();
2384 // create a copy now in case its modified during matching
2385 props
= OSDictionary::withDictionary( match
, match
->getCount());
2388 props
->setCapacityIncrement(1);
2390 // check the nub matches
2391 if( false == passiveMatch( props
, true ))
2394 // Check to see if driver reloc has been loaded.
2395 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2398 if( debugFlags
& kIOLogCatalogue
)
2399 LOG("%s: stalling for module\n", getName());
2401 // If reloc hasn't been loaded, exit;
2402 // reprobing will occur after reloc has been loaded.
2406 // reorder on family matchPropertyTable score.
2407 if( 0 == familyMatches
)
2408 familyMatches
= OSOrderedSet::withCapacity( 1,
2409 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2411 familyMatches
->setObject( props
);
2416 nextMatch
->release();
2425 if( familyMatches
) {
2428 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2431 familyMatches
->removeObject( props
);
2436 debugFlags
= getDebugFlags( props
);
2439 symbol
= OSDynamicCast( OSSymbol
,
2440 props
->getObject( gIOClassKey
));
2444 // alloc the driver instance
2445 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2448 IOLog("Couldn't alloc class \"%s\"\n",
2449 symbol
->getCStringNoCopy());
2453 // init driver instance
2454 if( !(inst
->init( props
))) {
2456 if( debugFlags
& kIOLogStart
)
2457 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2461 if( __state
[1] & kIOServiceSynchronousState
)
2462 inst
->__state
[1] |= kIOServiceSynchronousState
;
2464 // give the driver the default match category if not specified
2465 category
= OSDynamicCast( OSSymbol
,
2466 props
->getObject( gIOMatchCategoryKey
));
2468 category
= gIODefaultMatchCategoryKey
;
2469 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2471 // attach driver instance
2472 if( !(inst
->attach( this )))
2475 // pass in score from property table
2476 score
= familyMatches
->orderObject( props
);
2478 // & probe the new driver instance
2480 if( debugFlags
& kIOLogProbe
)
2481 LOG("%s::probe(%s)\n",
2482 inst
->getMetaClass()->getClassName(), getName());
2485 newInst
= inst
->probe( this, &score
);
2486 inst
->detach( this );
2489 if( debugFlags
& kIOLogProbe
)
2490 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2496 newPri
= OSNumber::withNumber( score
, 32 );
2498 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2502 // add to start list for the match category
2504 startDict
= OSDictionary::withCapacity( 1 );
2505 assert( startDict
);
2506 startList
= (OSOrderedSet
*)
2507 startDict
->getObject( category
);
2508 if( 0 == startList
) {
2509 startList
= OSOrderedSet::withCapacity( 1,
2510 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2511 if( startDict
&& startList
) {
2512 startDict
->setObject( category
, startList
);
2513 startList
->release();
2516 assert( startList
);
2518 startList
->setObject( newInst
);
2526 familyMatches
->release();
2530 // start the best (until success) of each category
2532 iter
= OSCollectionIterator::withCollection( startDict
);
2534 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2536 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2537 assert( startList
);
2542 while( true // (!started)
2543 && (inst
= (IOService
*)startList
->getFirstObject())) {
2546 startList
->removeObject(inst
);
2549 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2551 if( debugFlags
& kIOLogStart
) {
2553 LOG( "match category exists, skipping " );
2554 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2555 getName(), inst
->getRetainCount());
2558 if( false == started
)
2559 started
= startCandidate( inst
);
2561 if( (debugFlags
& kIOLogStart
) && (false == started
))
2562 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2563 inst
->getRetainCount());
2572 // adjust the busy count by -1 if matching is stalled for a module,
2573 // or +1 if a previously stalled matching is complete.
2574 lockForArbitration();
2577 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2579 __state
[1] |= kIOServiceModuleStallState
;
2581 } else if( __state
[1] & kIOServiceModuleStallState
) {
2582 __state
[1] &= ~kIOServiceModuleStallState
;
2586 _adjustBusy( adjBusy
);
2587 unlockForArbitration();
2590 startDict
->release();
2594 * Start a previously attached & probed instance,
2595 * called on exporting object instance
2598 bool IOService::startCandidate( IOService
* service
)
2602 ok
= service
->attach( this );
2606 if (this != gIOResources
)
2608 // stall for any nub resources
2610 // stall for any driver resources
2611 service
->checkResources();
2614 AbsoluteTime startTime
;
2615 AbsoluteTime endTime
;
2618 if (kIOLogStart
& gIOKitDebug
)
2619 clock_get_uptime(&startTime
);
2621 ok
= service
->start(this);
2623 if (kIOLogStart
& gIOKitDebug
)
2625 clock_get_uptime(&endTime
);
2627 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2629 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2630 absolutetime_to_nanoseconds(endTime
, &nano
);
2631 if (nano
> 500000000ULL)
2632 IOLog("%s::start took %ld ms\n", service
->getName(), (UInt32
)(nano
/ 1000000ULL));
2636 service
->detach( this );
2641 IOService
* IOService::resources( void )
2643 return( gIOResources
);
2646 void IOService::publishResource( const char * key
, OSObject
* value
)
2648 const OSSymbol
* sym
;
2650 if( (sym
= OSSymbol::withCString( key
))) {
2651 publishResource( sym
, value
);
2656 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
2659 value
= (OSObject
*) gIOServiceKey
;
2661 gIOResources
->setProperty( key
, value
);
2663 if( IORecursiveLockHaveLock( gNotificationLock
))
2666 gIOResourceGenerationCount
++;
2667 gIOResources
->registerService();
2670 bool IOService::addNeededResource( const char * key
)
2672 OSObject
* resourcesProp
;
2677 resourcesProp
= getProperty( gIOResourceMatchKey
);
2679 newKey
= OSString::withCString( key
);
2680 if( (0 == resourcesProp
) || (0 == newKey
))
2683 set
= OSDynamicCast( OSSet
, resourcesProp
);
2685 set
= OSSet::withCapacity( 1 );
2687 set
->setObject( resourcesProp
);
2692 set
->setObject( newKey
);
2694 ret
= setProperty( gIOResourceMatchKey
, set
);
2700 bool IOService::checkResource( OSObject
* matching
)
2703 OSDictionary
* table
;
2705 if( (str
= OSDynamicCast( OSString
, matching
))) {
2706 if( gIOResources
->getProperty( str
))
2711 table
= resourceMatching( str
);
2712 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
2715 IOLog("%s: Can't match using: %s\n", getName(),
2716 matching
->getMetaClass()->getClassName());
2717 /* false would stall forever */
2721 if( gIOKitDebug
& kIOLogConfig
)
2722 LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName());
2724 waitForService( table
);
2726 if( gIOKitDebug
& kIOLogConfig
)
2727 LOG("config(%x): waking\n", (int) IOThreadSelf() );
2732 bool IOService::checkResources( void )
2734 OSObject
* resourcesProp
;
2739 resourcesProp
= getProperty( gIOResourceMatchKey
);
2740 if( 0 == resourcesProp
)
2743 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
2745 iter
= OSCollectionIterator::withCollection( set
);
2747 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
2748 ok
= checkResource( resourcesProp
);
2753 ok
= checkResource( resourcesProp
);
2759 void _IOConfigThread::configThread( void )
2761 _IOConfigThread
* inst
;
2764 if( !(inst
= new _IOConfigThread
))
2768 if( !(IOCreateThread((IOThreadFunc
) &_IOConfigThread::main
, inst
)))
2781 void _IOConfigThread::free( void )
2786 void IOService::doServiceMatch( IOOptionBits options
)
2788 _IOServiceNotifier
* notify
;
2790 OSOrderedSet
* matches
;
2791 SInt32 catalogGeneration
;
2792 bool keepGuessing
= true;
2793 bool reRegistered
= true;
2795 // job->nub->deliverNotification( gIOPublishNotification,
2796 // kIOServiceRegisteredState, 0xffffffff );
2798 while( keepGuessing
) {
2800 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
2801 // the matches list should always be created by findDrivers()
2804 lockForArbitration();
2805 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
2806 deliverNotification( gIOFirstPublishNotification
,
2807 kIOServiceFirstPublishState
, 0xffffffff );
2809 __state
[1] &= ~kIOServiceNeedConfigState
;
2810 __state
[1] |= kIOServiceConfigState
;
2811 __state
[0] |= kIOServiceRegisteredState
;
2813 if( reRegistered
&& (0 == (__state
[0] & kIOServiceInactiveState
))) {
2815 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
2816 gNotifications
->getObject( gIOPublishNotification
) );
2818 while((notify
= (_IOServiceNotifier
*)
2819 iter
->getNextObject())) {
2821 if( passiveMatch( notify
->matching
)
2822 && (kIOServiceNotifyEnable
& notify
->state
))
2823 matches
->setObject( notify
);
2830 unlockForArbitration();
2832 if( matches
->getCount() && (kIOReturnSuccess
== getResources()))
2833 probeCandidates( matches
);
2838 lockForArbitration();
2839 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
2841 (reRegistered
|| (catalogGeneration
!=
2842 gIOCatalogue
->getGenerationCount()))
2843 && (0 == (__state
[0] & kIOServiceInactiveState
));
2846 unlockForArbitration();
2849 if( (0 == (__state
[0] & kIOServiceInactiveState
))
2850 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
2851 deliverNotification( gIOMatchedNotification
,
2852 kIOServiceMatchedState
, 0xffffffff );
2853 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
2854 deliverNotification( gIOFirstMatchNotification
,
2855 kIOServiceFirstMatchState
, 0xffffffff );
2858 __state
[1] &= ~kIOServiceConfigState
;
2859 if( __state
[0] & kIOServiceInactiveState
)
2860 scheduleTerminatePhase2();
2863 unlockForArbitration();
2866 UInt32
IOService::_adjustBusy( SInt32 delta
)
2871 bool wasQuiet
, nowQuiet
, needWake
;
2874 result
= __state
[1] & kIOServiceBusyStateMask
;
2878 next
->lockForArbitration();
2879 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
2880 assert( count
< kIOServiceBusyMax
);
2881 wasQuiet
= (0 == count
);
2882 assert( (!wasQuiet
) || (delta
> 0));
2883 next
->__state
[1] += delta
;
2884 nowQuiet
= (0 == (next
->__state
[1] & kIOServiceBusyStateMask
));
2885 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
2888 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
2889 IOLockLock( gIOServiceBusyLock
);
2890 thread_wakeup( (event_t
) next
);
2891 IOLockUnlock( gIOServiceBusyLock
);
2894 next
->unlockForArbitration();
2896 if( (wasQuiet
|| nowQuiet
) ) {
2897 MessageClientsContext context
;
2899 context
.service
= next
;
2900 context
.type
= kIOMessageServiceBusyStateChange
;
2901 context
.argument
= (void *) wasQuiet
; // busy now
2902 context
.argSize
= 0;
2904 applyToInterestNotifiers( next
, gIOBusyInterest
,
2905 &messageClientsApplier
, &context
);
2907 if( nowQuiet
&& (next
== gIOServiceRoot
))
2908 OSMetaClass::considerUnloads();
2911 delta
= nowQuiet
? -1 : +1;
2913 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
2918 void IOService::adjustBusy( SInt32 delta
)
2920 lockForArbitration();
2921 _adjustBusy( delta
);
2922 unlockForArbitration();
2925 UInt32
IOService::getBusyState( void )
2927 return( __state
[1] & kIOServiceBusyStateMask
);
2930 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
2931 mach_timespec_t
* timeout
)
2934 int waitResult
= THREAD_AWAKENED
;
2935 bool computeDeadline
= true;
2936 AbsoluteTime abstime
;
2939 lockForArbitration();
2940 IOLockLock( gIOServiceBusyLock
);
2941 wait
= (value
!= (__state
[1] & mask
));
2943 __state
[1] |= kIOServiceBusyWaiterState
;
2944 unlockForArbitration();
2946 if( computeDeadline
) {
2947 AbsoluteTime nsinterval
;
2948 clock_interval_to_absolutetime_interval(
2949 timeout
->tv_sec
, kSecondScale
, &abstime
);
2950 clock_interval_to_absolutetime_interval(
2951 timeout
->tv_nsec
, kNanosecondScale
, &nsinterval
);
2952 ADD_ABSOLUTETIME( &abstime
, &nsinterval
);
2953 clock_absolutetime_interval_to_deadline(
2954 abstime
, &abstime
);
2955 computeDeadline
= false;
2958 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
2961 assert_wait((event_t
)this, THREAD_UNINT
);
2963 unlockForArbitration();
2964 IOLockUnlock( gIOServiceBusyLock
);
2966 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2968 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2970 if( waitResult
== THREAD_TIMED_OUT
)
2971 return( kIOReturnTimeout
);
2973 return( kIOReturnSuccess
);
2976 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
2978 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
2981 bool IOService::serializeProperties( OSSerialize
* s
) const
2984 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
2985 sizeof( __state
), "__state");
2987 return( super::serializeProperties(s
) );
2991 void _IOConfigThread::main( _IOConfigThread
* self
)
2993 _IOServiceJob
* job
;
3001 semaphore_wait( gJobsSemaphore
);
3003 IOTakeLock( gJobsLock
);
3004 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
3006 gJobs
->removeObject(job
);
3009 // gNumConfigThreads--; // we're out of service
3010 gNumWaitingThreads
--; // we're out of service
3012 IOUnlock( gJobsLock
);
3018 if( gIOKitDebug
& kIOLogConfig
)
3019 LOG("config(%x): starting on %s, %d\n",
3020 (int) IOThreadSelf(), job
->nub
->getName(), job
->type
);
3022 switch( job
->type
) {
3025 nub
->doServiceMatch( job
->options
);
3029 LOG("config(%x): strange type (%d)\n",
3030 (int) IOThreadSelf(), job
->type
);
3037 IOTakeLock( gJobsLock
);
3038 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
3040 gNumWaitingThreads
++; // back in service
3041 // gNumConfigThreads++;
3043 if( 0 == --gNumConfigThreads
) {
3044 // IOLog("MATCH IDLE\n");
3045 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3048 IOUnlock( gJobsLock
);
3053 if( gIOKitDebug
& kIOLogConfig
)
3054 LOG("config(%x): terminating\n", (int) IOThreadSelf() );
3059 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3062 int waitResult
= THREAD_AWAKENED
;
3063 bool computeDeadline
= true;
3064 AbsoluteTime abstime
;
3066 IOLockLock( gJobsLock
);
3068 wait
= (0 != gNumConfigThreads
);
3071 if( computeDeadline
) {
3072 clock_interval_to_absolutetime_interval(
3073 msToWait
, kMillisecondScale
, &abstime
);
3074 clock_absolutetime_interval_to_deadline(
3075 abstime
, &abstime
);
3076 computeDeadline
= false;
3078 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
3079 abstime
, THREAD_UNINT
);
3081 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3085 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3086 IOLockUnlock( gJobsLock
);
3088 if( waitResult
== THREAD_TIMED_OUT
)
3089 return( kIOReturnTimeout
);
3091 return( kIOReturnSuccess
);
3094 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3101 IOTakeLock( gJobsLock
);
3104 gJobs
->setLastObject( job
);
3106 count
= gNumWaitingThreads
;
3107 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3109 create
= ( (gOutstandingJobs
> count
)
3110 && (gNumConfigThreads
< kMaxConfigThreads
) );
3112 gNumConfigThreads
++;
3113 gNumWaitingThreads
++;
3116 IOUnlock( gJobsLock
);
3121 if( gIOKitDebug
& kIOLogConfig
)
3122 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3123 _IOConfigThread::configThread();
3126 semaphore_signal( gJobsSemaphore
);
3129 // internal - call with gNotificationLock
3130 OSObject
* IOService::getExistingServices( OSDictionary
* matching
,
3131 IOOptionBits inState
, IOOptionBits options
)
3133 OSObject
* current
= 0;
3135 IOService
* service
;
3142 && (obj
= matching
->getObject(gIOProviderClassKey
))
3144 && gIOResourcesKey
->isEqualTo(obj
)
3145 && (service
= gIOResources
))
3147 if( (inState
== (service
->__state
[0] & inState
))
3148 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3149 && service
->passiveMatch( matching
))
3151 if( options
& kIONotifyOnce
)
3154 current
= OSSet::withObjects(
3155 (const OSObject
**) &service
, 1, 1 );
3160 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3161 kIORegistryIterateRecursively
);
3165 while( (service
= (IOService
*) iter
->getNextObject())) {
3166 if( (inState
== (service
->__state
[0] & inState
))
3167 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3168 && service
->passiveMatch( matching
)) {
3170 if( options
& kIONotifyOnce
) {
3175 ((OSSet
*)current
)->setObject( service
);
3177 current
= OSSet::withObjects(
3178 (const OSObject
**) &service
, 1, 1 );
3181 } while( !service
&& !iter
->isValid());
3186 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
3187 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3196 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3200 // is a lock even needed?
3203 iter
= (OSIterator
*) getExistingServices( matching
,
3204 kIOServiceMatchedState
);
3212 // internal - call with gNotificationLock
3213 IONotifier
* IOService::setNotification(
3214 const OSSymbol
* type
, OSDictionary
* matching
,
3215 IOServiceNotificationHandler handler
, void * target
, void * ref
,
3218 _IOServiceNotifier
* notify
= 0;
3224 notify
= new _IOServiceNotifier
;
3225 if( notify
&& !notify
->init()) {
3231 notify
->matching
= matching
;
3232 notify
->handler
= handler
;
3233 notify
->target
= target
;
3235 notify
->priority
= priority
;
3236 notify
->state
= kIOServiceNotifyEnable
;
3237 queue_init( ¬ify
->handlerInvocations
);
3241 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3242 set
= OSOrderedSet::withCapacity( 1,
3243 IONotifyOrdering
, 0 );
3245 gNotifications
->setObject( type
, set
);
3249 notify
->whence
= set
;
3251 set
->setObject( notify
);
3257 // internal - call with gNotificationLock
3258 IONotifier
* IOService::doInstallNotification(
3259 const OSSymbol
* type
, OSDictionary
* matching
,
3260 IOServiceNotificationHandler handler
,
3261 void * target
, void * ref
,
3262 SInt32 priority
, OSIterator
** existing
)
3265 IONotifier
* notify
;
3266 IOOptionBits inState
;
3271 if( type
== gIOPublishNotification
)
3272 inState
= kIOServiceRegisteredState
;
3274 else if( type
== gIOFirstPublishNotification
)
3275 inState
= kIOServiceFirstPublishState
;
3277 else if( (type
== gIOMatchedNotification
)
3278 || (type
== gIOFirstMatchNotification
))
3279 inState
= kIOServiceMatchedState
;
3280 else if( type
== gIOTerminatedNotification
)
3285 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3288 // get the current set
3289 exist
= (OSIterator
*) getExistingServices( matching
, inState
);
3299 IONotifier
* IOService::installNotification(
3300 const OSSymbol
* type
, OSDictionary
* matching
,
3301 IOServiceNotificationHandler handler
,
3302 void * target
, void * ref
,
3303 SInt32 priority
, OSIterator
** existing
)
3305 IONotifier
* notify
;
3309 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3310 priority
, existing
);
3317 IONotifier
* IOService::addNotification(
3318 const OSSymbol
* type
, OSDictionary
* matching
,
3319 IOServiceNotificationHandler handler
,
3320 void * target
, void * ref
,
3323 OSIterator
* existing
;
3324 _IOServiceNotifier
* notify
;
3327 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3328 handler
, target
, ref
, priority
, &existing
);
3330 // send notifications for existing set
3333 notify
->retain(); // in case handler remove()s
3334 while( (next
= (IOService
*) existing
->getNextObject())) {
3336 next
->lockForArbitration();
3337 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3338 next
->invokeNotifer( notify
);
3339 next
->unlockForArbitration();
3342 existing
->release();
3348 struct SyncNotifyVars
{
3349 semaphore_port_t waitHere
;
3353 bool IOService::syncNotificationHandler(
3354 void * /* target */, void * ref
,
3355 IOService
* newService
)
3358 // result may get written more than once before the
3359 // notification is removed!
3360 ((SyncNotifyVars
*) ref
)->result
= newService
;
3361 semaphore_signal( ((SyncNotifyVars
*) ref
)->waitHere
);
3366 IOService
* IOService::waitForService( OSDictionary
* matching
,
3367 mach_timespec_t
* timeout
)
3369 IONotifier
* notify
= 0;
3370 // priority doesn't help us much since we need a thread wakeup
3371 SInt32 priority
= 0;
3372 SyncNotifyVars state
;
3373 kern_return_t err
= kIOReturnBadArgument
;
3385 state
.result
= (IOService
*) getExistingServices( matching
,
3386 kIOServiceMatchedState
, kIONotifyOnce
);
3390 err
= semaphore_create( kernel_task
, &state
.waitHere
,
3391 SYNC_POLICY_FIFO
, 0 );
3392 if( KERN_SUCCESS
!= err
)
3395 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
3396 &IOService::syncNotificationHandler
, (void *) 0,
3397 (void *) &state
, priority
);
3405 err
= semaphore_timedwait( state
.waitHere
, *timeout
);
3407 err
= semaphore_wait( state
.waitHere
);
3411 notify
->remove(); // dequeues
3413 matching
->release();
3415 semaphore_destroy( kernel_task
, state
.waitHere
);
3417 return( state
.result
);
3420 void IOService::deliverNotification( const OSSymbol
* type
,
3421 IOOptionBits orNewState
, IOOptionBits andNewState
)
3423 _IOServiceNotifier
* notify
;
3425 OSArray
* willSend
= 0;
3427 lockForArbitration();
3429 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3430 || (type
== gIOTerminatedNotification
)) {
3434 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3435 gNotifications
->getObject( type
) );
3438 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
3440 if( passiveMatch( notify
->matching
)
3441 && (kIOServiceNotifyEnable
& notify
->state
)) {
3443 willSend
= OSArray::withCapacity(8);
3445 willSend
->setObject( notify
);
3451 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
3457 for( unsigned int idx
= 0;
3458 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
3460 invokeNotifer( notify
);
3462 willSend
->release();
3464 unlockForArbitration();
3467 IOOptionBits
IOService::getState( void ) const
3469 return( __state
[0] );
3473 * Helpers to make matching objects for simple cases
3476 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
3477 OSDictionary
* table
)
3480 table
= OSDictionary::withCapacity( 2 );
3482 table
->setObject(gIOProviderClassKey
, (OSObject
*)name
);
3487 OSDictionary
* IOService::serviceMatching( const char * name
,
3488 OSDictionary
* table
)
3490 const OSString
* str
;
3492 str
= OSSymbol::withCString( name
);
3496 table
= serviceMatching( str
, table
);
3501 OSDictionary
* IOService::nameMatching( const OSString
* name
,
3502 OSDictionary
* table
)
3505 table
= OSDictionary::withCapacity( 2 );
3507 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
3512 OSDictionary
* IOService::nameMatching( const char * name
,
3513 OSDictionary
* table
)
3515 const OSString
* str
;
3517 str
= OSSymbol::withCString( name
);
3521 table
= nameMatching( str
, table
);
3526 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
3527 OSDictionary
* table
)
3529 table
= serviceMatching( gIOResourcesKey
, table
);
3531 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
3536 OSDictionary
* IOService::resourceMatching( const char * name
,
3537 OSDictionary
* table
)
3539 const OSSymbol
* str
;
3541 str
= OSSymbol::withCString( name
);
3545 table
= resourceMatching( str
, table
);
3552 * _IOServiceNotifier
3555 // wait for all threads, other than the current one,
3556 // to exit the handler
3558 void _IOServiceNotifier::wait()
3560 _IOServiceNotifierInvocation
* next
;
3565 queue_iterate( &handlerInvocations
, next
,
3566 _IOServiceNotifierInvocation
*, link
) {
3567 if( next
->thread
!= current_thread() ) {
3573 state
|= kIOServiceNotifyWaiter
;
3580 void _IOServiceNotifier::free()
3582 assert( queue_empty( &handlerInvocations
));
3586 void _IOServiceNotifier::remove()
3591 whence
->removeObject( (OSObject
*) this );
3595 matching
->release();
3599 state
&= ~kIOServiceNotifyEnable
;
3608 bool _IOServiceNotifier::disable()
3614 ret
= (0 != (kIOServiceNotifyEnable
& state
));
3615 state
&= ~kIOServiceNotifyEnable
;
3624 void _IOServiceNotifier::enable( bool was
)
3628 state
|= kIOServiceNotifyEnable
;
3630 state
&= ~kIOServiceNotifyEnable
;
3638 IOService
* IOResources::resources( void )
3642 inst
= new IOResources
;
3643 if( inst
&& !inst
->init()) {
3651 IOWorkLoop
* IOResources::getWorkLoop() const
3653 // If we are the resource root then bringe over to the
3654 // platform to get its workloop
3655 if (this == (IOResources
*) gIOResources
)
3656 return getPlatform()->getWorkLoop();
3658 return IOService::getWorkLoop();
3661 bool IOResources::matchPropertyTable( OSDictionary
* table
)
3669 prop
= table
->getObject( gIOResourceMatchKey
);
3670 str
= OSDynamicCast( OSString
, prop
);
3672 ok
= (0 != getProperty( str
));
3674 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
3676 iter
= OSCollectionIterator::withCollection( set
);
3678 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
3679 ok
= (0 != getProperty( str
));
3688 IOReturn
IOResources::setProperties( OSObject
* properties
)
3691 const OSSymbol
* key
;
3692 OSDictionary
* dict
;
3693 OSCollectionIterator
* iter
;
3695 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
3696 if ( kIOReturnSuccess
!= err
)
3699 dict
= OSDynamicCast(OSDictionary
, properties
);
3701 return( kIOReturnBadArgument
);
3703 iter
= OSCollectionIterator::withCollection( dict
);
3705 return( kIOReturnBadArgument
);
3707 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
3709 if (gIOConsoleUsersKey
== key
)
3711 IORegistryEntry::getRegistryRoot()->setProperty(key
, dict
->getObject(key
));
3712 OSIncrementAtomic( &gIOConsoleUsersSeed
);
3713 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
3717 publishResource( key
, dict
->getObject(key
) );
3722 return( kIOReturnSuccess
);
3726 * Helpers for matching dictionaries.
3727 * Keys existing in matching are checked in properties.
3728 * Keys may be a string or OSCollection of IOStrings
3731 bool IOService::compareProperty( OSDictionary
* matching
,
3737 value
= matching
->getObject( key
);
3739 ok
= value
->isEqualTo( getProperty( key
));
3747 bool IOService::compareProperty( OSDictionary
* matching
,
3748 const OSString
* key
)
3753 value
= matching
->getObject( key
);
3755 ok
= value
->isEqualTo( getProperty( key
));
3762 bool IOService::compareProperties( OSDictionary
* matching
,
3763 OSCollection
* keys
)
3765 OSCollectionIterator
* iter
;
3766 const OSString
* key
;
3769 if( !matching
|| !keys
)
3772 iter
= OSCollectionIterator::withCollection( keys
);
3775 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
3776 ok
= compareProperty( matching
, key
);
3780 keys
->release(); // !! consume a ref !!
3785 /* Helper to add a location matching dict to the table */
3787 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
3789 OSDictionary
* dict
;
3794 dict
= OSDictionary::withCapacity( 1 );
3796 table
->setObject( gIOLocationMatchKey
, dict
);
3804 * Go looking for a provider to match a location dict.
3807 IOService
* IOService::matchLocation( IOService
* /* client */ )
3811 parent
= getProvider();
3814 parent
= parent
->matchLocation( this );
3819 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
3825 IORegistryEntry
* entry
;
3830 bool matchParent
= false;
3841 str
= OSDynamicCast( OSString
, table
->getObject( gIOProviderClassKey
));
3844 match
= (0 != where
->metaCast( str
));
3849 obj
= table
->getObject( gIONameMatchKey
);
3852 match
= where
->compareNames( obj
, changesOK
? &matched
: 0 );
3855 if( changesOK
&& matched
) {
3856 // leave a hint as to which name matched
3857 table
->setObject( gIONameMatchedKey
, matched
);
3862 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
3865 const OSSymbol
* sym
;
3869 sym
= where
->copyLocation();
3871 match
= sym
->isEqualTo( str
);
3878 obj
= table
->getObject( gIOPropertyMatchKey
);
3881 OSDictionary
* dict
;
3882 OSDictionary
* nextDict
;
3887 dict
= where
->dictionaryWithProperties();
3889 nextDict
= OSDynamicCast( OSDictionary
, obj
);
3893 iter
= OSCollectionIterator::withCollection(
3894 OSDynamicCast(OSCollection
, obj
));
3897 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
3898 iter
->getNextObject()))))) {
3899 match
= dict
->isEqualTo( nextDict
, nextDict
);
3912 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
3915 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
3916 match
= (where
== entry
);
3923 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
3927 IOService
* service
= 0;
3928 UInt32 serviceCount
= 0;
3931 iter
= where
->getClientIterator();
3933 while( (service
= (IOService
*) iter
->getNextObject())) {
3934 if( kIOServiceInactiveState
& service
->__state
[0])
3936 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
3942 match
= (serviceCount
== num
->unsigned32BitValue());
3947 if( done
== table
->getCount()) {
3948 // don't call family if we've done all the entries in the table
3949 matchParent
= false;
3953 // pass in score from property table
3954 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
3956 // do family specific matching
3957 match
= where
->matchPropertyTable( table
, &score
);
3961 if( kIOLogMatch
& getDebugFlags( table
))
3962 LOG("%s: family specific matching fails\n", where
->getName());
3969 newPri
= OSNumber::withNumber( score
, 32 );
3971 table
->setObject( gIOProbeScoreKey
, newPri
);
3976 if( !(match
= where
->compareProperty( table
, kIOBSDNameKey
)))
3979 matchParent
= false;
3981 obj
= OSDynamicCast( OSDictionary
,
3982 table
->getObject( gIOParentMatchKey
));
3986 table
= (OSDictionary
*) obj
;
3990 table
= OSDynamicCast( OSDictionary
,
3991 table
->getObject( gIOLocationMatchKey
));
3994 where
= where
->getProvider();
3996 where
= where
->matchLocation( where
);
3999 } while( table
&& where
);
4001 } while( matchParent
&& (where
= where
->getProvider()) );
4003 if( kIOLogMatch
& gIOKitDebug
)
4005 LOG("match parent @ %s = %d\n",
4006 where
->getName(), match
);
4012 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4013 UInt32 type
, OSDictionary
* properties
,
4014 IOUserClient
** handler
)
4016 const OSSymbol
*userClientClass
= 0;
4017 IOUserClient
*client
;
4020 // First try my own properties for a user client class name
4021 temp
= getProperty(gIOUserClientClassKey
);
4023 if (OSDynamicCast(OSSymbol
, temp
))
4024 userClientClass
= (const OSSymbol
*) temp
;
4025 else if (OSDynamicCast(OSString
, temp
)) {
4026 userClientClass
= OSSymbol::withString((OSString
*) temp
);
4027 if (userClientClass
)
4028 setProperty(kIOUserClientClassKey
,
4029 (OSObject
*) userClientClass
);
4033 // Didn't find one so lets just bomb out now without further ado.
4034 if (!userClientClass
)
4035 return kIOReturnUnsupported
;
4037 temp
= OSMetaClass::allocClassWithName(userClientClass
);
4039 return kIOReturnNoMemory
;
4041 if (OSDynamicCast(IOUserClient
, temp
))
4042 client
= (IOUserClient
*) temp
;
4045 return kIOReturnUnsupported
;
4048 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
4050 return kIOReturnBadArgument
;
4053 if ( !client
->attach(this) ) {
4055 return kIOReturnUnsupported
;
4058 if ( !client
->start(this) ) {
4059 client
->detach(this);
4061 return kIOReturnUnsupported
;
4065 return kIOReturnSuccess
;
4068 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4069 UInt32 type
, IOUserClient
** handler
)
4071 return( newUserClient( owningTask
, securityID
, type
, 0, handler
));
4074 IOReturn
IOService::requestProbe( IOOptionBits options
)
4076 return( kIOReturnUnsupported
);
4080 * Convert an IOReturn to text. Subclasses which add additional
4081 * IOReturn's should override this method and call
4082 * super::stringFromReturn if the desired value is not found.
4085 const char * IOService::stringFromReturn( IOReturn rtn
)
4087 static const IONamedValue IOReturn_values
[] = {
4088 {kIOReturnSuccess
, "success" },
4089 {kIOReturnError
, "general error" },
4090 {kIOReturnNoMemory
, "memory allocation error" },
4091 {kIOReturnNoResources
, "resource shortage" },
4092 {kIOReturnIPCError
, "Mach IPC failure" },
4093 {kIOReturnNoDevice
, "no such device" },
4094 {kIOReturnNotPrivileged
, "privilege violation" },
4095 {kIOReturnBadArgument
, "invalid argument" },
4096 {kIOReturnLockedRead
, "device is read locked" },
4097 {kIOReturnLockedWrite
, "device is write locked" },
4098 {kIOReturnExclusiveAccess
, "device is exclusive access" },
4099 {kIOReturnBadMessageID
, "bad IPC message ID" },
4100 {kIOReturnUnsupported
, "unsupported function" },
4101 {kIOReturnVMError
, "virtual memory error" },
4102 {kIOReturnInternalError
, "internal driver error" },
4103 {kIOReturnIOError
, "I/O error" },
4104 {kIOReturnCannotLock
, "cannot acquire lock" },
4105 {kIOReturnNotOpen
, "device is not open" },
4106 {kIOReturnNotReadable
, "device is not readable" },
4107 {kIOReturnNotWritable
, "device is not writeable" },
4108 {kIOReturnNotAligned
, "alignment error" },
4109 {kIOReturnBadMedia
, "media error" },
4110 {kIOReturnStillOpen
, "device is still open" },
4111 {kIOReturnRLDError
, "rld failure" },
4112 {kIOReturnDMAError
, "DMA failure" },
4113 {kIOReturnBusy
, "device is busy" },
4114 {kIOReturnTimeout
, "I/O timeout" },
4115 {kIOReturnOffline
, "device is offline" },
4116 {kIOReturnNotReady
, "device is not ready" },
4117 {kIOReturnNotAttached
, "device/channel is not attached" },
4118 {kIOReturnNoChannels
, "no DMA channels available" },
4119 {kIOReturnNoSpace
, "no space for data" },
4120 {kIOReturnPortExists
, "device port already exists" },
4121 {kIOReturnCannotWire
, "cannot wire physical memory" },
4122 {kIOReturnNoInterrupt
, "no interrupt attached" },
4123 {kIOReturnNoFrames
, "no DMA frames enqueued" },
4124 {kIOReturnMessageTooLarge
, "message is too large" },
4125 {kIOReturnNotPermitted
, "operation is not permitted" },
4126 {kIOReturnNoPower
, "device is without power" },
4127 {kIOReturnNoMedia
, "media is not present" },
4128 {kIOReturnUnformattedMedia
, "media is not formatted" },
4129 {kIOReturnUnsupportedMode
, "unsupported mode" },
4130 {kIOReturnUnderrun
, "data underrun" },
4131 {kIOReturnOverrun
, "data overrun" },
4132 {kIOReturnDeviceError
, "device error" },
4133 {kIOReturnNoCompletion
, "no completion routine" },
4134 {kIOReturnAborted
, "operation was aborted" },
4135 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
4136 {kIOReturnNotResponding
, "device is not responding" },
4137 {kIOReturnInvalid
, "unanticipated driver error" },
4141 return IOFindNameForValue(rtn
, IOReturn_values
);
4145 * Convert an IOReturn to an errno.
4147 int IOService::errnoFromReturn( IOReturn rtn
)
4151 case kIOReturnSuccess
:
4153 case kIOReturnNoMemory
:
4155 case kIOReturnNoDevice
:
4157 case kIOReturnVMError
:
4159 case kIOReturnNotPermitted
:
4161 case kIOReturnNotPrivileged
:
4163 case kIOReturnIOError
:
4165 case kIOReturnNotWritable
:
4167 case kIOReturnBadArgument
:
4169 case kIOReturnUnsupported
:
4173 case kIOReturnNoPower
:
4175 case kIOReturnDeviceError
:
4177 case kIOReturnTimeout
:
4179 case kIOReturnMessageTooLarge
:
4181 case kIOReturnNoSpace
:
4183 case kIOReturnCannotLock
:
4187 case kIOReturnBadMessageID
:
4188 case kIOReturnNoCompletion
:
4189 case kIOReturnNotAligned
:
4191 case kIOReturnNotReady
:
4193 case kIOReturnRLDError
:
4195 case kIOReturnPortExists
:
4196 case kIOReturnStillOpen
:
4198 case kIOReturnExclusiveAccess
:
4199 case kIOReturnLockedRead
:
4200 case kIOReturnLockedWrite
:
4201 case kIOReturnNotAttached
:
4202 case kIOReturnNotOpen
:
4203 case kIOReturnNotReadable
:
4205 case kIOReturnCannotWire
:
4206 case kIOReturnNoResources
:
4208 case kIOReturnAborted
:
4209 case kIOReturnOffline
:
4210 case kIOReturnNotResponding
:
4212 case kIOReturnBadMedia
:
4213 case kIOReturnNoMedia
:
4214 case kIOReturnUnformattedMedia
:
4215 return(ENXIO
); // (media error)
4216 case kIOReturnDMAError
:
4217 case kIOReturnOverrun
:
4218 case kIOReturnUnderrun
:
4219 return(EIO
); // (transfer error)
4220 case kIOReturnNoBandwidth
:
4221 case kIOReturnNoChannels
:
4222 case kIOReturnNoFrames
:
4223 case kIOReturnNoInterrupt
:
4224 return(EIO
); // (hardware error)
4225 case kIOReturnError
:
4226 case kIOReturnInternalError
:
4227 case kIOReturnInvalid
:
4228 return(EIO
); // (generic error)
4229 case kIOReturnIPCError
:
4230 return(EIO
); // (ipc error)
4232 return(EIO
); // (all other errors)
4236 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
4240 * Generic entry point for calls from the provider. A return value of
4241 * kIOReturnSuccess indicates that the message was received, and where
4242 * applicable, that it was successful.
4245 return kIOReturnUnsupported
;
4252 IOItemCount
IOService::getDeviceMemoryCount( void )
4257 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4259 count
= array
->getCount();
4266 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
4269 IODeviceMemory
* range
;
4271 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4273 range
= (IODeviceMemory
*) array
->getObject( index
);
4280 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
4281 IOOptionBits options
)
4283 IODeviceMemory
* range
;
4286 range
= getDeviceMemoryWithIndex( index
);
4288 map
= range
->map( options
);
4295 OSArray
* IOService::getDeviceMemory( void )
4297 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
4301 void IOService::setDeviceMemory( OSArray
* array
)
4303 setProperty( gIODeviceMemoryKey
, array
);
4310 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
4312 IOInterruptController
*interruptController
;
4315 OSSymbol
*interruptControllerName
;
4317 IOInterruptSource
*interruptSources
;
4319 // Get the parents list from the nub.
4320 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
4321 if (array
== 0) return kIOReturnNoResources
;
4323 // Allocate space for the IOInterruptSources if needed... then return early.
4324 if (nub
->_interruptSources
== 0) {
4325 numSources
= array
->getCount();
4326 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
4327 if (interruptSources
== 0) return kIOReturnNoMemory
;
4329 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
4331 nub
->_numInterruptSources
= numSources
;
4332 nub
->_interruptSources
= interruptSources
;
4333 return kIOReturnSuccess
;
4336 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
4337 if (interruptControllerName
== 0) return kIOReturnNoResources
;
4339 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
4340 if (interruptController
== 0) return kIOReturnNoResources
;
4342 // Get the interrupt numbers from the nub.
4343 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
4344 if (array
== 0) return kIOReturnNoResources
;
4345 data
= OSDynamicCast(OSData
, array
->getObject(source
));
4346 if (data
== 0) return kIOReturnNoResources
;
4348 // Set the interruptController and interruptSource in the nub's table.
4349 interruptSources
= nub
->_interruptSources
;
4350 interruptSources
[source
].interruptController
= interruptController
;
4351 interruptSources
[source
].vectorData
= data
;
4353 return kIOReturnSuccess
;
4356 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
4360 /* Make sure the _interruptSources are set */
4361 if (_interruptSources
== 0) {
4362 ret
= resolveInterrupt(this, source
);
4363 if (ret
!= kIOReturnSuccess
) return ret
;
4366 /* Make sure the local source number is valid */
4367 if ((source
< 0) || (source
>= _numInterruptSources
))
4368 return kIOReturnNoInterrupt
;
4370 /* Look up the contoller for the local source */
4371 *interruptController
= _interruptSources
[source
].interruptController
;
4373 if (*interruptController
== NULL
) {
4374 if (!resolve
) return kIOReturnNoInterrupt
;
4376 /* Try to reslove the interrupt */
4377 ret
= resolveInterrupt(this, source
);
4378 if (ret
!= kIOReturnSuccess
) return ret
;
4380 *interruptController
= _interruptSources
[source
].interruptController
;
4383 return kIOReturnSuccess
;
4386 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
4387 IOInterruptAction handler
,
4390 IOInterruptController
*interruptController
;
4393 ret
= lookupInterrupt(source
, true, &interruptController
);
4394 if (ret
!= kIOReturnSuccess
) return ret
;
4396 /* Register the source */
4397 return interruptController
->registerInterrupt(this, source
, target
,
4398 (IOInterruptHandler
)handler
,
4402 IOReturn
IOService::unregisterInterrupt(int source
)
4404 IOInterruptController
*interruptController
;
4407 ret
= lookupInterrupt(source
, false, &interruptController
);
4408 if (ret
!= kIOReturnSuccess
) return ret
;
4410 /* Unregister the source */
4411 return interruptController
->unregisterInterrupt(this, source
);
4414 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
4416 IOInterruptController
*interruptController
;
4419 ret
= lookupInterrupt(source
, true, &interruptController
);
4420 if (ret
!= kIOReturnSuccess
) return ret
;
4422 /* Return the type */
4423 return interruptController
->getInterruptType(this, source
, interruptType
);
4426 IOReturn
IOService::enableInterrupt(int source
)
4428 IOInterruptController
*interruptController
;
4431 ret
= lookupInterrupt(source
, false, &interruptController
);
4432 if (ret
!= kIOReturnSuccess
) return ret
;
4434 /* Enable the source */
4435 return interruptController
->enableInterrupt(this, source
);
4438 IOReturn
IOService::disableInterrupt(int source
)
4440 IOInterruptController
*interruptController
;
4443 ret
= lookupInterrupt(source
, false, &interruptController
);
4444 if (ret
!= kIOReturnSuccess
) return ret
;
4446 /* Disable the source */
4447 return interruptController
->disableInterrupt(this, source
);
4450 IOReturn
IOService::causeInterrupt(int source
)
4452 IOInterruptController
*interruptController
;
4455 ret
= lookupInterrupt(source
, false, &interruptController
);
4456 if (ret
!= kIOReturnSuccess
) return ret
;
4458 /* Cause an interrupt for the source */
4459 return interruptController
->causeInterrupt(this, source
);
4462 OSMetaClassDefineReservedUsed(IOService
, 0);
4463 OSMetaClassDefineReservedUsed(IOService
, 1);
4464 OSMetaClassDefineReservedUsed(IOService
, 2);
4465 OSMetaClassDefineReservedUsed(IOService
, 3);
4467 OSMetaClassDefineReservedUnused(IOService
, 4);
4468 OSMetaClassDefineReservedUnused(IOService
, 5);
4469 OSMetaClassDefineReservedUnused(IOService
, 6);
4470 OSMetaClassDefineReservedUnused(IOService
, 7);
4471 OSMetaClassDefineReservedUnused(IOService
, 8);
4472 OSMetaClassDefineReservedUnused(IOService
, 9);
4473 OSMetaClassDefineReservedUnused(IOService
, 10);
4474 OSMetaClassDefineReservedUnused(IOService
, 11);
4475 OSMetaClassDefineReservedUnused(IOService
, 12);
4476 OSMetaClassDefineReservedUnused(IOService
, 13);
4477 OSMetaClassDefineReservedUnused(IOService
, 14);
4478 OSMetaClassDefineReservedUnused(IOService
, 15);
4479 OSMetaClassDefineReservedUnused(IOService
, 16);
4480 OSMetaClassDefineReservedUnused(IOService
, 17);
4481 OSMetaClassDefineReservedUnused(IOService
, 18);
4482 OSMetaClassDefineReservedUnused(IOService
, 19);
4483 OSMetaClassDefineReservedUnused(IOService
, 20);
4484 OSMetaClassDefineReservedUnused(IOService
, 21);
4485 OSMetaClassDefineReservedUnused(IOService
, 22);
4486 OSMetaClassDefineReservedUnused(IOService
, 23);
4487 OSMetaClassDefineReservedUnused(IOService
, 24);
4488 OSMetaClassDefineReservedUnused(IOService
, 25);
4489 OSMetaClassDefineReservedUnused(IOService
, 26);
4490 OSMetaClassDefineReservedUnused(IOService
, 27);
4491 OSMetaClassDefineReservedUnused(IOService
, 28);
4492 OSMetaClassDefineReservedUnused(IOService
, 29);
4493 OSMetaClassDefineReservedUnused(IOService
, 30);
4494 OSMetaClassDefineReservedUnused(IOService
, 31);
4495 OSMetaClassDefineReservedUnused(IOService
, 32);
4496 OSMetaClassDefineReservedUnused(IOService
, 33);
4497 OSMetaClassDefineReservedUnused(IOService
, 34);
4498 OSMetaClassDefineReservedUnused(IOService
, 35);
4499 OSMetaClassDefineReservedUnused(IOService
, 36);
4500 OSMetaClassDefineReservedUnused(IOService
, 37);
4501 OSMetaClassDefineReservedUnused(IOService
, 38);
4502 OSMetaClassDefineReservedUnused(IOService
, 39);
4503 OSMetaClassDefineReservedUnused(IOService
, 40);
4504 OSMetaClassDefineReservedUnused(IOService
, 41);
4505 OSMetaClassDefineReservedUnused(IOService
, 42);
4506 OSMetaClassDefineReservedUnused(IOService
, 43);
4507 OSMetaClassDefineReservedUnused(IOService
, 44);
4508 OSMetaClassDefineReservedUnused(IOService
, 45);
4509 OSMetaClassDefineReservedUnused(IOService
, 46);
4510 OSMetaClassDefineReservedUnused(IOService
, 47);
4511 OSMetaClassDefineReservedUnused(IOService
, 48);
4512 OSMetaClassDefineReservedUnused(IOService
, 49);
4513 OSMetaClassDefineReservedUnused(IOService
, 50);
4514 OSMetaClassDefineReservedUnused(IOService
, 51);
4515 OSMetaClassDefineReservedUnused(IOService
, 52);
4516 OSMetaClassDefineReservedUnused(IOService
, 53);
4517 OSMetaClassDefineReservedUnused(IOService
, 54);
4518 OSMetaClassDefineReservedUnused(IOService
, 55);
4519 OSMetaClassDefineReservedUnused(IOService
, 56);
4520 OSMetaClassDefineReservedUnused(IOService
, 57);
4521 OSMetaClassDefineReservedUnused(IOService
, 58);
4522 OSMetaClassDefineReservedUnused(IOService
, 59);
4523 OSMetaClassDefineReservedUnused(IOService
, 60);
4524 OSMetaClassDefineReservedUnused(IOService
, 61);
4525 OSMetaClassDefineReservedUnused(IOService
, 62);
4526 OSMetaClassDefineReservedUnused(IOService
, 63);