2 * Copyright (c) 1998-2009 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <IOKit/system.h>
31 #include <IOKit/IOService.h>
32 #include <libkern/OSDebug.h>
33 #include <libkern/c++/OSContainers.h>
34 #include <libkern/c++/OSKext.h>
35 #include <libkern/c++/OSUnserialize.h>
36 #include <IOKit/IOCatalogue.h>
37 #include <IOKit/IOCommand.h>
38 #include <IOKit/IODeviceTreeSupport.h>
39 #include <IOKit/IODeviceMemory.h>
40 #include <IOKit/IOInterrupts.h>
41 #include <IOKit/IOInterruptController.h>
42 #include <IOKit/IOPlatformExpert.h>
43 #include <IOKit/IOMessage.h>
44 #include <IOKit/IOLib.h>
45 #include <IOKit/IOKitKeysPrivate.h>
46 #include <IOKit/IOBSD.h>
47 #include <IOKit/IOUserClient.h>
48 #include <IOKit/IOWorkLoop.h>
49 #include <IOKit/IOTimeStamp.h>
50 #include <IOKit/IOHibernatePrivate.h>
51 #include <mach/sync_policy.h>
52 #include <IOKit/assert.h>
53 #include <sys/errno.h>
55 #include <machine/pal_routines.h>
61 #include "IOServicePrivate.h"
62 #include "IOKitKernelInternal.h"
64 // take lockForArbitration before LOCKNOTIFY
66 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
68 #define super IORegistryEntry
70 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
72 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
74 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
76 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
78 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
80 OSDefineMetaClassAndStructors(IOResources
, IOService
)
82 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
84 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
86 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
88 static IOPlatformExpert
* gIOPlatform
;
89 static class IOPMrootDomain
* gIOPMRootDomain
;
90 const IORegistryPlane
* gIOServicePlane
;
91 const IORegistryPlane
* gIOPowerPlane
;
92 const OSSymbol
* gIODeviceMemoryKey
;
93 const OSSymbol
* gIOInterruptControllersKey
;
94 const OSSymbol
* gIOInterruptSpecifiersKey
;
96 const OSSymbol
* gIOResourcesKey
;
97 const OSSymbol
* gIOResourceMatchKey
;
98 const OSSymbol
* gIOProviderClassKey
;
99 const OSSymbol
* gIONameMatchKey
;
100 const OSSymbol
* gIONameMatchedKey
;
101 const OSSymbol
* gIOPropertyMatchKey
;
102 const OSSymbol
* gIOLocationMatchKey
;
103 const OSSymbol
* gIOParentMatchKey
;
104 const OSSymbol
* gIOPathMatchKey
;
105 const OSSymbol
* gIOMatchCategoryKey
;
106 const OSSymbol
* gIODefaultMatchCategoryKey
;
107 const OSSymbol
* gIOMatchedServiceCountKey
;
109 const OSSymbol
* gIOMapperIDKey
;
110 const OSSymbol
* gIOUserClientClassKey
;
111 const OSSymbol
* gIOKitDebugKey
;
113 const OSSymbol
* gIOCommandPoolSizeKey
;
115 const OSSymbol
* gIOConsoleLockedKey
;
116 const OSSymbol
* gIOConsoleUsersKey
;
117 const OSSymbol
* gIOConsoleSessionUIDKey
;
118 const OSSymbol
* gIOConsoleSessionAuditIDKey
;
119 const OSSymbol
* gIOConsoleUsersSeedKey
;
120 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
121 const OSSymbol
* gIOConsoleSessionLoginDoneKey
;
122 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
123 const OSSymbol
* gIOConsoleSessionScreenLockedTimeKey
;
125 clock_sec_t gIOConsoleLockTime
;
126 static bool gIOConsoleLoggedIn
;
127 static uint32_t gIOScreenLockState
;
128 static IORegistryEntry
* gIOChosenEntry
;
130 static int gIOResourceGenerationCount
;
132 const OSSymbol
* gIOServiceKey
;
133 const OSSymbol
* gIOPublishNotification
;
134 const OSSymbol
* gIOFirstPublishNotification
;
135 const OSSymbol
* gIOMatchedNotification
;
136 const OSSymbol
* gIOFirstMatchNotification
;
137 const OSSymbol
* gIOTerminatedNotification
;
139 const OSSymbol
* gIOGeneralInterest
;
140 const OSSymbol
* gIOBusyInterest
;
141 const OSSymbol
* gIOAppPowerStateInterest
;
142 const OSSymbol
* gIOPriorityPowerStateInterest
;
143 const OSSymbol
* gIOConsoleSecurityInterest
;
145 static OSDictionary
* gNotifications
;
146 static IORecursiveLock
* gNotificationLock
;
148 static IOService
* gIOResources
;
149 static IOService
* gIOServiceRoot
;
151 static OSOrderedSet
* gJobs
;
152 static semaphore_port_t gJobsSemaphore
;
153 static IOLock
* gJobsLock
;
154 static int gOutstandingJobs
;
155 static int gNumConfigThreads
;
156 static int gNumWaitingThreads
;
157 static IOLock
* gIOServiceBusyLock
;
159 static thread_t gIOTerminateThread
;
160 static UInt32 gIOTerminateWork
;
161 static OSArray
* gIOTerminatePhase2List
;
162 static OSArray
* gIOStopList
;
163 static OSArray
* gIOStopProviderList
;
164 static OSArray
* gIOFinalizeList
;
166 static SInt32 gIOConsoleUsersSeed
;
167 static OSData
* gIOConsoleUsersSeedValue
;
169 extern const OSSymbol
* gIODTPHandleKey
;
171 const OSSymbol
* gIOPlatformSleepActionKey
;
172 const OSSymbol
* gIOPlatformWakeActionKey
;
173 const OSSymbol
* gIOPlatformQuiesceActionKey
;
174 const OSSymbol
* gIOPlatformActiveActionKey
;
176 const OSSymbol
* gIOPlatformFunctionHandlerSet
;
178 static IOLock
* gIOConsoleUsersLock
;
179 static thread_call_t gIOConsoleLockCallout
;
181 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
183 #define LOCKREADNOTIFY() \
184 IORecursiveLockLock( gNotificationLock )
185 #define LOCKWRITENOTIFY() \
186 IORecursiveLockLock( gNotificationLock )
187 #define LOCKWRITE2READNOTIFY()
188 #define UNLOCKNOTIFY() \
189 IORecursiveLockUnlock( gNotificationLock )
190 #define SLEEPNOTIFY(event) \
191 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
192 #define SLEEPNOTIFYTO(event, deadline) \
193 IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT )
194 #define WAKEUPNOTIFY(event) \
195 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
197 #define randomDelay() \
198 int del = read_processor_clock(); \
199 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
202 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
204 #define queue_element(entry, element, type, field) do { \
205 vm_address_t __ele = (vm_address_t) (entry); \
206 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
207 (element) = (type) __ele; \
210 #define iterqueue(que, elt) \
211 for (queue_entry_t elt = queue_first(que); \
212 !queue_end(que, elt); \
213 elt = queue_next(elt))
215 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
217 struct ArbitrationLockQueueElement
{
226 static queue_head_t gArbitrationLockQueueActive
;
227 static queue_head_t gArbitrationLockQueueWaiting
;
228 static queue_head_t gArbitrationLockQueueFree
;
229 static IOLock
* gArbitrationLockQueueLock
;
231 bool IOService::isInactive( void ) const
232 { return( 0 != (kIOServiceInactiveState
& getState())); }
234 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
236 #if defined(__i386__) || defined(__x86_64__)
238 // Only used by the intel implementation of
239 // IOService::requireMaxBusStall(UInt32 ns)
240 // IOService::requireMaxInterruptDelay(uint32_t ns)
243 IOService
* fService
;
249 kCpuDelayBusStall
, kCpuDelayInterrupt
,
253 static OSData
*sCpuDelayData
= OSData::withCapacity(8 * sizeof(CpuDelayEntry
));
254 static IORecursiveLock
*sCpuDelayLock
= IORecursiveLockAlloc();
255 static OSArray
*sCpuLatencyHandlers
[kCpuNumDelayTypes
];
256 const OSSymbol
*sCPULatencyFunctionName
[kCpuNumDelayTypes
];
259 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
);
261 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
);
263 #endif /* defined(__i386__) || defined(__x86_64__) */
265 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
267 void IOService::initialize( void )
271 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
272 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
274 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
275 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
276 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
277 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
278 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
279 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
280 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
282 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
283 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
284 kIODefaultMatchCategoryKey
);
285 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
286 kIOMatchedServiceCountKey
);
288 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
290 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
291 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
293 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
294 gIOInterruptControllersKey
295 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
296 gIOInterruptSpecifiersKey
297 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
299 gIOMapperIDKey
= OSSymbol::withCStringNoCopy(kIOMapperIDKey
);
301 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
303 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
305 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
306 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
307 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
308 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
309 gIOConsoleSecurityInterest
= OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest
);
311 gNotifications
= OSDictionary::withCapacity( 1 );
312 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
313 kIOPublishNotification
);
314 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
315 kIOFirstPublishNotification
);
316 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
317 kIOMatchedNotification
);
318 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
319 kIOFirstMatchNotification
);
320 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
321 kIOTerminatedNotification
);
322 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
324 gIOConsoleLockedKey
= OSSymbol::withCStringNoCopy( kIOConsoleLockedKey
);
325 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
326 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
327 gIOConsoleSessionAuditIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey
);
329 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey
);
330 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey
);
331 gIOConsoleSessionLoginDoneKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey
);
332 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey
);
333 gIOConsoleSessionScreenLockedTimeKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey
);
335 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
337 gIOPlatformSleepActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformSleepActionKey
);
338 gIOPlatformWakeActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformWakeActionKey
);
339 gIOPlatformQuiesceActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformQuiesceActionKey
);
340 gIOPlatformActiveActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformActiveActionKey
);
342 gIOPlatformFunctionHandlerSet
= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet
);
343 #if defined(__i386__) || defined(__x86_64__)
344 sCPULatencyFunctionName
[kCpuDelayBusStall
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay
);
345 sCPULatencyFunctionName
[kCpuDelayInterrupt
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay
);
347 gNotificationLock
= IORecursiveLockAlloc();
349 assert( gIOServicePlane
&& gIODeviceMemoryKey
350 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
351 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
352 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
353 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
354 && gIOPublishNotification
&& gIOMatchedNotification
355 && gIOTerminatedNotification
&& gIOServiceKey
356 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
357 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
358 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
360 gJobsLock
= IOLockAlloc();
361 gJobs
= OSOrderedSet::withCapacity( 10 );
363 gIOServiceBusyLock
= IOLockAlloc();
365 gIOConsoleUsersLock
= IOLockAlloc();
367 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
369 gIOConsoleLockCallout
= thread_call_allocate(&IOService::consoleLockTimer
, NULL
);
371 IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey
, kOSBooleanTrue
);
373 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& gIOConsoleUsersLock
374 && gIOConsoleLockCallout
&& (err
== KERN_SUCCESS
) );
376 gIOResources
= IOResources::resources();
377 assert( gIOResources
);
379 gArbitrationLockQueueLock
= IOLockAlloc();
380 queue_init(&gArbitrationLockQueueActive
);
381 queue_init(&gArbitrationLockQueueWaiting
);
382 queue_init(&gArbitrationLockQueueFree
);
384 assert( gArbitrationLockQueueLock
);
386 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
387 gIOStopList
= OSArray::withCapacity( 16 );
388 gIOStopProviderList
= OSArray::withCapacity( 16 );
389 gIOFinalizeList
= OSArray::withCapacity( 16 );
390 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
393 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
396 static UInt64
getDebugFlags( OSDictionary
* props
)
398 OSNumber
* debugProp
;
401 debugProp
= OSDynamicCast( OSNumber
,
402 props
->getObject( gIOKitDebugKey
));
404 debugFlags
= debugProp
->unsigned64BitValue();
406 debugFlags
= gIOKitDebug
;
408 return( debugFlags
);
412 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
414 // Probe a matched service and return an instance to be started.
415 // The default score is from the property table, & may be altered
416 // during probe to change the start order.
418 IOService
* IOService::probe( IOService
* provider
,
424 bool IOService::start( IOService
* provider
)
429 void IOService::stop( IOService
* provider
)
433 void IOService::free( void )
435 requireMaxBusStall(0);
436 requireMaxInterruptDelay(0);
437 if( getPropertyTable())
438 unregisterAllInterest();
444 * Attach in service plane
446 bool IOService::attach( IOService
* provider
)
452 if( gIOKitDebug
& kIOLogAttach
)
453 LOG( "%s::attach(%s)\n", getName(),
454 provider
->getName());
456 provider
->lockForArbitration();
457 if( provider
->__state
[0] & kIOServiceInactiveState
)
460 ok
= attachToParent( provider
, gIOServicePlane
);
461 provider
->unlockForArbitration();
464 gIOServiceRoot
= this;
465 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
468 if (ok
&& !__provider
) (void) getProvider();
473 IOService
* IOService::getServiceRoot( void )
475 return( gIOServiceRoot
);
478 void IOService::detach( IOService
* provider
)
480 IOService
* newProvider
= 0;
484 if( gIOKitDebug
& kIOLogAttach
)
485 LOG("%s::detach(%s)\n", getName(), provider
->getName());
487 lockForArbitration();
489 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
490 && (provider
== getProvider()));
492 detachFromParent( provider
, gIOServicePlane
);
495 newProvider
= getProvider();
496 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
497 _adjustBusy( -busy
);
500 if (kIOServiceInactiveState
& __state
[0]) {
501 getMetaClass()->removeInstance(this);
504 unlockForArbitration();
507 newProvider
->lockForArbitration();
508 newProvider
->_adjustBusy(1);
509 newProvider
->unlockForArbitration();
512 // check for last client detach from a terminated service
513 if( provider
->lockForArbitration( true )) {
515 provider
->_adjustBusy( -1 );
516 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
517 && (0 == provider
->getClient())) {
518 provider
->scheduleFinalize();
520 provider
->unlockForArbitration();
525 * Register instance - publish it for matching
528 void IOService::registerService( IOOptionBits options
)
534 enum { kMaxPathLen
= 256 };
535 enum { kMaxChars
= 63 };
537 IORegistryEntry
* parent
= this;
538 IORegistryEntry
* root
= getRegistryRoot();
539 while( parent
&& (parent
!= root
))
540 parent
= parent
->getParentEntry( gIOServicePlane
);
542 if( parent
!= root
) {
543 IOLog("%s: not registry member at registerService()\n", getName());
547 // Allow the Platform Expert to adjust this node.
548 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
551 if( (this != gIOResources
)
552 && (kIOLogRegister
& gIOKitDebug
)) {
554 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
556 IOLog( "Registering: " );
559 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
562 if( len
> kMaxChars
) {
566 if( (skip
= strchr( path
, '/')))
572 IOLog( "%s\n", path
);
575 IOFree( pathBuf
, kMaxPathLen
);
578 startMatching( options
);
581 void IOService::startMatching( IOOptionBits options
)
583 IOService
* provider
;
586 bool needWake
= false;
591 lockForArbitration();
593 sync
= (options
& kIOServiceSynchronous
)
594 || ((provider
= getProvider())
595 && (provider
->__state
[1] & kIOServiceSynchronousState
));
597 if ( options
& kIOServiceAsynchronous
)
600 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
601 && (0 == (__state
[0] & kIOServiceInactiveState
));
603 __state
[1] |= kIOServiceNeedConfigState
;
605 // __state[0] &= ~kIOServiceInactiveState;
607 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
608 // OSKernelStackRemaining(), getName());
611 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
615 __state
[1] |= kIOServiceSynchronousState
;
617 __state
[1] &= ~kIOServiceSynchronousState
;
619 unlockForArbitration();
623 prevBusy
= _adjustBusy( 1 );
626 IOLockLock( gIOServiceBusyLock
);
627 thread_wakeup( (event_t
) this/*&__state[1]*/ );
628 IOLockUnlock( gIOServiceBusyLock
);
630 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
632 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
636 if( (__state
[1] & kIOServiceNeedConfigState
))
637 doServiceMatch( options
);
639 lockForArbitration();
640 IOLockLock( gIOServiceBusyLock
);
642 waitAgain
= ((prevBusy
< (__state
[1] & kIOServiceBusyStateMask
))
643 && (0 == (__state
[0] & kIOServiceInactiveState
)));
646 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
648 __state
[1] &= ~kIOServiceSyncPubState
;
650 unlockForArbitration();
653 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
655 IOLockUnlock( gIOServiceBusyLock
);
657 thread_block(THREAD_CONTINUE_NULL
);
659 } while( waitAgain
);
663 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
665 OSDictionary
* table
;
675 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
678 set
= (OSSet
*) copyExistingServices( table
,
679 kIOServiceRegisteredState
,
680 kIOServiceExistingSet
);
685 count
+= set
->getCount();
688 allSet
->merge((const OSSet
*) set
);
696 if( getDebugFlags( table
) & kIOLogMatch
)
697 LOG("Matching service count = %ld\n", (long)count
);
699 newTables
->removeObject(table
);
703 while( (service
= (IOService
*) allSet
->getAnyObject())) {
704 service
->startMatching(kIOServiceAsynchronous
);
705 allSet
->removeObject(service
);
710 newTables
->release();
712 return( kIOReturnSuccess
);
715 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
716 IOOptionBits options
)
720 job
= new _IOServiceJob
;
721 if( job
&& !job
->init()) {
729 job
->options
= options
;
730 nub
->retain(); // thread will release()
738 * Called on a registered service to see if it matches
742 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
744 return( matchPropertyTable(table
) );
747 bool IOService::matchPropertyTable( OSDictionary
* table
)
753 * Called on a matched service to allocate resources
754 * before first driver is attached.
757 IOReturn
IOService::getResources( void )
759 return( kIOReturnSuccess
);
763 * Client/provider accessors
766 IOService
* IOService::getProvider( void ) const
768 IOService
* self
= (IOService
*) this;
772 generation
= getGenerationCount();
773 if( __providerGeneration
== generation
)
774 return( __provider
);
776 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
777 if( parent
== IORegistryEntry::getRegistryRoot())
778 /* root is not an IOService */
781 self
->__provider
= parent
;
783 // save the count from before call to getParentEntry()
784 self
->__providerGeneration
= generation
;
789 IOWorkLoop
* IOService::getWorkLoop() const
791 IOService
*provider
= getProvider();
794 return provider
->getWorkLoop();
799 OSIterator
* IOService::getProviderIterator( void ) const
801 return( getParentIterator( gIOServicePlane
));
804 IOService
* IOService::getClient( void ) const
806 return( (IOService
*) getChildEntry( gIOServicePlane
));
809 OSIterator
* IOService::getClientIterator( void ) const
811 return( getChildIterator( gIOServicePlane
));
814 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
815 const IOService
* client
,
816 const IOService
* provider
)
818 _IOOpenServiceIterator
* inst
;
823 inst
= new _IOOpenServiceIterator
;
825 if( inst
&& !inst
->init()) {
831 inst
->client
= client
;
832 inst
->provider
= provider
;
838 void _IOOpenServiceIterator::free()
842 last
->unlockForArbitration();
846 OSObject
* _IOOpenServiceIterator::getNextObject()
851 last
->unlockForArbitration();
853 while( (next
= (IOService
*) iter
->getNextObject())) {
855 next
->lockForArbitration();
856 if( (client
&& (next
->isOpen( client
)))
857 || (provider
&& (provider
->isOpen( next
))) )
859 next
->unlockForArbitration();
867 bool _IOOpenServiceIterator::isValid()
869 return( iter
->isValid() );
872 void _IOOpenServiceIterator::reset()
875 last
->unlockForArbitration();
881 OSIterator
* IOService::getOpenProviderIterator( void ) const
883 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
886 OSIterator
* IOService::getOpenClientIterator( void ) const
888 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
892 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
893 bool waitForFunction
,
894 void *param1
, void *param2
,
895 void *param3
, void *param4
)
897 IOReturn result
= kIOReturnUnsupported
;
900 if (gIOPlatformFunctionHandlerSet
== functionName
)
902 #if defined(__i386__) || defined(__x86_64__)
903 const OSSymbol
* functionHandlerName
= (const OSSymbol
*) param1
;
904 IOService
* target
= (IOService
*) param2
;
905 bool enable
= (param3
!= 0);
907 if (sCPULatencyFunctionName
[kCpuDelayBusStall
] == functionHandlerName
)
908 result
= setLatencyHandler(kCpuDelayBusStall
, target
, enable
);
909 else if (sCPULatencyFunctionName
[kCpuDelayInterrupt
] == param1
)
910 result
= setLatencyHandler(kCpuDelayInterrupt
, target
, enable
);
911 #endif /* defined(__i386__) || defined(__x86_64__) */
914 if ((kIOReturnUnsupported
== result
) && (provider
= getProvider())) {
915 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
916 param1
, param2
, param3
, param4
);
922 IOReturn
IOService::callPlatformFunction( const char * functionName
,
923 bool waitForFunction
,
924 void *param1
, void *param2
,
925 void *param3
, void *param4
)
927 IOReturn result
= kIOReturnNoMemory
;
928 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
930 if (functionSymbol
!= 0) {
931 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
932 param1
, param2
, param3
, param4
);
933 functionSymbol
->release();
941 * Accessors for global services
944 IOPlatformExpert
* IOService::getPlatform( void )
946 return( gIOPlatform
);
949 class IOPMrootDomain
* IOService::getPMRootDomain( void )
951 return( gIOPMRootDomain
);
954 IOService
* IOService::getResourceService( void )
956 return( gIOResources
);
959 void IOService::setPlatform( IOPlatformExpert
* platform
)
961 gIOPlatform
= platform
;
962 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
965 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
967 gIOPMRootDomain
= rootDomain
;
968 publishResource("IOKit");
975 bool IOService::lockForArbitration( bool isSuccessRequired
)
979 ArbitrationLockQueueElement
* element
;
980 ArbitrationLockQueueElement
* active
;
981 ArbitrationLockQueueElement
* waiting
;
983 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
985 // lock global access
986 IOTakeLock( gArbitrationLockQueueLock
);
988 // obtain an unused queue element
989 if( !queue_empty( &gArbitrationLockQueueFree
)) {
990 queue_remove_first( &gArbitrationLockQueueFree
,
992 ArbitrationLockQueueElement
*,
995 element
= IONew( ArbitrationLockQueueElement
, 1 );
999 // prepare the queue element
1000 element
->thread
= IOThreadSelf();
1001 element
->service
= this;
1003 element
->required
= isSuccessRequired
;
1004 element
->aborted
= false;
1006 // determine whether this object is already locked (ie. on active queue)
1008 queue_iterate( &gArbitrationLockQueueActive
,
1010 ArbitrationLockQueueElement
*,
1013 if( active
->service
== element
->service
) {
1019 if( found
) { // this object is already locked
1021 // determine whether it is the same or a different thread trying to lock
1022 if( active
->thread
!= element
->thread
) { // it is a different thread
1024 ArbitrationLockQueueElement
* victim
= 0;
1026 // before placing this new thread on the waiting queue, we look for
1027 // a deadlock cycle...
1030 // determine whether the active thread holding the object we
1031 // want is waiting for another object to be unlocked
1033 queue_iterate( &gArbitrationLockQueueWaiting
,
1035 ArbitrationLockQueueElement
*,
1038 if( waiting
->thread
== active
->thread
) {
1039 assert( false == waiting
->aborted
);
1045 if( found
) { // yes, active thread waiting for another object
1047 // this may be a candidate for rejection if the required
1048 // flag is not set, should we detect a deadlock later on
1049 if( false == waiting
->required
)
1052 // find the thread that is holding this other object, that
1053 // is blocking the active thread from proceeding (fun :-)
1055 queue_iterate( &gArbitrationLockQueueActive
,
1056 active
, // (reuse active queue element)
1057 ArbitrationLockQueueElement
*,
1060 if( active
->service
== waiting
->service
) {
1066 // someone must be holding it or it wouldn't be waiting
1069 if( active
->thread
== element
->thread
) {
1071 // doh, it's waiting for the thread that originated
1072 // this whole lock (ie. current thread) -> deadlock
1073 if( false == element
->required
) { // willing to fail?
1075 // the originating thread doesn't have the required
1076 // flag, so it can fail
1077 success
= false; // (fail originating lock request)
1078 break; // (out of while)
1080 } else { // originating thread is not willing to fail
1082 // see if we came across a waiting thread that did
1083 // not have the 'required' flag set: we'll fail it
1086 // we do have a willing victim, fail it's lock
1087 victim
->aborted
= true;
1089 // take the victim off the waiting queue
1090 queue_remove( &gArbitrationLockQueueWaiting
,
1092 ArbitrationLockQueueElement
*,
1096 IOLockWakeup( gArbitrationLockQueueLock
,
1098 /* one thread */ true );
1100 // allow this thread to proceed (ie. wait)
1101 success
= true; // (put request on wait queue)
1102 break; // (out of while)
1105 // all the waiting threads we came across in
1106 // finding this loop had the 'required' flag
1107 // set, so we've got a deadlock we can't avoid
1108 panic("I/O Kit: Unrecoverable deadlock.");
1112 // repeat while loop, redefining active thread to be the
1113 // thread holding "this other object" (see above), and
1114 // looking for threads waiting on it; note the active
1115 // variable points to "this other object" already... so
1116 // there nothing to do in this else clause.
1118 } else { // no, active thread is not waiting for another object
1120 success
= true; // (put request on wait queue)
1121 break; // (out of while)
1125 if( success
) { // put the request on the waiting queue?
1126 kern_return_t wait_result
;
1128 // place this thread on the waiting queue and put it to sleep;
1129 // we place it at the tail of the queue...
1130 queue_enter( &gArbitrationLockQueueWaiting
,
1132 ArbitrationLockQueueElement
*,
1135 // declare that this thread will wait for a given event
1136 restart_sleep
: wait_result
= assert_wait( element
,
1137 element
->required
? THREAD_UNINT
1138 : THREAD_INTERRUPTIBLE
);
1140 // unlock global access
1141 IOUnlock( gArbitrationLockQueueLock
);
1143 // put thread to sleep, waiting for our event to fire...
1144 if (wait_result
== THREAD_WAITING
)
1145 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1148 // ...and we've been woken up; we might be in one of two states:
1149 // (a) we've been aborted and our queue element is not on
1150 // any of the three queues, but is floating around
1151 // (b) we're allowed to proceed with the lock and we have
1152 // already been moved from the waiting queue to the
1154 // ...plus a 3rd state, should the thread have been interrupted:
1155 // (c) we're still on the waiting queue
1157 // determine whether we were interrupted out of our sleep
1158 if( THREAD_INTERRUPTED
== wait_result
) {
1160 // re-lock global access
1161 IOTakeLock( gArbitrationLockQueueLock
);
1163 // determine whether we're still on the waiting queue
1165 queue_iterate( &gArbitrationLockQueueWaiting
,
1166 waiting
, // (reuse waiting queue element)
1167 ArbitrationLockQueueElement
*,
1170 if( waiting
== element
) {
1176 if( found
) { // yes, we're still on the waiting queue
1178 // determine whether we're willing to fail
1179 if( false == element
->required
) {
1181 // mark us as aborted
1182 element
->aborted
= true;
1184 // take us off the waiting queue
1185 queue_remove( &gArbitrationLockQueueWaiting
,
1187 ArbitrationLockQueueElement
*,
1189 } else { // we are not willing to fail
1191 // ignore interruption, go back to sleep
1196 // unlock global access
1197 IOUnlock( gArbitrationLockQueueLock
);
1199 // proceed as though this were a normal wake up
1200 wait_result
= THREAD_AWAKENED
;
1203 assert( THREAD_AWAKENED
== wait_result
);
1205 // determine whether we've been aborted while we were asleep
1206 if( element
->aborted
) {
1207 assert( false == element
->required
);
1209 // re-lock global access
1210 IOTakeLock( gArbitrationLockQueueLock
);
1212 action
= kPutOnFreeQueue
;
1214 } else { // we weren't aborted, so we must be ready to go :-)
1216 // we've already been moved from waiting to active queue
1220 } else { // the lock request is to be failed
1222 // return unused queue element to queue
1223 action
= kPutOnFreeQueue
;
1225 } else { // it is the same thread, recursive access is allowed
1227 // add one level of recursion
1230 // return unused queue element to queue
1231 action
= kPutOnFreeQueue
;
1234 } else { // this object is not already locked, so let this thread through
1235 action
= kPutOnActiveQueue
;
1239 // put the new element on a queue
1240 if( kPutOnActiveQueue
== action
) {
1241 queue_enter( &gArbitrationLockQueueActive
,
1243 ArbitrationLockQueueElement
*,
1245 } else if( kPutOnFreeQueue
== action
) {
1246 queue_enter( &gArbitrationLockQueueFree
,
1248 ArbitrationLockQueueElement
*,
1251 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1254 // unlock global access
1255 IOUnlock( gArbitrationLockQueueLock
);
1260 void IOService::unlockForArbitration( void )
1263 ArbitrationLockQueueElement
* element
;
1265 // lock global access
1266 IOTakeLock( gArbitrationLockQueueLock
);
1268 // find the lock element for this object (ie. on active queue)
1270 queue_iterate( &gArbitrationLockQueueActive
,
1272 ArbitrationLockQueueElement
*,
1275 if( element
->service
== this ) {
1283 // determine whether the lock has been taken recursively
1284 if( element
->count
> 1 ) {
1285 // undo one level of recursion
1290 // remove it from the active queue
1291 queue_remove( &gArbitrationLockQueueActive
,
1293 ArbitrationLockQueueElement
*,
1296 // put it on the free queue
1297 queue_enter( &gArbitrationLockQueueFree
,
1299 ArbitrationLockQueueElement
*,
1302 // determine whether a thread is waiting for object (head to tail scan)
1304 queue_iterate( &gArbitrationLockQueueWaiting
,
1306 ArbitrationLockQueueElement
*,
1309 if( element
->service
== this ) {
1315 if ( found
) { // we found an interested thread on waiting queue
1317 // remove it from the waiting queue
1318 queue_remove( &gArbitrationLockQueueWaiting
,
1320 ArbitrationLockQueueElement
*,
1323 // put it on the active queue
1324 queue_enter( &gArbitrationLockQueueActive
,
1326 ArbitrationLockQueueElement
*,
1329 // wake the waiting thread
1330 IOLockWakeup( gArbitrationLockQueueLock
,
1332 /* one thread */ true );
1336 // unlock global access
1337 IOUnlock( gArbitrationLockQueueLock
);
1340 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1343 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1344 context
, gIOServicePlane
);
1347 void IOService::applyToClients( IOServiceApplierFunction applier
,
1350 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1351 context
, gIOServicePlane
);
1360 // send a message to a client or interested party of this service
1361 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1362 void * argument
, vm_size_t argSize
)
1365 IOService
* service
;
1366 _IOServiceInterestNotifier
* notify
;
1368 if( (service
= OSDynamicCast( IOService
, client
)))
1369 ret
= service
->message( type
, this, argument
);
1371 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1373 _IOServiceNotifierInvocation invocation
;
1376 invocation
.thread
= current_thread();
1379 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1382 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1383 _IOServiceNotifierInvocation
*, link
);
1389 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1390 type
, this, argument
, argSize
);
1393 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1394 _IOServiceNotifierInvocation
*, link
);
1395 if( kIOServiceNotifyWaiter
& notify
->state
) {
1396 notify
->state
&= ~kIOServiceNotifyWaiter
;
1397 WAKEUPNOTIFY( notify
);
1402 ret
= kIOReturnSuccess
;
1405 ret
= kIOReturnBadArgument
;
1411 applyToInterestNotifiers(const IORegistryEntry
*target
,
1412 const OSSymbol
* typeOfInterest
,
1413 OSObjectApplierFunction applier
,
1416 OSArray
* copyArray
= 0;
1420 IOCommand
*notifyList
=
1421 OSDynamicCast( IOCommand
, target
->getProperty( typeOfInterest
));
1424 copyArray
= OSArray::withCapacity(1);
1426 // iterate over queue, entry is set to each element in the list
1427 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1428 _IOServiceInterestNotifier
* notify
;
1430 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1431 copyArray
->setObject(notify
);
1440 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1441 (*applier
)(next
, context
);
1442 copyArray
->release();
1446 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1447 OSObjectApplierFunction applier
,
1450 if (gIOGeneralInterest
== typeOfInterest
)
1451 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1452 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1455 struct MessageClientsContext
{
1456 IOService
* service
;
1463 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1466 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1468 ret
= context
->service
->messageClient( context
->type
,
1469 object
, context
->argument
, context
->argSize
);
1470 if( kIOReturnSuccess
!= ret
)
1474 // send a message to all clients
1475 IOReturn
IOService::messageClients( UInt32 type
,
1476 void * argument
, vm_size_t argSize
)
1478 MessageClientsContext context
;
1480 context
.service
= this;
1481 context
.type
= type
;
1482 context
.argument
= argument
;
1483 context
.argSize
= argSize
;
1484 context
.ret
= kIOReturnSuccess
;
1486 applyToInterested( gIOGeneralInterest
,
1487 &messageClientsApplier
, &context
);
1489 return( context
.ret
);
1492 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1493 IOOptionBits response
)
1495 return( kIOReturnUnsupported
);
1498 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1499 IOServiceInterestHandler handler
, void * target
, void * ref
)
1501 _IOServiceInterestNotifier
* notify
= 0;
1503 if( (typeOfInterest
!= gIOGeneralInterest
)
1504 && (typeOfInterest
!= gIOBusyInterest
)
1505 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1506 && (typeOfInterest
!= gIOConsoleSecurityInterest
)
1507 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1510 lockForArbitration();
1511 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1513 notify
= new _IOServiceInterestNotifier
;
1514 if( notify
&& !notify
->init()) {
1520 notify
->handler
= handler
;
1521 notify
->target
= target
;
1523 notify
->state
= kIOServiceNotifyEnable
;
1524 queue_init( ¬ify
->handlerInvocations
);
1530 // Get the head of the notifier linked list
1531 IOCommand
*notifyList
= (IOCommand
*) getProperty( typeOfInterest
);
1532 if (!notifyList
|| !OSDynamicCast(IOCommand
, notifyList
)) {
1533 notifyList
= OSTypeAlloc(IOCommand
);
1536 setProperty( typeOfInterest
, notifyList
);
1537 notifyList
->release();
1542 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1543 notify
->retain(); // ref'ed while in list
1549 unlockForArbitration();
1554 static void cleanInterestList( OSObject
* head
)
1556 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1561 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1562 queue_next(entry
) = queue_prev(entry
) = 0;
1564 _IOServiceInterestNotifier
* notify
;
1566 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1572 void IOService::unregisterAllInterest( void )
1574 cleanInterestList( getProperty( gIOGeneralInterest
));
1575 cleanInterestList( getProperty( gIOBusyInterest
));
1576 cleanInterestList( getProperty( gIOAppPowerStateInterest
));
1577 cleanInterestList( getProperty( gIOPriorityPowerStateInterest
));
1578 cleanInterestList( getProperty( gIOConsoleSecurityInterest
));
1582 * _IOServiceInterestNotifier
1585 // wait for all threads, other than the current one,
1586 // to exit the handler
1588 void _IOServiceInterestNotifier::wait()
1590 _IOServiceNotifierInvocation
* next
;
1595 queue_iterate( &handlerInvocations
, next
,
1596 _IOServiceNotifierInvocation
*, link
) {
1597 if( next
->thread
!= current_thread() ) {
1603 state
|= kIOServiceNotifyWaiter
;
1610 void _IOServiceInterestNotifier::free()
1612 assert( queue_empty( &handlerInvocations
));
1616 void _IOServiceInterestNotifier::remove()
1620 if( queue_next( &chain
)) {
1622 queue_next( &chain
) = queue_prev( &chain
) = 0;
1626 state
&= ~kIOServiceNotifyEnable
;
1635 bool _IOServiceInterestNotifier::disable()
1641 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1642 state
&= ~kIOServiceNotifyEnable
;
1651 void _IOServiceInterestNotifier::enable( bool was
)
1655 state
|= kIOServiceNotifyEnable
;
1657 state
&= ~kIOServiceNotifyEnable
;
1661 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1667 #define tailQ(o) setObject(o)
1668 #define headQ(o) setObject(0, o)
1669 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
1671 static void _workLoopAction( IOWorkLoop::Action action
,
1672 IOService
* service
,
1673 void * p0
= 0, void * p1
= 0,
1674 void * p2
= 0, void * p3
= 0 )
1678 if( (wl
= service
->getWorkLoop())) {
1680 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1683 (*action
)( service
, p0
, p1
, p2
, p3
);
1686 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1690 // if its our only provider
1691 ok
= isParent( provider
, gIOServicePlane
, true);
1695 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1696 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1703 bool IOService::terminatePhase1( IOOptionBits options
)
1708 OSArray
* makeInactive
;
1709 int waitResult
= THREAD_AWAKENED
;
1713 bool startPhase2
= false;
1715 TLOG("%s::terminatePhase1(%08llx)\n", getName(), (long long)options
);
1717 uint64_t regID
= getRegistryEntryID();
1719 IOSERVICE_TERMINATE_PHASE1
,
1721 (uintptr_t) (regID
>> 32),
1723 (uintptr_t) options
);
1726 if( options
& kIOServiceRecursing
) {
1727 __state
[1] |= kIOServiceRecursing
;
1732 makeInactive
= OSArray::withCapacity( 16 );
1741 didInactive
= victim
->lockForArbitration( true );
1743 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1745 victim
->__state
[0] |= kIOServiceInactiveState
;
1746 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1747 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1750 victim
->__state
[1] |= kIOServiceTermPhase1State
;
1752 victim
->_adjustBusy( 1 );
1754 } else if (victim
!= this) do {
1756 IOLockLock(gIOServiceBusyLock
);
1757 wait
= (victim
->__state
[1] & kIOServiceTermPhase1State
);
1759 TLOG("%s::waitPhase1(%s)\n", getName(), victim
->getName());
1760 victim
->__state
[1] |= kIOServiceTerm1WaiterState
;
1761 victim
->unlockForArbitration();
1762 assert_wait((event_t
)&victim
->__state
[1], THREAD_UNINT
);
1764 IOLockUnlock(gIOServiceBusyLock
);
1766 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
1767 TLOG("%s::did waitPhase1(%s)\n", getName(), victim
->getName());
1768 victim
->lockForArbitration();
1770 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
1772 victim
->unlockForArbitration();
1775 startPhase2
= didInactive
;
1778 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1779 IOUserClient::destroyUserReferences( victim
);
1781 iter
= victim
->getClientIterator();
1783 while( (client
= (IOService
*) iter
->getNextObject())) {
1784 TLOG("%s::requestTerminate(%s, %08llx)\n",
1785 client
->getName(), victim
->getName(), (long long)options
);
1786 ok
= client
->requestTerminate( victim
, options
);
1787 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1788 client
->getName(), victim
->getName(), ok
);
1790 uint64_t regID1
= client
->getRegistryEntryID();
1791 uint64_t regID2
= victim
->getRegistryEntryID();
1793 (ok
? IOSERVICE_TERMINATE_REQUEST_OK
1794 : IOSERVICE_TERMINATE_REQUEST_FAIL
),
1796 (uintptr_t) (regID1
>> 32),
1798 (uintptr_t) (regID2
>> 32));
1801 makeInactive
->setObject( client
);
1807 victim
= (IOService
*) makeInactive
->getObject(0);
1810 makeInactive
->removeObject(0);
1814 makeInactive
->release();
1818 lockForArbitration();
1819 __state
[1] &= ~kIOServiceTermPhase1State
;
1820 if (kIOServiceTerm1WaiterState
& __state
[1])
1822 __state
[1] &= ~kIOServiceTerm1WaiterState
;
1823 TLOG("%s::wakePhase1\n", getName());
1824 IOLockLock( gIOServiceBusyLock
);
1825 thread_wakeup( (event_t
) &__state
[1]);
1826 IOLockUnlock( gIOServiceBusyLock
);
1828 unlockForArbitration();
1830 scheduleTerminatePhase2( options
);
1835 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
1837 AbsoluteTime deadline
;
1838 int waitResult
= THREAD_AWAKENED
;
1839 bool wait
, haveDeadline
= false;
1841 options
|= kIOServiceRequired
;
1845 IOLockLock( gJobsLock
);
1847 if( (options
& kIOServiceSynchronous
)
1848 && (current_thread() != gIOTerminateThread
)) {
1851 wait
= (gIOTerminateThread
!= 0);
1853 // wait to become the terminate thread
1854 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
1858 gIOTerminateThread
= current_thread();
1859 gIOTerminatePhase2List
->setObject( this );
1863 while( gIOTerminateWork
)
1864 terminateWorker( options
);
1865 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1867 // wait for the victim to go non-busy
1868 if( !haveDeadline
) {
1869 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1870 haveDeadline
= true;
1872 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
1873 deadline
, THREAD_UNINT
);
1874 if( waitResult
== THREAD_TIMED_OUT
) {
1875 IOLog("%s::terminate(kIOServiceSynchronous) timeout\n", getName());
1878 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
1880 gIOTerminateThread
= 0;
1881 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1884 // ! kIOServiceSynchronous
1886 gIOTerminatePhase2List
->setObject( this );
1887 if( 0 == gIOTerminateWork
++) {
1888 if( !gIOTerminateThread
)
1889 kernel_thread_start(&terminateThread
, (void *) options
, &gIOTerminateThread
);
1891 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1895 IOLockUnlock( gJobsLock
);
1900 void IOService::terminateThread( void * arg
, wait_result_t waitResult
)
1902 IOLockLock( gJobsLock
);
1904 while (gIOTerminateWork
)
1905 terminateWorker( (uintptr_t) arg
);
1907 thread_deallocate(gIOTerminateThread
);
1908 gIOTerminateThread
= 0;
1909 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1911 IOLockUnlock( gJobsLock
);
1914 void IOService::scheduleStop( IOService
* provider
)
1916 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1918 uint64_t regID1
= getRegistryEntryID();
1919 uint64_t regID2
= provider
->getRegistryEntryID();
1921 IOSERVICE_TERMINATE_SCHEDULE_STOP
,
1923 (uintptr_t) (regID1
>> 32),
1925 (uintptr_t) (regID2
>> 32));
1927 IOLockLock( gJobsLock
);
1928 gIOStopList
->tailQ( this );
1929 gIOStopProviderList
->tailQ( provider
);
1931 if( 0 == gIOTerminateWork
++) {
1932 if( !gIOTerminateThread
)
1933 kernel_thread_start(&terminateThread
, (void *) 0, &gIOTerminateThread
);
1935 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1938 IOLockUnlock( gJobsLock
);
1941 void IOService::scheduleFinalize( void )
1943 TLOG("%s::scheduleFinalize\n", getName());
1945 uint64_t regID1
= getRegistryEntryID();
1947 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE
,
1949 (uintptr_t) (regID1
>> 32),
1952 IOLockLock( gJobsLock
);
1953 gIOFinalizeList
->tailQ( this );
1955 if( 0 == gIOTerminateWork
++) {
1956 if( !gIOTerminateThread
)
1957 kernel_thread_start(&terminateThread
, (void *) 0, &gIOTerminateThread
);
1959 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1962 IOLockUnlock( gJobsLock
);
1965 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1970 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1972 if( false == *defer
) {
1974 if( lockForArbitration( true )) {
1975 if( false == provider
->handleIsOpen( this ))
1976 scheduleStop( provider
);
1979 message( kIOMessageServiceIsRequestingClose
, provider
, (void *) options
);
1980 if( false == provider
->handleIsOpen( this ))
1981 scheduleStop( provider
);
1984 unlockForArbitration();
1991 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
1992 OSArray
* doPhase2List
,
1993 void *unused2 __unused
,
1994 void *unused3 __unused
)
2000 iter
= victim
->getClientIterator();
2002 while( (client
= (IOService
*) iter
->getNextObject())) {
2003 TLOG("%s::willTerminate(%s, %08llx)\n",
2004 client
->getName(), victim
->getName(), (long long)options
);
2006 uint64_t regID1
= client
->getRegistryEntryID();
2007 uint64_t regID2
= victim
->getRegistryEntryID();
2009 IOSERVICE_TERMINATE_WILL
,
2011 (uintptr_t) (regID1
>> 32),
2013 (uintptr_t) (regID2
>> 32));
2015 ok
= client
->willTerminate( victim
, options
);
2016 doPhase2List
->tailQ( client
);
2022 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
,
2023 void *unused1 __unused
, void *unused2 __unused
,
2024 void *unused3 __unused
)
2030 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *) options
);
2032 iter
= victim
->getClientIterator();
2034 while( (client
= (IOService
*) iter
->getNextObject())) {
2035 TLOG("%s::didTerminate(%s, %08llx)\n",
2036 client
->getName(), victim
->getName(), (long long)options
);
2037 client
->didTerminate( victim
, options
, &defer
);
2039 uint64_t regID1
= client
->getRegistryEntryID();
2040 uint64_t regID2
= victim
->getRegistryEntryID();
2042 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2043 : IOSERVICE_TERMINATE_DID
),
2045 (uintptr_t) (regID1
>> 32),
2047 (uintptr_t) (regID2
>> 32));
2049 TLOG("%s::didTerminate(%s, defer %d)\n",
2050 client
->getName(), victim
->getName(), defer
);
2056 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
,
2057 void *unused1 __unused
, void *unused2 __unused
,
2058 void *unused3 __unused
)
2060 TLOG("%s::finalize(%08llx)\n", victim
->getName(), (long long)options
);
2062 uint64_t regID1
= victim
->getRegistryEntryID();
2064 IOSERVICE_TERMINATE_FINALIZE
,
2066 (uintptr_t) (regID1
>> 32),
2069 victim
->finalize( options
);
2072 void IOService::actionStop( IOService
* provider
, IOService
* client
,
2073 void *unused1 __unused
, void *unused2 __unused
,
2074 void *unused3 __unused
)
2076 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
2078 uint64_t regID1
= provider
->getRegistryEntryID();
2079 uint64_t regID2
= client
->getRegistryEntryID();
2081 IOSERVICE_TERMINATE_STOP
,
2083 (uintptr_t) (regID1
>> 32),
2085 (uintptr_t) (regID2
>> 32));
2087 client
->stop( provider
);
2088 if( provider
->isOpen( client
))
2089 provider
->close( client
);
2090 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
2091 client
->detach( provider
);
2094 void IOService::terminateWorker( IOOptionBits options
)
2096 OSArray
* doPhase2List
;
2097 OSArray
* didPhase2List
;
2102 IOService
* provider
;
2108 options
|= kIOServiceRequired
;
2110 doPhase2List
= OSArray::withCapacity( 16 );
2111 didPhase2List
= OSArray::withCapacity( 16 );
2112 freeList
= OSSet::withCapacity( 16 );
2113 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
2117 workDone
= gIOTerminateWork
;
2119 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
2122 gIOTerminatePhase2List
->removeObject(0);
2123 IOLockUnlock( gJobsLock
);
2127 doPhase2
= victim
->lockForArbitration( true );
2129 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
2131 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
2132 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
2134 victim
->__state
[1] |= kIOServiceTermPhase2State
;
2136 victim
->unlockForArbitration();
2139 if( 0 == victim
->getClient()) {
2140 // no clients - will go to finalize
2141 IOLockLock( gJobsLock
);
2142 gIOFinalizeList
->tailQ( victim
);
2143 IOLockUnlock( gJobsLock
);
2145 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
2146 victim
, (void *) options
, (void *) doPhase2List
);
2148 didPhase2List
->headQ( victim
);
2151 victim
= (IOService
*) doPhase2List
->getObject(0);
2154 doPhase2List
->removeObject(0);
2158 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
2160 if( victim
->lockForArbitration( true )) {
2161 victim
->__state
[1] |= kIOServiceTermPhase3State
;
2162 victim
->unlockForArbitration();
2164 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
2165 victim
, (void *) options
);
2166 didPhase2List
->removeObject(0);
2168 IOLockLock( gJobsLock
);
2175 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
2177 IOLockUnlock( gJobsLock
);
2178 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
2179 victim
, (void *) options
);
2180 IOLockLock( gJobsLock
);
2182 freeList
->setObject( victim
);
2183 // safe if finalize list is append only
2184 gIOFinalizeList
->removeObject(0);
2188 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
2190 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
2193 if( !provider
->isChild( client
, gIOServicePlane
)) {
2194 // may be multiply queued - nop it
2195 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
2197 uint64_t regID1
= provider
->getRegistryEntryID();
2198 uint64_t regID2
= client
->getRegistryEntryID();
2200 IOSERVICE_TERMINATE_STOP_NOP
,
2202 (uintptr_t) (regID1
>> 32),
2204 (uintptr_t) (regID2
>> 32));
2207 // a terminated client is not ready for stop if it has clients, skip it
2208 if( (kIOServiceInactiveState
& client
->__state
[0]) && client
->getClient()) {
2209 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
2211 uint64_t regID1
= provider
->getRegistryEntryID();
2212 uint64_t regID2
= client
->getRegistryEntryID();
2214 IOSERVICE_TERMINATE_STOP_DEFER
,
2216 (uintptr_t) (regID1
>> 32),
2218 (uintptr_t) (regID2
>> 32));
2224 IOLockUnlock( gJobsLock
);
2225 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
2226 provider
, (void *) client
);
2227 IOLockLock( gJobsLock
);
2228 // check the finalize list now
2232 freeList
->setObject( client
);
2233 freeList
->setObject( provider
);
2235 // safe if stop list is append only
2236 gIOStopList
->removeObject( idx
);
2237 gIOStopProviderList
->removeObject( idx
);
2241 } while( doPhase3
);
2243 gIOTerminateWork
-= workDone
;
2244 moreToDo
= (gIOTerminateWork
!= 0);
2247 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
2249 IOSERVICE_TERMINATE_DONE
,
2250 (uintptr_t) gIOStopList
->getCount(), 0, 0, 0);
2253 } while( moreToDo
);
2255 IOLockUnlock( gJobsLock
);
2257 freeList
->release();
2258 doPhase2List
->release();
2259 didPhase2List
->release();
2261 IOLockLock( gJobsLock
);
2264 bool IOService::finalize( IOOptionBits options
)
2267 IOService
* provider
;
2269 iter
= getProviderIterator();
2273 while( (provider
= (IOService
*) iter
->getNextObject())) {
2276 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
2277 /* we come down here on programmatic terminate */
2279 if( provider
->isOpen( this ))
2280 provider
->close( this );
2284 if( provider
->lockForArbitration( true )) {
2285 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2286 scheduleStop( provider
);
2287 provider
->unlockForArbitration();
2304 void IOService::doServiceTerminate( IOOptionBits options
)
2308 // a method in case someone needs to override it
2309 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2313 if( client
->isParent( this, gIOServicePlane
, true))
2314 // we are the clients only provider
2315 ok
= client
->terminate( options
);
2322 bool IOService::terminate( IOOptionBits options
)
2324 options
|= kIOServiceTerminate
;
2326 return( terminatePhase1( options
));
2329 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2335 struct ServiceOpenMessageContext
2337 IOService
* service
;
2339 IOService
* excludeClient
;
2340 IOOptionBits options
;
2343 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2345 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2347 if( object
!= context
->excludeClient
)
2348 context
->service
->messageClient( context
->type
, object
, (void *) context
->options
);
2351 bool IOService::open( IOService
* forClient
,
2352 IOOptionBits options
,
2356 ServiceOpenMessageContext context
;
2358 context
.service
= this;
2359 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2360 context
.excludeClient
= forClient
;
2361 context
.options
= options
;
2363 applyToInterested( gIOGeneralInterest
,
2364 &serviceOpenMessageApplier
, &context
);
2366 if( false == lockForArbitration(false) )
2369 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2371 ok
= handleOpen( forClient
, options
, arg
);
2373 unlockForArbitration();
2378 void IOService::close( IOService
* forClient
,
2379 IOOptionBits options
)
2384 lockForArbitration();
2386 wasClosed
= handleIsOpen( forClient
);
2388 handleClose( forClient
, options
);
2389 last
= (__state
[1] & kIOServiceTermPhase3State
);
2392 unlockForArbitration();
2395 forClient
->scheduleStop( this );
2397 else if( wasClosed
) {
2399 ServiceOpenMessageContext context
;
2401 context
.service
= this;
2402 context
.type
= kIOMessageServiceWasClosed
;
2403 context
.excludeClient
= forClient
;
2404 context
.options
= options
;
2406 applyToInterested( gIOGeneralInterest
,
2407 &serviceOpenMessageApplier
, &context
);
2411 bool IOService::isOpen( const IOService
* forClient
) const
2413 IOService
* self
= (IOService
*) this;
2416 self
->lockForArbitration();
2418 ok
= handleIsOpen( forClient
);
2420 self
->unlockForArbitration();
2425 bool IOService::handleOpen( IOService
* forClient
,
2426 IOOptionBits options
,
2431 ok
= (0 == __owner
);
2433 __owner
= forClient
;
2435 else if( options
& kIOServiceSeize
) {
2436 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2437 __owner
, (void *) options
));
2438 if( ok
&& (0 == __owner
))
2439 __owner
= forClient
;
2446 void IOService::handleClose( IOService
* forClient
,
2447 IOOptionBits options
)
2449 if( __owner
== forClient
)
2453 bool IOService::handleIsOpen( const IOService
* forClient
) const
2456 return( __owner
== forClient
);
2458 return( __owner
!= forClient
);
2462 * Probing & starting
2464 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2466 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2467 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2475 val1
= obj1
->priority
;
2478 val2
= obj2
->priority
;
2480 return ( val1
- val2
);
2483 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2485 OSDictionary
* dict
;
2486 IOService
* service
;
2487 _IOServiceNotifier
* notify
;
2488 OSSymbol
* key
= (OSSymbol
*) ref
;
2491 if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2492 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2493 else if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2494 return( notify
->priority
);
2496 else if( (service
= OSDynamicCast( IOService
, entry
)))
2497 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2504 return( (SInt32
) offset
->unsigned32BitValue());
2506 return( kIODefaultProbeScore
);
2509 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2511 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2512 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2520 val1
= IOServiceObjectOrder( obj1
, ref
);
2523 val2
= IOServiceObjectOrder( obj2
, ref
);
2525 return ( val1
- val2
);
2528 IOService
* IOService::copyClientWithCategory( const OSSymbol
* category
)
2530 IOService
* service
= 0;
2532 const OSSymbol
* nextCat
;
2534 iter
= getClientIterator();
2536 while( (service
= (IOService
*) iter
->getNextObject())) {
2537 if( kIOServiceInactiveState
& service
->__state
[0])
2539 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2540 service
->getProperty( gIOMatchCategoryKey
));
2541 if( category
== nextCat
)
2552 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2555 service
= copyClientWithCategory(category
);
2561 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2563 _IOServiceNotifierInvocation invocation
;
2567 invocation
.thread
= current_thread();
2570 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2573 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2574 _IOServiceNotifierInvocation
*, link
);
2580 ret
= (*notify
->handler
)(notify
->target
, notify
->ref
, this, notify
);
2583 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2584 _IOServiceNotifierInvocation
*, link
);
2585 if( kIOServiceNotifyWaiter
& notify
->state
) {
2586 notify
->state
&= ~kIOServiceNotifyWaiter
;
2587 WAKEUPNOTIFY( notify
);
2596 * Alloc and probe matching classes,
2597 * called on the provider instance
2600 void IOService::probeCandidates( OSOrderedSet
* matches
)
2602 OSDictionary
* match
= 0;
2605 IOService
* newInst
;
2606 OSDictionary
* props
;
2609 OSOrderedSet
* familyMatches
= 0;
2610 OSOrderedSet
* startList
;
2611 OSDictionary
* startDict
= 0;
2612 const OSSymbol
* category
;
2614 _IOServiceNotifier
* notify
;
2615 OSObject
* nextMatch
= 0;
2617 bool needReloc
= false;
2621 IOService
* client
= NULL
;
2625 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2627 nextMatch
->retain();
2628 matches
->removeObject(nextMatch
);
2630 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2632 lockForArbitration();
2633 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2634 invokeNotifer( notify
);
2635 unlockForArbitration();
2636 nextMatch
->release();
2640 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2641 nextMatch
->release();
2648 debugFlags
= getDebugFlags( match
);
2652 category
= OSDynamicCast( OSSymbol
,
2653 match
->getObject( gIOMatchCategoryKey
));
2655 category
= gIODefaultMatchCategoryKey
;
2657 if( (client
= copyClientWithCategory(category
)) ) {
2659 if( debugFlags
& kIOLogMatch
)
2660 LOG("%s: match category %s exists\n", getName(),
2661 category
->getCStringNoCopy());
2663 nextMatch
->release();
2672 // create a copy now in case its modified during matching
2673 props
= OSDictionary::withDictionary( match
, match
->getCount());
2676 props
->setCapacityIncrement(1);
2678 // check the nub matches
2679 if( false == matchPassive(props
, kIOServiceChangesOK
| kIOServiceClassDone
))
2682 // Check to see if driver reloc has been loaded.
2683 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2686 if( debugFlags
& kIOLogCatalogue
)
2687 LOG("%s: stalling for module\n", getName());
2689 // If reloc hasn't been loaded, exit;
2690 // reprobing will occur after reloc has been loaded.
2694 // reorder on family matchPropertyTable score.
2695 if( 0 == familyMatches
)
2696 familyMatches
= OSOrderedSet::withCapacity( 1,
2697 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2699 familyMatches
->setObject( props
);
2704 nextMatch
->release();
2713 if( familyMatches
) {
2716 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2719 familyMatches
->removeObject( props
);
2724 debugFlags
= getDebugFlags( props
);
2727 symbol
= OSDynamicCast( OSSymbol
,
2728 props
->getObject( gIOClassKey
));
2732 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), symbol, props);
2734 // alloc the driver instance
2735 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2738 IOLog("Couldn't alloc class \"%s\"\n",
2739 symbol
->getCStringNoCopy());
2743 // init driver instance
2744 if( !(inst
->init( props
))) {
2746 if( debugFlags
& kIOLogStart
)
2747 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2751 if( __state
[1] & kIOServiceSynchronousState
)
2752 inst
->__state
[1] |= kIOServiceSynchronousState
;
2754 // give the driver the default match category if not specified
2755 category
= OSDynamicCast( OSSymbol
,
2756 props
->getObject( gIOMatchCategoryKey
));
2758 category
= gIODefaultMatchCategoryKey
;
2759 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2760 // attach driver instance
2761 if( !(inst
->attach( this )))
2764 // pass in score from property table
2765 score
= familyMatches
->orderObject( props
);
2767 // & probe the new driver instance
2769 if( debugFlags
& kIOLogProbe
)
2770 LOG("%s::probe(%s)\n",
2771 inst
->getMetaClass()->getClassName(), getName());
2774 newInst
= inst
->probe( this, &score
);
2775 inst
->detach( this );
2778 if( debugFlags
& kIOLogProbe
)
2779 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2785 newPri
= OSNumber::withNumber( score
, 32 );
2787 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2791 // add to start list for the match category
2793 startDict
= OSDictionary::withCapacity( 1 );
2794 assert( startDict
);
2795 startList
= (OSOrderedSet
*)
2796 startDict
->getObject( category
);
2797 if( 0 == startList
) {
2798 startList
= OSOrderedSet::withCapacity( 1,
2799 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2800 if( startDict
&& startList
) {
2801 startDict
->setObject( category
, startList
);
2802 startList
->release();
2805 assert( startList
);
2807 startList
->setObject( newInst
);
2815 familyMatches
->release();
2819 // start the best (until success) of each category
2821 iter
= OSCollectionIterator::withCollection( startDict
);
2823 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2825 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2826 assert( startList
);
2831 while( true // (!started)
2832 && (inst
= (IOService
*)startList
->getFirstObject())) {
2835 startList
->removeObject(inst
);
2838 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2840 if( debugFlags
& kIOLogStart
) {
2842 LOG( "match category exists, skipping " );
2843 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2844 getName(), inst
->getRetainCount());
2847 if( false == started
)
2848 started
= startCandidate( inst
);
2850 if( (debugFlags
& kIOLogStart
) && (false == started
))
2851 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2852 inst
->getRetainCount());
2861 // adjust the busy count by +1 if matching is stalled for a module,
2862 // or -1 if a previously stalled matching is complete.
2863 lockForArbitration();
2865 uint64_t regID
= getRegistryEntryID();
2868 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2872 IOSERVICE_MODULESTALL
,
2874 (uintptr_t) (regID
>> 32),
2878 __state
[1] |= kIOServiceModuleStallState
;
2881 } else if( __state
[1] & kIOServiceModuleStallState
) {
2884 IOSERVICE_MODULEUNSTALL
,
2886 (uintptr_t) (regID
>> 32),
2890 __state
[1] &= ~kIOServiceModuleStallState
;
2894 _adjustBusy( adjBusy
);
2895 unlockForArbitration();
2898 startDict
->release();
2902 * Start a previously attached & probed instance,
2903 * called on exporting object instance
2906 bool IOService::startCandidate( IOService
* service
)
2910 ok
= service
->attach( this );
2914 if (this != gIOResources
)
2916 // stall for any nub resources
2918 // stall for any driver resources
2919 service
->checkResources();
2922 AbsoluteTime startTime
;
2923 AbsoluteTime endTime
;
2926 if (kIOLogStart
& gIOKitDebug
)
2927 clock_get_uptime(&startTime
);
2929 ok
= service
->start(this);
2931 if (kIOLogStart
& gIOKitDebug
)
2933 clock_get_uptime(&endTime
);
2935 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2937 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2938 absolutetime_to_nanoseconds(endTime
, &nano
);
2939 if (nano
> 500000000ULL)
2940 IOLog("%s::start took %ld ms\n", service
->getName(), (long)(UInt32
)(nano
/ 1000000ULL));
2944 service
->detach( this );
2949 void IOService::publishResource( const char * key
, OSObject
* value
)
2951 const OSSymbol
* sym
;
2953 if( (sym
= OSSymbol::withCString( key
))) {
2954 publishResource( sym
, value
);
2959 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
2962 value
= (OSObject
*) gIOServiceKey
;
2964 gIOResources
->setProperty( key
, value
);
2966 if( IORecursiveLockHaveLock( gNotificationLock
))
2969 gIOResourceGenerationCount
++;
2970 gIOResources
->registerService();
2973 bool IOService::addNeededResource( const char * key
)
2975 OSObject
* resourcesProp
;
2980 resourcesProp
= getProperty( gIOResourceMatchKey
);
2982 newKey
= OSString::withCString( key
);
2983 if( (0 == resourcesProp
) || (0 == newKey
))
2986 set
= OSDynamicCast( OSSet
, resourcesProp
);
2988 set
= OSSet::withCapacity( 1 );
2990 set
->setObject( resourcesProp
);
2995 set
->setObject( newKey
);
2997 ret
= setProperty( gIOResourceMatchKey
, set
);
3003 bool IOService::checkResource( OSObject
* matching
)
3006 OSDictionary
* table
;
3008 if( (str
= OSDynamicCast( OSString
, matching
))) {
3009 if( gIOResources
->getProperty( str
))
3014 table
= resourceMatching( str
);
3015 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
3018 IOLog("%s: Can't match using: %s\n", getName(),
3019 matching
->getMetaClass()->getClassName());
3020 /* false would stall forever */
3024 if( gIOKitDebug
& kIOLogConfig
)
3025 LOG("config(%p): stalling %s\n", IOThreadSelf(), getName());
3027 waitForService( table
);
3029 if( gIOKitDebug
& kIOLogConfig
)
3030 LOG("config(%p): waking\n", IOThreadSelf() );
3035 bool IOService::checkResources( void )
3037 OSObject
* resourcesProp
;
3042 resourcesProp
= getProperty( gIOResourceMatchKey
);
3043 if( 0 == resourcesProp
)
3046 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
3048 iter
= OSCollectionIterator::withCollection( set
);
3050 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
3051 ok
= checkResource( resourcesProp
);
3056 ok
= checkResource( resourcesProp
);
3062 void _IOConfigThread::configThread( void )
3064 _IOConfigThread
* inst
;
3067 if( !(inst
= new _IOConfigThread
))
3072 if (KERN_SUCCESS
!= kernel_thread_start(&_IOConfigThread::main
, inst
, &unused
))
3085 void _IOConfigThread::free( void )
3087 thread_deallocate(current_thread());
3091 void IOService::doServiceMatch( IOOptionBits options
)
3093 _IOServiceNotifier
* notify
;
3095 OSOrderedSet
* matches
;
3096 SInt32 catalogGeneration
;
3097 bool keepGuessing
= true;
3098 bool reRegistered
= true;
3101 // job->nub->deliverNotification( gIOPublishNotification,
3102 // kIOServiceRegisteredState, 0xffffffff );
3104 while( keepGuessing
) {
3106 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
3107 // the matches list should always be created by findDrivers()
3110 lockForArbitration();
3111 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
3112 deliverNotification( gIOFirstPublishNotification
,
3113 kIOServiceFirstPublishState
, 0xffffffff );
3115 __state
[1] &= ~kIOServiceNeedConfigState
;
3116 __state
[1] |= kIOServiceConfigState
;
3117 didRegister
= (0 == (kIOServiceRegisteredState
& __state
[0]));
3118 __state
[0] |= kIOServiceRegisteredState
;
3120 keepGuessing
&= (0 == (__state
[0] & kIOServiceInactiveState
));
3121 if (reRegistered
&& keepGuessing
) {
3122 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3123 gNotifications
->getObject( gIOPublishNotification
) );
3125 while((notify
= (_IOServiceNotifier
*)
3126 iter
->getNextObject())) {
3128 if( matchPassive(notify
->matching
, 0)
3129 && (kIOServiceNotifyEnable
& notify
->state
))
3130 matches
->setObject( notify
);
3138 getMetaClass()->addInstance(this);
3140 unlockForArbitration();
3142 if (keepGuessing
&& matches
->getCount() && (kIOReturnSuccess
== getResources()))
3143 probeCandidates( matches
);
3148 lockForArbitration();
3149 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
3151 (reRegistered
|| (catalogGeneration
!=
3152 gIOCatalogue
->getGenerationCount()))
3153 && (0 == (__state
[0] & kIOServiceInactiveState
));
3156 unlockForArbitration();
3159 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3160 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
3161 deliverNotification( gIOMatchedNotification
,
3162 kIOServiceMatchedState
, 0xffffffff );
3163 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
3164 deliverNotification( gIOFirstMatchNotification
,
3165 kIOServiceFirstMatchState
, 0xffffffff );
3168 __state
[1] &= ~kIOServiceConfigState
;
3169 if( __state
[0] & kIOServiceInactiveState
)
3170 scheduleTerminatePhase2();
3173 unlockForArbitration();
3176 UInt32
IOService::_adjustBusy( SInt32 delta
)
3181 bool wasQuiet
, nowQuiet
, needWake
;
3184 result
= __state
[1] & kIOServiceBusyStateMask
;
3188 next
->lockForArbitration();
3189 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
3190 wasQuiet
= (0 == count
);
3191 if (((delta
< 0) && wasQuiet
) || ((delta
> 0) && (kIOServiceBusyMax
== count
)))
3192 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next
->getName(), count
, delta
);
3195 next
->__state
[1] = (next
->__state
[1] & ~kIOServiceBusyStateMask
) | count
;
3196 nowQuiet
= (0 == count
);
3197 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
3200 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
3201 IOLockLock( gIOServiceBusyLock
);
3202 thread_wakeup( (event_t
) next
);
3203 IOLockUnlock( gIOServiceBusyLock
);
3206 next
->unlockForArbitration();
3208 if( (wasQuiet
|| nowQuiet
) ) {
3209 uint64_t regID
= next
->getRegistryEntryID();
3212 ((wasQuiet
/*nowBusy*/) ? IOSERVICE_BUSY
: IOSERVICE_NONBUSY
),
3214 (uintptr_t) (regID
>> 32),
3220 next
->__timeBusy
= mach_absolute_time();
3224 next
->__accumBusy
+= mach_absolute_time() - next
->__timeBusy
;
3225 next
->__timeBusy
= 0;
3228 MessageClientsContext context
;
3230 context
.service
= next
;
3231 context
.type
= kIOMessageServiceBusyStateChange
;
3232 context
.argument
= (void *) wasQuiet
; /*nowBusy*/
3233 context
.argSize
= 0;
3235 applyToInterestNotifiers( next
, gIOBusyInterest
,
3236 &messageClientsApplier
, &context
);
3239 if( nowQuiet
&& (next
== gIOServiceRoot
)) {
3240 OSKext::considerUnloads();
3241 IOServiceTrace(IOSERVICE_REGISTRY_QUIET
, 0, 0, 0, 0);
3246 delta
= nowQuiet
? -1 : +1;
3248 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
3253 void IOService::adjustBusy( SInt32 delta
)
3255 lockForArbitration();
3256 _adjustBusy( delta
);
3257 unlockForArbitration();
3260 uint64_t IOService::getAccumulatedBusyTime( void )
3262 uint64_t accumBusy
= __accumBusy
;
3263 uint64_t timeBusy
= __timeBusy
;
3268 accumBusy
= __accumBusy
;
3269 timeBusy
= __timeBusy
;
3271 accumBusy
+= mach_absolute_time() - timeBusy
;
3273 while (timeBusy
!= __timeBusy
);
3275 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&accumBusy
, &nano
);
3280 UInt32
IOService::getBusyState( void )
3282 return( __state
[1] & kIOServiceBusyStateMask
);
3285 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3286 mach_timespec_t
* timeout
)
3288 panic("waitForState");
3289 return (kIOReturnUnsupported
);
3292 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3296 int waitResult
= THREAD_AWAKENED
;
3297 bool computeDeadline
= true;
3298 AbsoluteTime abstime
;
3301 lockForArbitration();
3302 IOLockLock( gIOServiceBusyLock
);
3303 wait
= (value
!= (__state
[1] & mask
));
3305 __state
[1] |= kIOServiceBusyWaiterState
;
3306 unlockForArbitration();
3307 if( timeout
!= UINT64_MAX
) {
3308 if( computeDeadline
) {
3309 AbsoluteTime nsinterval
;
3310 nanoseconds_to_absolutetime(timeout
, &nsinterval
);
3311 clock_absolutetime_interval_to_deadline(nsinterval
, &abstime
);
3312 computeDeadline
= false;
3314 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
3317 assert_wait((event_t
)this, THREAD_UNINT
);
3319 unlockForArbitration();
3320 IOLockUnlock( gIOServiceBusyLock
);
3322 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
3324 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3326 if( waitResult
== THREAD_TIMED_OUT
)
3327 return( kIOReturnTimeout
);
3329 return( kIOReturnSuccess
);
3332 IOReturn
IOService::waitQuiet( uint64_t timeout
)
3334 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
3337 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
3343 timeoutNS
= timeout
->tv_sec
;
3344 timeoutNS
*= kSecondScale
;
3345 timeoutNS
+= timeout
->tv_nsec
;
3348 timeoutNS
= UINT64_MAX
;
3350 return( waitForState( kIOServiceBusyStateMask
, 0, timeoutNS
));
3353 bool IOService::serializeProperties( OSSerialize
* s
) const
3356 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
3357 sizeof( __state
), "__state");
3359 return( super::serializeProperties(s
) );
3363 void _IOConfigThread::main(void * arg
, wait_result_t result
)
3365 _IOConfigThread
* self
= (_IOConfigThread
*) arg
;
3366 _IOServiceJob
* job
;
3370 thread_precedence_policy_data_t precedence
= { -1 };
3372 kr
= thread_policy_set(current_thread(),
3373 THREAD_PRECEDENCE_POLICY
,
3374 (thread_policy_t
) &precedence
,
3375 THREAD_PRECEDENCE_POLICY_COUNT
);
3376 if (KERN_SUCCESS
!= kr
)
3377 IOLog("thread_policy_set(%d)\n", kr
);
3383 semaphore_wait( gJobsSemaphore
);
3385 IOTakeLock( gJobsLock
);
3386 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
3388 gJobs
->removeObject(job
);
3391 // gNumConfigThreads--; // we're out of service
3392 gNumWaitingThreads
--; // we're out of service
3394 IOUnlock( gJobsLock
);
3400 if( gIOKitDebug
& kIOLogConfig
)
3401 LOG("config(%p): starting on %s, %d\n",
3402 IOThreadSelf(), job
->nub
->getName(), job
->type
);
3404 switch( job
->type
) {
3407 nub
->doServiceMatch( job
->options
);
3411 LOG("config(%p): strange type (%d)\n",
3412 IOThreadSelf(), job
->type
);
3419 IOTakeLock( gJobsLock
);
3420 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
3422 gNumWaitingThreads
++; // back in service
3423 // gNumConfigThreads++;
3425 if( 0 == --gNumConfigThreads
) {
3426 // IOLog("MATCH IDLE\n");
3427 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3430 IOUnlock( gJobsLock
);
3435 if( gIOKitDebug
& kIOLogConfig
)
3436 LOG("config(%p): terminating\n", IOThreadSelf() );
3441 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3444 int waitResult
= THREAD_AWAKENED
;
3445 bool computeDeadline
= true;
3446 AbsoluteTime deadline
;
3448 IOLockLock( gJobsLock
);
3450 wait
= (0 != gNumConfigThreads
);
3453 if( computeDeadline
) {
3454 clock_interval_to_deadline(
3455 msToWait
, kMillisecondScale
, &deadline
);
3456 computeDeadline
= false;
3458 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
3459 deadline
, THREAD_UNINT
);
3461 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3465 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3466 IOLockUnlock( gJobsLock
);
3468 if( waitResult
== THREAD_TIMED_OUT
)
3469 return( kIOReturnTimeout
);
3471 return( kIOReturnSuccess
);
3474 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3481 IOTakeLock( gJobsLock
);
3484 gJobs
->setLastObject( job
);
3486 count
= gNumWaitingThreads
;
3487 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3489 create
= ( (gOutstandingJobs
> count
)
3490 && (gNumConfigThreads
< kMaxConfigThreads
) );
3492 gNumConfigThreads
++;
3493 gNumWaitingThreads
++;
3496 IOUnlock( gJobsLock
);
3501 if( gIOKitDebug
& kIOLogConfig
)
3502 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3503 _IOConfigThread::configThread();
3506 semaphore_signal( gJobsSemaphore
);
3509 struct IOServiceMatchContext
3511 OSDictionary
* table
;
3519 bool IOService::instanceMatch(const OSObject
* entry
, void * context
)
3521 IOServiceMatchContext
* ctx
= (typeof(ctx
)) context
;
3522 IOService
* service
= (typeof(service
)) entry
;
3523 OSDictionary
* table
= ctx
->table
;
3524 uint32_t options
= ctx
->options
;
3525 uint32_t state
= ctx
->state
;
3532 match
= ((state
== (state
& service
->__state
[0]))
3533 && (0 == (service
->__state
[0] & kIOServiceInactiveState
)));
3535 ctx
->count
+= table
->getCount();
3536 match
= service
->matchInternal(table
, options
, &done
);
3543 if ((kIONotifyOnce
& options
) && (ctx
->done
== ctx
->count
))
3546 ctx
->result
= service
;
3549 else if (!ctx
->result
)
3551 ctx
->result
= OSSet::withObjects((const OSObject
**) &service
, 1, 1);
3555 ((OSSet
*)ctx
->result
)->setObject(service
);
3560 // internal - call with gNotificationLock
3561 OSObject
* IOService::copyExistingServices( OSDictionary
* matching
,
3562 IOOptionBits inState
, IOOptionBits options
)
3564 OSObject
* current
= 0;
3566 IOService
* service
;
3574 OSSerialize
* s
= OSSerialize::withCapacity(128);
3575 matching
->serialize(s
);
3578 if((obj
= matching
->getObject(gIOProviderClassKey
))
3580 && gIOResourcesKey
->isEqualTo(obj
)
3581 && (service
= gIOResources
))
3583 if( (inState
== (service
->__state
[0] & inState
))
3584 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3585 && service
->matchPassive(matching
, options
))
3587 if( options
& kIONotifyOnce
)
3593 current
= OSSet::withObjects((const OSObject
**) &service
, 1, 1 );
3598 IOServiceMatchContext ctx
;
3599 ctx
.table
= matching
;
3600 ctx
.state
= inState
;
3603 ctx
.options
= options
;
3606 if ((str
= OSDynamicCast(OSString
, obj
)))
3608 const OSSymbol
* sym
= OSSymbol::withString(str
);
3609 OSMetaClass::applyToInstancesOfClassName(sym
, instanceMatch
, &ctx
);
3614 IOService::gMetaClass
.applyToInstances(instanceMatch
, &ctx
);
3618 current
= ctx
.result
;
3620 options
|= kIOServiceInternalDone
| kIOServiceClassDone
;
3621 if (current
&& (ctx
.done
!= ctx
.count
))
3624 source
= OSDynamicCast(OSSet
, current
);
3626 while ((service
= (IOService
*) source
->getAnyObject()))
3628 if (service
->matchPassive(matching
, options
))
3630 if( options
& kIONotifyOnce
)
3638 ((OSSet
*)current
)->setObject( service
);
3642 current
= OSSet::withObjects(
3643 (const OSObject
**) &service
, 1, 1 );
3646 source
->removeObject(service
);
3654 OSObject
* _current
= 0;
3656 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3657 kIORegistryIterateRecursively
);
3661 while( (service
= (IOService
*) iter
->getNextObject())) {
3662 if( (inState
== (service
->__state
[0] & inState
))
3663 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3664 && service
->matchPassive(matching
, 0)) {
3666 if( options
& kIONotifyOnce
) {
3672 ((OSSet
*)_current
)->setObject( service
);
3674 _current
= OSSet::withObjects(
3675 (const OSObject
**) &service
, 1, 1 );
3678 } while( !service
&& !iter
->isValid());
3683 if ( ((current
!= 0) != (_current
!= 0))
3684 || (current
&& _current
&& !current
->isEqualTo(_current
)))
3686 OSSerialize
* s1
= OSSerialize::withCapacity(128);
3687 OSSerialize
* s2
= OSSerialize::withCapacity(128);
3688 current
->serialize(s1
);
3689 _current
->serialize(s2
);
3690 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", current
, _current
, s
->text(), s1
->text(), s2
->text());
3695 if (_current
) _current
->release();
3701 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
3702 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3711 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3715 // is a lock even needed?
3718 iter
= (OSIterator
*) copyExistingServices( matching
,
3719 kIOServiceMatchedState
);
3726 IOService
* IOService::copyMatchingService( OSDictionary
* matching
)
3728 IOService
* service
;
3730 // is a lock even needed?
3733 service
= (IOService
*) copyExistingServices( matching
,
3734 kIOServiceMatchedState
, kIONotifyOnce
);
3741 struct _IOServiceMatchingNotificationHandlerRef
3743 IOServiceNotificationHandler handler
;
3747 static bool _IOServiceMatchingNotificationHandler( void * target
, void * refCon
,
3748 IOService
* newService
,
3749 IONotifier
* notifier
)
3751 return ((*((_IOServiceNotifier
*) notifier
)->compatHandler
)(target
, refCon
, newService
));
3754 // internal - call with gNotificationLock
3755 IONotifier
* IOService::setNotification(
3756 const OSSymbol
* type
, OSDictionary
* matching
,
3757 IOServiceMatchingNotificationHandler handler
, void * target
, void * ref
,
3760 _IOServiceNotifier
* notify
= 0;
3766 notify
= new _IOServiceNotifier
;
3767 if( notify
&& !notify
->init()) {
3773 notify
->handler
= handler
;
3774 notify
->target
= target
;
3775 notify
->matching
= matching
;
3777 if (handler
== &_IOServiceMatchingNotificationHandler
)
3779 notify
->compatHandler
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->handler
;
3780 notify
->ref
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->ref
;
3784 notify
->priority
= priority
;
3785 notify
->state
= kIOServiceNotifyEnable
;
3786 queue_init( ¬ify
->handlerInvocations
);
3790 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3791 set
= OSOrderedSet::withCapacity( 1,
3792 IONotifyOrdering
, 0 );
3794 gNotifications
->setObject( type
, set
);
3798 notify
->whence
= set
;
3800 set
->setObject( notify
);
3806 // internal - call with gNotificationLock
3807 IONotifier
* IOService::doInstallNotification(
3808 const OSSymbol
* type
, OSDictionary
* matching
,
3809 IOServiceMatchingNotificationHandler handler
,
3810 void * target
, void * ref
,
3811 SInt32 priority
, OSIterator
** existing
)
3814 IONotifier
* notify
;
3815 IOOptionBits inState
;
3820 if( type
== gIOPublishNotification
)
3821 inState
= kIOServiceRegisteredState
;
3823 else if( type
== gIOFirstPublishNotification
)
3824 inState
= kIOServiceFirstPublishState
;
3826 else if( (type
== gIOMatchedNotification
)
3827 || (type
== gIOFirstMatchNotification
))
3828 inState
= kIOServiceMatchedState
;
3829 else if( type
== gIOTerminatedNotification
)
3834 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3837 // get the current set
3838 exist
= (OSIterator
*) copyExistingServices( matching
, inState
);
3847 #if !defined(__LP64__)
3848 IONotifier
* IOService::installNotification(const OSSymbol
* type
, OSDictionary
* matching
,
3849 IOServiceNotificationHandler handler
,
3850 void * target
, void * refCon
,
3851 SInt32 priority
, OSIterator
** existing
)
3853 IONotifier
* result
;
3854 _IOServiceMatchingNotificationHandlerRef ref
;
3855 ref
.handler
= handler
;
3858 result
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3859 &_IOServiceMatchingNotificationHandler
,
3860 target
, &ref
, priority
, existing
);
3862 matching
->release();
3866 #endif /* !defined(__LP64__) */
3869 IONotifier
* IOService::installNotification(
3870 const OSSymbol
* type
, OSDictionary
* matching
,
3871 IOServiceMatchingNotificationHandler handler
,
3872 void * target
, void * ref
,
3873 SInt32 priority
, OSIterator
** existing
)
3875 IONotifier
* notify
;
3879 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3880 priority
, existing
);
3887 IONotifier
* IOService::addNotification(
3888 const OSSymbol
* type
, OSDictionary
* matching
,
3889 IOServiceNotificationHandler handler
,
3890 void * target
, void * refCon
,
3893 IONotifier
* result
;
3894 _IOServiceMatchingNotificationHandlerRef ref
;
3896 ref
.handler
= handler
;
3899 result
= addMatchingNotification(type
, matching
, &_IOServiceMatchingNotificationHandler
,
3900 target
, &ref
, priority
);
3903 matching
->release();
3908 IONotifier
* IOService::addMatchingNotification(
3909 const OSSymbol
* type
, OSDictionary
* matching
,
3910 IOServiceMatchingNotificationHandler handler
,
3911 void * target
, void * ref
,
3914 OSIterator
* existing
= NULL
;
3915 _IOServiceNotifier
* notify
;
3918 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3919 handler
, target
, ref
, priority
, &existing
);
3921 // send notifications for existing set
3924 notify
->retain(); // in case handler remove()s
3925 while( (next
= (IOService
*) existing
->getNextObject())) {
3927 next
->lockForArbitration();
3928 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3929 next
->invokeNotifer( notify
);
3930 next
->unlockForArbitration();
3933 existing
->release();
3939 bool IOService::syncNotificationHandler(
3940 void * /* target */, void * ref
,
3941 IOService
* newService
,
3942 IONotifier
* notifier
)
3946 if (!*((IOService
**) ref
))
3948 newService
->retain();
3949 (*(IOService
**) ref
) = newService
;
3957 IOService
* IOService::waitForMatchingService( OSDictionary
* matching
,
3960 IONotifier
* notify
= 0;
3961 // priority doesn't help us much since we need a thread wakeup
3962 SInt32 priority
= 0;
3973 result
= (IOService
*) copyExistingServices( matching
,
3974 kIOServiceMatchedState
, kIONotifyOnce
);
3977 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
3978 &IOService::syncNotificationHandler
, (void *) 0,
3979 &result
, priority
);
3982 if (UINT64_MAX
!= timeout
)
3984 AbsoluteTime deadline
;
3985 nanoseconds_to_absolutetime(timeout
, &deadline
);
3986 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
3987 SLEEPNOTIFYTO(&result
, deadline
);
3991 SLEEPNOTIFY(&result
);
3999 notify
->remove(); // dequeues
4004 IOService
* IOService::waitForService( OSDictionary
* matching
,
4005 mach_timespec_t
* timeout
)
4012 timeoutNS
= timeout
->tv_sec
;
4013 timeoutNS
*= kSecondScale
;
4014 timeoutNS
+= timeout
->tv_nsec
;
4017 timeoutNS
= UINT64_MAX
;
4019 result
= waitForMatchingService(matching
, timeoutNS
);
4021 matching
->release();
4028 void IOService::deliverNotification( const OSSymbol
* type
,
4029 IOOptionBits orNewState
, IOOptionBits andNewState
)
4031 _IOServiceNotifier
* notify
;
4033 OSArray
* willSend
= 0;
4035 lockForArbitration();
4037 if( (0 == (__state
[0] & kIOServiceInactiveState
))
4038 || (type
== gIOTerminatedNotification
)) {
4042 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
4043 gNotifications
->getObject( type
) );
4046 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
4048 if( matchPassive(notify
->matching
, 0)
4049 && (kIOServiceNotifyEnable
& notify
->state
)) {
4051 willSend
= OSArray::withCapacity(8);
4053 willSend
->setObject( notify
);
4059 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
4065 for( unsigned int idx
= 0;
4066 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
4068 invokeNotifer( notify
);
4070 willSend
->release();
4072 unlockForArbitration();
4075 IOOptionBits
IOService::getState( void ) const
4077 return( __state
[0] );
4081 * Helpers to make matching objects for simple cases
4084 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
4085 OSDictionary
* table
)
4088 const OSString
* str
;
4090 str
= OSSymbol::withString(name
);
4095 table
= OSDictionary::withCapacity( 2 );
4097 table
->setObject(gIOProviderClassKey
, (OSObject
*)str
);
4103 OSDictionary
* IOService::serviceMatching( const char * name
,
4104 OSDictionary
* table
)
4106 const OSString
* str
;
4108 str
= OSSymbol::withCString( name
);
4112 table
= serviceMatching( str
, table
);
4117 OSDictionary
* IOService::nameMatching( const OSString
* name
,
4118 OSDictionary
* table
)
4121 table
= OSDictionary::withCapacity( 2 );
4123 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
4128 OSDictionary
* IOService::nameMatching( const char * name
,
4129 OSDictionary
* table
)
4131 const OSString
* str
;
4133 str
= OSSymbol::withCString( name
);
4137 table
= nameMatching( str
, table
);
4142 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
4143 OSDictionary
* table
)
4145 table
= serviceMatching( gIOResourcesKey
, table
);
4147 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
4152 OSDictionary
* IOService::resourceMatching( const char * name
,
4153 OSDictionary
* table
)
4155 const OSSymbol
* str
;
4157 str
= OSSymbol::withCString( name
);
4161 table
= resourceMatching( str
, table
);
4167 OSDictionary
* IOService::propertyMatching( const OSSymbol
* key
, const OSObject
* value
,
4168 OSDictionary
* table
)
4170 OSDictionary
* properties
;
4172 properties
= OSDictionary::withCapacity( 2 );
4175 properties
->setObject( key
, value
);
4178 table
= OSDictionary::withCapacity( 2 );
4180 table
->setObject( gIOPropertyMatchKey
, properties
);
4182 properties
->release();
4187 OSDictionary
* IOService::registryEntryIDMatching( uint64_t entryID
,
4188 OSDictionary
* table
)
4192 num
= OSNumber::withNumber( entryID
, 64 );
4197 table
= OSDictionary::withCapacity( 2 );
4199 table
->setObject( gIORegistryEntryIDKey
, num
);
4209 * _IOServiceNotifier
4212 // wait for all threads, other than the current one,
4213 // to exit the handler
4215 void _IOServiceNotifier::wait()
4217 _IOServiceNotifierInvocation
* next
;
4222 queue_iterate( &handlerInvocations
, next
,
4223 _IOServiceNotifierInvocation
*, link
) {
4224 if( next
->thread
!= current_thread() ) {
4230 state
|= kIOServiceNotifyWaiter
;
4237 void _IOServiceNotifier::free()
4239 assert( queue_empty( &handlerInvocations
));
4243 void _IOServiceNotifier::remove()
4248 whence
->removeObject( (OSObject
*) this );
4252 matching
->release();
4256 state
&= ~kIOServiceNotifyEnable
;
4265 bool _IOServiceNotifier::disable()
4271 ret
= (0 != (kIOServiceNotifyEnable
& state
));
4272 state
&= ~kIOServiceNotifyEnable
;
4281 void _IOServiceNotifier::enable( bool was
)
4285 state
|= kIOServiceNotifyEnable
;
4287 state
&= ~kIOServiceNotifyEnable
;
4295 IOService
* IOResources::resources( void )
4299 inst
= new IOResources
;
4300 if( inst
&& !inst
->init()) {
4308 bool IOResources::init( OSDictionary
* dictionary
)
4310 // Do super init first
4311 if ( !super::init() )
4314 // Allow PAL layer to publish a value
4315 const char *property_name
;
4318 pal_get_resource_property( &property_name
, &property_value
);
4320 if( property_name
) {
4322 const OSSymbol
* sym
;
4324 if( (num
= OSNumber::withNumber(property_value
, 32)) != 0 ) {
4325 if( (sym
= OSSymbol::withCString( property_name
)) != 0 ) {
4326 this->setProperty( sym
, num
);
4336 IOWorkLoop
* IOResources::getWorkLoop() const
4338 // If we are the resource root
4339 // then use the platform's workloop
4340 if (this == (IOResources
*) gIOResources
)
4341 return getPlatform()->getWorkLoop();
4343 return IOService::getWorkLoop();
4346 bool IOResources::matchPropertyTable( OSDictionary
* table
)
4354 prop
= table
->getObject( gIOResourceMatchKey
);
4355 str
= OSDynamicCast( OSString
, prop
);
4357 ok
= (0 != getProperty( str
));
4359 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
4361 iter
= OSCollectionIterator::withCollection( set
);
4363 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
4364 ok
= (0 != getProperty( str
));
4373 void IOService::consoleLockTimer(thread_call_param_t p0
, thread_call_param_t p1
)
4375 IOService::updateConsoleUsers(NULL
, 0);
4378 void IOService::updateConsoleUsers(OSArray
* consoleUsers
, IOMessage systemMessage
)
4380 IORegistryEntry
* regEntry
;
4381 OSObject
* locked
= kOSBooleanFalse
;
4384 OSDictionary
* user
;
4385 static IOMessage sSystemPower
;
4387 regEntry
= IORegistryEntry::getRegistryRoot();
4389 if (!gIOChosenEntry
)
4390 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
4392 IOLockLock(gIOConsoleUsersLock
);
4396 sSystemPower
= systemMessage
;
4398 if ((kIOMessageSystemHasPoweredOn
== systemMessage
) && IOHibernateWasScreenLocked())
4400 locked
= kOSBooleanTrue
;
4402 #endif /* HIBERNATION */
4408 gIOConsoleLoggedIn
= false;
4410 (user
= OSDynamicCast(OSDictionary
, consoleUsers
->getObject(idx
)));
4413 gIOConsoleLoggedIn
|= ((kOSBooleanTrue
== user
->getObject(gIOConsoleSessionOnConsoleKey
))
4414 && (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionLoginDoneKey
)));
4417 num
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionScreenLockedTimeKey
));
4420 gIOConsoleLockTime
= num
? num
->unsigned32BitValue() : 0;
4423 if (!gIOConsoleLoggedIn
4424 || (kIOMessageSystemWillSleep
== sSystemPower
)
4425 || (kIOMessageSystemPagingOff
== sSystemPower
))
4427 locked
= kOSBooleanTrue
;
4429 else if (gIOConsoleLockTime
)
4432 clock_usec_t microsecs
;
4434 clock_get_calendar_microtime(&now
, µsecs
);
4435 if (gIOConsoleLockTime
> now
)
4437 AbsoluteTime deadline
;
4438 clock_interval_to_deadline(gIOConsoleLockTime
- now
, kSecondScale
, &deadline
);
4439 thread_call_enter_delayed(gIOConsoleLockCallout
, deadline
);
4443 locked
= kOSBooleanTrue
;
4447 publish
= (consoleUsers
|| (locked
!= regEntry
->getProperty(gIOConsoleLockedKey
)));
4450 regEntry
->setProperty(gIOConsoleLockedKey
, locked
);
4453 regEntry
->setProperty(gIOConsoleUsersKey
, consoleUsers
);
4455 OSIncrementAtomic( &gIOConsoleUsersSeed
);
4461 uint32_t screenLockState
;
4463 if (locked
== kOSBooleanTrue
) screenLockState
= kIOScreenLockLocked
;
4464 else if (gIOConsoleLockTime
) screenLockState
= kIOScreenLockUnlocked
;
4465 else screenLockState
= kIOScreenLockNoLock
;
4467 if (screenLockState
!= gIOScreenLockState
) gIOChosenEntry
->setProperty(kIOScreenLockStateKey
, &screenLockState
, sizeof(screenLockState
));
4468 gIOScreenLockState
= screenLockState
;
4470 #endif /* HIBERNATION */
4472 IOLockUnlock(gIOConsoleUsersLock
);
4476 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
4478 MessageClientsContext context
;
4480 context
.service
= getServiceRoot();
4481 context
.type
= kIOMessageConsoleSecurityChange
;
4482 context
.argument
= (void *) regEntry
;
4483 context
.argSize
= 0;
4485 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest
,
4486 &messageClientsApplier
, &context
);
4490 IOReturn
IOResources::setProperties( OSObject
* properties
)
4493 const OSSymbol
* key
;
4494 OSDictionary
* dict
;
4495 OSCollectionIterator
* iter
;
4497 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
4498 if ( kIOReturnSuccess
!= err
)
4501 dict
= OSDynamicCast(OSDictionary
, properties
);
4503 return( kIOReturnBadArgument
);
4505 iter
= OSCollectionIterator::withCollection( dict
);
4507 return( kIOReturnBadArgument
);
4509 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
4511 if (gIOConsoleUsersKey
== key
) do
4513 OSArray
* consoleUsers
;
4514 consoleUsers
= OSDynamicCast(OSArray
, dict
->getObject(key
));
4517 IOService::updateConsoleUsers(consoleUsers
, 0);
4521 publishResource( key
, dict
->getObject(key
) );
4526 return( kIOReturnSuccess
);
4530 * Helpers for matching dictionaries.
4531 * Keys existing in matching are checked in properties.
4532 * Keys may be a string or OSCollection of IOStrings
4535 bool IOService::compareProperty( OSDictionary
* matching
,
4541 value
= matching
->getObject( key
);
4543 ok
= value
->isEqualTo( getProperty( key
));
4551 bool IOService::compareProperty( OSDictionary
* matching
,
4552 const OSString
* key
)
4557 value
= matching
->getObject( key
);
4559 ok
= value
->isEqualTo( getProperty( key
));
4566 bool IOService::compareProperties( OSDictionary
* matching
,
4567 OSCollection
* keys
)
4569 OSCollectionIterator
* iter
;
4570 const OSString
* key
;
4573 if( !matching
|| !keys
)
4576 iter
= OSCollectionIterator::withCollection( keys
);
4579 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
4580 ok
= compareProperty( matching
, key
);
4584 keys
->release(); // !! consume a ref !!
4589 /* Helper to add a location matching dict to the table */
4591 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
4593 OSDictionary
* dict
;
4598 dict
= OSDictionary::withCapacity( 1 );
4600 table
->setObject( gIOLocationMatchKey
, dict
);
4608 * Go looking for a provider to match a location dict.
4611 IOService
* IOService::matchLocation( IOService
* /* client */ )
4615 parent
= getProvider();
4618 parent
= parent
->matchLocation( this );
4623 bool IOService::matchInternal(OSDictionary
* table
, uint32_t options
, uint32_t * did
)
4628 IORegistryEntry
* entry
;
4631 bool changesOK
= (0 != (kIOServiceChangesOK
& options
));
4637 count
= table
->getCount();
4639 str
= OSDynamicCast(OSString
, table
->getObject(gIOProviderClassKey
));
4642 match
= ((kIOServiceClassDone
& options
) || (0 != metaCast(str
)));
4644 match
= (0 != metaCast( str
));
4645 if ((kIOServiceClassDone
& options
) && !match
) panic("classDone");
4647 if ((!match
) || (done
== count
)) break;
4650 obj
= table
->getObject( gIONameMatchKey
);
4653 match
= compareNames( obj
, changesOK
? &matched
: 0 );
4655 if( changesOK
&& matched
) {
4656 // leave a hint as to which name matched
4657 table
->setObject( gIONameMatchedKey
, matched
);
4660 if (done
== count
) break;
4663 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
4666 const OSSymbol
* sym
;
4669 sym
= copyLocation();
4671 match
= sym
->isEqualTo( str
);
4674 if ((!match
) || (done
== count
)) break;
4677 obj
= table
->getObject( gIOPropertyMatchKey
);
4680 OSDictionary
* dict
;
4681 OSDictionary
* nextDict
;
4685 dict
= dictionaryWithProperties();
4687 nextDict
= OSDynamicCast( OSDictionary
, obj
);
4691 iter
= OSCollectionIterator::withCollection(
4692 OSDynamicCast(OSCollection
, obj
));
4695 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
4696 iter
->getNextObject()))))) {
4697 match
= dict
->isEqualTo( nextDict
, nextDict
);
4706 if ((!match
) || (done
== count
)) break;
4709 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
4712 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
4713 match
= (this == entry
);
4716 if ((!match
) || (done
== count
)) break;
4719 num
= OSDynamicCast( OSNumber
, table
->getObject( gIORegistryEntryIDKey
));
4722 match
= (getRegistryEntryID() == num
->unsigned64BitValue());
4723 if ((!match
) || (done
== count
)) break;
4726 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
4730 IOService
* service
= 0;
4731 UInt32 serviceCount
= 0;
4734 iter
= getClientIterator();
4736 while( (service
= (IOService
*) iter
->getNextObject())) {
4737 if( kIOServiceInactiveState
& service
->__state
[0])
4739 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
4745 match
= (serviceCount
== num
->unsigned32BitValue());
4746 if ((!match
) || (done
== count
)) break;
4749 #define propMatch(key) \
4750 obj = table->getObject(key); \
4755 prop = copyProperty(key); \
4756 match = obj->isEqualTo(prop); \
4757 if (prop) prop->release(); \
4758 if ((!match) || (done == count)) break; \
4760 propMatch(kIOBSDNameKey
)
4761 propMatch(kIOBSDMajorKey
)
4762 propMatch(kIOBSDMinorKey
)
4763 propMatch(kIOBSDUnitKey
)
4768 if (did
) *did
= done
;
4772 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
4774 return (matchPassive(table
, changesOK
? kIOServiceChangesOK
: 0));
4777 bool IOService::matchPassive(OSDictionary
* table
, uint32_t options
)
4780 OSDictionary
* nextTable
;
4784 bool matchParent
= false;
4791 OSDictionary
* root
= table
;
4799 count
= table
->getCount();
4800 if (!(kIOServiceInternalDone
& options
))
4802 match
= where
->matchInternal(table
, options
, &done
);
4803 // don't call family if we've done all the entries in the table
4804 if ((!match
) || (done
== count
)) break;
4807 // pass in score from property table
4808 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
4810 // do family specific matching
4811 match
= where
->matchPropertyTable( table
, &score
);
4815 if( kIOLogMatch
& getDebugFlags( table
))
4816 LOG("%s: family specific matching fails\n", where
->getName());
4821 if (kIOServiceChangesOK
& options
) {
4823 newPri
= OSNumber::withNumber( score
, 32 );
4825 table
->setObject( gIOProbeScoreKey
, newPri
);
4831 matchParent
= false;
4833 nextTable
= OSDynamicCast(OSDictionary
,
4834 table
->getObject( gIOParentMatchKey
));
4836 // look for a matching entry anywhere up to root
4843 table
= OSDynamicCast(OSDictionary
,
4844 table
->getObject( gIOLocationMatchKey
));
4846 // look for a matching entry at matchLocation()
4848 where
= where
->getProvider();
4849 if (where
&& (where
= where
->matchLocation(where
))) continue;
4855 while( matchParent
&& (!match
) && (where
= where
->getProvider()) );
4860 OSSerialize
* s
= OSSerialize::withCapacity(128);
4862 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match
, s
->text());
4871 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4872 UInt32 type
, OSDictionary
* properties
,
4873 IOUserClient
** handler
)
4875 const OSSymbol
*userClientClass
= 0;
4876 IOUserClient
*client
;
4879 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
))
4880 return kIOReturnSuccess
;
4882 // First try my own properties for a user client class name
4883 temp
= getProperty(gIOUserClientClassKey
);
4885 if (OSDynamicCast(OSSymbol
, temp
))
4886 userClientClass
= (const OSSymbol
*) temp
;
4887 else if (OSDynamicCast(OSString
, temp
)) {
4888 userClientClass
= OSSymbol::withString((OSString
*) temp
);
4889 if (userClientClass
)
4890 setProperty(kIOUserClientClassKey
,
4891 (OSObject
*) userClientClass
);
4895 // Didn't find one so lets just bomb out now without further ado.
4896 if (!userClientClass
)
4897 return kIOReturnUnsupported
;
4899 // This reference is consumed by the IOServiceOpen call
4900 temp
= OSMetaClass::allocClassWithName(userClientClass
);
4902 return kIOReturnNoMemory
;
4904 if (OSDynamicCast(IOUserClient
, temp
))
4905 client
= (IOUserClient
*) temp
;
4908 return kIOReturnUnsupported
;
4911 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
4913 return kIOReturnBadArgument
;
4916 if ( !client
->attach(this) ) {
4918 return kIOReturnUnsupported
;
4921 if ( !client
->start(this) ) {
4922 client
->detach(this);
4924 return kIOReturnUnsupported
;
4928 return kIOReturnSuccess
;
4931 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4932 UInt32 type
, IOUserClient
** handler
)
4934 return( kIOReturnUnsupported
);
4937 IOReturn
IOService::requestProbe( IOOptionBits options
)
4939 return( kIOReturnUnsupported
);
4943 * Convert an IOReturn to text. Subclasses which add additional
4944 * IOReturn's should override this method and call
4945 * super::stringFromReturn if the desired value is not found.
4948 const char * IOService::stringFromReturn( IOReturn rtn
)
4950 static const IONamedValue IOReturn_values
[] = {
4951 {kIOReturnSuccess
, "success" },
4952 {kIOReturnError
, "general error" },
4953 {kIOReturnNoMemory
, "memory allocation error" },
4954 {kIOReturnNoResources
, "resource shortage" },
4955 {kIOReturnIPCError
, "Mach IPC failure" },
4956 {kIOReturnNoDevice
, "no such device" },
4957 {kIOReturnNotPrivileged
, "privilege violation" },
4958 {kIOReturnBadArgument
, "invalid argument" },
4959 {kIOReturnLockedRead
, "device is read locked" },
4960 {kIOReturnLockedWrite
, "device is write locked" },
4961 {kIOReturnExclusiveAccess
, "device is exclusive access" },
4962 {kIOReturnBadMessageID
, "bad IPC message ID" },
4963 {kIOReturnUnsupported
, "unsupported function" },
4964 {kIOReturnVMError
, "virtual memory error" },
4965 {kIOReturnInternalError
, "internal driver error" },
4966 {kIOReturnIOError
, "I/O error" },
4967 {kIOReturnCannotLock
, "cannot acquire lock" },
4968 {kIOReturnNotOpen
, "device is not open" },
4969 {kIOReturnNotReadable
, "device is not readable" },
4970 {kIOReturnNotWritable
, "device is not writeable" },
4971 {kIOReturnNotAligned
, "alignment error" },
4972 {kIOReturnBadMedia
, "media error" },
4973 {kIOReturnStillOpen
, "device is still open" },
4974 {kIOReturnRLDError
, "rld failure" },
4975 {kIOReturnDMAError
, "DMA failure" },
4976 {kIOReturnBusy
, "device is busy" },
4977 {kIOReturnTimeout
, "I/O timeout" },
4978 {kIOReturnOffline
, "device is offline" },
4979 {kIOReturnNotReady
, "device is not ready" },
4980 {kIOReturnNotAttached
, "device/channel is not attached" },
4981 {kIOReturnNoChannels
, "no DMA channels available" },
4982 {kIOReturnNoSpace
, "no space for data" },
4983 {kIOReturnPortExists
, "device port already exists" },
4984 {kIOReturnCannotWire
, "cannot wire physical memory" },
4985 {kIOReturnNoInterrupt
, "no interrupt attached" },
4986 {kIOReturnNoFrames
, "no DMA frames enqueued" },
4987 {kIOReturnMessageTooLarge
, "message is too large" },
4988 {kIOReturnNotPermitted
, "operation is not permitted" },
4989 {kIOReturnNoPower
, "device is without power" },
4990 {kIOReturnNoMedia
, "media is not present" },
4991 {kIOReturnUnformattedMedia
, "media is not formatted" },
4992 {kIOReturnUnsupportedMode
, "unsupported mode" },
4993 {kIOReturnUnderrun
, "data underrun" },
4994 {kIOReturnOverrun
, "data overrun" },
4995 {kIOReturnDeviceError
, "device error" },
4996 {kIOReturnNoCompletion
, "no completion routine" },
4997 {kIOReturnAborted
, "operation was aborted" },
4998 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
4999 {kIOReturnNotResponding
, "device is not responding" },
5000 {kIOReturnInvalid
, "unanticipated driver error" },
5004 return IOFindNameForValue(rtn
, IOReturn_values
);
5008 * Convert an IOReturn to an errno.
5010 int IOService::errnoFromReturn( IOReturn rtn
)
5014 case kIOReturnSuccess
:
5016 case kIOReturnNoMemory
:
5018 case kIOReturnNoDevice
:
5020 case kIOReturnVMError
:
5022 case kIOReturnNotPermitted
:
5024 case kIOReturnNotPrivileged
:
5026 case kIOReturnIOError
:
5028 case kIOReturnNotWritable
:
5030 case kIOReturnBadArgument
:
5032 case kIOReturnUnsupported
:
5036 case kIOReturnNoPower
:
5038 case kIOReturnDeviceError
:
5040 case kIOReturnTimeout
:
5042 case kIOReturnMessageTooLarge
:
5044 case kIOReturnNoSpace
:
5046 case kIOReturnCannotLock
:
5050 case kIOReturnBadMessageID
:
5051 case kIOReturnNoCompletion
:
5052 case kIOReturnNotAligned
:
5054 case kIOReturnNotReady
:
5056 case kIOReturnRLDError
:
5058 case kIOReturnPortExists
:
5059 case kIOReturnStillOpen
:
5061 case kIOReturnExclusiveAccess
:
5062 case kIOReturnLockedRead
:
5063 case kIOReturnLockedWrite
:
5064 case kIOReturnNotOpen
:
5065 case kIOReturnNotReadable
:
5067 case kIOReturnCannotWire
:
5068 case kIOReturnNoResources
:
5070 case kIOReturnAborted
:
5071 case kIOReturnOffline
:
5072 case kIOReturnNotResponding
:
5074 case kIOReturnBadMedia
:
5075 case kIOReturnNoMedia
:
5076 case kIOReturnNotAttached
:
5077 case kIOReturnUnformattedMedia
:
5078 return(ENXIO
); // (media error)
5079 case kIOReturnDMAError
:
5080 case kIOReturnOverrun
:
5081 case kIOReturnUnderrun
:
5082 return(EIO
); // (transfer error)
5083 case kIOReturnNoBandwidth
:
5084 case kIOReturnNoChannels
:
5085 case kIOReturnNoFrames
:
5086 case kIOReturnNoInterrupt
:
5087 return(EIO
); // (hardware error)
5088 case kIOReturnError
:
5089 case kIOReturnInternalError
:
5090 case kIOReturnInvalid
:
5091 return(EIO
); // (generic error)
5092 case kIOReturnIPCError
:
5093 return(EIO
); // (ipc error)
5095 return(EIO
); // (all other errors)
5099 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
5103 * Generic entry point for calls from the provider. A return value of
5104 * kIOReturnSuccess indicates that the message was received, and where
5105 * applicable, that it was successful.
5108 return kIOReturnUnsupported
;
5115 IOItemCount
IOService::getDeviceMemoryCount( void )
5120 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
5122 count
= array
->getCount();
5129 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
5132 IODeviceMemory
* range
;
5134 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
5136 range
= (IODeviceMemory
*) array
->getObject( index
);
5143 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
5144 IOOptionBits options
)
5146 IODeviceMemory
* range
;
5149 range
= getDeviceMemoryWithIndex( index
);
5151 map
= range
->map( options
);
5158 OSArray
* IOService::getDeviceMemory( void )
5160 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
5164 void IOService::setDeviceMemory( OSArray
* array
)
5166 setProperty( gIODeviceMemoryKey
, array
);
5170 * For machines where the transfers on an I/O bus can stall because
5171 * the CPU is in an idle mode, These APIs allow a driver to specify
5172 * the maximum bus stall that they can handle. 0 indicates no limit.
5175 setCPUSnoopDelay(UInt32 __unused ns
)
5177 #if defined(__i386__) || defined(__x86_64__)
5178 ml_set_maxsnoop(ns
);
5179 #endif /* defined(__i386__) || defined(__x86_64__) */
5185 #if defined(__i386__) || defined(__x86_64__)
5186 return ml_get_maxsnoop();
5189 #endif /* defined(__i386__) || defined(__x86_64__) */
5192 #if defined(__i386__) || defined(__x86_64__)
5194 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
)
5196 static const UInt kNoReplace
= -1U; // Must be an illegal index
5197 UInt replace
= kNoReplace
;
5198 bool setCpuDelay
= false;
5200 IORecursiveLockLock(sCpuDelayLock
);
5202 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
5203 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
5204 IOService
* holder
= NULL
;
5207 const CpuDelayEntry ne
= {service
, ns
, delayType
};
5209 // Set maximum delay.
5210 for (UInt i
= 0; i
< count
; i
++) {
5211 IOService
*thisService
= entries
[i
].fService
;
5212 bool sameType
= (delayType
== entries
[i
].fDelayType
);
5213 if ((service
== thisService
) && sameType
)
5215 else if (!thisService
) {
5216 if (kNoReplace
== replace
)
5219 else if (sameType
) {
5220 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
5224 holder
= thisService
;
5230 if (kNoReplace
== replace
)
5231 sCpuDelayData
->appendBytes(&ne
, sizeof(ne
));
5233 entries
[replace
] = ne
;
5236 ns
= -1U; // Set to max unsigned, i.e. no restriction
5238 for (UInt i
= 0; i
< count
; i
++) {
5239 // Clear a maximum delay.
5240 IOService
*thisService
= entries
[i
].fService
;
5241 if (thisService
&& (delayType
== entries
[i
].fDelayType
)) {
5242 UInt32 thisMax
= entries
[i
].fMaxDelay
;
5243 if (service
== thisService
)
5245 else if (thisMax
< ns
) {
5247 holder
= thisService
;
5252 // Check if entry found
5253 if (kNoReplace
!= replace
) {
5254 entries
[replace
].fService
= 0; // Null the entry
5261 // Must be safe to call from locked context
5262 if (delayType
== kCpuDelayBusStall
)
5264 ml_set_maxbusdelay(ns
);
5266 else if (delayType
== kCpuDelayInterrupt
)
5268 ml_set_maxintdelay(ns
);
5271 OSArray
* handlers
= sCpuLatencyHandlers
[delayType
];
5273 if (handlers
) for (unsigned int idx
= 0;
5274 (target
= (IOService
*) handlers
->getObject(idx
));
5277 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
5278 (void *) (uintptr_t) ns
, holder
,
5283 IORecursiveLockUnlock(sCpuDelayLock
);
5287 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
)
5289 IOReturn result
= kIOReturnNotFound
;
5293 IORecursiveLockLock(sCpuDelayLock
);
5297 if (enable
&& !sCpuLatencyHandlers
[delayType
])
5298 sCpuLatencyHandlers
[delayType
] = OSArray::withCapacity(4);
5299 array
= sCpuLatencyHandlers
[delayType
];
5302 idx
= array
->getNextIndexOfObject(target
, 0);
5307 array
->removeObject(idx
);
5308 result
= kIOReturnSuccess
;
5314 result
= kIOReturnExclusiveAccess
;
5317 array
->setObject(target
);
5319 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
5320 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
5321 UInt32 ns
= -1U; // Set to max unsigned, i.e. no restriction
5322 IOService
* holder
= NULL
;
5324 for (UInt i
= 0; i
< count
; i
++) {
5325 if (entries
[i
].fService
5326 && (delayType
== entries
[i
].fDelayType
)
5327 && (entries
[i
].fMaxDelay
< ns
)) {
5328 ns
= entries
[i
].fMaxDelay
;
5329 holder
= entries
[i
].fService
;
5332 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
5333 (void *) (uintptr_t) ns
, holder
,
5335 result
= kIOReturnSuccess
;
5340 IORecursiveLockUnlock(sCpuDelayLock
);
5345 #endif /* defined(__i386__) || defined(__x86_64__) */
5348 requireMaxBusStall(UInt32 __unused ns
)
5350 #if defined(__i386__) || defined(__x86_64__)
5351 requireMaxCpuDelay(this, ns
, kCpuDelayBusStall
);
5356 requireMaxInterruptDelay(uint32_t __unused ns
)
5358 #if defined(__i386__) || defined(__x86_64__)
5359 requireMaxCpuDelay(this, ns
, kCpuDelayInterrupt
);
5367 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
5369 IOInterruptController
*interruptController
;
5372 OSSymbol
*interruptControllerName
;
5374 IOInterruptSource
*interruptSources
;
5376 // Get the parents list from the nub.
5377 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
5378 if (array
== 0) return kIOReturnNoResources
;
5380 // Allocate space for the IOInterruptSources if needed... then return early.
5381 if (nub
->_interruptSources
== 0) {
5382 numSources
= array
->getCount();
5383 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
5384 if (interruptSources
== 0) return kIOReturnNoMemory
;
5386 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
5388 nub
->_numInterruptSources
= numSources
;
5389 nub
->_interruptSources
= interruptSources
;
5390 return kIOReturnSuccess
;
5393 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
5394 if (interruptControllerName
== 0) return kIOReturnNoResources
;
5396 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
5397 if (interruptController
== 0) return kIOReturnNoResources
;
5399 // Get the interrupt numbers from the nub.
5400 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
5401 if (array
== 0) return kIOReturnNoResources
;
5402 data
= OSDynamicCast(OSData
, array
->getObject(source
));
5403 if (data
== 0) return kIOReturnNoResources
;
5405 // Set the interruptController and interruptSource in the nub's table.
5406 interruptSources
= nub
->_interruptSources
;
5407 interruptSources
[source
].interruptController
= interruptController
;
5408 interruptSources
[source
].vectorData
= data
;
5410 return kIOReturnSuccess
;
5413 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
5417 /* Make sure the _interruptSources are set */
5418 if (_interruptSources
== 0) {
5419 ret
= resolveInterrupt(this, source
);
5420 if (ret
!= kIOReturnSuccess
) return ret
;
5423 /* Make sure the local source number is valid */
5424 if ((source
< 0) || (source
>= _numInterruptSources
))
5425 return kIOReturnNoInterrupt
;
5427 /* Look up the contoller for the local source */
5428 *interruptController
= _interruptSources
[source
].interruptController
;
5430 if (*interruptController
== NULL
) {
5431 if (!resolve
) return kIOReturnNoInterrupt
;
5433 /* Try to reslove the interrupt */
5434 ret
= resolveInterrupt(this, source
);
5435 if (ret
!= kIOReturnSuccess
) return ret
;
5437 *interruptController
= _interruptSources
[source
].interruptController
;
5440 return kIOReturnSuccess
;
5443 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
5444 IOInterruptAction handler
,
5447 IOInterruptController
*interruptController
;
5450 ret
= lookupInterrupt(source
, true, &interruptController
);
5451 if (ret
!= kIOReturnSuccess
) return ret
;
5453 /* Register the source */
5454 return interruptController
->registerInterrupt(this, source
, target
,
5455 (IOInterruptHandler
)handler
,
5459 IOReturn
IOService::unregisterInterrupt(int source
)
5461 IOInterruptController
*interruptController
;
5464 ret
= lookupInterrupt(source
, false, &interruptController
);
5465 if (ret
!= kIOReturnSuccess
) return ret
;
5467 /* Unregister the source */
5468 return interruptController
->unregisterInterrupt(this, source
);
5471 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
5473 IOInterruptController
*interruptController
;
5476 ret
= lookupInterrupt(source
, true, &interruptController
);
5477 if (ret
!= kIOReturnSuccess
) return ret
;
5479 /* Return the type */
5480 return interruptController
->getInterruptType(this, source
, interruptType
);
5483 IOReturn
IOService::enableInterrupt(int source
)
5485 IOInterruptController
*interruptController
;
5488 ret
= lookupInterrupt(source
, false, &interruptController
);
5489 if (ret
!= kIOReturnSuccess
) return ret
;
5491 /* Enable the source */
5492 return interruptController
->enableInterrupt(this, source
);
5495 IOReturn
IOService::disableInterrupt(int source
)
5497 IOInterruptController
*interruptController
;
5500 ret
= lookupInterrupt(source
, false, &interruptController
);
5501 if (ret
!= kIOReturnSuccess
) return ret
;
5503 /* Disable the source */
5504 return interruptController
->disableInterrupt(this, source
);
5507 IOReturn
IOService::causeInterrupt(int source
)
5509 IOInterruptController
*interruptController
;
5512 ret
= lookupInterrupt(source
, false, &interruptController
);
5513 if (ret
!= kIOReturnSuccess
) return ret
;
5515 /* Cause an interrupt for the source */
5516 return interruptController
->causeInterrupt(this, source
);
5520 OSMetaClassDefineReservedUnused(IOService
, 0);
5521 OSMetaClassDefineReservedUnused(IOService
, 1);
5522 OSMetaClassDefineReservedUnused(IOService
, 2);
5523 OSMetaClassDefineReservedUnused(IOService
, 3);
5524 OSMetaClassDefineReservedUnused(IOService
, 4);
5525 OSMetaClassDefineReservedUnused(IOService
, 5);
5527 OSMetaClassDefineReservedUsed(IOService
, 0);
5528 OSMetaClassDefineReservedUsed(IOService
, 1);
5529 OSMetaClassDefineReservedUsed(IOService
, 2);
5530 OSMetaClassDefineReservedUsed(IOService
, 3);
5531 OSMetaClassDefineReservedUsed(IOService
, 4);
5532 OSMetaClassDefineReservedUsed(IOService
, 5);
5534 OSMetaClassDefineReservedUnused(IOService
, 6);
5535 OSMetaClassDefineReservedUnused(IOService
, 7);
5536 OSMetaClassDefineReservedUnused(IOService
, 8);
5537 OSMetaClassDefineReservedUnused(IOService
, 9);
5538 OSMetaClassDefineReservedUnused(IOService
, 10);
5539 OSMetaClassDefineReservedUnused(IOService
, 11);
5540 OSMetaClassDefineReservedUnused(IOService
, 12);
5541 OSMetaClassDefineReservedUnused(IOService
, 13);
5542 OSMetaClassDefineReservedUnused(IOService
, 14);
5543 OSMetaClassDefineReservedUnused(IOService
, 15);
5544 OSMetaClassDefineReservedUnused(IOService
, 16);
5545 OSMetaClassDefineReservedUnused(IOService
, 17);
5546 OSMetaClassDefineReservedUnused(IOService
, 18);
5547 OSMetaClassDefineReservedUnused(IOService
, 19);
5548 OSMetaClassDefineReservedUnused(IOService
, 20);
5549 OSMetaClassDefineReservedUnused(IOService
, 21);
5550 OSMetaClassDefineReservedUnused(IOService
, 22);
5551 OSMetaClassDefineReservedUnused(IOService
, 23);
5552 OSMetaClassDefineReservedUnused(IOService
, 24);
5553 OSMetaClassDefineReservedUnused(IOService
, 25);
5554 OSMetaClassDefineReservedUnused(IOService
, 26);
5555 OSMetaClassDefineReservedUnused(IOService
, 27);
5556 OSMetaClassDefineReservedUnused(IOService
, 28);
5557 OSMetaClassDefineReservedUnused(IOService
, 29);
5558 OSMetaClassDefineReservedUnused(IOService
, 30);
5559 OSMetaClassDefineReservedUnused(IOService
, 31);
5560 OSMetaClassDefineReservedUnused(IOService
, 32);
5561 OSMetaClassDefineReservedUnused(IOService
, 33);
5562 OSMetaClassDefineReservedUnused(IOService
, 34);
5563 OSMetaClassDefineReservedUnused(IOService
, 35);
5564 OSMetaClassDefineReservedUnused(IOService
, 36);
5565 OSMetaClassDefineReservedUnused(IOService
, 37);
5566 OSMetaClassDefineReservedUnused(IOService
, 38);
5567 OSMetaClassDefineReservedUnused(IOService
, 39);
5568 OSMetaClassDefineReservedUnused(IOService
, 40);
5569 OSMetaClassDefineReservedUnused(IOService
, 41);
5570 OSMetaClassDefineReservedUnused(IOService
, 42);
5571 OSMetaClassDefineReservedUnused(IOService
, 43);
5572 OSMetaClassDefineReservedUnused(IOService
, 44);
5573 OSMetaClassDefineReservedUnused(IOService
, 45);
5574 OSMetaClassDefineReservedUnused(IOService
, 46);
5575 OSMetaClassDefineReservedUnused(IOService
, 47);