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>
49 #include <IOKit/IOWorkLoop.h>
50 #include <mach/sync_policy.h>
51 #include <IOKit/assert.h>
52 #include <sys/errno.h>
57 #include "IOServicePrivate.h"
59 // take lockForArbitration before LOCKNOTIFY
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 static class IOPMrootDomain
* gIOPMRootDomain
;
85 const IORegistryPlane
* gIOServicePlane
;
86 const IORegistryPlane
* gIOPowerPlane
;
87 const OSSymbol
* gIODeviceMemoryKey
;
88 const OSSymbol
* gIOInterruptControllersKey
;
89 const OSSymbol
* gIOInterruptSpecifiersKey
;
91 const OSSymbol
* gIOResourcesKey
;
92 const OSSymbol
* gIOResourceMatchKey
;
93 const OSSymbol
* gIOProviderClassKey
;
94 const OSSymbol
* gIONameMatchKey
;
95 const OSSymbol
* gIONameMatchedKey
;
96 const OSSymbol
* gIOPropertyMatchKey
;
97 const OSSymbol
* gIOLocationMatchKey
;
98 const OSSymbol
* gIOParentMatchKey
;
99 const OSSymbol
* gIOPathMatchKey
;
100 const OSSymbol
* gIOMatchCategoryKey
;
101 const OSSymbol
* gIODefaultMatchCategoryKey
;
102 const OSSymbol
* gIOMatchedServiceCountKey
;
104 const OSSymbol
* gIOUserClientClassKey
;
105 const OSSymbol
* gIOKitDebugKey
;
107 const OSSymbol
* gIOCommandPoolSizeKey
;
109 static int gIOResourceGenerationCount
;
111 const OSSymbol
* gIOServiceKey
;
112 const OSSymbol
* gIOPublishNotification
;
113 const OSSymbol
* gIOFirstPublishNotification
;
114 const OSSymbol
* gIOMatchedNotification
;
115 const OSSymbol
* gIOFirstMatchNotification
;
116 const OSSymbol
* gIOTerminatedNotification
;
118 const OSSymbol
* gIOGeneralInterest
;
119 const OSSymbol
* gIOBusyInterest
;
120 const OSSymbol
* gIOAppPowerStateInterest
;
121 const OSSymbol
* gIOPriorityPowerStateInterest
;
123 static OSDictionary
* gNotifications
;
124 static IORecursiveLock
* gNotificationLock
;
126 static IOService
* gIOResources
;
127 static IOService
* gIOServiceRoot
;
129 static OSOrderedSet
* gJobs
;
130 static semaphore_port_t gJobsSemaphore
;
131 static IOLock
* gJobsLock
;
132 static int gOutstandingJobs
;
133 static int gNumConfigThreads
;
134 static int gNumWaitingThreads
;
135 static IOLock
* gIOServiceBusyLock
;
137 static thread_t gIOTerminateThread
;
138 static UInt32 gIOTerminateWork
;
139 static OSArray
* gIOTerminatePhase2List
;
140 static OSArray
* gIOStopList
;
141 static OSArray
* gIOStopProviderList
;
142 static OSArray
* gIOFinalizeList
;
144 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
146 #define LOCKREADNOTIFY() \
147 IORecursiveLockLock( gNotificationLock )
148 #define LOCKWRITENOTIFY() \
149 IORecursiveLockLock( gNotificationLock )
150 #define LOCKWRITE2READNOTIFY()
151 #define UNLOCKNOTIFY() \
152 IORecursiveLockUnlock( gNotificationLock )
153 #define SLEEPNOTIFY(event) \
154 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
155 #define WAKEUPNOTIFY(event) \
156 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
158 #define randomDelay() \
159 int del = read_processor_clock(); \
160 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
163 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
165 struct ArbitrationLockQueueElement
{
174 static queue_head_t gArbitrationLockQueueActive
;
175 static queue_head_t gArbitrationLockQueueWaiting
;
176 static queue_head_t gArbitrationLockQueueFree
;
177 static IOLock
* gArbitrationLockQueueLock
;
179 bool IOService::isInactive( void ) const
180 { return( 0 != (kIOServiceInactiveState
& getState())); }
182 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
184 void IOService::initialize( void )
188 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
189 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
191 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
192 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
193 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
194 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
195 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
196 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
197 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
199 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
200 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
201 kIODefaultMatchCategoryKey
);
202 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
203 kIOMatchedServiceCountKey
);
205 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
207 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
208 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
210 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
211 gIOInterruptControllersKey
212 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
213 gIOInterruptSpecifiersKey
214 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
216 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
218 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
220 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
221 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
222 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
223 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
225 gNotifications
= OSDictionary::withCapacity( 1 );
226 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
227 kIOPublishNotification
);
228 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
229 kIOFirstPublishNotification
);
230 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
231 kIOMatchedNotification
);
232 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
233 kIOFirstMatchNotification
);
234 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
235 kIOTerminatedNotification
);
236 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
238 gNotificationLock
= IORecursiveLockAlloc();
240 assert( gIOServicePlane
&& gIODeviceMemoryKey
241 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
242 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
243 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
244 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
245 && gIOPublishNotification
&& gIOMatchedNotification
246 && gIOTerminatedNotification
&& gIOServiceKey
);
248 gJobsLock
= IOLockAlloc();
249 gJobs
= OSOrderedSet::withCapacity( 10 );
251 gIOServiceBusyLock
= IOLockAlloc();
253 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
255 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& (err
== KERN_SUCCESS
) );
257 gIOResources
= IOResources::resources();
258 assert( gIOResources
);
260 gArbitrationLockQueueLock
= IOLockAlloc();
261 queue_init(&gArbitrationLockQueueActive
);
262 queue_init(&gArbitrationLockQueueWaiting
);
263 queue_init(&gArbitrationLockQueueFree
);
265 assert( gArbitrationLockQueueLock
);
267 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
268 gIOStopList
= OSArray::withCapacity( 16 );
269 gIOStopProviderList
= OSArray::withCapacity( 16 );
270 gIOFinalizeList
= OSArray::withCapacity( 16 );
271 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
274 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
277 static UInt64
getDebugFlags( OSDictionary
* props
)
279 OSNumber
* debugProp
;
282 debugProp
= OSDynamicCast( OSNumber
,
283 props
->getObject( gIOKitDebugKey
));
285 debugFlags
= debugProp
->unsigned64BitValue();
287 debugFlags
= gIOKitDebug
;
289 return( debugFlags
);
293 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
295 // Probe a matched service and return an instance to be started.
296 // The default score is from the property table, & may be altered
297 // during probe to change the start order.
299 IOService
* IOService::probe( IOService
* provider
,
305 bool IOService::start( IOService
* provider
)
310 void IOService::stop( IOService
* provider
)
314 void IOService::free( void )
316 if( getPropertyTable())
317 unregisterAllInterest();
323 * Attach in service plane
325 bool IOService::attach( IOService
* provider
)
331 if( gIOKitDebug
& kIOLogAttach
)
332 LOG( "%s::attach(%s)\n", getName(),
333 provider
->getName());
335 provider
->lockForArbitration();
336 if( provider
->__state
[0] & kIOServiceInactiveState
)
339 ok
= attachToParent( provider
, gIOServicePlane
);
340 provider
->unlockForArbitration();
343 gIOServiceRoot
= this;
344 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
350 IOService
* IOService::getServiceRoot( void )
352 return( gIOServiceRoot
);
355 void IOService::detach( IOService
* provider
)
357 IOService
* newProvider
= 0;
361 if( gIOKitDebug
& kIOLogAttach
)
362 LOG("%s::detach(%s)\n", getName(), provider
->getName());
364 lockForArbitration();
366 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
367 && (provider
== getProvider()));
369 detachFromParent( provider
, gIOServicePlane
);
372 newProvider
= getProvider();
373 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
374 _adjustBusy( -busy
);
377 unlockForArbitration();
380 newProvider
->lockForArbitration();
381 newProvider
->_adjustBusy(1);
382 newProvider
->unlockForArbitration();
385 // check for last client detach from a terminated service
386 if( provider
->lockForArbitration( true )) {
388 provider
->_adjustBusy( -1 );
389 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
390 && (0 == provider
->getClient())) {
391 provider
->scheduleFinalize();
393 provider
->unlockForArbitration();
398 * Register instance - publish it for matching
401 void IOService::registerService( IOOptionBits options
= 0 )
407 enum { kMaxPathLen
= 256 };
408 enum { kMaxChars
= 63 };
410 IORegistryEntry
* parent
= this;
411 IORegistryEntry
* root
= getRegistryRoot();
412 while( parent
&& (parent
!= root
))
413 parent
= parent
->getParentEntry( gIOServicePlane
);
415 if( parent
!= root
) {
416 IOLog("%s: not registry member at registerService()\n", getName());
420 // Allow the Platform Expert to adjust this node.
421 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
424 if( (this != gIOResources
)
425 && (kIOLogRegister
& gIOKitDebug
)) {
427 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
429 IOLog( "Registering: " );
432 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
435 if( len
> kMaxChars
) {
439 if( (skip
= strchr( path
, '/')))
445 IOLog( "%s\n", path
);
448 IOFree( pathBuf
, kMaxPathLen
);
451 startMatching( options
);
454 void IOService::startMatching( IOOptionBits options
= 0 )
456 IOService
* provider
;
459 bool needWake
= false;
464 lockForArbitration();
466 sync
= (options
& kIOServiceSynchronous
)
467 || ((provider
= getProvider())
468 && (provider
->__state
[1] & kIOServiceSynchronousState
));
471 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
472 && (0 == (__state
[0] & kIOServiceInactiveState
));
474 __state
[1] |= kIOServiceNeedConfigState
;
476 // __state[0] &= ~kIOServiceInactiveState;
478 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
479 // OSKernelStackRemaining(), getName());
482 prevBusy
= _adjustBusy( 1 );
483 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
487 __state
[1] |= kIOServiceSynchronousState
;
489 __state
[1] &= ~kIOServiceSynchronousState
;
491 unlockForArbitration();
496 IOLockLock( gIOServiceBusyLock
);
497 thread_wakeup( (event_t
) this/*&__state[1]*/ );
498 IOLockUnlock( gIOServiceBusyLock
);
500 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
502 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
506 if( (__state
[1] & kIOServiceNeedConfigState
))
507 doServiceMatch( options
);
509 lockForArbitration();
510 IOLockLock( gIOServiceBusyLock
);
512 waitAgain
= (prevBusy
!= (__state
[1] & kIOServiceBusyStateMask
));
514 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
516 __state
[1] &= ~kIOServiceSyncPubState
;
518 unlockForArbitration();
521 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
523 IOLockUnlock( gIOServiceBusyLock
);
525 thread_block(THREAD_CONTINUE_NULL
);
527 } while( waitAgain
);
531 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
533 OSDictionary
* table
;
542 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
545 iter
= (OSIterator
*) getExistingServices( table
,
546 kIOServiceRegisteredState
);
549 while( (service
= (IOService
*) iter
->getNextObject())) {
550 service
->startMatching(kIOServiceAsynchronous
);
558 if( getDebugFlags( table
) & kIOLogMatch
)
559 LOG("Matching service count = %ld\n", count
);
561 newTables
->removeObject(table
);
564 newTables
->release();
566 return( kIOReturnSuccess
);
569 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
570 IOOptionBits options
= 0 )
574 job
= new _IOServiceJob
;
575 if( job
&& !job
->init()) {
583 job
->options
= options
;
584 nub
->retain(); // thread will release()
592 * Called on a registered service to see if it matches
596 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
598 return( matchPropertyTable(table
) );
601 bool IOService::matchPropertyTable( OSDictionary
* table
)
607 * Called on a matched service to allocate resources
608 * before first driver is attached.
611 IOReturn
IOService::getResources( void )
613 return( kIOReturnSuccess
);
617 * Client/provider accessors
620 IOService
* IOService::getProvider( void ) const
622 IOService
* self
= (IOService
*) this;
627 generation
= getGenerationCount();
628 if( __providerGeneration
== generation
)
631 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
632 if( parent
== IORegistryEntry::getRegistryRoot())
633 /* root is not an IOService */
636 self
->__provider
= parent
;
637 // save the count before getParentEntry()
638 self
->__providerGeneration
= generation
;
643 IOWorkLoop
* IOService::getWorkLoop() const
645 IOService
*provider
= getProvider();
648 return provider
->getWorkLoop();
653 OSIterator
* IOService::getProviderIterator( void ) const
655 return( getParentIterator( gIOServicePlane
));
658 IOService
* IOService::getClient( void ) const
660 return( (IOService
*) getChildEntry( gIOServicePlane
));
663 OSIterator
* IOService::getClientIterator( void ) const
665 return( getChildIterator( gIOServicePlane
));
668 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
669 const IOService
* client
,
670 const IOService
* provider
)
672 _IOOpenServiceIterator
* inst
;
677 inst
= new _IOOpenServiceIterator
;
679 if( inst
&& !inst
->init()) {
685 inst
->client
= client
;
686 inst
->provider
= provider
;
692 void _IOOpenServiceIterator::free()
696 last
->unlockForArbitration();
700 OSObject
* _IOOpenServiceIterator::getNextObject()
705 last
->unlockForArbitration();
707 while( (next
= (IOService
*) iter
->getNextObject())) {
709 next
->lockForArbitration();
710 if( (client
&& (next
->isOpen( client
)))
711 || (provider
&& (provider
->isOpen( next
))) )
713 next
->unlockForArbitration();
721 bool _IOOpenServiceIterator::isValid()
723 return( iter
->isValid() );
726 void _IOOpenServiceIterator::reset()
729 last
->unlockForArbitration();
735 OSIterator
* IOService::getOpenProviderIterator( void ) const
737 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
740 OSIterator
* IOService::getOpenClientIterator( void ) const
742 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
746 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
747 bool waitForFunction
,
748 void *param1
, void *param2
,
749 void *param3
, void *param4
)
751 IOReturn result
= kIOReturnUnsupported
;
752 IOService
*provider
= getProvider();
755 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
756 param1
, param2
, param3
, param4
);
762 IOReturn
IOService::callPlatformFunction( const char * functionName
,
763 bool waitForFunction
,
764 void *param1
, void *param2
,
765 void *param3
, void *param4
)
767 IOReturn result
= kIOReturnNoMemory
;
768 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
770 if (functionSymbol
!= 0) {
771 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
772 param1
, param2
, param3
, param4
);
773 functionSymbol
->release();
781 * Accessors for global services
784 IOPlatformExpert
* IOService::getPlatform( void )
786 return( gIOPlatform
);
789 class IOPMrootDomain
* IOService::getPMRootDomain( void )
791 return( gIOPMRootDomain
);
794 IOService
* IOService::getResourceService( void )
796 return( gIOResources
);
799 void IOService::setPlatform( IOPlatformExpert
* platform
)
801 gIOPlatform
= platform
;
802 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
805 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
807 gIOPMRootDomain
= rootDomain
;
808 publishResource("IOKit");
815 bool IOService::lockForArbitration( bool isSuccessRequired
= true )
819 ArbitrationLockQueueElement
* element
;
820 ArbitrationLockQueueElement
* active
;
821 ArbitrationLockQueueElement
* waiting
;
823 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
825 // lock global access
826 IOTakeLock( gArbitrationLockQueueLock
);
828 // obtain an unused queue element
829 if( !queue_empty( &gArbitrationLockQueueFree
)) {
830 queue_remove_first( &gArbitrationLockQueueFree
,
832 ArbitrationLockQueueElement
*,
835 element
= IONew( ArbitrationLockQueueElement
, 1 );
839 // prepare the queue element
840 element
->thread
= IOThreadSelf();
841 element
->service
= this;
843 element
->required
= isSuccessRequired
;
844 element
->aborted
= false;
846 // determine whether this object is already locked (ie. on active queue)
848 queue_iterate( &gArbitrationLockQueueActive
,
850 ArbitrationLockQueueElement
*,
853 if( active
->service
== element
->service
) {
859 if( found
) { // this object is already locked
861 // determine whether it is the same or a different thread trying to lock
862 if( active
->thread
!= element
->thread
) { // it is a different thread
864 ArbitrationLockQueueElement
* victim
= 0;
866 // before placing this new thread on the waiting queue, we look for
867 // a deadlock cycle...
870 // determine whether the active thread holding the object we
871 // want is waiting for another object to be unlocked
873 queue_iterate( &gArbitrationLockQueueWaiting
,
875 ArbitrationLockQueueElement
*,
878 if( waiting
->thread
== active
->thread
) {
879 assert( false == waiting
->aborted
);
885 if( found
) { // yes, active thread waiting for another object
887 // this may be a candidate for rejection if the required
888 // flag is not set, should we detect a deadlock later on
889 if( false == waiting
->required
)
892 // find the thread that is holding this other object, that
893 // is blocking the active thread from proceeding (fun :-)
895 queue_iterate( &gArbitrationLockQueueActive
,
896 active
, // (reuse active queue element)
897 ArbitrationLockQueueElement
*,
900 if( active
->service
== waiting
->service
) {
906 // someone must be holding it or it wouldn't be waiting
909 if( active
->thread
== element
->thread
) {
911 // doh, it's waiting for the thread that originated
912 // this whole lock (ie. current thread) -> deadlock
913 if( false == element
->required
) { // willing to fail?
915 // the originating thread doesn't have the required
916 // flag, so it can fail
917 success
= false; // (fail originating lock request)
918 break; // (out of while)
920 } else { // originating thread is not willing to fail
922 // see if we came across a waiting thread that did
923 // not have the 'required' flag set: we'll fail it
926 // we do have a willing victim, fail it's lock
927 victim
->aborted
= true;
929 // take the victim off the waiting queue
930 queue_remove( &gArbitrationLockQueueWaiting
,
932 ArbitrationLockQueueElement
*,
936 IOLockWakeup( gArbitrationLockQueueLock
,
938 /* one thread */ true );
940 // allow this thread to proceed (ie. wait)
941 success
= true; // (put request on wait queue)
942 break; // (out of while)
945 // all the waiting threads we came across in
946 // finding this loop had the 'required' flag
947 // set, so we've got a deadlock we can't avoid
948 panic("I/O Kit: Unrecoverable deadlock.");
952 // repeat while loop, redefining active thread to be the
953 // thread holding "this other object" (see above), and
954 // looking for threads waiting on it; note the active
955 // variable points to "this other object" already... so
956 // there nothing to do in this else clause.
958 } else { // no, active thread is not waiting for another object
960 success
= true; // (put request on wait queue)
961 break; // (out of while)
965 if( success
) { // put the request on the waiting queue?
966 kern_return_t wait_result
;
968 // place this thread on the waiting queue and put it to sleep;
969 // we place it at the tail of the queue...
970 queue_enter( &gArbitrationLockQueueWaiting
,
972 ArbitrationLockQueueElement
*,
975 // declare that this thread will wait for a given event
976 restart_sleep
: wait_result
= assert_wait( element
,
977 element
->required
? THREAD_UNINT
978 : THREAD_INTERRUPTIBLE
);
980 // unlock global access
981 IOUnlock( gArbitrationLockQueueLock
);
983 // put thread to sleep, waiting for our event to fire...
984 if (wait_result
== THREAD_WAITING
)
985 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
988 // ...and we've been woken up; we might be in one of two states:
989 // (a) we've been aborted and our queue element is not on
990 // any of the three queues, but is floating around
991 // (b) we're allowed to proceed with the lock and we have
992 // already been moved from the waiting queue to the
994 // ...plus a 3rd state, should the thread have been interrupted:
995 // (c) we're still on the waiting queue
997 // determine whether we were interrupted out of our sleep
998 if( THREAD_INTERRUPTED
== wait_result
) {
1000 // re-lock global access
1001 IOTakeLock( gArbitrationLockQueueLock
);
1003 // determine whether we're still on the waiting queue
1005 queue_iterate( &gArbitrationLockQueueWaiting
,
1006 waiting
, // (reuse waiting queue element)
1007 ArbitrationLockQueueElement
*,
1010 if( waiting
== element
) {
1016 if( found
) { // yes, we're still on the waiting queue
1018 // determine whether we're willing to fail
1019 if( false == element
->required
) {
1021 // mark us as aborted
1022 element
->aborted
= true;
1024 // take us off the waiting queue
1025 queue_remove( &gArbitrationLockQueueWaiting
,
1027 ArbitrationLockQueueElement
*,
1029 } else { // we are not willing to fail
1031 // ignore interruption, go back to sleep
1036 // unlock global access
1037 IOUnlock( gArbitrationLockQueueLock
);
1039 // proceed as though this were a normal wake up
1040 wait_result
= THREAD_AWAKENED
;
1043 assert( THREAD_AWAKENED
== wait_result
);
1045 // determine whether we've been aborted while we were asleep
1046 if( element
->aborted
) {
1047 assert( false == element
->required
);
1049 // re-lock global access
1050 IOTakeLock( gArbitrationLockQueueLock
);
1052 action
= kPutOnFreeQueue
;
1054 } else { // we weren't aborted, so we must be ready to go :-)
1056 // we've already been moved from waiting to active queue
1060 } else { // the lock request is to be failed
1062 // return unused queue element to queue
1063 action
= kPutOnFreeQueue
;
1065 } else { // it is the same thread, recursive access is allowed
1067 // add one level of recursion
1070 // return unused queue element to queue
1071 action
= kPutOnFreeQueue
;
1074 } else { // this object is not already locked, so let this thread through
1075 action
= kPutOnActiveQueue
;
1079 // put the new element on a queue
1080 if( kPutOnActiveQueue
== action
) {
1081 queue_enter( &gArbitrationLockQueueActive
,
1083 ArbitrationLockQueueElement
*,
1085 } else if( kPutOnFreeQueue
== action
) {
1086 queue_enter( &gArbitrationLockQueueFree
,
1088 ArbitrationLockQueueElement
*,
1091 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1094 // unlock global access
1095 IOUnlock( gArbitrationLockQueueLock
);
1100 void IOService::unlockForArbitration( void )
1103 ArbitrationLockQueueElement
* element
;
1105 // lock global access
1106 IOTakeLock( gArbitrationLockQueueLock
);
1108 // find the lock element for this object (ie. on active queue)
1110 queue_iterate( &gArbitrationLockQueueActive
,
1112 ArbitrationLockQueueElement
*,
1115 if( element
->service
== this ) {
1123 // determine whether the lock has been taken recursively
1124 if( element
->count
> 1 ) {
1125 // undo one level of recursion
1130 // remove it from the active queue
1131 queue_remove( &gArbitrationLockQueueActive
,
1133 ArbitrationLockQueueElement
*,
1136 // put it on the free queue
1137 queue_enter( &gArbitrationLockQueueFree
,
1139 ArbitrationLockQueueElement
*,
1142 // determine whether a thread is waiting for object (head to tail scan)
1144 queue_iterate( &gArbitrationLockQueueWaiting
,
1146 ArbitrationLockQueueElement
*,
1149 if( element
->service
== this ) {
1155 if ( found
) { // we found an interested thread on waiting queue
1157 // remove it from the waiting queue
1158 queue_remove( &gArbitrationLockQueueWaiting
,
1160 ArbitrationLockQueueElement
*,
1163 // put it on the active queue
1164 queue_enter( &gArbitrationLockQueueActive
,
1166 ArbitrationLockQueueElement
*,
1169 // wake the waiting thread
1170 IOLockWakeup( gArbitrationLockQueueLock
,
1172 /* one thread */ true );
1176 // unlock global access
1177 IOUnlock( gArbitrationLockQueueLock
);
1180 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1183 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1184 context
, gIOServicePlane
);
1187 void IOService::applyToClients( IOServiceApplierFunction applier
,
1190 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1191 context
, gIOServicePlane
);
1200 // send a message to a client or interested party of this service
1201 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1202 void * argument
= 0, vm_size_t argSize
= 0 )
1205 IOService
* service
;
1206 _IOServiceInterestNotifier
* notify
;
1208 if( (service
= OSDynamicCast( IOService
, client
)))
1209 ret
= service
->message( type
, this, argument
);
1211 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1213 _IOServiceNotifierInvocation invocation
;
1216 invocation
.thread
= current_thread();
1219 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1222 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1223 _IOServiceNotifierInvocation
*, link
);
1229 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1230 type
, this, argument
, argSize
);
1233 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1234 _IOServiceNotifierInvocation
*, link
);
1235 if( kIOServiceNotifyWaiter
& notify
->state
) {
1236 notify
->state
&= ~kIOServiceNotifyWaiter
;
1237 WAKEUPNOTIFY( notify
);
1242 ret
= kIOReturnSuccess
;
1245 ret
= kIOReturnBadArgument
;
1250 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1251 OSObjectApplierFunction applier
,
1257 OSArray
* copyArray
;
1259 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1262 array
= OSDynamicCast( OSArray
, getProperty( typeOfInterest
));
1264 copyArray
= OSArray::withArray( array
);
1268 (next
= array
->getObject( index
));
1270 (*applier
)(next
, context
);
1272 copyArray
->release();
1278 struct MessageClientsContext
{
1279 IOService
* service
;
1286 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1289 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1291 ret
= context
->service
->messageClient( context
->type
,
1292 object
, context
->argument
, context
->argSize
);
1293 if( kIOReturnSuccess
!= ret
)
1297 // send a message to all clients
1298 IOReturn
IOService::messageClients( UInt32 type
,
1299 void * argument
= 0, vm_size_t argSize
= 0 )
1301 MessageClientsContext context
;
1303 context
.service
= this;
1304 context
.type
= type
;
1305 context
.argument
= argument
;
1306 context
.argSize
= argSize
;
1307 context
.ret
= kIOReturnSuccess
;
1309 applyToInterested( gIOGeneralInterest
,
1310 &messageClientsApplier
, &context
);
1312 return( context
.ret
);
1315 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1316 IOOptionBits response
)
1318 return( kIOReturnUnsupported
);
1321 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1322 IOServiceInterestHandler handler
, void * target
, void * ref
)
1324 _IOServiceInterestNotifier
* notify
= 0;
1327 if( (typeOfInterest
!= gIOGeneralInterest
)
1328 && (typeOfInterest
!= gIOBusyInterest
)
1329 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1330 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1333 lockForArbitration();
1334 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1336 notify
= new _IOServiceInterestNotifier
;
1337 if( notify
&& !notify
->init()) {
1343 notify
->handler
= handler
;
1344 notify
->target
= target
;
1346 notify
->state
= kIOServiceNotifyEnable
;
1347 queue_init( ¬ify
->handlerInvocations
);
1352 if( 0 == (set
= (OSArray
*) getProperty( typeOfInterest
))) {
1353 set
= OSArray::withCapacity( 1 );
1355 setProperty( typeOfInterest
, set
);
1359 notify
->whence
= set
;
1361 set
->setObject( notify
);
1365 unlockForArbitration();
1370 static void cleanInterestArray( OSObject
* object
)
1374 _IOServiceInterestNotifier
* next
;
1376 if( (array
= OSDynamicCast( OSArray
, object
))) {
1379 (next
= (_IOServiceInterestNotifier
*)
1380 array
->getObject( index
));
1388 void IOService::unregisterAllInterest( void )
1390 cleanInterestArray( getProperty( gIOGeneralInterest
));
1391 cleanInterestArray( getProperty( gIOBusyInterest
));
1392 cleanInterestArray( getProperty( gIOAppPowerStateInterest
));
1393 cleanInterestArray( getProperty( gIOPriorityPowerStateInterest
));
1397 * _IOServiceInterestNotifier
1400 // wait for all threads, other than the current one,
1401 // to exit the handler
1403 void _IOServiceInterestNotifier::wait()
1405 _IOServiceNotifierInvocation
* next
;
1410 queue_iterate( &handlerInvocations
, next
,
1411 _IOServiceNotifierInvocation
*, link
) {
1412 if( next
->thread
!= current_thread() ) {
1418 state
|= kIOServiceNotifyWaiter
;
1425 void _IOServiceInterestNotifier::free()
1427 assert( queue_empty( &handlerInvocations
));
1431 void _IOServiceInterestNotifier::remove()
1436 whence
->removeObject(whence
->getNextIndexOfObject(
1437 (OSObject
*) this, 0 ));
1441 state
&= ~kIOServiceNotifyEnable
;
1450 bool _IOServiceInterestNotifier::disable()
1456 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1457 state
&= ~kIOServiceNotifyEnable
;
1466 void _IOServiceInterestNotifier::enable( bool was
)
1470 state
|= kIOServiceNotifyEnable
;
1472 state
&= ~kIOServiceNotifyEnable
;
1476 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1482 #define tailQ(o) setObject(o)
1483 #define headQ(o) setObject(0, o)
1484 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); }
1486 inline void _workLoopAction( IOWorkLoop::Action action
,
1487 IOService
* service
,
1488 void * p0
= 0, void * p1
= 0,
1489 void * p2
= 0, void * p3
= 0 )
1493 if( (wl
= service
->getWorkLoop())) {
1495 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1498 (*action
)( service
, p0
, p1
, p2
, p3
);
1501 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1505 // if its our only provider
1506 ok
= isParent( provider
, gIOServicePlane
, true);
1510 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1511 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1518 bool IOService::terminatePhase1( IOOptionBits options
= 0 )
1523 OSArray
* makeInactive
;
1526 bool startPhase2
= false;
1528 TLOG("%s::terminatePhase1(%08lx)\n", getName(), options
);
1531 if( options
& kIOServiceRecursing
) {
1532 __state
[1] |= kIOServiceRecursing
;
1537 makeInactive
= OSArray::withCapacity( 16 );
1546 didInactive
= victim
->lockForArbitration( true );
1548 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1550 victim
->__state
[0] |= kIOServiceInactiveState
;
1551 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1552 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1553 victim
->_adjustBusy( 1 );
1555 victim
->unlockForArbitration();
1558 startPhase2
= didInactive
;
1561 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1562 IOUserClient::destroyUserReferences( victim
);
1563 victim
->unregisterAllInterest();
1565 iter
= victim
->getClientIterator();
1567 while( (client
= (IOService
*) iter
->getNextObject())) {
1568 TLOG("%s::requestTerminate(%s, %08lx)\n",
1569 client
->getName(), victim
->getName(), options
);
1570 ok
= client
->requestTerminate( victim
, options
);
1571 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1572 client
->getName(), victim
->getName(), ok
);
1574 makeInactive
->setObject( client
);
1580 victim
= (IOService
*) makeInactive
->getObject(0);
1583 makeInactive
->removeObject(0);
1587 makeInactive
->release();
1590 scheduleTerminatePhase2( options
);
1595 void IOService::scheduleTerminatePhase2( IOOptionBits options
= 0 )
1597 AbsoluteTime deadline
;
1599 bool wait
, haveDeadline
= false;
1601 options
|= kIOServiceRequired
;
1605 IOLockLock( gJobsLock
);
1607 if( (options
& kIOServiceSynchronous
)
1608 && (current_thread() != gIOTerminateThread
)) {
1611 wait
= (gIOTerminateThread
!= 0);
1613 // wait to become the terminate thread
1614 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
1618 gIOTerminateThread
= current_thread();
1619 gIOTerminatePhase2List
->setObject( this );
1623 terminateWorker( options
);
1624 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1626 // wait for the victim to go non-busy
1627 if( !haveDeadline
) {
1628 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1629 haveDeadline
= true;
1631 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
1632 deadline
, THREAD_UNINT
);
1633 if( waitResult
== THREAD_TIMED_OUT
) {
1634 TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName());
1636 thread_cancel_timer();
1638 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
1640 gIOTerminateThread
= 0;
1641 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1644 // ! kIOServiceSynchronous
1646 gIOTerminatePhase2List
->setObject( this );
1647 if( 0 == gIOTerminateWork
++)
1648 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) options
);
1651 IOLockUnlock( gJobsLock
);
1656 void IOService::terminateThread( void * arg
)
1658 IOLockLock( gJobsLock
);
1660 terminateWorker( (IOOptionBits
) arg
);
1662 gIOTerminateThread
= 0;
1663 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1665 IOLockUnlock( gJobsLock
);
1668 void IOService::scheduleStop( IOService
* provider
)
1670 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1672 IOLockLock( gJobsLock
);
1673 gIOStopList
->tailQ( this );
1674 gIOStopProviderList
->tailQ( provider
);
1676 if( 0 == gIOTerminateWork
++) {
1677 if( !gIOTerminateThread
)
1678 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1680 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1683 IOLockUnlock( gJobsLock
);
1686 void IOService::scheduleFinalize( void )
1688 TLOG("%s::scheduleFinalize\n", getName());
1690 IOLockLock( gJobsLock
);
1691 gIOFinalizeList
->tailQ( this );
1693 if( 0 == gIOTerminateWork
++) {
1694 if( !gIOTerminateThread
)
1695 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1697 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1700 IOLockUnlock( gJobsLock
);
1703 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1708 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1710 if( false == *defer
) {
1712 if( lockForArbitration( true )) {
1713 if( false == provider
->handleIsOpen( this ))
1714 scheduleStop( provider
);
1717 message( kIOMessageServiceIsRequestingClose
, provider
, (void *) options
);
1718 if( false == provider
->handleIsOpen( this ))
1719 scheduleStop( provider
);
1722 unlockForArbitration();
1729 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
1730 OSArray
* doPhase2List
)
1736 iter
= victim
->getClientIterator();
1738 while( (client
= (IOService
*) iter
->getNextObject())) {
1739 TLOG("%s::willTerminate(%s, %08lx)\n",
1740 client
->getName(), victim
->getName(), options
);
1741 ok
= client
->willTerminate( victim
, options
);
1742 doPhase2List
->tailQ( client
);
1748 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
)
1754 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *) options
);
1756 iter
= victim
->getClientIterator();
1758 while( (client
= (IOService
*) iter
->getNextObject())) {
1759 TLOG("%s::didTerminate(%s, %08lx)\n",
1760 client
->getName(), victim
->getName(), options
);
1761 client
->didTerminate( victim
, options
, &defer
);
1762 TLOG("%s::didTerminate(%s, defer %d)\n",
1763 client
->getName(), victim
->getName(), defer
);
1769 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
)
1771 TLOG("%s::finalize(%08lx)\n", victim
->getName(), options
);
1772 victim
->finalize( options
);
1775 void IOService::actionStop( IOService
* provider
, IOService
* client
)
1777 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
1778 client
->stop( provider
);
1779 if( provider
->isOpen( client
))
1780 provider
->close( client
);
1781 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
1782 client
->detach( provider
);
1785 void IOService::terminateWorker( IOOptionBits options
)
1787 OSArray
* doPhase2List
;
1788 OSArray
* didPhase2List
;
1793 IOService
* provider
;
1799 options
|= kIOServiceRequired
;
1801 doPhase2List
= OSArray::withCapacity( 16 );
1802 didPhase2List
= OSArray::withCapacity( 16 );
1803 freeList
= OSSet::withCapacity( 16 );
1804 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
1808 workDone
= gIOTerminateWork
;
1810 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
1813 gIOTerminatePhase2List
->removeObject(0);
1814 IOLockUnlock( gJobsLock
);
1818 doPhase2
= victim
->lockForArbitration( true );
1820 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
1822 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
1823 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
1825 victim
->__state
[1] |= kIOServiceTermPhase2State
;
1827 victim
->unlockForArbitration();
1830 if( 0 == victim
->getClient()) {
1831 // no clients - will go to finalize
1832 IOLockLock( gJobsLock
);
1833 gIOFinalizeList
->tailQ( victim
);
1834 IOLockUnlock( gJobsLock
);
1836 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
1837 victim
, (void *) options
, (void *) doPhase2List
);
1839 didPhase2List
->headQ( victim
);
1842 victim
= (IOService
*) doPhase2List
->getObject(0);
1845 doPhase2List
->removeObject(0);
1849 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
1851 if( victim
->lockForArbitration( true )) {
1852 victim
->__state
[1] |= kIOServiceTermPhase3State
;
1853 victim
->unlockForArbitration();
1855 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
1856 victim
, (void *) options
);
1857 didPhase2List
->removeObject(0);
1859 IOLockLock( gJobsLock
);
1866 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
1868 IOLockUnlock( gJobsLock
);
1869 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
1870 victim
, (void *) options
);
1871 IOLockLock( gJobsLock
);
1873 freeList
->setObject( victim
);
1874 // safe if finalize list is append only
1875 gIOFinalizeList
->removeObject(0);
1879 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
1881 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
1884 if( !provider
->isChild( client
, gIOServicePlane
)) {
1885 // may be multiply queued - nop it
1886 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
1888 // not ready for stop if it has clients, skip it
1889 if( (client
->__state
[1] & kIOServiceTermPhase3State
) && client
->getClient()) {
1890 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
1895 IOLockUnlock( gJobsLock
);
1896 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
1897 provider
, (void *) client
);
1898 IOLockLock( gJobsLock
);
1899 // check the finalize list now
1903 freeList
->setObject( client
);
1904 freeList
->setObject( provider
);
1906 // safe if stop list is append only
1907 gIOStopList
->removeObject( idx
);
1908 gIOStopProviderList
->removeObject( idx
);
1912 } while( doPhase3
);
1914 gIOTerminateWork
-= workDone
;
1915 moreToDo
= (gIOTerminateWork
!= 0);
1918 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
1921 } while( moreToDo
);
1923 IOLockUnlock( gJobsLock
);
1925 freeList
->release();
1926 doPhase2List
->release();
1927 didPhase2List
->release();
1929 IOLockLock( gJobsLock
);
1932 bool IOService::finalize( IOOptionBits options
)
1935 IOService
* provider
;
1937 iter
= getProviderIterator();
1941 while( (provider
= (IOService
*) iter
->getNextObject())) {
1944 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
1945 /* we come down here on programmatic terminate */
1947 if( provider
->isOpen( this ))
1948 provider
->close( this );
1952 if( provider
->lockForArbitration( true )) {
1953 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
1954 scheduleStop( provider
);
1955 provider
->unlockForArbitration();
1972 void IOService::doServiceTerminate( IOOptionBits options
)
1976 // a method in case someone needs to override it
1977 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
1981 if( client
->isParent( this, gIOServicePlane
, true))
1982 // we are the clients only provider
1983 ok
= client
->terminate( options
);
1990 bool IOService::terminate( IOOptionBits options
= 0 )
1992 options
|= kIOServiceTerminate
;
1994 return( terminatePhase1( options
));
1997 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003 struct ServiceOpenMessageContext
2005 IOService
* service
;
2007 IOService
* excludeClient
;
2008 IOOptionBits options
;
2011 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2013 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2015 if( object
!= context
->excludeClient
)
2016 context
->service
->messageClient( context
->type
, object
, (void *) context
->options
);
2019 bool IOService::open( IOService
* forClient
,
2020 IOOptionBits options
= 0,
2024 ServiceOpenMessageContext context
;
2026 context
.service
= this;
2027 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2028 context
.excludeClient
= forClient
;
2029 context
.options
= options
;
2031 applyToInterested( gIOGeneralInterest
,
2032 &serviceOpenMessageApplier
, &context
);
2034 if( false == lockForArbitration(false) )
2037 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2039 ok
= handleOpen( forClient
, options
, arg
);
2041 unlockForArbitration();
2046 void IOService::close( IOService
* forClient
,
2047 IOOptionBits options
= 0 )
2052 lockForArbitration();
2054 wasClosed
= handleIsOpen( forClient
);
2056 handleClose( forClient
, options
);
2057 last
= (__state
[1] & kIOServiceTermPhase3State
);
2060 unlockForArbitration();
2063 forClient
->scheduleStop( this );
2065 else if( wasClosed
) {
2067 ServiceOpenMessageContext context
;
2069 context
.service
= this;
2070 context
.type
= kIOMessageServiceWasClosed
;
2071 context
.excludeClient
= forClient
;
2072 context
.options
= options
;
2074 applyToInterested( gIOGeneralInterest
,
2075 &serviceOpenMessageApplier
, &context
);
2079 bool IOService::isOpen( const IOService
* forClient
= 0 ) const
2081 IOService
* self
= (IOService
*) this;
2084 self
->lockForArbitration();
2086 ok
= handleIsOpen( forClient
);
2088 self
->unlockForArbitration();
2093 bool IOService::handleOpen( IOService
* forClient
,
2094 IOOptionBits options
,
2099 ok
= (0 == __owner
);
2101 __owner
= forClient
;
2103 else if( options
& kIOServiceSeize
) {
2104 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2105 __owner
, (void *) options
));
2106 if( ok
&& (0 == __owner
))
2107 __owner
= forClient
;
2114 void IOService::handleClose( IOService
* forClient
,
2115 IOOptionBits options
)
2117 if( __owner
== forClient
)
2121 bool IOService::handleIsOpen( const IOService
* forClient
) const
2124 return( __owner
== forClient
);
2126 return( __owner
!= forClient
);
2130 * Probing & starting
2132 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2134 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2135 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2143 val1
= obj1
->priority
;
2146 val2
= obj2
->priority
;
2148 return ( val1
- val2
);
2151 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2153 OSDictionary
* dict
;
2154 IOService
* service
;
2155 _IOServiceNotifier
* notify
;
2156 OSSymbol
* key
= (OSSymbol
*) ref
;
2159 if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2160 return( notify
->priority
);
2162 else if( (service
= OSDynamicCast( IOService
, entry
)))
2163 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2164 else if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2165 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2172 return( (SInt32
) offset
->unsigned32BitValue());
2174 return( kIODefaultProbeScore
);
2177 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2179 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2180 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2188 val1
= IOServiceObjectOrder( obj1
, ref
);
2191 val2
= IOServiceObjectOrder( obj2
, ref
);
2193 return ( val1
- val2
);
2196 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2198 IOService
* service
= 0;
2200 const OSSymbol
* nextCat
;
2202 iter
= getClientIterator();
2204 while( (service
= (IOService
*) iter
->getNextObject())) {
2205 if( kIOServiceInactiveState
& service
->__state
[0])
2207 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2208 service
->getProperty( gIOMatchCategoryKey
));
2209 if( category
== nextCat
)
2217 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2219 _IOServiceNotifierInvocation invocation
;
2223 invocation
.thread
= current_thread();
2226 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2229 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2230 _IOServiceNotifierInvocation
*, link
);
2236 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
, this );
2239 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2240 _IOServiceNotifierInvocation
*, link
);
2241 if( kIOServiceNotifyWaiter
& notify
->state
) {
2242 notify
->state
&= ~kIOServiceNotifyWaiter
;
2243 WAKEUPNOTIFY( notify
);
2252 * Alloc and probe matching classes,
2253 * called on the provider instance
2256 void IOService::probeCandidates( OSOrderedSet
* matches
)
2258 OSDictionary
* match
= 0;
2261 IOService
* newInst
;
2262 OSDictionary
* props
;
2265 OSOrderedSet
* familyMatches
= 0;
2266 OSOrderedSet
* startList
;
2267 OSDictionary
* startDict
= 0;
2268 const OSSymbol
* category
;
2270 _IOServiceNotifier
* notify
;
2271 OSObject
* nextMatch
= 0;
2273 bool needReloc
= false;
2279 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2281 nextMatch
->retain();
2282 matches
->removeObject(nextMatch
);
2284 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2286 lockForArbitration();
2287 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2288 invokeNotifer( notify
);
2289 unlockForArbitration();
2290 nextMatch
->release();
2294 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2295 nextMatch
->release();
2302 debugFlags
= getDebugFlags( match
);
2306 category
= OSDynamicCast( OSSymbol
,
2307 match
->getObject( gIOMatchCategoryKey
));
2309 category
= gIODefaultMatchCategoryKey
;
2311 if( getClientWithCategory( category
)) {
2313 if( debugFlags
& kIOLogMatch
)
2314 LOG("%s: match category %s exists\n", getName(),
2315 category
->getCStringNoCopy());
2317 nextMatch
->release();
2322 // create a copy now in case its modified during matching
2323 props
= OSDictionary::withDictionary( match
, match
->getCount());
2326 props
->setCapacityIncrement(1);
2328 // check the nub matches
2329 if( false == passiveMatch( props
, true ))
2332 // Check to see if driver reloc has been loaded.
2333 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2336 if( debugFlags
& kIOLogCatalogue
)
2337 LOG("%s: stalling for module\n", getName());
2339 // If reloc hasn't been loaded, exit;
2340 // reprobing will occur after reloc has been loaded.
2344 // reorder on family matchPropertyTable score.
2345 if( 0 == familyMatches
)
2346 familyMatches
= OSOrderedSet::withCapacity( 1,
2347 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2349 familyMatches
->setObject( props
);
2354 nextMatch
->release();
2363 if( familyMatches
) {
2366 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2369 familyMatches
->removeObject( props
);
2374 debugFlags
= getDebugFlags( props
);
2377 symbol
= OSDynamicCast( OSSymbol
,
2378 props
->getObject( gIOClassKey
));
2382 // alloc the driver instance
2383 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2386 IOLog("Couldn't alloc class \"%s\"\n",
2387 symbol
->getCStringNoCopy());
2391 // init driver instance
2392 if( !(inst
->init( props
))) {
2394 if( debugFlags
& kIOLogStart
)
2395 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2399 if( __state
[1] & kIOServiceSynchronousState
)
2400 inst
->__state
[1] |= kIOServiceSynchronousState
;
2402 // give the driver the default match category if not specified
2403 category
= OSDynamicCast( OSSymbol
,
2404 props
->getObject( gIOMatchCategoryKey
));
2406 category
= gIODefaultMatchCategoryKey
;
2407 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2409 // attach driver instance
2410 if( !(inst
->attach( this )))
2413 // pass in score from property table
2414 score
= familyMatches
->orderObject( props
);
2416 // & probe the new driver instance
2418 if( debugFlags
& kIOLogProbe
)
2419 LOG("%s::probe(%s)\n",
2420 inst
->getMetaClass()->getClassName(), getName());
2423 newInst
= inst
->probe( this, &score
);
2424 inst
->detach( this );
2427 if( debugFlags
& kIOLogProbe
)
2428 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2434 newPri
= OSNumber::withNumber( score
, 32 );
2436 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2440 // add to start list for the match category
2442 startDict
= OSDictionary::withCapacity( 1 );
2443 assert( startDict
);
2444 startList
= (OSOrderedSet
*)
2445 startDict
->getObject( category
);
2446 if( 0 == startList
) {
2447 startList
= OSOrderedSet::withCapacity( 1,
2448 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2449 if( startDict
&& startList
) {
2450 startDict
->setObject( category
, startList
);
2451 startList
->release();
2454 assert( startList
);
2456 startList
->setObject( newInst
);
2464 familyMatches
->release();
2468 // start the best (until success) of each category
2470 iter
= OSCollectionIterator::withCollection( startDict
);
2472 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2474 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2475 assert( startList
);
2480 while( true // (!started)
2481 && (inst
= (IOService
*)startList
->getFirstObject())) {
2484 startList
->removeObject(inst
);
2487 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2489 if( debugFlags
& kIOLogStart
) {
2491 LOG( "match category exists, skipping " );
2492 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2493 getName(), inst
->getRetainCount());
2496 if( false == started
)
2497 started
= startCandidate( inst
);
2499 if( (debugFlags
& kIOLogStart
) && (false == started
))
2500 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2501 inst
->getRetainCount());
2510 // adjust the busy count by -1 if matching is stalled for a module,
2511 // or +1 if a previously stalled matching is complete.
2512 lockForArbitration();
2515 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2517 __state
[1] |= kIOServiceModuleStallState
;
2519 } else if( __state
[1] & kIOServiceModuleStallState
) {
2520 __state
[1] &= ~kIOServiceModuleStallState
;
2524 _adjustBusy( adjBusy
);
2525 unlockForArbitration();
2528 startDict
->release();
2532 * Start a previously attached & probed instance,
2533 * called on exporting object instance
2536 bool IOService::startCandidate( IOService
* service
)
2540 ok
= service
->attach( this );
2543 // stall for any nub resources
2545 // stall for any driver resources
2546 service
->checkResources();
2549 ok
= service
->start( this );
2551 service
->detach( this );
2556 IOService
* IOService::resources( void )
2558 return( gIOResources
);
2561 void IOService::publishResource( const char * key
, OSObject
* value
= 0 )
2563 const OSSymbol
* sym
;
2565 if( (sym
= OSSymbol::withCString( key
))) {
2566 publishResource( sym
, value
);
2571 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
= 0 )
2574 value
= (OSObject
*) gIOServiceKey
;
2576 gIOResources
->setProperty( key
, value
);
2578 gIOResourceGenerationCount
++;
2579 gIOResources
->registerService();
2582 bool IOService::addNeededResource( const char * key
)
2584 OSObject
* resources
;
2589 resources
= getProperty( gIOResourceMatchKey
);
2591 newKey
= OSString::withCString( key
);
2592 if( (0 == resources
) || (0 == newKey
))
2595 set
= OSDynamicCast( OSSet
, resources
);
2597 set
= OSSet::withCapacity( 1 );
2599 set
->setObject( resources
);
2604 set
->setObject( newKey
);
2606 ret
= setProperty( gIOResourceMatchKey
, set
);
2612 bool IOService::checkResource( OSObject
* matching
)
2615 OSDictionary
* table
;
2617 if( (str
= OSDynamicCast( OSString
, matching
))) {
2618 if( gIOResources
->getProperty( str
))
2623 table
= resourceMatching( str
);
2624 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
2627 IOLog("%s: Can't match using: %s\n", getName(),
2628 matching
->getMetaClass()->getClassName());
2629 /* false would stall forever */
2633 if( gIOKitDebug
& kIOLogConfig
)
2634 LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName());
2636 waitForService( table
);
2638 if( gIOKitDebug
& kIOLogConfig
)
2639 LOG("config(%x): waking\n", (int) IOThreadSelf() );
2644 bool IOService::checkResources( void )
2646 OSObject
* resources
;
2651 resources
= getProperty( gIOResourceMatchKey
);
2655 if( (set
= OSDynamicCast( OSSet
, resources
))) {
2657 iter
= OSCollectionIterator::withCollection( set
);
2659 while( ok
&& (resources
= iter
->getNextObject()) )
2660 ok
= checkResource( resources
);
2665 ok
= checkResource( resources
);
2671 _IOConfigThread
* _IOConfigThread::configThread( void )
2673 _IOConfigThread
* inst
;
2676 if( !(inst
= new _IOConfigThread
))
2680 if( !(inst
->thread
= IOCreateThread
2681 ( (IOThreadFunc
) &_IOConfigThread::main
, inst
)))
2694 void _IOConfigThread::free( void )
2699 void IOService::doServiceMatch( IOOptionBits options
)
2701 _IOServiceNotifier
* notify
;
2703 OSOrderedSet
* matches
;
2704 SInt32 catalogGeneration
;
2705 bool keepGuessing
= true;
2706 bool reRegistered
= true;
2708 // job->nub->deliverNotification( gIOPublishNotification,
2709 // kIOServiceRegisteredState, 0xffffffff );
2711 while( keepGuessing
) {
2713 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
2714 // the matches list should always be created by findDrivers()
2717 lockForArbitration();
2718 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
2719 deliverNotification( gIOFirstPublishNotification
,
2720 kIOServiceFirstPublishState
, 0xffffffff );
2722 __state
[1] &= ~kIOServiceNeedConfigState
;
2723 __state
[1] |= kIOServiceConfigState
;
2724 __state
[0] |= kIOServiceRegisteredState
;
2726 if( reRegistered
&& (0 == (__state
[0] & kIOServiceInactiveState
))) {
2728 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
2729 gNotifications
->getObject( gIOPublishNotification
) );
2731 while((notify
= (_IOServiceNotifier
*)
2732 iter
->getNextObject())) {
2734 if( passiveMatch( notify
->matching
)
2735 && (kIOServiceNotifyEnable
& notify
->state
))
2736 matches
->setObject( notify
);
2743 unlockForArbitration();
2745 if( matches
->getCount() && (kIOReturnSuccess
== getResources()))
2746 probeCandidates( matches
);
2751 lockForArbitration();
2752 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
2754 (reRegistered
|| (catalogGeneration
!=
2755 gIOCatalogue
->getGenerationCount()))
2756 && (0 == (__state
[0] & kIOServiceInactiveState
));
2759 unlockForArbitration();
2762 if( (0 == (__state
[0] & kIOServiceInactiveState
))
2763 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
2764 deliverNotification( gIOMatchedNotification
,
2765 kIOServiceMatchedState
, 0xffffffff );
2766 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
2767 deliverNotification( gIOFirstMatchNotification
,
2768 kIOServiceFirstMatchState
, 0xffffffff );
2771 __state
[1] &= ~kIOServiceConfigState
;
2772 if( __state
[0] & kIOServiceInactiveState
)
2773 scheduleTerminatePhase2();
2776 unlockForArbitration();
2779 UInt32
IOService::_adjustBusy( SInt32 delta
)
2784 bool wasQuiet
, nowQuiet
, needWake
;
2787 result
= __state
[1] & kIOServiceBusyStateMask
;
2791 next
->lockForArbitration();
2792 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
2793 assert( count
< kIOServiceBusyMax
);
2794 wasQuiet
= (0 == count
);
2795 assert( (!wasQuiet
) || (delta
> 0));
2796 next
->__state
[1] += delta
;
2797 nowQuiet
= (0 == (next
->__state
[1] & kIOServiceBusyStateMask
));
2798 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
2801 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
2802 IOLockLock( gIOServiceBusyLock
);
2803 thread_wakeup( (event_t
) next
);
2804 IOLockUnlock( gIOServiceBusyLock
);
2807 next
->unlockForArbitration();
2809 if( (wasQuiet
|| nowQuiet
) ) {
2812 OSObject
* interested
;
2814 array
= OSDynamicCast( OSArray
, next
->getProperty( gIOBusyInterest
));
2818 (interested
= array
->getObject( index
));
2820 next
->messageClient(kIOMessageServiceBusyStateChange
,
2821 interested
, (void *) wasQuiet
/* busy now */);
2826 if( nowQuiet
&& (next
== gIOServiceRoot
))
2827 OSMetaClass::considerUnloads();
2830 delta
= nowQuiet
? -1 : +1;
2832 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
2837 void IOService::adjustBusy( SInt32 delta
)
2839 lockForArbitration();
2840 _adjustBusy( delta
);
2841 unlockForArbitration();
2844 UInt32
IOService::getBusyState( void )
2846 return( __state
[1] & kIOServiceBusyStateMask
);
2849 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
2850 mach_timespec_t
* timeout
= 0 )
2853 int waitResult
= THREAD_AWAKENED
;
2854 bool computeDeadline
= true;
2855 AbsoluteTime abstime
;
2858 lockForArbitration();
2859 IOLockLock( gIOServiceBusyLock
);
2860 wait
= (value
!= (__state
[1] & mask
));
2862 __state
[1] |= kIOServiceBusyWaiterState
;
2863 unlockForArbitration();
2864 assert_wait( (event_t
) this, THREAD_UNINT
);
2866 if( computeDeadline
) {
2867 AbsoluteTime nsinterval
;
2868 clock_interval_to_absolutetime_interval(
2869 timeout
->tv_sec
, kSecondScale
, &abstime
);
2870 clock_interval_to_absolutetime_interval(
2871 timeout
->tv_nsec
, kNanosecondScale
, &nsinterval
);
2872 ADD_ABSOLUTETIME( &abstime
, &nsinterval
);
2873 clock_absolutetime_interval_to_deadline(
2874 abstime
, &abstime
);
2875 computeDeadline
= false;
2877 thread_set_timer_deadline( abstime
);
2880 unlockForArbitration();
2881 IOLockUnlock( gIOServiceBusyLock
);
2883 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2884 if( timeout
&& (waitResult
!= THREAD_TIMED_OUT
))
2885 thread_cancel_timer();
2888 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2890 if( waitResult
== THREAD_TIMED_OUT
)
2891 return( kIOReturnTimeout
);
2893 return( kIOReturnSuccess
);
2896 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
= 0 )
2898 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
2901 bool IOService::serializeProperties( OSSerialize
* s
) const
2904 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
2905 sizeof( __state
), "__state");
2907 return( super::serializeProperties(s
) );
2911 void _IOConfigThread::main( _IOConfigThread
* self
)
2913 _IOServiceJob
* job
;
2921 semaphore_wait( gJobsSemaphore
);
2923 IOTakeLock( gJobsLock
);
2924 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
2926 gJobs
->removeObject(job
);
2929 // gNumConfigThreads--; // we're out of service
2930 gNumWaitingThreads
--; // we're out of service
2932 IOUnlock( gJobsLock
);
2938 if( gIOKitDebug
& kIOLogConfig
)
2939 LOG("config(%x): starting on %s, %d\n",
2940 (int) IOThreadSelf(), job
->nub
->getName(), job
->type
);
2942 switch( job
->type
) {
2945 nub
->doServiceMatch( job
->options
);
2949 LOG("config(%x): strange type (%d)\n",
2950 (int) IOThreadSelf(), job
->type
);
2957 IOTakeLock( gJobsLock
);
2958 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
2960 gNumWaitingThreads
++; // back in service
2961 // gNumConfigThreads++;
2963 if( 0 == --gNumConfigThreads
) {
2964 // IOLog("MATCH IDLE\n");
2965 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
2968 IOUnlock( gJobsLock
);
2973 if( gIOKitDebug
& kIOLogConfig
)
2974 LOG("config(%x): terminating\n", (int) IOThreadSelf() );
2979 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
2982 int waitResult
= THREAD_AWAKENED
;
2983 bool computeDeadline
= true;
2984 AbsoluteTime abstime
;
2986 IOLockLock( gJobsLock
);
2988 wait
= (0 != gNumConfigThreads
);
2991 if( computeDeadline
) {
2992 clock_interval_to_absolutetime_interval(
2993 msToWait
, kMillisecondScale
, &abstime
);
2994 clock_absolutetime_interval_to_deadline(
2995 abstime
, &abstime
);
2996 computeDeadline
= false;
2998 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
2999 abstime
, THREAD_UNINT
);
3001 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3005 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3006 IOLockUnlock( gJobsLock
);
3008 if( waitResult
== THREAD_TIMED_OUT
)
3009 return( kIOReturnTimeout
);
3011 return( kIOReturnSuccess
);
3014 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3021 IOTakeLock( gJobsLock
);
3024 gJobs
->setLastObject( job
);
3026 count
= gNumWaitingThreads
;
3027 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3029 create
= ( (gOutstandingJobs
> count
)
3030 && (gNumConfigThreads
< kMaxConfigThreads
) );
3032 gNumConfigThreads
++;
3033 gNumWaitingThreads
++;
3036 IOUnlock( gJobsLock
);
3041 if( gIOKitDebug
& kIOLogConfig
)
3042 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3043 _IOConfigThread::configThread();
3046 semaphore_signal( gJobsSemaphore
);
3050 // internal - call with gNotificationLock
3051 OSObject
* IOService::getExistingServices( OSDictionary
* matching
,
3052 IOOptionBits inState
, IOOptionBits options
= 0 )
3054 OSObject
* current
= 0;
3056 IOService
* service
;
3061 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3062 kIORegistryIterateRecursively
);
3066 while( (service
= (IOService
*) iter
->getNextObject())) {
3067 if( (inState
== (service
->__state
[0] & inState
))
3068 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3069 && service
->passiveMatch( matching
)) {
3071 if( options
& kIONotifyOnce
) {
3076 ((OSSet
*)current
)->setObject( service
);
3078 current
= OSSet::withObjects(
3079 & (const OSObject
*) service
, 1, 1 );
3082 } while( !service
&& !iter
->isValid());
3086 if( current
&& (0 == (options
& kIONotifyOnce
))) {
3087 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3096 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3100 // is a lock even needed?
3103 iter
= (OSIterator
*) getExistingServices( matching
,
3104 kIOServiceMatchedState
);
3112 // internal - call with gNotificationLock
3113 IONotifier
* IOService::setNotification(
3114 const OSSymbol
* type
, OSDictionary
* matching
,
3115 IOServiceNotificationHandler handler
, void * target
, void * ref
,
3116 SInt32 priority
= 0 )
3118 _IOServiceNotifier
* notify
= 0;
3124 notify
= new _IOServiceNotifier
;
3125 if( notify
&& !notify
->init()) {
3131 notify
->matching
= matching
;
3132 notify
->handler
= handler
;
3133 notify
->target
= target
;
3135 notify
->priority
= priority
;
3136 notify
->state
= kIOServiceNotifyEnable
;
3137 queue_init( ¬ify
->handlerInvocations
);
3141 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3142 set
= OSOrderedSet::withCapacity( 1,
3143 IONotifyOrdering
, 0 );
3145 gNotifications
->setObject( type
, set
);
3149 notify
->whence
= set
;
3151 set
->setObject( notify
);
3157 // internal - call with gNotificationLock
3158 IONotifier
* IOService::doInstallNotification(
3159 const OSSymbol
* type
, OSDictionary
* matching
,
3160 IOServiceNotificationHandler handler
,
3161 void * target
, void * ref
,
3162 SInt32 priority
, OSIterator
** existing
)
3165 IONotifier
* notify
;
3166 IOOptionBits inState
;
3171 if( type
== gIOPublishNotification
)
3172 inState
= kIOServiceRegisteredState
;
3174 else if( type
== gIOFirstPublishNotification
)
3175 inState
= kIOServiceFirstPublishState
;
3177 else if( (type
== gIOMatchedNotification
)
3178 || (type
== gIOFirstMatchNotification
))
3179 inState
= kIOServiceMatchedState
;
3180 else if( type
== gIOTerminatedNotification
)
3185 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3188 // get the current set
3189 exist
= (OSIterator
*) getExistingServices( matching
, inState
);
3199 IONotifier
* IOService::installNotification(
3200 const OSSymbol
* type
, OSDictionary
* matching
,
3201 IOServiceNotificationHandler handler
,
3202 void * target
, void * ref
,
3203 SInt32 priority
, OSIterator
** existing
)
3205 IONotifier
* notify
;
3209 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3210 priority
, existing
);
3217 IONotifier
* IOService::addNotification(
3218 const OSSymbol
* type
, OSDictionary
* matching
,
3219 IOServiceNotificationHandler handler
,
3220 void * target
, void * ref
= 0,
3221 SInt32 priority
= 0 )
3223 OSIterator
* existing
;
3224 _IOServiceNotifier
* notify
;
3227 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3228 handler
, target
, ref
, priority
, &existing
);
3230 // send notifications for existing set
3233 notify
->retain(); // in case handler remove()s
3234 while( (next
= (IOService
*) existing
->getNextObject())) {
3236 next
->lockForArbitration();
3237 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3238 next
->invokeNotifer( notify
);
3239 next
->unlockForArbitration();
3242 existing
->release();
3248 struct SyncNotifyVars
{
3249 semaphore_port_t waitHere
;
3253 bool IOService::syncNotificationHandler(
3254 void * /* target */, void * ref
,
3255 IOService
* newService
)
3258 // result may get written more than once before the
3259 // notification is removed!
3260 ((SyncNotifyVars
*) ref
)->result
= newService
;
3261 semaphore_signal( ((SyncNotifyVars
*) ref
)->waitHere
);
3266 IOService
* IOService::waitForService( OSDictionary
* matching
,
3267 mach_timespec_t
* timeout
= 0 )
3269 IONotifier
* notify
= 0;
3270 // priority doesn't help us much since we need a thread wakeup
3271 SInt32 priority
= 0;
3272 SyncNotifyVars state
;
3273 kern_return_t err
= kIOReturnBadArgument
;
3285 state
.result
= (IOService
*) getExistingServices( matching
,
3286 kIOServiceMatchedState
, kIONotifyOnce
);
3290 err
= semaphore_create( kernel_task
, &state
.waitHere
,
3291 SYNC_POLICY_FIFO
, 0 );
3292 if( KERN_SUCCESS
!= err
)
3295 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
3296 &IOService::syncNotificationHandler
, (void *) 0,
3297 (void *) &state
, priority
);
3305 err
= semaphore_timedwait( state
.waitHere
, *timeout
);
3307 err
= semaphore_wait( state
.waitHere
);
3311 notify
->remove(); // dequeues
3313 matching
->release();
3315 semaphore_destroy( kernel_task
, state
.waitHere
);
3317 return( state
.result
);
3320 void IOService::deliverNotification( const OSSymbol
* type
,
3321 IOOptionBits orNewState
, IOOptionBits andNewState
)
3323 _IOServiceNotifier
* notify
;
3325 OSArray
* willSend
= 0;
3327 lockForArbitration();
3329 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3330 || (type
== gIOTerminatedNotification
)) {
3334 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3335 gNotifications
->getObject( type
) );
3338 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
3340 if( passiveMatch( notify
->matching
)
3341 && (kIOServiceNotifyEnable
& notify
->state
)) {
3343 willSend
= OSArray::withCapacity(8);
3345 willSend
->setObject( notify
);
3351 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
3357 for( unsigned int idx
= 0;
3358 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
3360 invokeNotifer( notify
);
3362 willSend
->release();
3364 unlockForArbitration();
3367 IOOptionBits
IOService::getState( void ) const
3369 return( __state
[0] );
3373 * Helpers to make matching objects for simple cases
3376 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
3377 OSDictionary
* table
= 0 )
3380 table
= OSDictionary::withCapacity( 2 );
3382 table
->setObject(gIOProviderClassKey
, (OSObject
*)name
);
3387 OSDictionary
* IOService::serviceMatching( const char * name
,
3388 OSDictionary
* table
= 0 )
3390 const OSString
* str
;
3392 str
= OSSymbol::withCString( name
);
3396 table
= serviceMatching( str
, table
);
3401 OSDictionary
* IOService::nameMatching( const OSString
* name
,
3402 OSDictionary
* table
= 0 )
3405 table
= OSDictionary::withCapacity( 2 );
3407 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
3412 OSDictionary
* IOService::nameMatching( const char * name
,
3413 OSDictionary
* table
= 0 )
3415 const OSString
* str
;
3417 str
= OSSymbol::withCString( name
);
3421 table
= nameMatching( str
, table
);
3426 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
3427 OSDictionary
* table
= 0 )
3429 table
= serviceMatching( gIOResourcesKey
, table
);
3431 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
3436 OSDictionary
* IOService::resourceMatching( const char * name
,
3437 OSDictionary
* table
= 0 )
3439 const OSSymbol
* str
;
3441 str
= OSSymbol::withCString( name
);
3445 table
= resourceMatching( str
, table
);
3452 * _IOServiceNotifier
3455 // wait for all threads, other than the current one,
3456 // to exit the handler
3458 void _IOServiceNotifier::wait()
3460 _IOServiceNotifierInvocation
* next
;
3465 queue_iterate( &handlerInvocations
, next
,
3466 _IOServiceNotifierInvocation
*, link
) {
3467 if( next
->thread
!= current_thread() ) {
3473 state
|= kIOServiceNotifyWaiter
;
3480 void _IOServiceNotifier::free()
3482 assert( queue_empty( &handlerInvocations
));
3486 void _IOServiceNotifier::remove()
3491 whence
->removeObject( (OSObject
*) this );
3495 matching
->release();
3499 state
&= ~kIOServiceNotifyEnable
;
3508 bool _IOServiceNotifier::disable()
3514 ret
= (0 != (kIOServiceNotifyEnable
& state
));
3515 state
&= ~kIOServiceNotifyEnable
;
3524 void _IOServiceNotifier::enable( bool was
)
3528 state
|= kIOServiceNotifyEnable
;
3530 state
&= ~kIOServiceNotifyEnable
;
3538 IOService
* IOResources::resources( void )
3542 inst
= new IOResources
;
3543 if( inst
&& !inst
->init()) {
3551 IOWorkLoop
* IOResources::getWorkLoop() const
3553 // If we are the resource root then bringe over to the
3554 // platform to get its workloop
3555 if (this == (IOResources
*) gIOResources
)
3556 return getPlatform()->getWorkLoop();
3558 return IOService::getWorkLoop();
3561 bool IOResources::matchPropertyTable( OSDictionary
* table
)
3569 prop
= table
->getObject( gIOResourceMatchKey
);
3570 str
= OSDynamicCast( OSString
, prop
);
3572 ok
= (0 != getProperty( str
));
3574 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
3576 iter
= OSCollectionIterator::withCollection( set
);
3578 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
3579 ok
= (0 != getProperty( str
));
3588 IOReturn
IOResources::setProperties( OSObject
* properties
)
3591 const OSSymbol
* key
;
3592 OSDictionary
* dict
;
3593 OSCollectionIterator
* iter
;
3595 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
3596 if ( kIOReturnSuccess
!= err
)
3599 dict
= OSDynamicCast(OSDictionary
, properties
);
3601 return( kIOReturnBadArgument
);
3603 iter
= OSCollectionIterator::withCollection( dict
);
3605 return( kIOReturnBadArgument
);
3607 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
3608 publishResource( key
, dict
->getObject(key
) );
3613 return( kIOReturnSuccess
);
3617 * Helpers for matching dictionaries.
3618 * Keys existing in matching are checked in properties.
3619 * Keys may be a string or OSCollection of IOStrings
3622 bool IOService::compareProperty( OSDictionary
* matching
,
3628 value
= matching
->getObject( key
);
3630 ok
= value
->isEqualTo( getProperty( key
));
3638 bool IOService::compareProperty( OSDictionary
* matching
,
3639 const OSString
* key
)
3644 value
= matching
->getObject( key
);
3646 ok
= value
->isEqualTo( getProperty( key
));
3653 bool IOService::compareProperties( OSDictionary
* matching
,
3654 OSCollection
* keys
)
3656 OSCollectionIterator
* iter
;
3657 const OSString
* key
;
3660 if( !matching
|| !keys
)
3663 iter
= OSCollectionIterator::withCollection( keys
);
3666 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
3667 ok
= compareProperty( matching
, key
);
3671 keys
->release(); // !! consume a ref !!
3676 /* Helper to add a location matching dict to the table */
3678 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
3680 OSDictionary
* dict
;
3685 dict
= OSDictionary::withCapacity( 1 );
3687 table
->setObject( gIOLocationMatchKey
, dict
);
3695 * Go looking for a provider to match a location dict.
3698 IOService
* IOService::matchLocation( IOService
* /* client */ )
3702 parent
= getProvider();
3705 parent
= parent
->matchLocation( this );
3710 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
3716 IORegistryEntry
* entry
;
3721 bool matchParent
= false;
3732 str
= OSDynamicCast( OSString
, table
->getObject( gIOProviderClassKey
));
3735 match
= (0 != where
->metaCast( str
));
3740 obj
= table
->getObject( gIONameMatchKey
);
3743 match
= where
->compareNames( obj
, changesOK
? &matched
: 0 );
3746 if( changesOK
&& matched
) {
3747 // leave a hint as to which name matched
3748 table
->setObject( gIONameMatchedKey
, matched
);
3753 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
3756 const OSSymbol
* sym
;
3760 sym
= where
->copyLocation();
3762 match
= sym
->isEqualTo( str
);
3769 obj
= table
->getObject( gIOPropertyMatchKey
);
3772 OSDictionary
* dict
;
3773 OSDictionary
* nextDict
;
3778 dict
= where
->dictionaryWithProperties();
3780 nextDict
= OSDynamicCast( OSDictionary
, obj
);
3784 iter
= OSCollectionIterator::withCollection(
3785 OSDynamicCast(OSCollection
, obj
));
3788 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
3789 iter
->getNextObject()))))) {
3790 match
= dict
->isEqualTo( nextDict
, nextDict
);
3803 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
3806 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
3807 match
= (where
== entry
);
3814 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
3818 IOService
* service
= 0;
3819 UInt32 serviceCount
= 0;
3822 iter
= where
->getClientIterator();
3824 while( (service
= (IOService
*) iter
->getNextObject())) {
3825 if( kIOServiceInactiveState
& service
->__state
[0])
3827 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
3833 match
= (serviceCount
== num
->unsigned32BitValue());
3838 if( done
== table
->getCount()) {
3839 // don't call family if we've done all the entries in the table
3840 matchParent
= false;
3844 // pass in score from property table
3845 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
3847 // do family specific matching
3848 match
= where
->matchPropertyTable( table
, &score
);
3852 if( kIOLogMatch
& getDebugFlags( table
))
3853 LOG("%s: family specific matching fails\n", where
->getName());
3860 newPri
= OSNumber::withNumber( score
, 32 );
3862 table
->setObject( gIOProbeScoreKey
, newPri
);
3867 if( !(match
= where
->compareProperty( table
, kIOBSDNameKey
)))
3870 matchParent
= false;
3872 obj
= OSDynamicCast( OSDictionary
,
3873 table
->getObject( gIOParentMatchKey
));
3877 table
= (OSDictionary
*) obj
;
3881 table
= OSDynamicCast( OSDictionary
,
3882 table
->getObject( gIOLocationMatchKey
));
3885 where
= where
->getProvider();
3887 where
= where
->matchLocation( where
);
3890 } while( table
&& where
);
3892 } while( matchParent
&& (where
= where
->getProvider()) );
3894 if( kIOLogMatch
& gIOKitDebug
)
3896 LOG("match parent @ %s = %d\n",
3897 where
->getName(), match
);
3903 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
3904 UInt32 type
, OSDictionary
* properties
,
3905 IOUserClient
** handler
)
3907 const OSSymbol
*userClientClass
= 0;
3908 IOUserClient
*client
;
3911 // First try my own properties for a user client class name
3912 temp
= getProperty(gIOUserClientClassKey
);
3914 if (OSDynamicCast(OSSymbol
, temp
))
3915 userClientClass
= (const OSSymbol
*) temp
;
3916 else if (OSDynamicCast(OSString
, temp
)) {
3917 userClientClass
= OSSymbol::withString((OSString
*) temp
);
3918 if (userClientClass
)
3919 setProperty(kIOUserClientClassKey
,
3920 (OSObject
*) userClientClass
);
3924 // Didn't find one so lets just bomb out now without further ado.
3925 if (!userClientClass
)
3926 return kIOReturnUnsupported
;
3928 temp
= OSMetaClass::allocClassWithName(userClientClass
);
3930 return kIOReturnNoMemory
;
3932 if (OSDynamicCast(IOUserClient
, temp
))
3933 client
= (IOUserClient
*) temp
;
3936 return kIOReturnUnsupported
;
3939 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
3941 return kIOReturnBadArgument
;
3944 if ( !client
->attach(this) ) {
3946 return kIOReturnUnsupported
;
3949 if ( !client
->start(this) ) {
3950 client
->detach(this);
3952 return kIOReturnUnsupported
;
3956 return kIOReturnSuccess
;
3959 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
3960 UInt32 type
, IOUserClient
** handler
)
3962 return( newUserClient( owningTask
, securityID
, type
, 0, handler
));
3965 IOReturn
IOService::requestProbe( IOOptionBits options
)
3967 return( kIOReturnUnsupported
);
3971 * Convert an IOReturn to text. Subclasses which add additional
3972 * IOReturn's should override this method and call
3973 * super::stringFromReturn if the desired value is not found.
3976 const char * IOService::stringFromReturn( IOReturn rtn
)
3978 static const IONamedValue IOReturn_values
[] = {
3979 {kIOReturnSuccess
, "success" },
3980 {kIOReturnError
, "general error" },
3981 {kIOReturnNoMemory
, "memory allocation error" },
3982 {kIOReturnNoResources
, "resource shortage" },
3983 {kIOReturnIPCError
, "Mach IPC failure" },
3984 {kIOReturnNoDevice
, "no such device" },
3985 {kIOReturnNotPrivileged
, "privilege violation" },
3986 {kIOReturnBadArgument
, "invalid argument" },
3987 {kIOReturnLockedRead
, "device is read locked" },
3988 {kIOReturnLockedWrite
, "device is write locked" },
3989 {kIOReturnExclusiveAccess
, "device is exclusive access" },
3990 {kIOReturnBadMessageID
, "bad IPC message ID" },
3991 {kIOReturnUnsupported
, "unsupported function" },
3992 {kIOReturnVMError
, "virtual memory error" },
3993 {kIOReturnInternalError
, "internal driver error" },
3994 {kIOReturnIOError
, "I/O error" },
3995 {kIOReturnCannotLock
, "cannot acquire lock" },
3996 {kIOReturnNotOpen
, "device is not open" },
3997 {kIOReturnNotReadable
, "device is not readable" },
3998 {kIOReturnNotWritable
, "device is not writeable" },
3999 {kIOReturnNotAligned
, "alignment error" },
4000 {kIOReturnBadMedia
, "media error" },
4001 {kIOReturnStillOpen
, "device is still open" },
4002 {kIOReturnRLDError
, "rld failure" },
4003 {kIOReturnDMAError
, "DMA failure" },
4004 {kIOReturnBusy
, "device is busy" },
4005 {kIOReturnTimeout
, "I/O timeout" },
4006 {kIOReturnOffline
, "device is offline" },
4007 {kIOReturnNotReady
, "device is not ready" },
4008 {kIOReturnNotAttached
, "device/channel is not attached" },
4009 {kIOReturnNoChannels
, "no DMA channels available" },
4010 {kIOReturnNoSpace
, "no space for data" },
4011 {kIOReturnPortExists
, "device port already exists" },
4012 {kIOReturnCannotWire
, "cannot wire physical memory" },
4013 {kIOReturnNoInterrupt
, "no interrupt attached" },
4014 {kIOReturnNoFrames
, "no DMA frames enqueued" },
4015 {kIOReturnMessageTooLarge
, "message is too large" },
4016 {kIOReturnNotPermitted
, "operation is not permitted" },
4017 {kIOReturnNoPower
, "device is without power" },
4018 {kIOReturnNoMedia
, "media is not present" },
4019 {kIOReturnUnformattedMedia
, "media is not formatted" },
4020 {kIOReturnUnsupportedMode
, "unsupported mode" },
4021 {kIOReturnUnderrun
, "data underrun" },
4022 {kIOReturnOverrun
, "data overrun" },
4023 {kIOReturnDeviceError
, "device error" },
4024 {kIOReturnNoCompletion
, "no completion routine" },
4025 {kIOReturnAborted
, "operation was aborted" },
4026 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
4027 {kIOReturnNotResponding
, "device is not responding" },
4028 {kIOReturnInvalid
, "unanticipated driver error" },
4032 return IOFindNameForValue(rtn
, IOReturn_values
);
4036 * Convert an IOReturn to an errno.
4038 int IOService::errnoFromReturn( IOReturn rtn
)
4042 case kIOReturnSuccess
:
4044 case kIOReturnNoMemory
:
4046 case kIOReturnNoDevice
:
4048 case kIOReturnVMError
:
4050 case kIOReturnNotPermitted
:
4052 case kIOReturnNotPrivileged
:
4054 case kIOReturnIOError
:
4056 case kIOReturnNotWritable
:
4058 case kIOReturnBadArgument
:
4060 case kIOReturnUnsupported
:
4064 case kIOReturnNoPower
:
4066 case kIOReturnDeviceError
:
4068 case kIOReturnTimeout
:
4070 case kIOReturnMessageTooLarge
:
4072 case kIOReturnNoSpace
:
4074 case kIOReturnCannotLock
:
4078 case kIOReturnBadMessageID
:
4079 case kIOReturnNoCompletion
:
4080 case kIOReturnNotAligned
:
4082 case kIOReturnNotReady
:
4084 case kIOReturnRLDError
:
4086 case kIOReturnPortExists
:
4087 case kIOReturnStillOpen
:
4089 case kIOReturnExclusiveAccess
:
4090 case kIOReturnLockedRead
:
4091 case kIOReturnLockedWrite
:
4092 case kIOReturnNotAttached
:
4093 case kIOReturnNotOpen
:
4094 case kIOReturnNotReadable
:
4096 case kIOReturnCannotWire
:
4097 case kIOReturnNoResources
:
4099 case kIOReturnAborted
:
4100 case kIOReturnOffline
:
4101 case kIOReturnNotResponding
:
4103 case kIOReturnBadMedia
:
4104 case kIOReturnNoMedia
:
4105 case kIOReturnUnformattedMedia
:
4106 return(ENXIO
); // (media error)
4107 case kIOReturnDMAError
:
4108 case kIOReturnOverrun
:
4109 case kIOReturnUnderrun
:
4110 return(EIO
); // (transfer error)
4111 case kIOReturnNoBandwidth
:
4112 case kIOReturnNoChannels
:
4113 case kIOReturnNoFrames
:
4114 case kIOReturnNoInterrupt
:
4115 return(EIO
); // (hardware error)
4116 case kIOReturnError
:
4117 case kIOReturnInternalError
:
4118 case kIOReturnInvalid
:
4119 return(EIO
); // (generic error)
4120 case kIOReturnIPCError
:
4121 return(EIO
); // (ipc error)
4123 return(EIO
); // (all other errors)
4127 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
4131 * Generic entry point for calls from the provider. A return value of
4132 * kIOReturnSuccess indicates that the message was received, and where
4133 * applicable, that it was successful.
4136 return kIOReturnUnsupported
;
4143 IOItemCount
IOService::getDeviceMemoryCount( void )
4148 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4150 count
= array
->getCount();
4157 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
4160 IODeviceMemory
* range
;
4162 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4164 range
= (IODeviceMemory
*) array
->getObject( index
);
4171 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
4172 IOOptionBits options
= 0 )
4174 IODeviceMemory
* range
;
4177 range
= getDeviceMemoryWithIndex( index
);
4179 map
= range
->map( options
);
4186 OSArray
* IOService::getDeviceMemory( void )
4188 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
4192 void IOService::setDeviceMemory( OSArray
* array
)
4194 setProperty( gIODeviceMemoryKey
, array
);
4201 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
4203 IOInterruptController
*interruptController
;
4206 OSSymbol
*interruptControllerName
;
4208 IOInterruptSource
*interruptSources
;
4210 // Get the parents list from the nub.
4211 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
4212 if (array
== 0) return kIOReturnNoResources
;
4214 // Allocate space for the IOInterruptSources if needed... then return early.
4215 if (nub
->_interruptSources
== 0) {
4216 numSources
= array
->getCount();
4217 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
4218 if (interruptSources
== 0) return kIOReturnNoMemory
;
4220 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
4222 nub
->_numInterruptSources
= numSources
;
4223 nub
->_interruptSources
= interruptSources
;
4224 return kIOReturnSuccess
;
4227 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
4228 if (interruptControllerName
== 0) return kIOReturnNoResources
;
4230 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
4231 if (interruptController
== 0) return kIOReturnNoResources
;
4233 // Get the interrupt numbers from the nub.
4234 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
4235 if (array
== 0) return kIOReturnNoResources
;
4236 data
= OSDynamicCast(OSData
, array
->getObject(source
));
4237 if (data
== 0) return kIOReturnNoResources
;
4239 // Set the interruptController and interruptSource in the nub's table.
4240 interruptSources
= nub
->_interruptSources
;
4241 interruptSources
[source
].interruptController
= interruptController
;
4242 interruptSources
[source
].vectorData
= data
;
4244 return kIOReturnSuccess
;
4247 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
4251 /* Make sure the _interruptSources are set */
4252 if (_interruptSources
== 0) {
4253 ret
= resolveInterrupt(this, source
);
4254 if (ret
!= kIOReturnSuccess
) return ret
;
4257 /* Make sure the local source number is valid */
4258 if ((source
< 0) || (source
>= _numInterruptSources
))
4259 return kIOReturnNoInterrupt
;
4261 /* Look up the contoller for the local source */
4262 *interruptController
= _interruptSources
[source
].interruptController
;
4264 if (*interruptController
== NULL
) {
4265 if (!resolve
) return kIOReturnNoInterrupt
;
4267 /* Try to reslove the interrupt */
4268 ret
= resolveInterrupt(this, source
);
4269 if (ret
!= kIOReturnSuccess
) return ret
;
4271 *interruptController
= _interruptSources
[source
].interruptController
;
4274 return kIOReturnSuccess
;
4277 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
4278 IOInterruptAction handler
,
4281 IOInterruptController
*interruptController
;
4284 ret
= lookupInterrupt(source
, true, &interruptController
);
4285 if (ret
!= kIOReturnSuccess
) return ret
;
4287 /* Register the source */
4288 return interruptController
->registerInterrupt(this, source
, target
,
4289 (IOInterruptHandler
)handler
,
4293 IOReturn
IOService::unregisterInterrupt(int source
)
4295 IOInterruptController
*interruptController
;
4298 ret
= lookupInterrupt(source
, false, &interruptController
);
4299 if (ret
!= kIOReturnSuccess
) return ret
;
4301 /* Unregister the source */
4302 return interruptController
->unregisterInterrupt(this, source
);
4305 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
4307 IOInterruptController
*interruptController
;
4310 ret
= lookupInterrupt(source
, true, &interruptController
);
4311 if (ret
!= kIOReturnSuccess
) return ret
;
4313 /* Return the type */
4314 return interruptController
->getInterruptType(this, source
, interruptType
);
4317 IOReturn
IOService::enableInterrupt(int source
)
4319 IOInterruptController
*interruptController
;
4322 ret
= lookupInterrupt(source
, false, &interruptController
);
4323 if (ret
!= kIOReturnSuccess
) return ret
;
4325 /* Enable the source */
4326 return interruptController
->enableInterrupt(this, source
);
4329 IOReturn
IOService::disableInterrupt(int source
)
4331 IOInterruptController
*interruptController
;
4334 ret
= lookupInterrupt(source
, false, &interruptController
);
4335 if (ret
!= kIOReturnSuccess
) return ret
;
4337 /* Disable the source */
4338 return interruptController
->disableInterrupt(this, source
);
4341 IOReturn
IOService::causeInterrupt(int source
)
4343 IOInterruptController
*interruptController
;
4346 ret
= lookupInterrupt(source
, false, &interruptController
);
4347 if (ret
!= kIOReturnSuccess
) return ret
;
4349 /* Cause an interrupt for the source */
4350 return interruptController
->causeInterrupt(this, source
);
4353 OSMetaClassDefineReservedUsed(IOService
, 0);
4354 OSMetaClassDefineReservedUsed(IOService
, 1);
4355 OSMetaClassDefineReservedUsed(IOService
, 2);
4357 OSMetaClassDefineReservedUnused(IOService
, 3);
4358 OSMetaClassDefineReservedUnused(IOService
, 4);
4359 OSMetaClassDefineReservedUnused(IOService
, 5);
4360 OSMetaClassDefineReservedUnused(IOService
, 6);
4361 OSMetaClassDefineReservedUnused(IOService
, 7);
4362 OSMetaClassDefineReservedUnused(IOService
, 8);
4363 OSMetaClassDefineReservedUnused(IOService
, 9);
4364 OSMetaClassDefineReservedUnused(IOService
, 10);
4365 OSMetaClassDefineReservedUnused(IOService
, 11);
4366 OSMetaClassDefineReservedUnused(IOService
, 12);
4367 OSMetaClassDefineReservedUnused(IOService
, 13);
4368 OSMetaClassDefineReservedUnused(IOService
, 14);
4369 OSMetaClassDefineReservedUnused(IOService
, 15);
4370 OSMetaClassDefineReservedUnused(IOService
, 16);
4371 OSMetaClassDefineReservedUnused(IOService
, 17);
4372 OSMetaClassDefineReservedUnused(IOService
, 18);
4373 OSMetaClassDefineReservedUnused(IOService
, 19);
4374 OSMetaClassDefineReservedUnused(IOService
, 20);
4375 OSMetaClassDefineReservedUnused(IOService
, 21);
4376 OSMetaClassDefineReservedUnused(IOService
, 22);
4377 OSMetaClassDefineReservedUnused(IOService
, 23);
4378 OSMetaClassDefineReservedUnused(IOService
, 24);
4379 OSMetaClassDefineReservedUnused(IOService
, 25);
4380 OSMetaClassDefineReservedUnused(IOService
, 26);
4381 OSMetaClassDefineReservedUnused(IOService
, 27);
4382 OSMetaClassDefineReservedUnused(IOService
, 28);
4383 OSMetaClassDefineReservedUnused(IOService
, 29);
4384 OSMetaClassDefineReservedUnused(IOService
, 30);
4385 OSMetaClassDefineReservedUnused(IOService
, 31);
4386 OSMetaClassDefineReservedUnused(IOService
, 32);
4387 OSMetaClassDefineReservedUnused(IOService
, 33);
4388 OSMetaClassDefineReservedUnused(IOService
, 34);
4389 OSMetaClassDefineReservedUnused(IOService
, 35);
4390 OSMetaClassDefineReservedUnused(IOService
, 36);
4391 OSMetaClassDefineReservedUnused(IOService
, 37);
4392 OSMetaClassDefineReservedUnused(IOService
, 38);
4393 OSMetaClassDefineReservedUnused(IOService
, 39);
4394 OSMetaClassDefineReservedUnused(IOService
, 40);
4395 OSMetaClassDefineReservedUnused(IOService
, 41);
4396 OSMetaClassDefineReservedUnused(IOService
, 42);
4397 OSMetaClassDefineReservedUnused(IOService
, 43);
4398 OSMetaClassDefineReservedUnused(IOService
, 44);
4399 OSMetaClassDefineReservedUnused(IOService
, 45);
4400 OSMetaClassDefineReservedUnused(IOService
, 46);
4401 OSMetaClassDefineReservedUnused(IOService
, 47);
4402 OSMetaClassDefineReservedUnused(IOService
, 48);
4403 OSMetaClassDefineReservedUnused(IOService
, 49);
4404 OSMetaClassDefineReservedUnused(IOService
, 50);
4405 OSMetaClassDefineReservedUnused(IOService
, 51);
4406 OSMetaClassDefineReservedUnused(IOService
, 52);
4407 OSMetaClassDefineReservedUnused(IOService
, 53);
4408 OSMetaClassDefineReservedUnused(IOService
, 54);
4409 OSMetaClassDefineReservedUnused(IOService
, 55);
4410 OSMetaClassDefineReservedUnused(IOService
, 56);
4411 OSMetaClassDefineReservedUnused(IOService
, 57);
4412 OSMetaClassDefineReservedUnused(IOService
, 58);
4413 OSMetaClassDefineReservedUnused(IOService
, 59);
4414 OSMetaClassDefineReservedUnused(IOService
, 60);
4415 OSMetaClassDefineReservedUnused(IOService
, 61);
4416 OSMetaClassDefineReservedUnused(IOService
, 62);
4417 OSMetaClassDefineReservedUnused(IOService
, 63);