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 * Copyright (c) 1991-1999 Apple Computer, Inc. All rights reserved.
27 * 29-Jan-91 Portions from IODevice.m, Doug Mitchell at NeXT, Created.
28 * 18-Jun-98 start IOKit objc
29 * 10-Nov-98 start iokit cpp
30 * 25-Feb-99 sdouglas, add threads and locks to ensure deadlock
34 #include <IOKit/system.h>
36 #include <IOKit/IOService.h>
37 #include <libkern/c++/OSContainers.h>
38 #include <libkern/c++/OSUnserialize.h>
39 #include <IOKit/IOCatalogue.h>
40 #include <IOKit/IODeviceMemory.h>
41 #include <IOKit/IOInterrupts.h>
42 #include <IOKit/IOInterruptController.h>
43 #include <IOKit/IOPlatformExpert.h>
44 #include <IOKit/IOMessage.h>
45 #include <IOKit/IOLib.h>
46 #include <IOKit/IOKitKeys.h>
47 #include <IOKit/IOBSD.h>
48 #include <IOKit/IOUserClient.h>
50 //#define LESS_THREAD_CREATE
54 #include "IOServicePrivate.h"
55 #include <mach/sync_policy.h>
57 #include <IOKit/assert.h>
59 #include <sys/errno.h>
61 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
63 #define super IORegistryEntry
65 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
67 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
69 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
71 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
73 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
75 OSDefineMetaClassAndStructors(IOResources
, IOService
)
77 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
79 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
81 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
83 static IOPlatformExpert
* gIOPlatform
;
84 const IORegistryPlane
* gIOServicePlane
;
85 const IORegistryPlane
* gIOPowerPlane
;
86 const OSSymbol
* gIODeviceMemoryKey
;
87 const OSSymbol
* gIOInterruptControllersKey
;
88 const OSSymbol
* gIOInterruptSpecifiersKey
;
90 const OSSymbol
* gIOResourcesKey
;
91 const OSSymbol
* gIOResourceMatchKey
;
92 const OSSymbol
* gIOProviderClassKey
;
93 const OSSymbol
* gIONameMatchKey
;
94 const OSSymbol
* gIONameMatchedKey
;
95 const OSSymbol
* gIOPropertyMatchKey
;
96 const OSSymbol
* gIOLocationMatchKey
;
97 const OSSymbol
* gIOPathMatchKey
;
98 const OSSymbol
* gIOMatchCategoryKey
;
99 const OSSymbol
* gIODefaultMatchCategoryKey
;
100 const OSSymbol
* gIOMatchedServiceCountKey
;
102 const OSSymbol
* gIOUserClientClassKey
;
103 const OSSymbol
* gIOKitDebugKey
;
105 const OSSymbol
* gIOCommandPoolSizeKey
;
107 static int gIOResourceGenerationCount
;
109 const OSSymbol
* gIOServiceKey
;
110 const OSSymbol
* gIOPublishNotification
;
111 const OSSymbol
* gIOFirstPublishNotification
;
112 const OSSymbol
* gIOMatchedNotification
;
113 const OSSymbol
* gIOFirstMatchNotification
;
114 const OSSymbol
* gIOTerminatedNotification
;
116 const OSSymbol
* gIOGeneralInterest
;
117 const OSSymbol
* gIOBusyInterest
;
118 const OSSymbol
* gIOAppPowerStateInterest
;
120 static OSDictionary
* gNotifications
;
121 static IORecursiveLock
* gNotificationLock
;
123 static IOService
* gIOResources
;
124 static IOService
* gIOServiceRoot
;
126 static OSOrderedSet
* gJobs
;
127 static semaphore_port_t gJobsSemaphore
;
128 static IOLock
* gJobsLock
;
129 static int gOutstandingJobs
;
130 static int gNumConfigThreads
;
131 static int gNumWaitingThreads
;
132 static IOLock
* gIOServiceBusyLock
;
134 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
136 #define LOCKREADNOTIFY() \
137 IORecursiveLockLock( gNotificationLock )
138 #define LOCKWRITENOTIFY() \
139 IORecursiveLockLock( gNotificationLock )
140 #define LOCKWRITE2READNOTIFY()
141 #define UNLOCKNOTIFY() \
142 IORecursiveLockUnlock( gNotificationLock )
144 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
146 struct ArbitrationLockQueueElement
{
155 static queue_head_t gArbitrationLockQueueActive
;
156 static queue_head_t gArbitrationLockQueueWaiting
;
157 static queue_head_t gArbitrationLockQueueFree
;
158 static IOLock
* gArbitrationLockQueueLock
;
160 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
162 void IOService::initialize( void )
166 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
167 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
169 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
170 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
171 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
172 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
173 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
174 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
176 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
177 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
178 kIODefaultMatchCategoryKey
);
179 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
180 kIOMatchedServiceCountKey
);
182 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
184 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
185 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
187 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
188 gIOInterruptControllersKey
189 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
190 gIOInterruptSpecifiersKey
191 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
193 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
195 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
197 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
198 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
199 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
201 gNotifications
= OSDictionary::withCapacity( 1 );
202 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
203 kIOPublishNotification
);
204 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
205 kIOFirstPublishNotification
);
206 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
207 kIOMatchedNotification
);
208 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
209 kIOFirstMatchNotification
);
210 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
211 kIOTerminatedNotification
);
212 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
214 gNotificationLock
= IORecursiveLockAlloc();
216 assert( gIOServicePlane
&& gIODeviceMemoryKey
217 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
218 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
219 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
220 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
221 && gIOPublishNotification
&& gIOMatchedNotification
222 && gIOTerminatedNotification
&& gIOServiceKey
);
224 gJobsLock
= IOLockAlloc();
225 gJobs
= OSOrderedSet::withCapacity( 10 );
227 gIOServiceBusyLock
= IOLockAlloc();
229 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
231 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& (err
== KERN_SUCCESS
) );
233 gIOResources
= IOResources::resources();
234 assert( gIOResources
);
236 gArbitrationLockQueueLock
= IOLockAlloc();
237 queue_init(&gArbitrationLockQueueActive
);
238 queue_init(&gArbitrationLockQueueWaiting
);
239 queue_init(&gArbitrationLockQueueFree
);
241 assert( gArbitrationLockQueueLock
);
243 #ifdef LESS_THREAD_CREATE
244 for( int i
= 0; i
< kMaxConfigThreads
; i
++)
245 _IOConfigThread::configThread();
250 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
253 static UInt64
getDebugFlags( OSDictionary
* props
)
255 OSNumber
* debugProp
;
258 debugProp
= OSDynamicCast( OSNumber
,
259 props
->getObject( gIOKitDebugKey
));
261 debugFlags
= debugProp
->unsigned64BitValue();
263 debugFlags
= gIOKitDebug
;
265 return( debugFlags
);
269 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
271 // Probe a matched service and return an instance to be started.
272 // The default score is from the property table, & may be altered
273 // during probe to change the start order.
275 IOService
* IOService::probe( IOService
* /* provider */,
276 SInt32
* /* score */)
281 bool IOService::start( IOService
* provider
)
286 void IOService::stop( IOService
* /* provider */ )
291 * Attach in service plane
293 bool IOService::attach( IOService
* provider
)
299 if( gIOKitDebug
& kIOLogAttach
)
300 LOG( "%s::attach(%s)\n", getName(),
301 provider
->getName());
303 provider
->lockForArbitration();
304 if( provider
->__state
[0] & kIOServiceInactiveState
)
307 ok
= attachToParent( provider
, gIOServicePlane
);
308 provider
->unlockForArbitration();
312 gIOServiceRoot
= this;
313 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
314 gIOResources
->attachToParent( getRegistryRoot(),
316 publishResource("IOKit");
322 IOService
* IOService::getServiceRoot( void )
324 return( gIOServiceRoot
);
327 void IOService::detach( IOService
* provider
)
329 if( gIOKitDebug
& kIOLogAttach
)
330 LOG("%s::detach(%s)\n", getName(), provider
->getName());
332 lockForArbitration();
334 if( (__state
[1] & kIOServiceBusyStateMask
)
335 && (provider
== getProvider()))
336 provider
->adjustBusy( -1 );
338 detachFromParent( provider
, gIOServicePlane
);
340 unlockForArbitration();
344 * Register instance - publish it for matching
347 void IOService::registerService( IOOptionBits options
= 0 )
353 enum { kMaxPathLen
= 256 };
354 enum { kMaxChars
= 63 };
356 IORegistryEntry
* parent
= this;
357 IORegistryEntry
* root
= getRegistryRoot();
358 while( parent
&& (parent
!= root
))
359 parent
= parent
->getParentEntry( gIOServicePlane
);
361 if( parent
!= root
) {
362 IOLog("%s: not registry member at registerService()\n", getName());
366 // Allow the Platform Expert to adjust this node.
367 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
370 if( (this != gIOResources
)
371 && (kIOLogRegister
& gIOKitDebug
)) {
373 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
375 IOLog( "Registering: " );
378 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
381 if( len
> kMaxChars
) {
385 if( (skip
= strchr( path
, '/')))
391 IOLog( "%s\n", path
);
394 IOFree( pathBuf
, kMaxPathLen
);
397 startMatching( options
);
400 void IOService::startMatching( IOOptionBits options
= 0 )
402 IOService
* provider
;
407 lockForArbitration();
409 sync
= (options
& kIOServiceSynchronous
)
410 || ((provider
= getProvider())
411 && (provider
->__state
[1] & kIOServiceSynchronousState
));
413 __state
[1] |= kIOServiceSynchronousState
;
415 __state
[1] &= ~kIOServiceSynchronousState
;
417 needConfig
= (0 == (__state
[1] & kIOServiceConfigState
))
418 && (0 == (__state
[0] & kIOServiceInactiveState
))
419 && (kIOServiceRegisteredState
!=
420 (__state
[0] & (kIOServiceRegisteredState
421 | kIOServiceMatchedState
)));
422 __state
[1] |= kIOServiceConfigState
;
423 // __state[0] &= ~kIOServiceInactiveState;
425 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
426 // OSKernelStackRemaining(), getName());
428 unlockForArbitration();
433 doServiceMatch( options
);
436 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
440 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
442 OSDictionary
* table
;
451 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
454 iter
= (OSIterator
*) getExistingServices( table
,
455 kIOServiceMatchedState
);
458 while( (service
= (IOService
*) iter
->getNextObject())) {
459 service
->startMatching();
467 if( getDebugFlags( table
) & kIOLogMatch
)
468 LOG("Matching service count = %ld\n", count
);
470 newTables
->removeObject(table
);
473 newTables
->release();
475 return( kIOReturnSuccess
);
478 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
479 IOOptionBits options
= 0 )
483 job
= new _IOServiceJob
;
484 if( job
&& !job
->init()) {
492 job
->options
= options
;
493 nub
->retain(); // thread will release()
501 * Called on a registered service to see if it matches
505 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
507 return( matchPropertyTable(table
) );
510 bool IOService::matchPropertyTable( OSDictionary
* table
)
516 * Called on a matched service to allocate resources
517 * before first driver is attached.
520 IOReturn
IOService::getResources( void )
522 return( kIOReturnSuccess
);
526 * Client/provider accessors
529 IOService
* IOService::getProvider( void ) const
531 IOService
* self
= (IOService
*) this;
536 generation
= getGenerationCount();
537 if( __providerGeneration
== generation
)
540 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
541 if( parent
== IORegistryEntry::getRegistryRoot())
542 /* root is not an IOService */
545 self
->__provider
= parent
;
546 // save the count before getParentEntry()
547 self
->__providerGeneration
= generation
;
552 IOWorkLoop
* IOService::getWorkLoop() const
554 IOService
*provider
= getProvider();
557 return provider
->getWorkLoop();
562 OSIterator
* IOService::getProviderIterator( void ) const
564 return( getParentIterator( gIOServicePlane
));
567 IOService
* IOService::getClient( void ) const
569 return( (IOService
*) getChildEntry( gIOServicePlane
));
572 OSIterator
* IOService::getClientIterator( void ) const
574 return( getChildIterator( gIOServicePlane
));
577 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
578 const IOService
* client
,
579 const IOService
* provider
)
581 _IOOpenServiceIterator
* inst
;
586 inst
= new _IOOpenServiceIterator
;
588 if( inst
&& !inst
->init()) {
594 inst
->client
= client
;
595 inst
->provider
= provider
;
601 void _IOOpenServiceIterator::free()
605 last
->unlockForArbitration();
609 OSObject
* _IOOpenServiceIterator::getNextObject()
614 last
->unlockForArbitration();
616 while( (next
= (IOService
*) iter
->getNextObject())) {
618 next
->lockForArbitration();
619 if( (client
&& (next
->isOpen( client
)))
620 || (provider
&& (provider
->isOpen( next
))) )
622 next
->unlockForArbitration();
630 bool _IOOpenServiceIterator::isValid()
632 return( iter
->isValid() );
635 void _IOOpenServiceIterator::reset()
638 last
->unlockForArbitration();
644 OSIterator
* IOService::getOpenProviderIterator( void ) const
646 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
649 OSIterator
* IOService::getOpenClientIterator( void ) const
651 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
655 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
656 bool waitForFunction
,
657 void *param1
, void *param2
,
658 void *param3
, void *param4
)
660 IOReturn result
= kIOReturnUnsupported
;
661 IOService
*provider
= getProvider();
664 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
665 param1
, param2
, param3
, param4
);
671 IOReturn
IOService::callPlatformFunction( const char * functionName
,
672 bool waitForFunction
,
673 void *param1
, void *param2
,
674 void *param3
, void *param4
)
676 IOReturn result
= kIOReturnNoMemory
;
677 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
679 if (functionSymbol
!= 0) {
680 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
681 param1
, param2
, param3
, param4
);
682 functionSymbol
->release();
690 * Platform expert accessors
693 IOPlatformExpert
* IOService::getPlatform( void )
695 return( gIOPlatform
);
698 void IOService::setPlatform( IOPlatformExpert
* platform
)
700 gIOPlatform
= platform
;
707 bool IOService::lockForArbitration( bool isSuccessRequired
= true )
711 ArbitrationLockQueueElement
* element
;
712 ArbitrationLockQueueElement
* active
;
713 ArbitrationLockQueueElement
* waiting
;
715 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
717 // lock global access
718 IOTakeLock( gArbitrationLockQueueLock
);
720 // obtain an unused queue element
721 if( !queue_empty( &gArbitrationLockQueueFree
)) {
722 queue_remove_first( &gArbitrationLockQueueFree
,
724 ArbitrationLockQueueElement
*,
727 element
= IONew( ArbitrationLockQueueElement
, 1 );
731 // prepare the queue element
732 element
->thread
= IOThreadSelf();
733 element
->service
= this;
735 element
->required
= isSuccessRequired
;
736 element
->aborted
= false;
738 // determine whether this object is already locked (ie. on active queue)
740 queue_iterate( &gArbitrationLockQueueActive
,
742 ArbitrationLockQueueElement
*,
745 if( active
->service
== element
->service
) {
751 if( found
) { // this object is already locked
753 // determine whether it is the same or a different thread trying to lock
754 if( active
->thread
!= element
->thread
) { // it is a different thread
756 ArbitrationLockQueueElement
* victim
= 0;
758 // before placing this new thread on the waiting queue, we look for
759 // a deadlock cycle...
762 // determine whether the active thread holding the object we
763 // want is waiting for another object to be unlocked
765 queue_iterate( &gArbitrationLockQueueWaiting
,
767 ArbitrationLockQueueElement
*,
770 if( waiting
->thread
== active
->thread
) {
771 assert( false == waiting
->aborted
);
777 if( found
) { // yes, active thread waiting for another object
779 // this may be a candidate for rejection if the required
780 // flag is not set, should we detect a deadlock later on
781 if( false == waiting
->required
)
784 // find the thread that is holding this other object, that
785 // is blocking the active thread from proceeding (fun :-)
787 queue_iterate( &gArbitrationLockQueueActive
,
788 active
, // (reuse active queue element)
789 ArbitrationLockQueueElement
*,
792 if( active
->service
== waiting
->service
) {
798 // someone must be holding it or it wouldn't be waiting
801 if( active
->thread
== element
->thread
) {
803 // doh, it's waiting for the thread that originated
804 // this whole lock (ie. current thread) -> deadlock
805 if( false == element
->required
) { // willing to fail?
807 // the originating thread doesn't have the required
808 // flag, so it can fail
809 success
= false; // (fail originating lock request)
810 break; // (out of while)
812 } else { // originating thread is not willing to fail
814 // see if we came across a waiting thread that did
815 // not have the 'required' flag set: we'll fail it
818 // we do have a willing victim, fail it's lock
819 victim
->aborted
= true;
821 // take the victim off the waiting queue
822 queue_remove( &gArbitrationLockQueueWaiting
,
824 ArbitrationLockQueueElement
*,
828 thread_wakeup_one(victim
);
830 // allow this thread to proceed (ie. wait)
831 success
= true; // (put request on wait queue)
832 break; // (out of while)
835 // all the waiting threads we came across in
836 // finding this loop had the 'required' flag
837 // set, so we've got a deadlock we can't avoid
838 panic("I/O Kit: Unrecoverable deadlock.");
842 // repeat while loop, redefining active thread to be the
843 // thread holding "this other object" (see above), and
844 // looking for threads waiting on it; note the active
845 // variable points to "this other object" already... so
846 // there nothing to do in this else clause.
848 } else { // no, active thread is not waiting for another object
850 success
= true; // (put request on wait queue)
851 break; // (out of while)
855 if( success
) { // put the request on the waiting queue?
856 kern_return_t wait_result
;
858 // place this thread on the waiting queue and put it to sleep;
859 // we place it at the tail of the queue...
860 queue_enter( &gArbitrationLockQueueWaiting
,
862 ArbitrationLockQueueElement
*,
865 // declare that this thread will wait for a given event
866 restart_sleep
: assert_wait( element
,
867 element
->required
? THREAD_UNINT
868 : THREAD_INTERRUPTIBLE
);
870 // unlock global access
871 IOUnlock( gArbitrationLockQueueLock
);
873 // put thread to sleep, waiting for our event to fire...
874 wait_result
= thread_block((void (*)(void)) 0);
876 // ...and we've been woken up; we might be in one of two states:
877 // (a) we've been aborted and our queue element is not on
878 // any of the three queues, but is floating around
879 // (b) we're allowed to proceed with the lock and we have
880 // already been moved from the waiting queue to the
882 // ...plus a 3rd state, should the thread have been interrupted:
883 // (c) we're still on the waiting queue
885 // determine whether we were interrupted out of our sleep
886 if( THREAD_INTERRUPTED
== wait_result
) {
888 // re-lock global access
889 IOTakeLock( gArbitrationLockQueueLock
);
891 // determine whether we're still on the waiting queue
893 queue_iterate( &gArbitrationLockQueueWaiting
,
894 waiting
, // (reuse waiting queue element)
895 ArbitrationLockQueueElement
*,
898 if( waiting
== element
) {
904 if( found
) { // yes, we're still on the waiting queue
906 // determine whether we're willing to fail
907 if( false == element
->required
) {
909 // mark us as aborted
910 element
->aborted
= true;
912 // take us off the waiting queue
913 queue_remove( &gArbitrationLockQueueWaiting
,
915 ArbitrationLockQueueElement
*,
917 } else { // we are not willing to fail
919 // ignore interruption, go back to sleep
924 // unlock global access
925 IOUnlock( gArbitrationLockQueueLock
);
927 // proceed as though this were a normal wake up
928 wait_result
= THREAD_AWAKENED
;
931 assert( THREAD_AWAKENED
== wait_result
);
933 // determine whether we've been aborted while we were asleep
934 if( element
->aborted
) {
935 assert( false == element
->required
);
937 // re-lock global access
938 IOTakeLock( gArbitrationLockQueueLock
);
940 action
= kPutOnFreeQueue
;
942 } else { // we weren't aborted, so we must be ready to go :-)
944 // we've already been moved from waiting to active queue
948 } else { // the lock request is to be failed
950 // return unused queue element to queue
951 action
= kPutOnFreeQueue
;
953 } else { // it is the same thread, recursive access is allowed
955 // add one level of recursion
958 // return unused queue element to queue
959 action
= kPutOnFreeQueue
;
962 } else { // this object is not already locked, so let this thread through
963 action
= kPutOnActiveQueue
;
967 // put the new element on a queue
968 if( kPutOnActiveQueue
== action
) {
969 queue_enter( &gArbitrationLockQueueActive
,
971 ArbitrationLockQueueElement
*,
973 } else if( kPutOnFreeQueue
== action
) {
974 queue_enter( &gArbitrationLockQueueFree
,
976 ArbitrationLockQueueElement
*,
979 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
982 // unlock global access
983 IOUnlock( gArbitrationLockQueueLock
);
988 void IOService::unlockForArbitration( void )
991 ArbitrationLockQueueElement
* element
;
993 // lock global access
994 IOTakeLock( gArbitrationLockQueueLock
);
996 // find the lock element for this object (ie. on active queue)
998 queue_iterate( &gArbitrationLockQueueActive
,
1000 ArbitrationLockQueueElement
*,
1003 if( element
->service
== this ) {
1011 // determine whether the lock has been taken recursively
1012 if( element
->count
> 1 ) {
1013 // undo one level of recursion
1018 // remove it from the active queue
1019 queue_remove( &gArbitrationLockQueueActive
,
1021 ArbitrationLockQueueElement
*,
1024 // put it on the free queue
1025 queue_enter( &gArbitrationLockQueueFree
,
1027 ArbitrationLockQueueElement
*,
1030 // determine whether a thread is waiting for object (head to tail scan)
1032 queue_iterate( &gArbitrationLockQueueWaiting
,
1034 ArbitrationLockQueueElement
*,
1037 if( element
->service
== this ) {
1043 if ( found
) { // we found an interested thread on waiting queue
1045 // remove it from the waiting queue
1046 queue_remove( &gArbitrationLockQueueWaiting
,
1048 ArbitrationLockQueueElement
*,
1051 // put it on the active queue
1052 queue_enter( &gArbitrationLockQueueActive
,
1054 ArbitrationLockQueueElement
*,
1057 // wake the waiting thread
1058 thread_wakeup_one(element
);
1062 // unlock global access
1063 IOUnlock( gArbitrationLockQueueLock
);
1066 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1069 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1070 context
, gIOServicePlane
);
1073 void IOService::applyToClients( IOServiceApplierFunction applier
,
1076 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1077 context
, gIOServicePlane
);
1086 // send a message to a client or interested party of this service
1087 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1088 void * argument
= 0, vm_size_t argSize
= 0 )
1091 IOService
* service
;
1092 _IOServiceInterestNotifier
* notify
;
1094 if( (service
= OSDynamicCast( IOService
, client
)))
1095 ret
= service
->message( type
, this, argument
);
1097 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1099 _IOServiceNotifierInvocation invocation
;
1102 invocation
.thread
= current_thread();
1105 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1108 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1109 _IOServiceNotifierInvocation
*, link
);
1115 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1116 type
, this, argument
, argSize
);
1119 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1120 _IOServiceNotifierInvocation
*, link
);
1121 if( kIOServiceNotifyWaiter
& notify
->state
) {
1122 notify
->state
&= ~kIOServiceNotifyWaiter
;
1123 thread_wakeup( (event_t
) notify
);
1128 ret
= kIOReturnSuccess
;
1131 ret
= kIOReturnBadArgument
;
1136 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1137 OSObjectApplierFunction applier
,
1143 OSArray
* copyArray
;
1145 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1148 array
= OSDynamicCast( OSArray
, getProperty( typeOfInterest
));
1150 copyArray
= OSArray::withArray( array
);
1154 (next
= array
->getObject( index
));
1156 (*applier
)(next
, context
);
1158 copyArray
->release();
1164 struct MessageClientsContext
{
1165 IOService
* service
;
1172 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1175 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1177 ret
= context
->service
->messageClient( context
->type
,
1178 object
, context
->argument
, context
->argSize
);
1179 if( kIOReturnSuccess
!= ret
)
1183 // send a message to all clients
1184 IOReturn
IOService::messageClients( UInt32 type
,
1185 void * argument
= 0, vm_size_t argSize
= 0 )
1187 MessageClientsContext context
;
1189 context
.service
= this;
1190 context
.type
= type
;
1191 context
.argument
= argument
;
1192 context
.argSize
= argSize
;
1193 context
.ret
= kIOReturnSuccess
;
1195 applyToInterested( gIOGeneralInterest
,
1196 &messageClientsApplier
, &context
);
1198 return( context
.ret
);
1201 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1202 IOOptionBits response
)
1204 return( kIOReturnUnsupported
);
1207 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1208 IOServiceInterestHandler handler
, void * target
, void * ref
)
1210 _IOServiceInterestNotifier
* notify
= 0;
1213 if( (typeOfInterest
!= gIOGeneralInterest
)
1214 && (typeOfInterest
!= gIOBusyInterest
)
1215 && (typeOfInterest
!= gIOAppPowerStateInterest
))
1218 lockForArbitration();
1219 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1221 notify
= new _IOServiceInterestNotifier
;
1222 if( notify
&& !notify
->init()) {
1228 notify
->handler
= handler
;
1229 notify
->target
= target
;
1231 notify
->state
= kIOServiceNotifyEnable
;
1232 queue_init( ¬ify
->handlerInvocations
);
1237 if( 0 == (set
= (OSArray
*) getProperty( typeOfInterest
))) {
1238 set
= OSArray::withCapacity( 1 );
1240 setProperty( typeOfInterest
, set
);
1244 notify
->whence
= set
;
1246 set
->setObject( notify
);
1250 unlockForArbitration();
1255 static void cleanInterestArray( OSObject
* object
)
1259 _IOServiceInterestNotifier
* next
;
1261 if( (array
= OSDynamicCast( OSArray
, object
))) {
1264 (next
= (_IOServiceInterestNotifier
*)
1265 array
->getObject( index
));
1273 void IOService::unregisterAllInterest( void )
1275 cleanInterestArray( getProperty( gIOGeneralInterest
));
1276 cleanInterestArray( getProperty( gIOBusyInterest
));
1280 * _IOServiceInterestNotifier
1283 // wait for all threads, other than the current one,
1284 // to exit the handler
1286 void _IOServiceInterestNotifier::wait()
1288 _IOServiceNotifierInvocation
* next
;
1293 queue_iterate( &handlerInvocations
, next
,
1294 _IOServiceNotifierInvocation
*, link
) {
1295 if( next
->thread
!= current_thread() ) {
1301 state
|= kIOServiceNotifyWaiter
;
1302 assert_wait( this, THREAD_UNINT
);
1304 thread_block((void (*)(void)) 0);
1311 void _IOServiceInterestNotifier::free()
1313 assert( queue_empty( &handlerInvocations
));
1317 void _IOServiceInterestNotifier::remove()
1322 whence
->removeObject(whence
->getNextIndexOfObject(
1323 (OSObject
*) this, 0 ));
1327 state
&= ~kIOServiceNotifyEnable
;
1336 bool _IOServiceInterestNotifier::disable()
1342 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1343 state
&= ~kIOServiceNotifyEnable
;
1352 void _IOServiceInterestNotifier::enable( bool was
)
1356 state
|= kIOServiceNotifyEnable
;
1358 state
&= ~kIOServiceNotifyEnable
;
1367 // a method in case someone needs to override it
1368 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
1372 if( client
->isParent( this, gIOServicePlane
, true))
1373 // we are the clients only provider
1374 ok
= client
->terminate( options
);
1381 struct TerminateClientsContext
{
1382 IOService
* provider
;
1383 IOOptionBits options
;
1386 static void terminateInterestApplier( OSObject
* object
, void * ctx
)
1388 TerminateClientsContext
* context
= (TerminateClientsContext
*) ctx
;
1390 context
->provider
->messageClient( kIOMessageServiceIsTerminated
,
1391 object
, (void *) context
->options
);
1394 static void terminateClientsApplier( IOService
* client
, void * ctx
)
1396 TerminateClientsContext
* context
= (TerminateClientsContext
*) ctx
;
1398 if( gIOKitDebug
& kIOLogYield
)
1399 LOG("%s::terminateClient(%s,%08lx)\n",
1400 context
->provider
->getName(),
1401 client
->getName(), context
->options
);
1403 context
->provider
->terminateClient( client
,
1404 ((context
->options
) | kIOServiceRecursing
) & ~kIOServiceSynchronous
);
1407 static void terminateRequestClose( IOService
* client
, void * ctx
)
1409 TerminateClientsContext
* context
= (TerminateClientsContext
*) ctx
;
1410 IOService
* provider
= context
->provider
;
1412 if( provider
->isOpen( client
)) {
1413 if( gIOKitDebug
& kIOLogYield
)
1414 LOG("%s::terminate request close(%s,%08lx)\n",
1415 provider
->getName(),
1416 client
->getName(), context
->options
);
1417 provider
->messageClient( kIOMessageServiceIsRequestingClose
,
1418 client
, (void *) context
->options
);
1422 bool IOService::terminate( IOOptionBits options
= 0 )
1427 TerminateClientsContext context
;
1429 if( false == lockForArbitration( (options
& kIOServiceRequired
) ))
1434 context
.provider
= this;
1435 context
.options
= options
;
1437 ok
= (options
& kIOServiceRequired
);
1438 wasClosed
= (false == handleIsOpen( 0 ));
1443 applyToClients( &terminateRequestClose
, (void *) &context
);
1444 wasClosed
= (false == handleIsOpen( 0 ));
1449 madeInactive
= (0 == (__state
[0] & kIOServiceInactiveState
));
1451 __state
[0] |= kIOServiceInactiveState
;
1452 __state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
);
1453 if( 0 == (options
& kIOServiceRecursing
))
1454 __state
[1] |= kIOServiceTerminatedState
;
1457 madeInactive
= false;
1459 unlockForArbitration();
1464 applyToInterested( gIOGeneralInterest
,
1465 &terminateInterestApplier
, (void *) &context
);
1467 deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1469 applyToClients( &terminateClientsApplier
, (void *) &context
);
1471 if( wasClosed
&& (0 == (options
& kIOServiceRecursing
))) {
1472 if( options
& kIOServiceSynchronous
)
1473 doServiceTerminate( 0 );
1475 ok
= (0 != _IOServiceJob::startJob( this, kTerminateNubJob
, 0 ));
1477 if( options
& kIOServiceSynchronous
)
1486 void IOService::doServiceTerminate( IOOptionBits options
)
1491 OSArray
* deathList
= 0;
1497 deathList
= OSArray::withObjects( & (const OSObject
*) next
, 1, 1 );
1498 assert( deathList
);
1504 iter
= next
->getClientIterator();
1508 while( (client
= (IOService
*) iter
->getNextObject())) {
1510 if( gIOKitDebug
& kIOLogYield
)
1511 LOG("%s::actionClients(%s)\n",
1512 next
->getName(), client
->getName());
1514 client
->stop( next
);
1516 if( next
->isOpen( client
))
1517 next
->close( client
);
1519 client
->detach( next
);
1521 client
->lockForArbitration();
1522 if( (client
->__state
[0] & kIOServiceInactiveState
)
1523 && (0 == (client
->__state
[1] & kIOServiceTerminatedState
))
1524 && (0 == client
->getProvider()) ) {
1525 client
->__state
[1] |= kIOServiceTerminatedState
;
1526 finalize
= (false == client
->handleIsOpen( 0 ));
1529 client
->unlockForArbitration();
1532 deathList
->setObject( client
);
1537 } while( (next
= (IOService
*) deathList
->getObject( ++index
)) );
1541 next
= (IOService
*) deathList
->getObject( index
);
1544 deathList
->removeObject( index
);
1546 IOUserClient::destroyUserReferences( next
);
1548 next
->unregisterAllInterest();
1550 ok
= next
->finalize( options
);
1553 if( gIOKitDebug
& kIOLogYield
)
1554 LOG("%s __state = %08lx:%08lx\n", next
->getName(),
1555 next
->__state
[0], next
->__state
[1]);
1556 next
->adjustBusy( -1 );
1561 deathList
->release();
1564 bool IOService::finalize( IOOptionBits options
)
1567 IOService
* provider
;
1569 iter
= getProviderIterator();
1573 while( (provider
= (IOService
*) iter
->getNextObject())) {
1574 /* we come down here on programmatic terminate */
1576 if( provider
->isOpen( this ))
1577 provider
->close( this );
1590 bool IOService::open( IOService
* forClient
,
1591 IOOptionBits options
= 0,
1596 if( false == lockForArbitration(false) )
1599 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
1601 ok
= handleOpen( forClient
, options
, arg
);
1603 unlockForArbitration();
1608 void IOService::close( IOService
* forClient
,
1609 IOOptionBits options
= 0 )
1617 lockForArbitration();
1619 wasClosed
= handleIsOpen( forClient
);
1621 handleClose( forClient
, options
);
1623 last
= ( (__state
[1] & kIOServiceTerminatedState
)
1624 && (false == handleIsOpen( 0 )) );
1627 unlockForArbitration();
1630 ok
= (0 != _IOServiceJob::startJob( this, kTerminateNubJob
, 0 ));
1633 } else if( wasClosed
) {
1635 iter
= getClientIterator();
1639 while( (client
= (IOService
*) iter
->getNextObject())) {
1640 if( client
!= forClient
)
1641 messageClient( kIOMessageServiceWasClosed
, client
, 0 );
1648 bool IOService::isOpen( const IOService
* forClient
= 0 ) const
1650 IOService
* self
= (IOService
*) this;
1653 self
->lockForArbitration();
1655 ok
= handleIsOpen( forClient
);
1657 self
->unlockForArbitration();
1662 bool IOService::handleOpen( IOService
* forClient
,
1663 IOOptionBits options
,
1668 ok
= (0 == __owner
);
1670 __owner
= forClient
;
1672 else if( options
& kIOServiceSeize
) {
1673 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
1674 __owner
, (void *) options
));
1675 if( ok
&& (0 == __owner
))
1676 __owner
= forClient
;
1682 void IOService::handleClose( IOService
* forClient
,
1683 IOOptionBits options
)
1685 if( __owner
== forClient
)
1689 bool IOService::handleIsOpen( const IOService
* forClient
) const
1692 return( __owner
== forClient
);
1694 return( __owner
!= forClient
);
1698 * Probing & starting
1700 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
1702 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
1703 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
1711 val1
= obj1
->priority
;
1714 val2
= obj2
->priority
;
1716 return ( val1
- val2
);
1719 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
1721 OSDictionary
* dict
;
1722 IOService
* service
;
1723 _IOServiceNotifier
* notify
;
1724 OSSymbol
* key
= (OSSymbol
*) ref
;
1727 if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
1728 return( notify
->priority
);
1730 else if( (service
= OSDynamicCast( IOService
, entry
)))
1731 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
1732 else if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
1733 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
1740 return( (SInt32
) offset
->unsigned32BitValue());
1742 return( kIODefaultProbeScore
);
1745 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
1747 const OSObject
* obj1
= (const OSObject
*) inObj1
;
1748 const OSObject
* obj2
= (const OSObject
*) inObj2
;
1756 val1
= IOServiceObjectOrder( obj1
, ref
);
1759 val2
= IOServiceObjectOrder( obj2
, ref
);
1761 return ( val1
- val2
);
1764 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
1766 IOService
* service
= 0;
1768 const OSSymbol
* nextCat
;
1770 iter
= getClientIterator();
1772 while( (service
= (IOService
*) iter
->getNextObject())) {
1773 if( kIOServiceInactiveState
& service
->__state
[0])
1775 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
1776 service
->getProperty( gIOMatchCategoryKey
));
1777 if( category
== nextCat
)
1785 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
1787 _IOServiceNotifierInvocation invocation
;
1791 invocation
.thread
= current_thread();
1794 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1797 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1798 _IOServiceNotifierInvocation
*, link
);
1804 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
, this );
1807 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1808 _IOServiceNotifierInvocation
*, link
);
1809 if( kIOServiceNotifyWaiter
& notify
->state
) {
1810 notify
->state
&= ~kIOServiceNotifyWaiter
;
1811 thread_wakeup( (event_t
) notify
);
1820 * Alloc and probe matching classes,
1821 * called on the provider instance
1824 void IOService::probeCandidates( OSOrderedSet
* matches
)
1826 OSDictionary
* match
= 0;
1829 IOService
* newInst
;
1830 OSDictionary
* props
;
1833 OSOrderedSet
* familyMatches
= 0;
1834 OSOrderedSet
* startList
;
1835 OSDictionary
* startDict
= 0;
1836 const OSSymbol
* category
;
1838 _IOServiceNotifier
* notify
;
1839 OSObject
* nextMatch
= 0;
1841 bool needReloc
= false;
1847 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
1849 nextMatch
->retain();
1850 matches
->removeObject(nextMatch
);
1852 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
1854 lockForArbitration();
1855 if( 0 == (__state
[0] & kIOServiceInactiveState
))
1856 invokeNotifer( notify
);
1857 unlockForArbitration();
1858 nextMatch
->release();
1862 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
1863 nextMatch
->release();
1870 debugFlags
= getDebugFlags( match
);
1874 category
= OSDynamicCast( OSSymbol
,
1875 match
->getObject( gIOMatchCategoryKey
));
1877 category
= gIODefaultMatchCategoryKey
;
1879 if( getClientWithCategory( category
)) {
1881 if( debugFlags
& kIOLogMatch
)
1882 LOG("%s: match category %s exists\n", getName(),
1883 category
->getCStringNoCopy());
1885 nextMatch
->release();
1890 // create a copy now in case its modified during matching
1891 props
= OSDictionary::withDictionary( match
, match
->getCount());
1894 props
->setCapacityIncrement(1);
1896 // check the nub matches
1897 if( false == passiveMatch( props
, true ))
1900 // Check to see if driver reloc has been loaded.
1901 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
1904 if( debugFlags
& kIOLogCatalogue
)
1905 LOG("%s: stalling for module\n", getName());
1907 // If reloc hasn't been loaded, exit;
1908 // reprobing will occur after reloc has been loaded.
1912 // reorder on family matchPropertyTable score.
1913 if( 0 == familyMatches
)
1914 familyMatches
= OSOrderedSet::withCapacity( 1,
1915 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
1917 familyMatches
->setObject( props
);
1922 nextMatch
->release();
1931 if( familyMatches
) {
1934 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
1937 familyMatches
->removeObject( props
);
1942 debugFlags
= getDebugFlags( props
);
1945 symbol
= OSDynamicCast( OSSymbol
,
1946 props
->getObject( gIOClassKey
));
1950 // alloc the driver instance
1951 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
1954 IOLog("Couldn't alloc class \"%s\"\n",
1955 symbol
->getCStringNoCopy());
1959 // init driver instance
1960 if( !(inst
->init( props
))) {
1962 if( debugFlags
& kIOLogStart
)
1963 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
1967 if( __state
[1] & kIOServiceSynchronousState
)
1968 inst
->__state
[1] |= kIOServiceSynchronousState
;
1970 // give the driver the default match category if not specified
1971 category
= OSDynamicCast( OSSymbol
,
1972 props
->getObject( gIOMatchCategoryKey
));
1974 category
= gIODefaultMatchCategoryKey
;
1975 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
1977 // attach driver instance
1978 if( !(inst
->attach( this )))
1981 // pass in score from property table
1982 score
= familyMatches
->orderObject( props
);
1984 // & probe the new driver instance
1986 if( debugFlags
& kIOLogProbe
)
1987 LOG("%s::probe(%s)\n",
1988 inst
->getMetaClass()->getClassName(), getName());
1991 newInst
= inst
->probe( this, &score
);
1992 inst
->detach( this );
1995 if( debugFlags
& kIOLogProbe
)
1996 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2002 newPri
= OSNumber::withNumber( score
, 32 );
2004 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2008 // add to start list for the match category
2010 startDict
= OSDictionary::withCapacity( 1 );
2011 assert( startDict
);
2012 startList
= (OSOrderedSet
*)
2013 startDict
->getObject( category
);
2014 if( 0 == startList
) {
2015 startList
= OSOrderedSet::withCapacity( 1,
2016 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2017 if( startDict
&& startList
) {
2018 startDict
->setObject( category
, startList
);
2019 startList
->release();
2022 assert( startList
);
2024 startList
->setObject( newInst
);
2032 familyMatches
->release();
2036 // start the best (until success) of each category
2038 iter
= OSCollectionIterator::withCollection( startDict
);
2040 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2042 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2043 assert( startList
);
2048 while( true // (!started)
2049 && (inst
= (IOService
*)startList
->getFirstObject())) {
2052 startList
->removeObject(inst
);
2055 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2057 if( debugFlags
& kIOLogStart
) {
2059 LOG( "match category exists, skipping " );
2060 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2061 getName(), inst
->getRetainCount());
2064 if( false == started
)
2065 started
= startCandidate( inst
);
2067 if( (debugFlags
& kIOLogStart
) && (false == started
))
2068 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2069 inst
->getRetainCount());
2078 startDict
->release();
2082 * Start a previously attached & probed instance,
2083 * called on exporting object instance
2086 bool IOService::startCandidate( IOService
* service
)
2090 ok
= service
->attach( this );
2093 // stall for any nub resources
2095 // stall for any driver resources
2096 service
->checkResources();
2098 ok
= service
->start( this );
2100 service
->detach( this );
2105 IOService
* IOService::resources( void )
2107 return( gIOResources
);
2110 void IOService::publishResource( const char * key
, OSObject
* value
= 0 )
2112 const OSSymbol
* sym
;
2114 if( (sym
= OSSymbol::withCString( key
))) {
2115 publishResource( sym
, value
);
2120 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
= 0 )
2123 value
= (OSObject
*) gIOServiceKey
;
2125 gIOResources
->setProperty( key
, value
);
2127 gIOResourceGenerationCount
++;
2128 gIOResources
->registerService();
2131 bool IOService::addNeededResource( const char * key
)
2133 OSObject
* resources
;
2138 resources
= getProperty( gIOResourceMatchKey
);
2140 newKey
= OSString::withCString( key
);
2141 if( (0 == resources
) || (0 == newKey
))
2144 set
= OSDynamicCast( OSSet
, resources
);
2146 set
= OSSet::withCapacity( 1 );
2148 set
->setObject( resources
);
2153 set
->setObject( newKey
);
2155 ret
= setProperty( gIOResourceMatchKey
, set
);
2161 bool IOService::checkResource( OSObject
* matching
)
2164 OSDictionary
* table
;
2166 if( (str
= OSDynamicCast( OSString
, matching
))) {
2167 if( gIOResources
->getProperty( str
))
2172 table
= resourceMatching( str
);
2173 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
2176 IOLog("%s: Can't match using: %s\n", getName(),
2177 matching
->getMetaClass()->getClassName());
2178 /* false would stall forever */
2182 if( gIOKitDebug
& kIOLogConfig
)
2183 LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName());
2185 waitForService( table
);
2187 if( gIOKitDebug
& kIOLogConfig
)
2188 LOG("config(%x): waking\n", (int) IOThreadSelf() );
2193 bool IOService::checkResources( void )
2195 OSObject
* resources
;
2200 resources
= getProperty( gIOResourceMatchKey
);
2204 if( (set
= OSDynamicCast( OSSet
, resources
))) {
2206 iter
= OSCollectionIterator::withCollection( set
);
2208 while( ok
&& (resources
= iter
->getNextObject()) )
2209 ok
= checkResource( resources
);
2214 ok
= checkResource( resources
);
2220 _IOConfigThread
* _IOConfigThread::configThread( void )
2222 _IOConfigThread
* inst
;
2225 if( !(inst
= new _IOConfigThread
))
2229 if( !(inst
->thread
= IOCreateThread
2230 ( (IOThreadFunc
) &_IOConfigThread::main
, inst
)))
2243 void _IOConfigThread::free( void )
2248 void IOService::doServiceMatch( IOOptionBits options
)
2250 _IOServiceNotifier
* notify
;
2252 OSOrderedSet
* matches
;
2253 SInt32 catalogGeneration
;
2254 bool keepGuessing
= true;
2255 bool reRegistered
= true;
2257 // job->nub->deliverNotification( gIOPublishNotification,
2258 // kIOServiceRegisteredState, 0xffffffff );
2260 while( keepGuessing
) {
2262 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
2263 // the matches list should always be created by findDrivers()
2266 lockForArbitration();
2267 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
2268 deliverNotification( gIOFirstPublishNotification
,
2269 kIOServiceFirstPublishState
, 0xffffffff );
2271 __state
[1] &= ~kIOServiceConfigState
;
2272 __state
[0] |= kIOServiceRegisteredState
;
2274 if( reRegistered
&& (0 == (__state
[0] & kIOServiceInactiveState
))) {
2276 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
2277 gNotifications
->getObject( gIOPublishNotification
) );
2279 while((notify
= (_IOServiceNotifier
*)
2280 iter
->getNextObject())) {
2282 if( passiveMatch( notify
->matching
)
2283 && (kIOServiceNotifyEnable
& notify
->state
))
2284 matches
->setObject( notify
);
2291 unlockForArbitration();
2293 if( matches
->getCount() && (kIOReturnSuccess
== getResources()))
2294 probeCandidates( matches
);
2299 lockForArbitration();
2300 reRegistered
= (0 != (__state
[1] & kIOServiceConfigState
));
2302 (reRegistered
|| (catalogGeneration
!=
2303 gIOCatalogue
->getGenerationCount()))
2304 && (0 == (__state
[0] & kIOServiceInactiveState
));
2307 unlockForArbitration();
2310 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
2311 deliverNotification( gIOMatchedNotification
,
2312 kIOServiceMatchedState
, 0xffffffff );
2313 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
2314 deliverNotification( gIOFirstMatchNotification
,
2315 kIOServiceFirstMatchState
, 0xffffffff );
2318 unlockForArbitration();
2323 void IOService::adjustBusy( SInt32 delta
)
2327 bool wasQuiet
, nowQuiet
;
2332 IOTakeLock( gIOServiceBusyLock
);
2336 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
2337 assert( count
< kIOServiceBusyMax
);
2338 wasQuiet
= (0 == count
);
2339 assert( (!wasQuiet
) || (delta
> 0));
2340 next
->__state
[1] += delta
;
2341 nowQuiet
= (0 == (next
->__state
[1] & kIOServiceBusyStateMask
));
2344 thread_wakeup( (event_t
) next
);
2346 if( (wasQuiet
|| nowQuiet
) ) {
2349 OSObject
* interested
;
2351 array
= OSDynamicCast( OSArray
, next
->getProperty( gIOBusyInterest
));
2355 (interested
= array
->getObject( index
));
2357 next
->messageClient(kIOMessageServiceBusyStateChange
,
2358 interested
, (void *) wasQuiet
/* busy now */);
2363 if( nowQuiet
&& (next
== gIOServiceRoot
))
2364 OSMetaClass::considerUnloads();
2367 delta
= nowQuiet
? -1 : +1;
2369 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
2371 IOUnlock( gIOServiceBusyLock
);
2374 UInt32
IOService::getBusyState( void )
2376 return( __state
[1] & kIOServiceBusyStateMask
);
2379 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
2380 mach_timespec_t
* timeout
= 0 )
2383 int waitResult
= THREAD_AWAKENED
;
2384 bool computeDeadline
= true;
2385 AbsoluteTime abstime
;
2388 IOTakeLock( gIOServiceBusyLock
);
2389 wait
= (value
!= (__state
[1] & mask
));
2392 assert_wait( (event_t
) this, THREAD_UNINT
);
2395 if ( computeDeadline
)
2397 AbsoluteTime nsinterval
;
2398 clock_interval_to_absolutetime_interval(
2399 timeout
->tv_sec
, kSecondScale
, &abstime
);
2400 clock_interval_to_absolutetime_interval(
2401 timeout
->tv_nsec
, kNanosecondScale
, &nsinterval
);
2402 ADD_ABSOLUTETIME( &abstime
, &nsinterval
);
2403 clock_absolutetime_interval_to_deadline(
2404 abstime
, &abstime
);
2405 computeDeadline
= false;
2407 thread_set_timer_deadline( abstime
);
2410 IOUnlock( gIOServiceBusyLock
);
2413 waitResult
= thread_block((void (*)(void)) 0);
2414 if ( timeout
&& (waitResult
!= THREAD_TIMED_OUT
))
2415 thread_cancel_timer();
2418 } while( wait
&& ( waitResult
!= THREAD_TIMED_OUT
) );
2420 if ( waitResult
== THREAD_TIMED_OUT
)
2421 return( kIOReturnTimeout
);
2423 return( kIOReturnSuccess
);
2426 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
= 0 )
2428 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
2431 bool IOService::serializeProperties( OSSerialize
* s
) const
2434 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
2435 sizeof( __state
), "__state");
2437 return( super::serializeProperties(s
) );
2441 void _IOConfigThread::main( _IOConfigThread
* self
)
2443 _IOServiceJob
* job
;
2450 #define randomDelay() \
2451 int del = read_processor_clock(); \
2452 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
2457 semaphore_wait( gJobsSemaphore
);
2459 IOTakeLock( gJobsLock
);
2460 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
2462 gJobs
->removeObject(job
);
2465 #ifndef LESS_THREAD_CREATE
2466 // gNumConfigThreads--; // we're out of service
2467 gNumWaitingThreads
--; // we're out of service
2470 IOUnlock( gJobsLock
);
2476 if( gIOKitDebug
& kIOLogConfig
)
2477 LOG("config(%x): starting on %s, %d\n",
2478 (int) IOThreadSelf(), job
->nub
->getName(), job
->type
);
2480 switch( job
->type
) {
2483 nub
->doServiceMatch( job
->options
);
2486 case kTerminateNubJob
:
2487 nub
->doServiceTerminate( job
->options
);
2491 LOG("config(%x): strange type (%d)\n",
2492 (int) IOThreadSelf(), job
->type
);
2499 IOTakeLock( gJobsLock
);
2500 #ifndef LESS_THREAD_CREATE
2501 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
2503 gNumWaitingThreads
++; // back in service
2504 // gNumConfigThreads++;
2506 gNumConfigThreads
--;
2508 IOUnlock( gJobsLock
);
2513 if( gIOKitDebug
& kIOLogConfig
)
2514 LOG("config(%x): terminating\n", (int) IOThreadSelf() );
2519 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
2526 IOTakeLock( gJobsLock
);
2529 gJobs
->setLastObject( job
);
2531 count
= gNumWaitingThreads
;
2532 // if( gNumConfigThreads) count++;// assume we're called from a config thread
2534 create
= ( (gOutstandingJobs
> count
)
2535 && (gNumConfigThreads
< kMaxConfigThreads
) );
2537 gNumConfigThreads
++;
2538 gNumWaitingThreads
++;
2541 IOUnlock( gJobsLock
);
2546 if( gIOKitDebug
& kIOLogConfig
)
2547 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
2548 _IOConfigThread::configThread();
2551 semaphore_signal( gJobsSemaphore
);
2555 // internal - call with gNotificationLock
2556 OSObject
* IOService::getExistingServices( OSDictionary
* matching
,
2557 IOOptionBits inState
, IOOptionBits options
= 0 )
2559 OSObject
* current
= 0;
2561 IOService
* service
;
2566 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
2567 kIORegistryIterateRecursively
);
2571 while( (service
= (IOService
*) iter
->getNextObject())) {
2572 if( (inState
== (service
->__state
[0] & inState
))
2573 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
2574 && service
->passiveMatch( matching
)) {
2576 if( options
& kIONotifyOnce
) {
2581 ((OSSet
*)current
)->setObject( service
);
2583 current
= OSSet::withObjects(
2584 & (const OSObject
*) service
, 1, 1 );
2587 } while( !service
&& !iter
->isValid());
2591 if( current
&& (0 == (options
& kIONotifyOnce
))) {
2592 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
2601 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
2605 // is a lock even needed?
2608 iter
= (OSIterator
*) getExistingServices( matching
,
2609 kIOServiceRegisteredState
);
2617 // internal - call with gNotificationLock
2618 IONotifier
* IOService::setNotification(
2619 const OSSymbol
* type
, OSDictionary
* matching
,
2620 IOServiceNotificationHandler handler
, void * target
, void * ref
,
2621 SInt32 priority
= 0 )
2623 _IOServiceNotifier
* notify
= 0;
2629 notify
= new _IOServiceNotifier
;
2630 if( notify
&& !notify
->init()) {
2636 notify
->matching
= matching
;
2637 notify
->handler
= handler
;
2638 notify
->target
= target
;
2640 notify
->priority
= priority
;
2641 notify
->state
= kIOServiceNotifyEnable
;
2642 queue_init( ¬ify
->handlerInvocations
);
2646 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
2647 set
= OSOrderedSet::withCapacity( 1,
2648 IONotifyOrdering
, 0 );
2650 gNotifications
->setObject( type
, set
);
2654 notify
->whence
= set
;
2656 set
->setObject( notify
);
2662 // internal - call with gNotificationLock
2663 IONotifier
* IOService::doInstallNotification(
2664 const OSSymbol
* type
, OSDictionary
* matching
,
2665 IOServiceNotificationHandler handler
,
2666 void * target
, void * ref
,
2667 SInt32 priority
, OSIterator
** existing
)
2670 IONotifier
* notify
;
2671 IOOptionBits inState
;
2676 if( (type
== gIOPublishNotification
)
2677 || (type
== gIOFirstPublishNotification
))
2678 inState
= kIOServiceRegisteredState
;
2679 else if( (type
== gIOMatchedNotification
)
2680 || (type
== gIOFirstMatchNotification
))
2681 inState
= kIOServiceMatchedState
;
2682 else if( type
== gIOTerminatedNotification
)
2687 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
2690 // get the current set
2691 exist
= (OSIterator
*) getExistingServices( matching
, inState
);
2701 IONotifier
* IOService::installNotification(
2702 const OSSymbol
* type
, OSDictionary
* matching
,
2703 IOServiceNotificationHandler handler
,
2704 void * target
, void * ref
,
2705 SInt32 priority
, OSIterator
** existing
)
2707 IONotifier
* notify
;
2711 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
2712 priority
, existing
);
2719 IONotifier
* IOService::addNotification(
2720 const OSSymbol
* type
, OSDictionary
* matching
,
2721 IOServiceNotificationHandler handler
,
2722 void * target
, void * ref
= 0,
2723 SInt32 priority
= 0 )
2725 OSIterator
* existing
;
2726 _IOServiceNotifier
* notify
;
2729 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
2730 handler
, target
, ref
, priority
, &existing
);
2732 // send notifications for existing set
2735 notify
->retain(); // in case handler remove()s
2736 while( (next
= (IOService
*) existing
->getNextObject())) {
2738 next
->lockForArbitration();
2739 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
2740 next
->invokeNotifer( notify
);
2741 next
->unlockForArbitration();
2744 existing
->release();
2750 struct SyncNotifyVars
{
2751 semaphore_port_t waitHere
;
2755 bool IOService::syncNotificationHandler(
2756 void * /* target */, void * ref
,
2757 IOService
* newService
)
2760 // result may get written more than once before the
2761 // notification is removed!
2762 ((SyncNotifyVars
*) ref
)->result
= newService
;
2763 semaphore_signal( ((SyncNotifyVars
*) ref
)->waitHere
);
2768 IOService
* IOService::waitForService( OSDictionary
* matching
,
2769 mach_timespec_t
* timeout
= 0 )
2771 IONotifier
* notify
= 0;
2772 // priority doesn't help us much since we need a thread wakeup
2773 SInt32 priority
= 0;
2774 SyncNotifyVars state
;
2775 kern_return_t err
= kIOReturnBadArgument
;
2787 state
.result
= (IOService
*) getExistingServices( matching
,
2788 kIOServiceMatchedState
, kIONotifyOnce
);
2792 err
= semaphore_create( kernel_task
, &state
.waitHere
,
2793 SYNC_POLICY_FIFO
, 0 );
2794 if( KERN_SUCCESS
!= err
)
2797 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
2798 &IOService::syncNotificationHandler
, (void *) 0,
2799 (void *) &state
, priority
);
2807 err
= semaphore_timedwait( state
.waitHere
, *timeout
);
2809 err
= semaphore_wait( state
.waitHere
);
2813 notify
->remove(); // dequeues
2815 matching
->release();
2817 semaphore_destroy( kernel_task
, state
.waitHere
);
2819 return( state
.result
);
2822 void IOService::deliverNotification( const OSSymbol
* type
,
2823 IOOptionBits orNewState
, IOOptionBits andNewState
)
2825 _IOServiceNotifier
* notify
;
2827 OSArray
* willSend
= 0;
2829 lockForArbitration();
2831 if( (0 == (__state
[0] & kIOServiceInactiveState
))
2832 || (type
== gIOTerminatedNotification
)) {
2836 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
2837 gNotifications
->getObject( type
) );
2840 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
2842 if( passiveMatch( notify
->matching
)
2843 && (kIOServiceNotifyEnable
& notify
->state
)) {
2845 willSend
= OSArray::withCapacity(8);
2847 willSend
->setObject( notify
);
2853 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
2859 for( unsigned int idx
= 0;
2860 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
2862 invokeNotifer( notify
);
2864 willSend
->release();
2866 unlockForArbitration();
2869 IOOptionBits
IOService::getState( void ) const
2871 return( __state
[0] );
2875 * Helpers to make matching objects for simple cases
2878 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
2879 OSDictionary
* table
= 0 )
2882 table
= OSDictionary::withCapacity( 2 );
2884 table
->setObject(gIOProviderClassKey
, (OSObject
*)name
);
2889 OSDictionary
* IOService::serviceMatching( const char * name
,
2890 OSDictionary
* table
= 0 )
2892 const OSString
* str
;
2894 str
= OSSymbol::withCString( name
);
2898 table
= serviceMatching( str
, table
);
2903 OSDictionary
* IOService::nameMatching( const OSString
* name
,
2904 OSDictionary
* table
= 0 )
2907 table
= OSDictionary::withCapacity( 2 );
2909 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
2914 OSDictionary
* IOService::nameMatching( const char * name
,
2915 OSDictionary
* table
= 0 )
2917 const OSString
* str
;
2919 str
= OSSymbol::withCString( name
);
2923 table
= nameMatching( str
, table
);
2928 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
2929 OSDictionary
* table
= 0 )
2931 table
= serviceMatching( gIOResourcesKey
, table
);
2933 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
2938 OSDictionary
* IOService::resourceMatching( const char * name
,
2939 OSDictionary
* table
= 0 )
2941 const OSSymbol
* str
;
2943 str
= OSSymbol::withCString( name
);
2947 table
= resourceMatching( str
, table
);
2954 * _IOServiceNotifier
2957 // wait for all threads, other than the current one,
2958 // to exit the handler
2960 void _IOServiceNotifier::wait()
2962 _IOServiceNotifierInvocation
* next
;
2967 queue_iterate( &handlerInvocations
, next
,
2968 _IOServiceNotifierInvocation
*, link
) {
2969 if( next
->thread
!= current_thread() ) {
2975 state
|= kIOServiceNotifyWaiter
;
2976 assert_wait( this, THREAD_UNINT
);
2978 thread_block((void (*)(void)) 0);
2985 void _IOServiceNotifier::free()
2987 assert( queue_empty( &handlerInvocations
));
2991 void _IOServiceNotifier::remove()
2996 whence
->removeObject( (OSObject
*) this );
3000 matching
->release();
3004 state
&= ~kIOServiceNotifyEnable
;
3013 bool _IOServiceNotifier::disable()
3019 ret
= (0 != (kIOServiceNotifyEnable
& state
));
3020 state
&= ~kIOServiceNotifyEnable
;
3029 void _IOServiceNotifier::enable( bool was
)
3033 state
|= kIOServiceNotifyEnable
;
3035 state
&= ~kIOServiceNotifyEnable
;
3043 IOService
* IOResources::resources( void )
3047 inst
= new IOResources
;
3048 if( inst
&& !inst
->init()) {
3056 IOWorkLoop
* IOResources::getWorkLoop() const
3058 // If we are the resource root then bringe over to the
3059 // platform to get its workloop
3060 if (this == (IOResources
*) gIOResources
)
3061 return getPlatform()->getWorkLoop();
3063 return IOService::getWorkLoop();
3066 bool IOResources::matchPropertyTable( OSDictionary
* table
)
3074 prop
= table
->getObject( gIOResourceMatchKey
);
3075 str
= OSDynamicCast( OSString
, prop
);
3077 ok
= (0 != getProperty( str
));
3079 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
3081 iter
= OSCollectionIterator::withCollection( set
);
3083 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
3084 ok
= (0 != getProperty( str
));
3094 * Helpers for matching dictionaries.
3095 * Keys existing in matching are checked in properties.
3096 * Keys may be a string or OSCollection of IOStrings
3099 bool IOService::compareProperty( OSDictionary
* matching
,
3105 value
= matching
->getObject( key
);
3107 ok
= value
->isEqualTo( getProperty( key
));
3115 bool IOService::compareProperty( OSDictionary
* matching
,
3116 const OSString
* key
)
3121 value
= matching
->getObject( key
);
3123 ok
= value
->isEqualTo( getProperty( key
));
3130 bool IOService::compareProperties( OSDictionary
* matching
,
3131 OSCollection
* keys
)
3133 OSCollectionIterator
* iter
;
3134 const OSString
* key
;
3137 if( !matching
|| !keys
)
3140 iter
= OSCollectionIterator::withCollection( keys
);
3143 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
3144 ok
= compareProperty( matching
, key
);
3148 keys
->release(); // !! consume a ref !!
3153 /* Helper to add a location matching dict to the table */
3155 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
3157 OSDictionary
* dict
;
3162 dict
= OSDictionary::withCapacity( 1 );
3164 table
->setObject( gIOLocationMatchKey
, dict
);
3172 * Go looking for a provider to match a location dict.
3175 IOService
* IOService::matchLocation( IOService
* /* client */ )
3179 parent
= getProvider();
3182 parent
= parent
->matchLocation( this );
3187 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
3193 IORegistryEntry
* entry
;
3207 str
= OSDynamicCast( OSString
, table
->getObject( gIOProviderClassKey
));
3210 match
= (0 != where
->metaCast( str
));
3215 obj
= table
->getObject( gIONameMatchKey
);
3218 match
= compareNames( obj
, changesOK
? &matched
: 0 );
3221 if( changesOK
&& matched
) {
3222 // leave a hint as to which name matched
3223 table
->setObject( gIONameMatchedKey
, matched
);
3227 obj
= table
->getObject( gIOPropertyMatchKey
);
3230 OSDictionary
* dict
;
3231 OSDictionary
* nextDict
;
3235 dict
= where
->dictionaryWithProperties();
3237 nextDict
= OSDynamicCast( OSDictionary
, obj
);
3241 iter
= OSCollectionIterator::withCollection(
3242 OSDynamicCast(OSCollection
, obj
));
3245 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
3246 iter
->getNextObject()))))) {
3247 match
= dict
->isEqualTo( nextDict
, nextDict
);
3260 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
3263 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
3264 match
= (where
== entry
);
3271 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
3275 IOService
* service
= 0;
3276 UInt32 serviceCount
= 0;
3279 iter
= getClientIterator();
3281 while( (service
= (IOService
*) iter
->getNextObject())) {
3282 if( kIOServiceInactiveState
& service
->__state
[0])
3284 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
3290 match
= (serviceCount
== num
->unsigned32BitValue());
3295 if( done
== table
->getCount())
3296 // don't call family if we've done all the entries in the table
3299 // pass in score from property table
3300 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
3302 // do family specific matching
3303 match
= where
->matchPropertyTable( table
, &score
);
3307 if( kIOLogMatch
& getDebugFlags( table
))
3308 LOG("%s: family specific matching fails\n", where
->getName());
3315 newPri
= OSNumber::withNumber( score
, 32 );
3317 table
->setObject( gIOProbeScoreKey
, newPri
);
3322 if( !(match
= where
->compareProperty( table
, kIOBSDNameKey
)))
3325 table
= OSDynamicCast( OSDictionary
,
3326 table
->getObject( gIOLocationMatchKey
));
3329 where
= where
->getProvider();
3331 where
= where
->matchLocation( where
);
3334 } while( table
&& where
);
3336 if( kIOLogMatch
& gIOKitDebug
)
3338 LOG("match location @ %s = %d\n",
3339 where
->getName(), match
);
3345 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
3346 UInt32 type
, OSDictionary
* properties
,
3347 IOUserClient
** handler
)
3349 const OSSymbol
*userClientClass
= 0;
3350 IOUserClient
*client
;
3353 // First try my own properties for a user client class name
3354 temp
= getProperty(gIOUserClientClassKey
);
3356 if (OSDynamicCast(OSSymbol
, temp
))
3357 userClientClass
= (const OSSymbol
*) temp
;
3358 else if (OSDynamicCast(OSString
, temp
)) {
3359 userClientClass
= OSSymbol::withString((OSString
*) temp
);
3360 if (userClientClass
)
3361 setProperty(kIOUserClientClassKey
,
3362 (OSObject
*) userClientClass
);
3366 // Didn't find one so lets just bomb out now without further ado.
3367 if (!userClientClass
)
3368 return kIOReturnUnsupported
;
3370 temp
= OSMetaClass::allocClassWithName(userClientClass
);
3372 return kIOReturnNoMemory
;
3374 if (OSDynamicCast(IOUserClient
, temp
))
3375 client
= (IOUserClient
*) temp
;
3378 return kIOReturnUnsupported
;
3381 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
3383 return kIOReturnBadArgument
;
3386 if ( !client
->attach(this) ) {
3388 return kIOReturnUnsupported
;
3391 if ( !client
->start(this) ) {
3392 client
->detach(this);
3394 return kIOReturnUnsupported
;
3398 return kIOReturnSuccess
;
3401 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
3402 UInt32 type
, IOUserClient
** handler
)
3404 return( newUserClient( owningTask
, securityID
, type
, 0, handler
));
3407 IOReturn
IOService::requestProbe( IOOptionBits options
)
3409 return( kIOReturnUnsupported
);
3413 * Convert an IOReturn to text. Subclasses which add additional
3414 * IOReturn's should override this method and call
3415 * super::stringFromReturn if the desired value is not found.
3418 const char * IOService::stringFromReturn( IOReturn rtn
)
3420 static const IONamedValue IOReturn_values
[] = {
3421 {kIOReturnSuccess
, "success" },
3422 {kIOReturnError
, "general error" },
3423 {kIOReturnNoMemory
, "memory allocation error" },
3424 {kIOReturnNoResources
, "resource shortage" },
3425 {kIOReturnIPCError
, "Mach IPC failure" },
3426 {kIOReturnNoDevice
, "no such device" },
3427 {kIOReturnNotPrivileged
, "privilege violation" },
3428 {kIOReturnBadArgument
, "invalid argument" },
3429 {kIOReturnLockedRead
, "device is read locked" },
3430 {kIOReturnLockedWrite
, "device is write locked" },
3431 {kIOReturnExclusiveAccess
, "device is exclusive access" },
3432 {kIOReturnBadMessageID
, "bad IPC message ID" },
3433 {kIOReturnUnsupported
, "unsupported function" },
3434 {kIOReturnVMError
, "virtual memory error" },
3435 {kIOReturnInternalError
, "internal driver error" },
3436 {kIOReturnIOError
, "I/O error" },
3437 {kIOReturnCannotLock
, "cannot acquire lock" },
3438 {kIOReturnNotOpen
, "device is not open" },
3439 {kIOReturnNotReadable
, "device is not readable" },
3440 {kIOReturnNotWritable
, "device is not writeable" },
3441 {kIOReturnNotAligned
, "alignment error" },
3442 {kIOReturnBadMedia
, "media error" },
3443 {kIOReturnStillOpen
, "device is still open" },
3444 {kIOReturnRLDError
, "rld failure" },
3445 {kIOReturnDMAError
, "DMA failure" },
3446 {kIOReturnBusy
, "device is busy" },
3447 {kIOReturnTimeout
, "I/O timeout" },
3448 {kIOReturnOffline
, "device is offline" },
3449 {kIOReturnNotReady
, "device is not ready" },
3450 {kIOReturnNotAttached
, "device/channel is not attached" },
3451 {kIOReturnNoChannels
, "no DMA channels available" },
3452 {kIOReturnNoSpace
, "no space for data" },
3453 {kIOReturnPortExists
, "device port already exists" },
3454 {kIOReturnCannotWire
, "cannot wire physical memory" },
3455 {kIOReturnNoInterrupt
, "no interrupt attached" },
3456 {kIOReturnNoFrames
, "no DMA frames enqueued" },
3457 {kIOReturnMessageTooLarge
, "message is too large" },
3458 {kIOReturnNotPermitted
, "operation is not permitted" },
3459 {kIOReturnNoPower
, "device is without power" },
3460 {kIOReturnNoMedia
, "media is not present" },
3461 {kIOReturnUnformattedMedia
, "media is not formatted" },
3462 {kIOReturnUnsupportedMode
, "unsupported mode" },
3463 {kIOReturnUnderrun
, "data underrun" },
3464 {kIOReturnOverrun
, "data overrun" },
3465 {kIOReturnDeviceError
, "device error" },
3466 {kIOReturnNoCompletion
, "no completion routine" },
3467 {kIOReturnAborted
, "operation was aborted" },
3468 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
3469 {kIOReturnNotResponding
, "device is not responding" },
3470 {kIOReturnInvalid
, "unanticipated driver error" },
3474 return IOFindNameForValue(rtn
, IOReturn_values
);
3478 * Convert an IOReturn to an errno.
3480 int IOService::errnoFromReturn( IOReturn rtn
)
3484 case kIOReturnSuccess
:
3486 case kIOReturnNoMemory
:
3488 case kIOReturnNoDevice
:
3490 case kIOReturnVMError
:
3492 case kIOReturnNotPermitted
:
3494 case kIOReturnNotPrivileged
:
3496 case kIOReturnIOError
:
3498 case kIOReturnNotWritable
:
3500 case kIOReturnBadArgument
:
3502 case kIOReturnUnsupported
:
3506 case kIOReturnNoPower
:
3508 case kIOReturnDeviceError
:
3510 case kIOReturnTimeout
:
3512 case kIOReturnMessageTooLarge
:
3514 case kIOReturnNoSpace
:
3516 case kIOReturnCannotLock
:
3520 case kIOReturnBadMessageID
:
3521 case kIOReturnNoCompletion
:
3522 case kIOReturnNotAligned
:
3524 case kIOReturnNotReady
:
3526 case kIOReturnRLDError
:
3528 case kIOReturnPortExists
:
3529 case kIOReturnStillOpen
:
3531 case kIOReturnExclusiveAccess
:
3532 case kIOReturnLockedRead
:
3533 case kIOReturnLockedWrite
:
3534 case kIOReturnNotAttached
:
3535 case kIOReturnNotOpen
:
3536 case kIOReturnNotReadable
:
3538 case kIOReturnCannotWire
:
3539 case kIOReturnNoResources
:
3541 case kIOReturnAborted
:
3542 case kIOReturnOffline
:
3543 case kIOReturnNotResponding
:
3545 case kIOReturnBadMedia
:
3546 case kIOReturnNoMedia
:
3547 case kIOReturnUnformattedMedia
:
3548 return(EIO
); // (media error)
3549 case kIOReturnDMAError
:
3550 case kIOReturnOverrun
:
3551 case kIOReturnUnderrun
:
3552 return(EIO
); // (transfer error)
3553 case kIOReturnNoBandwidth
:
3554 case kIOReturnNoChannels
:
3555 case kIOReturnNoFrames
:
3556 case kIOReturnNoInterrupt
:
3557 return(EIO
); // (hardware error)
3558 case kIOReturnError
:
3559 case kIOReturnInternalError
:
3560 case kIOReturnInvalid
:
3561 return(EIO
); // (generic error)
3562 case kIOReturnIPCError
:
3563 return(EIO
); // (ipc error)
3565 return(EIO
); // (all other errors)
3569 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
3573 * Generic entry point for calls from the provider. A return value of
3574 * kIOReturnSuccess indicates that the message was received, and where
3575 * applicable, that it was successful.
3578 return kIOReturnUnsupported
;
3585 IOItemCount
IOService::getDeviceMemoryCount( void )
3590 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
3592 count
= array
->getCount();
3599 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
3602 IODeviceMemory
* range
;
3604 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
3606 range
= (IODeviceMemory
*) array
->getObject( index
);
3613 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
3614 IOOptionBits options
= 0 )
3616 IODeviceMemory
* range
;
3619 range
= getDeviceMemoryWithIndex( index
);
3621 map
= range
->map( options
);
3628 OSArray
* IOService::getDeviceMemory( void )
3630 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
3634 void IOService::setDeviceMemory( OSArray
* array
)
3636 setProperty( gIODeviceMemoryKey
, array
);
3643 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
3645 IOInterruptController
*interruptController
;
3646 OSDictionary
*propTable
;
3649 OSSymbol
*interruptControllerName
;
3651 IOInterruptSource
*interruptSources
;
3653 // Get the property table from the nub.
3654 propTable
= nub
->getPropertyTable();
3655 if (propTable
== 0) return kIOReturnNoResources
;
3657 // Get the parents list from the property table.
3658 array
= OSDynamicCast(OSArray
,
3659 propTable
->getObject(gIOInterruptControllersKey
));
3660 if (array
== 0) return kIOReturnNoResources
;
3662 // Allocate space for the IOInterruptSources if needed... then return early.
3663 if (nub
->_interruptSources
== 0) {
3664 numSources
= array
->getCount();
3665 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
3666 if (interruptSources
== 0) return kIOReturnNoMemory
;
3668 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
3670 nub
->_numInterruptSources
= numSources
;
3671 nub
->_interruptSources
= interruptSources
;
3672 return kIOReturnSuccess
;
3675 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
3676 if (interruptControllerName
== 0) return kIOReturnNoResources
;
3678 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
3679 if (interruptController
== 0) return kIOReturnNoResources
;
3681 // Get the interrupt numbers from the property table.
3682 array
= OSDynamicCast(OSArray
,
3683 propTable
->getObject(gIOInterruptSpecifiersKey
));
3684 if (array
== 0) return kIOReturnNoResources
;
3685 data
= OSDynamicCast(OSData
, array
->getObject(source
));
3686 if (data
== 0) return kIOReturnNoResources
;
3688 // Set the interruptController and interruptSource in the nub's table.
3689 interruptSources
= nub
->_interruptSources
;
3690 interruptSources
[source
].interruptController
= interruptController
;
3691 interruptSources
[source
].vectorData
= data
;
3693 return kIOReturnSuccess
;
3696 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
3700 /* Make sure the _interruptSources are set */
3701 if (_interruptSources
== 0) {
3702 ret
= resolveInterrupt(this, source
);
3703 if (ret
!= kIOReturnSuccess
) return ret
;
3706 /* Make sure the local source number is valid */
3707 if ((source
< 0) || (source
>= _numInterruptSources
))
3708 return kIOReturnNoInterrupt
;
3710 /* Look up the contoller for the local source */
3711 *interruptController
= _interruptSources
[source
].interruptController
;
3713 if (*interruptController
== NULL
) {
3714 if (!resolve
) return kIOReturnNoInterrupt
;
3716 /* Try to reslove the interrupt */
3717 ret
= resolveInterrupt(this, source
);
3718 if (ret
!= kIOReturnSuccess
) return ret
;
3720 *interruptController
= _interruptSources
[source
].interruptController
;
3723 return kIOReturnSuccess
;
3726 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
3727 IOInterruptAction handler
,
3730 IOInterruptController
*interruptController
;
3733 ret
= lookupInterrupt(source
, true, &interruptController
);
3734 if (ret
!= kIOReturnSuccess
) return ret
;
3736 /* Register the source */
3737 return interruptController
->registerInterrupt(this, source
, target
,
3738 (IOInterruptHandler
)handler
,
3742 IOReturn
IOService::unregisterInterrupt(int source
)
3744 IOInterruptController
*interruptController
;
3747 ret
= lookupInterrupt(source
, false, &interruptController
);
3748 if (ret
!= kIOReturnSuccess
) return ret
;
3750 /* Unregister the source */
3751 return interruptController
->unregisterInterrupt(this, source
);
3754 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
3756 IOInterruptController
*interruptController
;
3759 ret
= lookupInterrupt(source
, true, &interruptController
);
3760 if (ret
!= kIOReturnSuccess
) return ret
;
3762 /* Return the type */
3763 return interruptController
->getInterruptType(this, source
, interruptType
);
3766 IOReturn
IOService::enableInterrupt(int source
)
3768 IOInterruptController
*interruptController
;
3771 ret
= lookupInterrupt(source
, false, &interruptController
);
3772 if (ret
!= kIOReturnSuccess
) return ret
;
3774 /* Enable the source */
3775 return interruptController
->enableInterrupt(this, source
);
3778 IOReturn
IOService::disableInterrupt(int source
)
3780 IOInterruptController
*interruptController
;
3783 ret
= lookupInterrupt(source
, false, &interruptController
);
3784 if (ret
!= kIOReturnSuccess
) return ret
;
3786 /* Disable the source */
3787 return interruptController
->disableInterrupt(this, source
);
3790 IOReturn
IOService::causeInterrupt(int source
)
3792 IOInterruptController
*interruptController
;
3795 ret
= lookupInterrupt(source
, false, &interruptController
);
3796 if (ret
!= kIOReturnSuccess
) return ret
;
3798 /* Cause an interrupt for the source */
3799 return interruptController
->causeInterrupt(this, source
);
3802 OSMetaClassDefineReservedUnused(IOService
, 0);
3803 OSMetaClassDefineReservedUnused(IOService
, 1);
3804 OSMetaClassDefineReservedUnused(IOService
, 2);
3805 OSMetaClassDefineReservedUnused(IOService
, 3);
3806 OSMetaClassDefineReservedUnused(IOService
, 4);
3807 OSMetaClassDefineReservedUnused(IOService
, 5);
3808 OSMetaClassDefineReservedUnused(IOService
, 6);
3809 OSMetaClassDefineReservedUnused(IOService
, 7);
3810 OSMetaClassDefineReservedUnused(IOService
, 8);
3811 OSMetaClassDefineReservedUnused(IOService
, 9);
3812 OSMetaClassDefineReservedUnused(IOService
, 10);
3813 OSMetaClassDefineReservedUnused(IOService
, 11);
3814 OSMetaClassDefineReservedUnused(IOService
, 12);
3815 OSMetaClassDefineReservedUnused(IOService
, 13);
3816 OSMetaClassDefineReservedUnused(IOService
, 14);
3817 OSMetaClassDefineReservedUnused(IOService
, 15);
3818 OSMetaClassDefineReservedUnused(IOService
, 16);
3819 OSMetaClassDefineReservedUnused(IOService
, 17);
3820 OSMetaClassDefineReservedUnused(IOService
, 18);
3821 OSMetaClassDefineReservedUnused(IOService
, 19);
3822 OSMetaClassDefineReservedUnused(IOService
, 20);
3823 OSMetaClassDefineReservedUnused(IOService
, 21);
3824 OSMetaClassDefineReservedUnused(IOService
, 22);
3825 OSMetaClassDefineReservedUnused(IOService
, 23);
3826 OSMetaClassDefineReservedUnused(IOService
, 24);
3827 OSMetaClassDefineReservedUnused(IOService
, 25);
3828 OSMetaClassDefineReservedUnused(IOService
, 26);
3829 OSMetaClassDefineReservedUnused(IOService
, 27);
3830 OSMetaClassDefineReservedUnused(IOService
, 28);
3831 OSMetaClassDefineReservedUnused(IOService
, 29);
3832 OSMetaClassDefineReservedUnused(IOService
, 30);
3833 OSMetaClassDefineReservedUnused(IOService
, 31);
3834 OSMetaClassDefineReservedUnused(IOService
, 32);
3835 OSMetaClassDefineReservedUnused(IOService
, 33);
3836 OSMetaClassDefineReservedUnused(IOService
, 34);
3837 OSMetaClassDefineReservedUnused(IOService
, 35);
3838 OSMetaClassDefineReservedUnused(IOService
, 36);
3839 OSMetaClassDefineReservedUnused(IOService
, 37);
3840 OSMetaClassDefineReservedUnused(IOService
, 38);
3841 OSMetaClassDefineReservedUnused(IOService
, 39);
3842 OSMetaClassDefineReservedUnused(IOService
, 40);
3843 OSMetaClassDefineReservedUnused(IOService
, 41);
3844 OSMetaClassDefineReservedUnused(IOService
, 42);
3845 OSMetaClassDefineReservedUnused(IOService
, 43);
3846 OSMetaClassDefineReservedUnused(IOService
, 44);
3847 OSMetaClassDefineReservedUnused(IOService
, 45);
3848 OSMetaClassDefineReservedUnused(IOService
, 46);
3849 OSMetaClassDefineReservedUnused(IOService
, 47);
3850 OSMetaClassDefineReservedUnused(IOService
, 48);
3851 OSMetaClassDefineReservedUnused(IOService
, 49);
3852 OSMetaClassDefineReservedUnused(IOService
, 50);
3853 OSMetaClassDefineReservedUnused(IOService
, 51);
3854 OSMetaClassDefineReservedUnused(IOService
, 52);
3855 OSMetaClassDefineReservedUnused(IOService
, 53);
3856 OSMetaClassDefineReservedUnused(IOService
, 54);
3857 OSMetaClassDefineReservedUnused(IOService
, 55);
3858 OSMetaClassDefineReservedUnused(IOService
, 56);
3859 OSMetaClassDefineReservedUnused(IOService
, 57);
3860 OSMetaClassDefineReservedUnused(IOService
, 58);
3861 OSMetaClassDefineReservedUnused(IOService
, 59);
3862 OSMetaClassDefineReservedUnused(IOService
, 60);
3863 OSMetaClassDefineReservedUnused(IOService
, 61);
3864 OSMetaClassDefineReservedUnused(IOService
, 62);
3865 OSMetaClassDefineReservedUnused(IOService
, 63);